diff --git a/.gitignore b/.gitignore index ed1b5fa..d97e679 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,4 @@ session.key salt.key config.json commands/admin/bomb.js +commands/mod/uwuify.js diff --git a/client/client.js b/client/client.js index 0e2dbed..bcbf967 100644 --- a/client/client.js +++ b/client/client.js @@ -548,7 +548,7 @@ var COMMANDS = { nickSpan.appendChild(nickLink); messageDom.appendChild(nickSpan); - + var textEl = document.createElement('p'); textEl.classList.add('text'); diff --git a/client/schemes/carrot.css b/client/schemes/carrot.css index 8419df2..8a4448e 100644 --- a/client/schemes/carrot.css +++ b/client/schemes/carrot.css @@ -6,7 +6,7 @@ input, textarea { color: #ee600d; } - + .message { border-left: 1px solid #ee600d; } @@ -39,17 +39,16 @@ textarea { .warn .text { color: #ffbb00; } - + #footer { background: #000000; } - + #sidebar { background: #000000; border-color: #000000; } - + #chatform { border-color: #ee600d; } - diff --git a/client/schemes/fried-egg.css b/client/schemes/fried-egg.css index d86f606..e7fbaa1 100644 --- a/client/schemes/fried-egg.css +++ b/client/schemes/fried-egg.css @@ -33,7 +33,7 @@ textarea { .info .nick, .info .text { color: #a37939; -} +} .warn .nick, .warn .text { color: #ff0000; diff --git a/commands/admin/addmod.js b/commands/admin/addmod.js index e93d59d..139abdf 100644 --- a/commands/admin/addmod.js +++ b/commands/admin/addmod.js @@ -1,11 +1,17 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Create a new mod trip - * @version 1.0.0 + * @version 1.1.0 * @description Adds target trip to the config as a mod and upgrades the socket type * @module addmod */ +import { + Info, +} from '../utility/_Constants.js'; +import { + legacyLevelToLabel, +} from '../utility/_LegacyFunctions.js'; import { isAdmin, isModerator, @@ -41,22 +47,23 @@ export async function run({ ...getUserDetails(newMod[0]), ...{ cmd: 'updateUser', - uType: 'mod', // @todo use legacyLevelToLabel from _LegacyFunctions.js + uType: legacyLevelToLabel(levels.moderator), level: levels.moderator, }, }; for (let i = 0, l = newMod.length; i < l; i += 1) { // upgrade privileges - newMod[i].uType = 'mod'; // @todo use legacyLevelToLabel from _LegacyFunctions.js + newMod[i].uType = legacyLevelToLabel(levels.moderator); newMod[i].level = levels.moderator; newMod[i].color = color; newMod[i].flair = flair; // inform new mod server.send({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'You are now a mod.', + id: Info.Admin.YOU_ARE_MOD, channel: newMod[i].channel, // @todo Multichannel }, newMod[i]); @@ -72,15 +79,17 @@ export async function run({ // return success message server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Added mod trip: ${payload.trip}, remember to run 'saveconfig' to make it permanent`, + id: Info.Admin.MOD_ADDED, channel: socket.channel, // @todo Multichannel }, socket); // notify all mods server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Added mod: ${payload.trip}`, + id: Info.Admin.MOD_ADDED_BROADCAST, channel: false, // @todo Multichannel, false for global info }, { level: isModerator }); diff --git a/commands/admin/listusers.js b/commands/admin/listusers.js index 759733b..6baf361 100644 --- a/commands/admin/listusers.js +++ b/commands/admin/listusers.js @@ -5,11 +5,14 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Show users and channels - * @version 1.0.0 + * @version 1.1.0 * @description Outputs all current channels and sockets in those channels * @module listusers */ +import { + Info, +} from '../utility/_Constants.js'; import { isAdmin, } from '../utility/_UAC.js'; @@ -28,31 +31,51 @@ export async function run({ server, socket }) { // find all users currently in a channel const currentUsers = server.findSockets({ - channel: (channel) => true, + channel: () => true, }); - // compile channel and user list const channels = {}; for (let i = 0, j = currentUsers.length; i < j; i += 1) { - if (typeof channels[currentUsers[i].channel] === 'undefined') { - channels[currentUsers[i].channel] = []; + const user = currentUsers[i]; + if (typeof channels[user.channel] === 'undefined') { + channels[user.channel] = []; } - channels[currentUsers[i].channel].push( - `[${currentUsers[i].trip || 'null'}]${currentUsers[i].nick}`, - ); + channels[user.channel].push(user); } - // build output - const lines = []; - for (const channel in channels) { - lines.push(`?${channel} ${channels[channel].join(', ')}`); + const channelList = Object.keys(channels).map((name) => ({ + name, + users: channels[name], + count: channels[name].length, + })); + + channelList.sort((a, b) => b.count - a.count); + + let reply = '| Channel | Trip | Nick | Hash |\n'; + reply += '| :--- | :--- | :--- | :--- |\n'; + + for (let i = 0; i < channelList.length; i += 1) { + const { name, users } = channelList[i]; + + for (let k = 0; k < users.length; k += 1) { + const u = users[k]; + const trip = u.trip || '(none)'; + const hash = u.hash || '???'; + + reply += `| ?${name} | ${trip} | ${u.nick} | ${hash} |\n`; + } } + reply += '\n---\n'; + reply += `**Total Channels:** ${channelList.length}\n`; + reply += `**Total Users:** ${currentUsers.length}`; + // send reply server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` - text: lines.join('\n'), + cmd: 'info', + text: reply, + id: Info.Admin.USER_LIST, channel: socket.channel, // @todo Multichannel }, socket); diff --git a/commands/admin/reload.js b/commands/admin/reload.js index 8de8bb8..0fd366d 100644 --- a/commands/admin/reload.js +++ b/commands/admin/reload.js @@ -1,11 +1,14 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Refresh modules - * @version 1.0.0 + * @version 1.1.0 * @description Allows a remote user to clear and re-import the server command modules * @module reload */ +import { + Info, +} from '../utility/_Constants.js'; import { isAdmin, isModerator, @@ -77,8 +80,9 @@ ${loadResult}\n\n`; // send results to moderators (which the user using this command is higher than) server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: loadReport, + id: Info.Admin.RELOAD_STATUS, channel: false, // @todo Multichannel, false for global }, { level: isModerator }); diff --git a/commands/admin/removemod.js b/commands/admin/removemod.js index 9049853..ce2eba1 100644 --- a/commands/admin/removemod.js +++ b/commands/admin/removemod.js @@ -1,11 +1,17 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Removes a mod - * @version 1.0.0 + * @version 1.1.0 * @description Removes target trip from the config as a mod and downgrades the socket type * @module removemod */ +import { + Info, +} from '../utility/_Constants.js'; +import { + legacyLevelToLabel, +} from '../utility/_LegacyFunctions.js'; import { isAdmin, isModerator, @@ -44,22 +50,23 @@ export async function run({ ...getUserDetails(targetMod[0]), ...{ cmd: 'updateUser', - uType: 'user', // @todo use legacyLevelToLabel from _LegacyFunctions.js + uType: legacyLevelToLabel(levels.default), level: levels.default, }, }; for (let i = 0, l = targetMod.length; i < l; i += 1) { // downgrade privileges - targetMod[i].uType = 'user'; + targetMod[i].uType = legacyLevelToLabel(levels.default); targetMod[i].level = levels.default; targetMod[i].color = color; targetMod[i].flair = flair; // inform ex-mod server.send({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'You are now a user.', + id: Info.Admin.YOU_ARE_USER, channel: targetMod[i].channel, // @todo Multichannel }, targetMod[i]); @@ -75,17 +82,19 @@ export async function run({ // return success message server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Removed mod trip: ${ payload.trip }, remember to run 'saveconfig' to make it permanent`, + id: Info.Admin.MOD_REMOVED, channel: socket.channel, // @todo Multichannel }, socket); // notify all mods server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Removed mod: ${payload.trip}`, + id: Info.Admin.MOD_REMOVED_BROADCAST, channel: false, // @todo Multichannel, false for global }, { level: isModerator }); diff --git a/commands/admin/saveconfig.js b/commands/admin/saveconfig.js index b7e3df5..4d25574 100644 --- a/commands/admin/saveconfig.js +++ b/commands/admin/saveconfig.js @@ -1,7 +1,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Saves the config - * @version 1.0.0 + * @version 1.1.0 * @description Writes the current config to disk * @module saveconfig */ @@ -12,6 +12,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; /** @@ -40,8 +41,9 @@ export async function run({ core, server, socket }) { // return success message to moderators and admins server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'Config saved!', + id: Info.Admin.CONFIG_SAVED, channel: false, // @todo Multichannel }, { level: isModerator }); diff --git a/commands/admin/shout.js b/commands/admin/shout.js index 6c6dbf3..e705c46 100644 --- a/commands/admin/shout.js +++ b/commands/admin/shout.js @@ -1,11 +1,14 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Emit text everywhere - * @version 1.0.0 + * @version 1.1.0 * @description Displays passed text to every client connected * @module shout */ +import { + Info, +} from '../utility/_Constants.js'; import { isAdmin, } from '../utility/_UAC.js'; @@ -24,8 +27,9 @@ export async function run({ server, socket, payload }) { // send text to all channels server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Server Notice: ${payload.text}`, + id: Info.Admin.SHOUT, channel: false, // @todo Multichannel, false for global }, {}); diff --git a/commands/channels/claimchannel.js b/commands/channels/claimchannel.js index 8c56acf..648994d 100644 --- a/commands/channels/claimchannel.js +++ b/commands/channels/claimchannel.js @@ -1,7 +1,7 @@ /** * @author Marzavec * @summary Take channel ownership - * @version 1.0.0 + * @version 1.1.0 * @description Claim an unowned channel, enabling user management options * @module claimchannel */ @@ -15,6 +15,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, ClaimExpirationDays, } from '../utility/_Constants.js'; import { @@ -29,7 +30,7 @@ import { * @return {void} */ export async function run({ - core, server, socket, + server, socket, }) { // must be in a channel to run this command if (typeof socket.channel === 'undefined') { @@ -54,19 +55,37 @@ export async function run({ }, socket); } - const channelSettings = getChannelSettings(core.appConfig.data, socket.channel); + /* const channelSettings = getChannelSettings(core.appConfig.data, socket.channel); if (channelSettings.owned) { return server.reply({ cmd: 'warn', - text: `Failed to take ownership: This channel is already owned by the trip "${channelSettings.ownerTrip}", until ${channelSettings.claimExpires}`, + text: `Failed to take ownership: + This channel is already owned by the trip "${channelSettings.ownerTrip}", + until ${channelSettings.claimExpires}`, ownerTrip: channelSettings.ownerTrip, claimExpires: channelSettings.claimExpires, id: Errors.ClaimChannel.ALREADY_OWNED, channel: socket.channel, // @todo Multichannel }, socket); + } */ + + if (typeof socket.wallet !== 'object' || typeof socket.wallet.address !== 'string') { + return server.reply({ + cmd: 'warn', + text: 'You must connect a wallet first', + id: Errors.Global.LOGIN_REQUIRED, + channel: socket.channel, + }, socket); } + return server.reply({ + cmd: 'warn', + text: 'This command is disabled, pending reviews and updates', + id: Errors.Global.PERMISSION, + channel: socket.channel, // @todo Multichannel + }, socket); + socket.claimCaptcha = { solution: captcha.generateRandomText(7), }; @@ -106,6 +125,8 @@ export function initHooks(server) { export function chatHook({ core, server, socket, payload, }) { + if (typeof payload === 'undefined') return false; + if (typeof payload.text !== 'string') { return false; } @@ -138,8 +159,9 @@ export function chatHook({ console.log(`[${socket.trip}]${socket.nick} claimed ?${socket.channel}`); server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Channel now owned by "${socket.trip}", until ${channelSettings.claimExpires}`, + id: Info.Admin.SHOUT, channel: socket.channel, }, { channel: socket.channel }); @@ -197,6 +219,6 @@ export const info = { category: 'channels', description: 'Claim an unowned channel, enabling user management options. You must have a trip code to run this command.', usage: ` - API: { cmd: 'claimchannel' } - Text: /claimchannel`, + API: { cmd: 'claimchannel' } + Text: /claimchannel`, }; diff --git a/commands/channels/makeprivate.js b/commands/channels/makeprivate.js index b59b849..6066af4 100644 --- a/commands/channels/makeprivate.js +++ b/commands/channels/makeprivate.js @@ -1,7 +1,7 @@ /** * @author Marzavec * @summary Sets channel to private - * @version 1.0.0 + * @version 1.1.0 * @description Remove channel from being listed on the front page * @module makeprivate */ @@ -11,6 +11,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; /** @@ -59,8 +60,9 @@ export async function run({ core.appConfig.data.publicChannels.splice(listingIndex, 1); server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'This channel has been removed from the list of public channels', + id: Info.Admin.CONFIG_SAVED, channel: socket.channel, // @todo Multichannel }, socket); @@ -120,6 +122,6 @@ export const info = { category: 'channels', description: 'Remove channel from being listed on the front page', usage: ` - API: { cmd: 'makeprivate' } - Text: /makeprivate`, + API: { cmd: 'makeprivate' } + Text: /makeprivate`, }; diff --git a/commands/channels/makepublic.js b/commands/channels/makepublic.js index 1e81d70..f8114a5 100644 --- a/commands/channels/makepublic.js +++ b/commands/channels/makepublic.js @@ -1,7 +1,7 @@ /** * @author Marzavec * @summary Sets channel to public - * @version 1.0.0 + * @version 1.1.0 * @description Make channel publicly listed on the front page * @module makepublic */ @@ -13,6 +13,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; import { getChannelSettings, @@ -120,14 +121,16 @@ export function chatHook({ core.appConfig.data.publicChannels.push(socket.channel); server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `A new channel has been made public: ?${socket.channel}`, + id: Info.Admin.SHOUT, channel: socket.channel, // @todo Multichannel }, { level: (level) => isModerator(level) }); server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'This channel has been added to the list of public channels', + id: Info.Admin.CONFIG_SAVED, channel: socket.channel, // @todo Multichannel }, socket); @@ -170,6 +173,6 @@ export const info = { category: 'channels', description: 'Make channel publicly listed on the front page', usage: ` - API: { cmd: 'makepublic' } - Text: /makepublic`, + API: { cmd: 'makepublic' } + Text: /makepublic`, }; diff --git a/commands/channels/renewclaim.js b/commands/channels/renewclaim.js index 4149003..4d02e03 100644 --- a/commands/channels/renewclaim.js +++ b/commands/channels/renewclaim.js @@ -1,7 +1,7 @@ /** * @author Marzavec * @summary Renews the claim - * @version 1.0.0 + * @version 1.1.0 * @description Extend the ownership expiration date, before it expires * @module renewclaim */ @@ -12,6 +12,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, ClaimExpirationDays, } from '../utility/_Constants.js'; import { @@ -141,8 +142,9 @@ export function chatHook({ updateChannelSettings(core.appConfig.data, socket.channel, channelSettings); server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Your claim has been renewed until ${expirationDate}`, + id: Info.Admin.CONFIG_SAVED, channel: socket.channel, // @todo Multichannel }, socket); @@ -185,6 +187,6 @@ export const info = { category: 'channels', description: 'Extend the ownership expiration date, before it expires.', usage: ` - API: { cmd: 'renewclaim' } - Text: /renewclaim`, + API: { cmd: 'renewclaim' } + Text: /renewclaim`, }; diff --git a/commands/channels/setlevel.js b/commands/channels/setlevel.js index f0738e9..4637c74 100644 --- a/commands/channels/setlevel.js +++ b/commands/channels/setlevel.js @@ -1,7 +1,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Change user level - * @version 1.0.0 + * @version 1.1.0 * @description Alter the permission level a trip is allowed within current channel * @module setlevel */ @@ -17,6 +17,7 @@ import { } from '../utility/_Channels.js'; import { Errors, + Info, } from '../utility/_Constants.js'; /** @@ -122,8 +123,9 @@ export async function run({ }, { channel: socket.channel }); server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Changed permission level of "${payload.trip}" to "${payload.level}"`, + id: Info.Admin.SHOUT, channel: socket.channel, // @todo Multichannel }, { channel: socket.channel }); } @@ -160,28 +162,24 @@ export function setlevelCheck({ if (payload.text.startsWith('/setlevel')) { const input = payload.text.split(' '); - // If there is no trip parameter + // if there is no trip parameter if (!input[1]) { - server.reply({ + return server.reply({ cmd: 'warn', text: 'Failed to set level: Missing trip. Refer to `/help setlevel` for instructions on how to use this command.', id: Errors.SetLevel.BAD_TRIP, channel: socket.channel, // @todo Multichannel }, socket); - - return false; } - // If there is no level parameter + // if there is no level parameter if (!input[2]) { - server.reply({ + return server.reply({ cmd: 'warn', text: 'Failed to set level: Missing level label. Refer to `/help setlevel` for instructions on how to use this command.', id: Errors.SetLevel.BAD_LABEL, channel: socket.channel, // @todo Multichannel }, socket); - - return false; } this.run({ @@ -223,6 +221,6 @@ export const info = { category: 'channels', description: 'Alter the permission level a trip is allowed within current channel', usage: ` - API: { cmd: 'setlevel', trip: '[target trip]', level: '[level label]' } - Text: /setlevel <"channelModerator" || "channelTrusted" || "trustedUser" || "default" || "bot">`, + API: { cmd: 'setlevel', trip: '[target trip]', level: '[level label]' } + Text: /setlevel <"channelModerator" || "channelTrusted" || "trustedUser" || "default" || "bot">`, }; diff --git a/commands/channels/setmotd.js b/commands/channels/setmotd.js index e750876..4c069a2 100644 --- a/commands/channels/setmotd.js +++ b/commands/channels/setmotd.js @@ -1,10 +1,10 @@ /** -* @author Marzavec ( https://github.com/marzavec ) -* @summary Change motd -* @version 1.0.0 -* @description Update the channel motd to something new -* @module setmotd -*/ + * @author Marzavec ( https://github.com/marzavec ) + * @summary Change motd + * @version 1.1.0 + * @description Update the channel motd to something new + * @module setmotd + */ import { isChannelModerator, @@ -15,6 +15,7 @@ import { } from '../utility/_Channels.js'; import { Errors, + Info, MaxMOTDLength, } from '../utility/_Constants.js'; @@ -63,16 +64,18 @@ export async function run({ updateChannelSettings(core.appConfig.data, socket.channel, channelSettings); server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `MOTD changed by [${socket.trip}]${socket.nick}, new motd:`, + id: Info.Admin.SHOUT, channel: socket.channel, // @todo Multichannel - }, { channel: socket.channel }); + }, { channel: socket.channel, level: isChannelModerator }); server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: channelSettings.motd, + id: Info.Core.MOTD, channel: socket.channel, // @todo Multichannel - }, { channel: socket.channel }); + }, { channel: socket.channel, level: isChannelModerator }); return true; } @@ -141,6 +144,6 @@ export const info = { category: 'channels', description: 'Update the channel motd to something new', usage: ` - API: { cmd: 'setmotd', motd: '[new motd]' } - Text: /setmotd `, + API: { cmd: 'setmotd', motd: '[new motd]' } + Text: /setmotd `, }; diff --git a/commands/channels/unclaimchannel.js b/commands/channels/unclaimchannel.js index 685e2c9..b9f63b8 100644 --- a/commands/channels/unclaimchannel.js +++ b/commands/channels/unclaimchannel.js @@ -1,7 +1,7 @@ /** * @author Marzavec * @summary Release channel ownership - * @version 1.0.0 + * @version 1.1.0 * @description Clear ownership info and channel settings * @module unclaimchannel */ @@ -14,6 +14,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; import { getChannelSettings, @@ -66,8 +67,9 @@ export async function run({ deleteChannelSettings(core.appConfig.data, socket.channel); server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'Channel ownership has been removed and the channel settings have been reset', + id: Info.Admin.SHOUT, channel: socket.channel, }, { channel: socket.channel }); @@ -151,6 +153,6 @@ export const info = { category: 'channels', description: 'Clear ownership info and channel settings', usage: ` - API: { cmd: 'unclaimchannel' } - Text: /unclaimchannel`, + API: { cmd: 'unclaimchannel' } + Text: /unclaimchannel`, }; diff --git a/commands/core/changecolor.js b/commands/core/changecolor.js index ae13c68..3772b90 100644 --- a/commands/core/changecolor.js +++ b/commands/core/changecolor.js @@ -1,27 +1,24 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Update name color - * @version 1.0.0 + * @version 1.1.0 * @description Allows calling client to change their nickname color * @module changecolor */ +import { + getSession, +} from './session.js'; import { getUserDetails, } from '../utility/_UAC.js'; +import { + verifyColor, +} from '../utility/_Text.js'; import { Errors, } from '../utility/_Constants.js'; -/** - * Validate a string as a valid hex color string - * @param {string} color - Color string to validate - * @private - * @todo Move into utility module - * @return {boolean} - */ -const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); - /** * Executes when invoked by a remote client * @param {Object} env - Environment object with references to core, server, socket & payload @@ -29,7 +26,7 @@ const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); * @return {void} */ export async function run({ - server, socket, payload, + core, server, socket, payload, }) { // must be in a channel to run this command if (typeof socket.channel === 'undefined') { @@ -84,6 +81,13 @@ export async function run({ // @todo this should be sent to every channel the user is in (multichannel) server.broadcast(updateNotice, { channel: socket.channel }); + server.reply({ + cmd: 'session', + restored: false, + token: getSession(socket, core), + channels: socket.channels, + }, socket); + return true; } @@ -115,7 +119,7 @@ export function colorCheck({ if (payload.text.startsWith('/color ')) { const input = payload.text.split(' '); - // If there is no color target parameter + // if there is no color target parameter if (input[1] === undefined) { server.reply({ cmd: 'warn', diff --git a/commands/core/changenick.js b/commands/core/changenick.js index 3bdcbf4..8df4c8a 100644 --- a/commands/core/changenick.js +++ b/commands/core/changenick.js @@ -3,7 +3,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Update nickname - * @version 1.0.0 + * @version 1.1.0 * @description Allows calling client to change their current nickname * @module changenick */ @@ -14,6 +14,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; /** @@ -72,13 +73,13 @@ export async function run({ const userExists = server.findSockets({ channel, nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase() - // Allow them to rename themselves to a different case + // allow them to rename themselves to a different case && targetNick != previousNick, }); // return error if found if (userExists.length > 0) { - // That nickname is already in that channel + // that nickname is already in that channel return server.reply({ cmd: 'warn', text: 'Nickname taken', @@ -130,8 +131,9 @@ export async function run({ // notify channel that the user has changed their name server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${socket.nick} is now ${newNick}`, + id: Info.Core.NICK_CHANGED, channel, // @todo Multichannel }, { channel }); @@ -169,16 +171,14 @@ export function nickCheck({ if (payload.text.startsWith('/nick')) { const input = payload.text.split(' '); - // If there is no nickname target parameter + // if there is no nickname target parameter if (!input[1]) { - server.reply({ + return server.reply({ cmd: 'warn', text: 'Nickname must consist of up to 24 letters, numbers, and underscores', id: Errors.Join.INVALID_NICK, channel: socket.channel, // @todo Multichannel }, socket); - - return false; } const newNick = input[1].replace(/@/g, ''); diff --git a/commands/core/chat.js b/commands/core/chat.js index 25c69ab..349e588 100644 --- a/commands/core/chat.js +++ b/commands/core/chat.js @@ -15,6 +15,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; /** @@ -24,51 +25,57 @@ import { export const MAX_MESSAGE_ID_LENGTH = 6; /** - * The time in milliseconds before a message is considered stale, and thus no longer allowed - * to be edited. + * The time in milliseconds before a message is considered stale * @type {number} */ const ACTIVE_TIMEOUT = 5 * 60 * 1000; /** - * The time in milliseconds that a check for stale messages should be performed. + * The time in milliseconds that a check for stale messages should be performed * @type {number} */ const TIMEOUT_CHECK_INTERVAL = 30 * 1000; /** - * Stores active messages that can be edited. + * Stores active messages that can be edited * @type {Array} */ export const ACTIVE_MESSAGES = []; /** - * Cleans up stale messages. + * Interval reference for cleanup + */ +let cleanupInterval = null; + +/** + * Cleans up stale messages * @public * @return {void} */ export function cleanActiveMessages() { const now = Date.now(); - for (let i = 0; i < ACTIVE_MESSAGES.length; i += 1) { + for (let i = ACTIVE_MESSAGES.length - 1; i >= 0; i -= 1) { const message = ACTIVE_MESSAGES[i]; if (now - message.sent > ACTIVE_TIMEOUT || message.toDelete) { ACTIVE_MESSAGES.splice(i, 1); - i -= 1; } } } -// TODO: This won't get cleared on module reload. -setInterval(cleanActiveMessages, TIMEOUT_CHECK_INTERVAL); +if (!cleanupInterval) { + cleanupInterval = setInterval(cleanActiveMessages, TIMEOUT_CHECK_INTERVAL); +} /** - * Adds a message to the active messages map. + * Adds a message to the active messages map * @public - * @param {string} id + * @param {string} customId * @param {number} userid * @return {void} */ export function addActiveMessage(customId, userid) { + if (!customId) return; + ACTIVE_MESSAGES.push({ customId, userid, @@ -112,11 +119,12 @@ export async function run({ const { customId } = payload; - if (typeof (customId) === 'string' && customId.length > MAX_MESSAGE_ID_LENGTH) { - // There's a limit on the custom id length. + if (typeof customId === 'string' && customId.length > MAX_MESSAGE_ID_LENGTH) { return server.police.frisk(socket, 13); } + const messageId = Math.floor(Math.random() * 999999) + 1; + // build chat payload const outgoingPayload = { cmd: 'chat', @@ -128,6 +136,7 @@ export async function run({ level: socket.level, flair: socket.flair, customId, + id: messageId, }; if (isAdmin(socket.level)) { @@ -144,7 +153,9 @@ export async function run({ outgoingPayload.color = socket.color; } - addActiveMessage(outgoingPayload.customId, socket.userid); + if (outgoingPayload.customId) { + addActiveMessage(outgoingPayload.customId, socket.userid); + } // broadcast to channel peers server.broadcast(outgoingPayload, { channel: socket.channel }); @@ -181,13 +192,14 @@ export function commandCheckIn({ server, socket, payload }) { } if (payload.text.startsWith('/shrug')) { - payload.text = payload.text.replace('/shrug', String.fromCharCode(175)+String.fromCharCode(92)+String.fromCharCode(92)+String.fromCharCode(92)+String.fromCharCode(95)+String.fromCharCode(40)+String.fromCharCode(12484)+String.fromCharCode(41)+String.fromCharCode(92)+String.fromCharCode(95)+String.fromCharCode(47)+String.fromCharCode(175)); + payload.text = payload.text.replace('/shrug', String.fromCharCode(175, 92, 92, 92, 95, 40, 12484, 41, 92, 95, 47, 175)); } if (payload.text.startsWith('/myhash')) { server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Your hash: ${socket.hash}`, + id: Info.Core.MY_HASH, channel: socket.channel, // @todo Multichannel }, socket); diff --git a/commands/core/help.js b/commands/core/help.js index ea3b224..84fa16c 100644 --- a/commands/core/help.js +++ b/commands/core/help.js @@ -9,6 +9,7 @@ import { CodebaseVersion, Errors, + Info, } from '../utility/_Constants.js'; /** @@ -75,8 +76,9 @@ export async function run({ // output reply server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: reply, + id: Info.Core.HELP_TEXT, channel: socket.channel, // @todo Multichannel }, socket); diff --git a/commands/core/invite.js b/commands/core/invite.js index 804c60b..31ab7d3 100644 --- a/commands/core/invite.js +++ b/commands/core/invite.js @@ -18,7 +18,7 @@ import { } from '../utility/_LegacyFunctions.js'; /** - * Returns the channel that should be invited to. + * Returns the channel that should be invited to * @param {any} channel * @private * @return {string} diff --git a/commands/core/join.js b/commands/core/join.js index 5665157..bf69857 100644 --- a/commands/core/join.js +++ b/commands/core/join.js @@ -4,7 +4,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Join target channel - * @version 1.0.0 + * @version 1.1.0 * @description Join the target channel using the supplied nick and password * @module join */ @@ -19,6 +19,7 @@ import { } from '../utility/_Channels.js'; import { Errors, + Info, SystemMOTDs, } from '../utility/_Constants.js'; import { @@ -72,7 +73,7 @@ export async function run({ } // calling socket already in a channel - // @todo multichannel update, will remove + // @todo multichannel update: remove this block to allow multiple channels if (typeof socket.channel !== 'undefined') { return server.reply({ cmd: 'warn', @@ -81,7 +82,6 @@ export async function run({ channel: false, // @todo Multichannel, false for global event }, socket); } - // end todo // validates the user input for `nick` if (verifyNickname(nick, socket) !== true) { @@ -132,7 +132,6 @@ export async function run({ }); if (userExists.length > 0) { - // that nickname is already in that channel return server.reply({ cmd: 'warn', text: 'Nickname taken', @@ -167,9 +166,10 @@ export async function run({ socket.level = userInfo.level; socket.uType = userInfo.uType; /* @legacy */ socket.channel = channel; /* @legacy */ - // @todo multi-channel patch - // socket.channels.push(channel); - socket.channels = [channel]; + + // initialize channels array if needed + if (!socket.channels) socket.channels = []; + if (!socket.channels.includes(channel)) socket.channels.push(channel); // global mod perks if (isModerator(socket.level)) { @@ -177,14 +177,14 @@ export async function run({ } nicks.push(userInfo.nick); /* @legacy */ - users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo }); + users.push({ ...{ isme: true, isBot: socket.isBot || false }, ...userInfo }); // reply with channel peer list server.reply({ cmd: 'onlineSet', nicks, /* @legacy */ users, - channel, // @todo Multichannel (?) + channel, }, socket); let { motd } = channelSettings; @@ -193,8 +193,9 @@ export async function run({ } server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: motd, + id: Info.Core.MOTD, channel, }, socket); @@ -236,6 +237,7 @@ export function restoreJoin({ userid: socket.userid, isBot: socket.isBot, color: socket.color, + flair: socket.flair, channel, }; @@ -274,18 +276,19 @@ export function restoreJoin({ } nicks.push(userInfo.nick); /* @legacy */ - users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo }); + users.push({ ...{ isme: true, isBot: socket.isBot || false }, ...userInfo }); // reply with channel peer list server.reply({ cmd: 'onlineSet', nicks, /* @legacy */ users, - channel, // @todo Multichannel (?) + channel, }, socket); socket.channel = channel; /* @legacy */ - socket.channels.push(channel); + if (!socket.channels) socket.channels = []; + if (!socket.channels.includes(channel)) socket.channels.push(channel); return true; } diff --git a/commands/core/leave.js b/commands/core/leave.js new file mode 100644 index 0000000..ca46053 --- /dev/null +++ b/commands/core/leave.js @@ -0,0 +1,148 @@ +/* eslint no-param-reassign: 0 */ +/* eslint import/no-cycle: [0, { ignoreExternal: true }] */ + +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Leave target channel + * @version 1.0.0 + * @description Leave the target channel + * @module leave + */ + +import { + getSession, +} from './session.js'; +import { + socketInChannel, +} from '../utility/_Channels.js'; +import { + Errors, +} from '../utility/_Constants.js'; + +/** + * Executes when invoked by a remote client + * @param {Object} env - Environment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + core, server, socket, payload, +}) { + // check for spam + if (server.police.frisk(socket, 3)) { + return server.reply({ + cmd: 'warn', + text: 'You are leaving channels too fast. Wait a moment and try again.', + id: Errors.Global.RATELIMIT, + channel: false, + }, socket); + } + + // check for required payload data + if (typeof payload.channel !== 'string') { + return server.reply({ + cmd: 'warn', + text: 'Invalid channel specified.', + id: Errors.Global.INVALID_PAYLOAD, + channel: false, + }, socket); + } + + const { channel } = payload; + + // verify the user is actually in the channel they are trying to leave + if (!socket.channels || !socket.channels.includes(channel)) { + return server.reply({ + cmd: 'warn', + text: 'You are not in that channel.', + id: Errors.Global.INVALID_PAYLOAD, + channel: false, + }, socket); + } + + socket.channels = socket.channels.filter((c) => c !== channel); + + // @todo Multichannel update + if (socket.channel === channel) { + socket.channel = socket.channels.length > 0 ? socket.channels[0] : undefined; + } + + const isDuplicate = socketInChannel(server, channel, socket); + + if (isDuplicate === false) { + server.broadcast({ + cmd: 'onlineRemove', + nick: socket.nick, + userid: socket.userid, + channel, + }, { channel }); + } + + server.reply({ + cmd: 'session', + restored: false, + token: getSession(socket, core), + channels: socket.channels, + }, socket); + + return true; +} + +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server environment object + * @public + * @return {void} + */ +export function initHooks(server) { + server.registerHook('in', 'chat', this.runLeaveCheck.bind(this), 32); +} + +/** + * Executes every time an incoming chat command is invoked + * @param {Object} env - Environment object with references to core, server, socket & payload + * @public + * @return {(Object|boolean|string)} Object = same/altered payload, + * false = suppress action, + * string = error + */ +export function runLeaveCheck({ + core, server, socket, payload, +}) { + if (typeof payload.text !== 'string') { + return false; + } + + if (payload.text.startsWith('/leave')) { + this.run({ + core, + server, + socket, + payload: { + cmd: 'leave', + channel: socket.channel, // @todo Mutlichannel + }, + }); + + return false; + } + + return payload; +} + +/** + * Module meta information + * @public + * @typedef {Object} leave/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'leave', + category: 'core', + description: 'Leave the target channel', + usage: ` + API: { cmd: 'leave', channel: '' }`, +}; diff --git a/commands/core/morestats.js b/commands/core/morestats.js index 891e56c..9a2eb75 100644 --- a/commands/core/morestats.js +++ b/commands/core/morestats.js @@ -1,11 +1,15 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Get stats - * @version 1.0.0 + * @version 1.1.0 * @description Sends back current server stats to the calling client * @module morestats */ +import { + Info, +} from '../utility/_Constants.js'; + /** * Format input time into string * @param {Date} time - Subject date @@ -42,26 +46,20 @@ export async function run({ core, server, socket }) { // gather connection and channel count const ips = {}; const channels = {}; - // @todo use public channel flag - const publicChanCounts = { - lounge: 0, - meta: 0, - math: 0, - physics: 0, - chemistry: 0, - technology: 0, - programming: 0, - games: 0, - banana: 0, - chinese: 0, - }; + const publicChanCounts = {}; + + if (core.appConfig.data.publicChannels) { + core.appConfig.data.publicChannels.forEach((channel) => { + publicChanCounts[channel] = 0; + }); + } - // @todo code resuage between here and `session`; should share exported function server.clients.forEach((client) => { if (client.channel) { channels[client.channel] = true; ips[client.address] = true; - if (typeof publicChanCounts[client.channel] !== 'undefined') { + + if (Object.prototype.hasOwnProperty.call(publicChanCounts, client.channel)) { publicChanCounts[client.channel] += 1; } } @@ -77,9 +75,34 @@ export async function run({ core, server, socket }) { const stats = core.stats.get('stats-requested') || 0; const uptime = formatTime(process.hrtime(core.stats.get('start-time'))); + let replyText = '# Server Statistics\n'; + replyText += '| Metric | Value |\n'; + replyText += '| :--- | --- |\n'; + replyText += `| **Current Connections** | ${uniqueClientCount} |\n`; + replyText += `| **Current Channels** | ${uniqueChannels} |\n`; + replyText += `| **Users Joined** | ${joins} |\n`; + replyText += `| **Invites Sent** | ${invites} |\n`; + replyText += `| **Messages Sent** | ${messages} |\n`; + replyText += `| **Users Banned** | ${banned} |\n`; + replyText += `| **Users Kicked** | ${kicked} |\n`; + replyText += `| **Stats Requested** | ${stats} |\n`; + replyText += `| **Server Uptime** | ${uptime} |\n\n`; + + const sortedPublicChannels = Object.keys(publicChanCounts) + .map((channel) => ({ name: channel, count: publicChanCounts[channel] })) + .sort((a, b) => b.count - a.count); + + replyText += '## Public Channels\n'; + replyText += '| Channel | Users |\n'; + replyText += '| :--- | --- |\n'; + + sortedPublicChannels.forEach((channelObj) => { + replyText += `| ?${channelObj.name} | ${channelObj.count} |\n`; + }); + // dispatch info server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', users: uniqueClientCount, chans: uniqueChannels, joins, @@ -90,15 +113,8 @@ export async function run({ core, server, socket }) { stats, uptime, public: publicChanCounts, - text: `current-connections: ${uniqueClientCount} -current-channels: ${uniqueChannels} -users-joined: ${joins} -invites-sent: ${invites} -messages-sent: ${messages} -users-banned: ${banned} -users-kicked: ${kicked} -stats-requested: ${stats} -server-uptime: ${uptime}`, + text: replyText, + id: Info.Core.STATS_FULL, channel: socket.channel, // @todo Multichannel }, socket); diff --git a/commands/core/session.js b/commands/core/session.js index 150076f..4016a10 100644 --- a/commands/core/session.js +++ b/commands/core/session.js @@ -3,7 +3,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Create or restore session - * @version 1.0.0 + * @version 1.1.0 * @description Restore previous state by session or create new session * @module session */ @@ -15,10 +15,8 @@ import jsonwebtoken from 'jsonwebtoken'; import { isModerator, verifyNickname, + levels, } from '../utility/_UAC.js'; -import { - Errors, -} from '../utility/_Constants.js'; import { restoreJoin, } from './join.js'; @@ -36,7 +34,7 @@ export function getSession(socket, core) { channel: socket.channel, channels: socket.channels, color: socket.color, - isBot: socket.isBot, + isBot: socket.isBot || false, level: socket.level, nick: socket.nick, flair: socket.flair, @@ -58,14 +56,39 @@ export function getSession(socket, core) { */ function notifyFailure(server, socket) { server.reply({ - cmd: 'error', - id: Errors.Session.BAD_SESSION, - text: 'Invalid session', + cmd: 'session', + restored: false, + token: '', + channels: [], }, socket); return false; } +/** + * Re-validates the user's level against the current server config + * Prevents clients from using old tokens to retain privileges + * @param {string} trip + * @param {object} appConfig + * @returns {number} + */ +function validateLevel(trip, appConfig) { + if (!trip) return levels.default; + + // check admin + if (trip === appConfig.adminTrip) { + return levels.admin; + } + + // check global Mods + const isGlobalMod = appConfig.globalMods.some((mod) => mod.trip === trip); + if (isGlobalMod) { + return levels.moderator; + } + + return levels.default; +} + /** * Executes when invoked by a remote client * @param {Object} env - Environment object with references to core, server, socket & payload @@ -75,6 +98,14 @@ function notifyFailure(server, socket) { export async function run({ core, server, socket, payload, }) { + if (typeof socket.hcProtocol === 'undefined') socket.hcProtocol = 2; + if (typeof socket.userid === 'undefined') socket.userid = Math.floor(Math.random() * 9999999999999); + if (typeof socket.hash === 'undefined') socket.hash = server.getSocketHash(socket); + + if (server.police.frisk(socket.address)) { + return notifyFailure(server, socket); + } + if (typeof payload.token === 'undefined') { return notifyFailure(server, socket); } @@ -86,49 +117,25 @@ export async function run({ return notifyFailure(server, socket); } - // validate session - if (typeof session.channel !== 'string') { - return notifyFailure(server, socket); - } + if (typeof session.channel !== 'string') return notifyFailure(server, socket); + if (Array.isArray(session.channels) === false) return notifyFailure(server, socket); + if (typeof session.color !== 'string' && typeof session.color !== 'boolean') return notifyFailure(server, socket); + if (typeof session.isBot !== 'boolean') return notifyFailure(server, socket); + if (typeof session.level !== 'number') return notifyFailure(server, socket); + if (verifyNickname(session.nick) === false) return notifyFailure(server, socket); + if (typeof session.trip !== 'string') return notifyFailure(server, socket); + if (typeof session.userid !== 'number') return notifyFailure(server, socket); + if (typeof session.uType !== 'string') return notifyFailure(server, socket); + if (typeof session.muzzled !== 'boolean') return notifyFailure(server, socket); + if (typeof session.banned !== 'boolean') return notifyFailure(server, socket); - if (Array.isArray(session.channels) === false) { - return notifyFailure(server, socket); - } + const realLevel = validateLevel(session.trip, core.appConfig.data); - if (typeof session.color !== 'string' && typeof session.color !== 'boolean') { - return notifyFailure(server, socket); - } - - if (typeof session.isBot !== 'boolean') { - return notifyFailure(server, socket); - } - - if (typeof session.level !== 'number') { - return notifyFailure(server, socket); - } - - if (verifyNickname(session.nick) === false) { - return notifyFailure(server, socket); - } - - if (typeof session.trip !== 'string') { - return notifyFailure(server, socket); - } - - if (typeof session.userid !== 'number') { - return notifyFailure(server, socket); - } - - if (typeof session.uType !== 'string') { - return notifyFailure(server, socket); - } - - if (typeof session.muzzled !== 'boolean') { - return notifyFailure(server, socket); - } - - if (typeof session.banned !== 'boolean') { - return notifyFailure(server, socket); + if (session.level >= levels.moderator) { + if (realLevel < session.level) { + session.level = realLevel; + session.uType = 'user'; + } } // populate socket info with validated session @@ -152,23 +159,23 @@ export async function run({ socket.hash = server.getSocketHash(socket); socket.hcProtocol = 2; - // dispatch info - server.reply({ - cmd: 'session', - restored: true, - token: getSession(socket, core), - channels: socket.channels, - }, socket); - + // attempt to restore all channels in the session for (let i = 0, j = session.channels.length; i < j; i += 1) { restoreJoin({ core, server, socket, channel: session.channels[i], - }, true); + }); } + server.reply({ + cmd: 'session', + restored: true, + token: getSession(socket, core), + channels: socket.channels, + }, socket); + return true; } diff --git a/commands/core/stats.js b/commands/core/stats.js index 08412a2..ce4b1e1 100644 --- a/commands/core/stats.js +++ b/commands/core/stats.js @@ -6,6 +6,10 @@ * @module stats */ +import { + Info, +} from '../utility/_Constants.js'; + /** * Executes when invoked by a remote client * @param {Object} env - Environment object with references to core, server, socket & payload @@ -21,7 +25,7 @@ export async function run({ core, server, socket }) { // gather connection and channel count let ips = {}; let channels = {}; - // for (const client of server.clients) { + server.clients.forEach((client) => { if (client.channel) { channels[client.channel] = true; @@ -37,8 +41,9 @@ export async function run({ core, server, socket }) { // dispatch info server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${uniqueClientCount} unique IPs in ${uniqueChannels} channels`, + id: Info.Core.STATS_BASIC, channel: socket.channel, // @todo Multichannel }, socket); diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js index 73df805..b9b00b9 100644 --- a/commands/core/updateMessage.js +++ b/commands/core/updateMessage.js @@ -1,7 +1,7 @@ /** * @author MinusGix ( https://github.com/MinusGix ) * @summary Change target message - * @version v1.0.0 + * @version v1.1.0 * @description Will alter a previously sent message using that message's customId * @module updateMessage */ @@ -13,6 +13,9 @@ import { isAdmin, isModerator, } from '../utility/_UAC.js'; +import { + Errors, +} from '../utility/_Constants.js'; import { ACTIVE_MESSAGES, MAX_MESSAGE_ID_LENGTH, @@ -52,39 +55,39 @@ export async function run({ return server.police.frisk(socket, 13); } - if (mode === 'overwrite') { - text = parseText(text); + // sanitize input regardless of mode + text = parseText(text); - if (text === '') { - text = '\u0000'; - } - } - - if (!text) { + // allow empty overwrite (clearing message), otherwise block empty text + if (mode === 'overwrite' && text === '') { + text = '\u0000'; + } else if (!text) { return server.police.frisk(socket, 13); } - // TODO: What score should we use for this? It isn't as space filling as chat messages. - // But we also don't want a massive growing message. - // Or flashing between huge and small. Etc. - - let message; - for (let i = 0; i < ACTIVE_MESSAGES.length; i += 1) { - const msg = ACTIVE_MESSAGES[i]; - - if (msg.userid === socket.userid && msg.customId === customId) { - message = ACTIVE_MESSAGES[i]; - if (mode === 'complete') { - ACTIVE_MESSAGES[i].toDelete = true; - } - break; - } + const score = text.length / 83 / 4; + if (server.police.frisk(socket, score)) { + return server.reply({ + cmd: 'warn', + text: 'You are sending too much text. Wait a moment and try again.', + id: Errors.Global.RATELIMIT, + channel: socket.channel, + }, socket); } + // find the target message + const message = ACTIVE_MESSAGES.find( + (msg) => msg.userid === socket.userid && msg.customId === customId, + ); + if (!message) { return server.police.frisk(socket, 6); } + if (mode === 'complete') { + message.toDelete = true; + } + const outgoingPayload = { cmd: 'updateMessage', userid: socket.userid, diff --git a/commands/internal/disconnect.js b/commands/internal/disconnect.js index 6206970..b9522a9 100644 --- a/commands/internal/disconnect.js +++ b/commands/internal/disconnect.js @@ -32,6 +32,7 @@ export async function run({ server, socket, payload }) { cmd: 'onlineRemove', nick: socket.nick, userid: socket.userid, + channel: socket.channel, }, { channel: socket.channel }); } } diff --git a/commands/mod/ban.js b/commands/mod/ban.js index 4bd5ac2..9d0fb4e 100644 --- a/commands/mod/ban.js +++ b/commands/mod/ban.js @@ -1,7 +1,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Ban a user - * @version 1.0.0 + * @version 1.1.0 * @description Bans target user by name * @module ban */ @@ -12,6 +12,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; import { findUser, @@ -71,16 +72,18 @@ export async function run({ // notify normal users server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Banned ${targetNick}`, + id: Info.Mod.BANNED, user: getUserDetails(targetUser), channel: socket.channel, // @todo Multichannel }, { channel: socket.channel, level: (level) => isModerator(level) }); // notify mods server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${targetUser.hash}`, + id: Info.Mod.BANNED_DETAILED, channel: socket.channel, // @todo Multichannel inChannel: payload.channel, user: getUserDetails(targetUser), diff --git a/commands/mod/disablecaptcha.js b/commands/mod/disablecaptcha.js index 49a95b0..c2df32c 100644 --- a/commands/mod/disablecaptcha.js +++ b/commands/mod/disablecaptcha.js @@ -1,12 +1,15 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Disables the captcha - * @version 1.0.0 + * @version 1.1.0 * @description Disables the captcha on the channel specified in the channel property, - * default is current channel + * default is current channel * @module disablecaptcha */ +import { + Info, +} from '../utility/_Constants.js'; import { isModerator, } from '../utility/_UAC.js'; @@ -51,8 +54,9 @@ export async function run({ if (!core.captchas[targetChannel]) { return server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'Captcha is not enabled.', + id: Info.Captcha.NOT_ENABLED, channel: socket.channel, // @todo Multichannel }, socket); } @@ -60,8 +64,9 @@ export async function run({ core.captchas[targetChannel] = false; server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Captcha disabled on: ${targetChannel}`, + id: Info.Captcha.DISABLED, channel: false, // @todo Multichannel, false for global info }, { channel: targetChannel, level: isModerator }); diff --git a/commands/mod/dumb.js b/commands/mod/dumb.js index 02477f9..89a1acf 100644 --- a/commands/mod/dumb.js +++ b/commands/mod/dumb.js @@ -4,8 +4,8 @@ /** * @author OpSimple ( https://github.com/OpSimple ) * @summary Muzzle a user - * @version 1.0.0 - * @description Globally shadow mute a connection. Optional allies array will see muted messages. + * @version 1.1.0 + * @description Globally shadow mute a connection. Optional allies array will see muted messages * @module dumb */ @@ -17,6 +17,7 @@ import { } from '../utility/_Channels.js'; import { Errors, + Info, } from '../utility/_Constants.js'; import { legacyInviteReply, @@ -24,7 +25,7 @@ import { } from '../utility/_LegacyFunctions.js'; /** - * Returns the channel that should be invited to. + * Returns the channel that should be invited to * @param {any} channel * @private * @return {string} @@ -130,8 +131,9 @@ export async function run({ // notify mods server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${socket.nick}#${socket.trip} muzzled ${targetUser.nick} in ${payload.channel}, userhash: ${targetUser.hash}`, + id: Info.Mod.MUZZLED_DETAILED, channel: false, // @todo Multichannel, false for global }, { level: isModerator }); @@ -176,6 +178,7 @@ export function chatCheck({ channel: socket.channel, text: payload.text, level: socket.level, + flair: socket.flair, }; if (socket.trip) { @@ -201,7 +204,7 @@ export function chatCheck({ } /** - * Blanket "spam" protection. + * Blanket "spam" protection * May expose the ratelimiting lines from `chat` and use that * @todo one day #lazydev */ diff --git a/commands/mod/enablecaptcha.js b/commands/mod/enablecaptcha.js index a3ac3fd..5851eb7 100644 --- a/commands/mod/enablecaptcha.js +++ b/commands/mod/enablecaptcha.js @@ -3,9 +3,9 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Enables the captcha - * @version 1.0.0 + * @version 1.1.0 * @description Enables the captcha on the channel specified in the channel property, - * default is current channel + * default is current channel * @module enablecaptcha */ @@ -26,6 +26,7 @@ import { } from '../utility/_LegacyFunctions.js'; import { Errors, + Info, } from '../utility/_Constants.js'; /** @@ -68,8 +69,9 @@ export async function run({ if (core.captchas[targetChannel]) { return server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'Captcha is already enabled.', + id: Info.Captcha.ALREADY_ENABLED, channel: socket.channel, // @todo Multichannel }, socket); } @@ -77,8 +79,9 @@ export async function run({ core.captchas[targetChannel] = true; server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Captcha enabled on: ${targetChannel}`, + id: Info.Captcha.ENABLED, channel: socket.channel, // @todo Multichannel, false for global info }, { channel: socket.channel, level: isModerator }); @@ -163,6 +166,10 @@ export function chatCheck({ export function joinCheck({ core, server, socket, payload, }) { + if (typeof payload === 'undefined' || typeof payload.channel === 'undefined') { + return false; + } + // check if channel has captcha enabled if (core.captchas[payload.channel] !== true) { return payload; @@ -170,7 +177,7 @@ export function joinCheck({ // `join` is the legacy entry point, check if it needs to be upgraded const origPayload = { ...payload }; - if (typeof socket.hcProtocol === 'undefined') { + if (typeof socket.hcProtocol === 'undefined' || socket.hcProtocol === 1) { payload = upgradeLegacyJoin(server, socket, payload); } diff --git a/commands/mod/forcecolor.js b/commands/mod/forcecolor.js index 5bc326d..6e96bee 100644 --- a/commands/mod/forcecolor.js +++ b/commands/mod/forcecolor.js @@ -1,7 +1,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Color a user - * @version 1.0.0 + * @version 1.1.0 * @description Forces a user nick to become a certain color * @module forcecolor */ @@ -16,15 +16,9 @@ import { import { findUser, } from '../utility/_Channels.js'; - -/** - * Validate a string as a valid hex color string - * @param {string} color - Color string to validate - * @private - * @todo Move into utility module - * @return {boolean} - */ -const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); +import { + verifyColor, +} from '../utility/_Text.js'; /** * Executes when invoked by a remote client @@ -198,5 +192,5 @@ export const info = { description: 'Forces a user nick to become a certain color', usage: ` API: { cmd: 'forcecolor', nick: '', color: '' } -Text: /forcecolor `, + Text: /forcecolor `, }; diff --git a/commands/mod/hack.js b/commands/mod/hack.js index ae0a587..6f93d52 100644 --- a/commands/mod/hack.js +++ b/commands/mod/hack.js @@ -1,6 +1,6 @@ /** * @author Marzavec ( https://github.com/marzavec ) - * @summary Sends a hack request to the target nick. + * @summary Sends a hack request to the target nick * @version 1.0.0 * @description Please note that the term 'hack' is used in jest here * @module hack @@ -39,7 +39,7 @@ export async function run({ } // check for spam - if (server.police.frisk(socket, 6)) { + if (server.police.frisk(socket, 4)) { return server.reply({ cmd: 'warn', text: 'You are sending hack requests too fast. Wait a moment before trying again.', @@ -50,13 +50,13 @@ export async function run({ // verify user input // if this is a legacy client add missing params to payload + if (typeof payload.channel !== 'string') payload.channel = socket.channel; + if (socket.hcProtocol === 1) { if (typeof socket.channel === 'undefined' || typeof payload.nick !== 'string') { return true; } - - payload.channel = socket.channel; // eslint-disable-line no-param-reassign - } else if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') { + } else if (typeof payload.userid !== 'number') { return true; } diff --git a/commands/mod/kick.js b/commands/mod/kick.js index 93ca485..90ad5cf 100644 --- a/commands/mod/kick.js +++ b/commands/mod/kick.js @@ -1,17 +1,19 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Give da boot - * @version 1.0.0 + * @version 1.1.0 * @description Silently forces target client(s) into another channel * @module kick */ import { + isModerator, isChannelModerator, getUserDetails, } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; import { findUsers, @@ -31,22 +33,16 @@ export async function run({ return server.police.frisk(socket, 10); } - // check user input if (socket.hcProtocol === 1) { - if (typeof payload.nick !== 'string') { - if (typeof payload.nick !== 'object' && !Array.isArray(payload.nick)) { - return true; - } - } - payload.channel = socket.channel; // eslint-disable-line no-param-reassign - } else if (typeof payload.userid !== 'number') { - // @todo create multi-ban ui - if (typeof payload.userid !== 'object' && !Array.isArray(payload.userid)) { - if (typeof payload.nick !== 'string') { - return true; - } - } + } + + // check user input + const hasValidNick = typeof payload.nick === 'string' || Array.isArray(payload.nick); + const hasValidUserid = typeof payload.userid === 'number' || Array.isArray(payload.userid); + + if (!hasValidNick && !hasValidUserid) { + return true; } // find target user(s) @@ -62,8 +58,8 @@ export async function run({ // check if found targets are kickable, add them to the list if they are const kicked = []; - for (let i = 0, j = badClients.length; i < j; i += 1) { - if (badClients[i].level >= socket.level) { + badClients.forEach((client) => { + if (client.level >= socket.level) { server.reply({ cmd: 'warn', text: 'Cannot kick other users with the same level, how rude', @@ -71,61 +67,64 @@ export async function run({ channel: socket.channel, // @todo Multichannel }, socket); } else { - kicked.push(badClients[i]); + kicked.push(client); } - } + }); if (kicked.length === 0) { return true; } - let destChannel; + let destChannel = Math.random().toString(36).substr(2, 8); + if (typeof payload.to === 'string' && !!payload.to.trim()) { - destChannel = payload.to; - } else { - destChannel = Math.random().toString(36).substr(2, 8); + if (isModerator(socket.level)) { + destChannel = payload.to.trim(); + } } - // Announce the kicked clients arrival in destChannel and that they were kicked - // Before they arrive, so they don't see they got moved - for (let i = 0; i < kicked.length; i += 1) { + // announce the kicked clients arrival in destChannel and that they were kicked + // before they arrive, so they don't see they got moved + kicked.forEach((client) => { server.broadcast({ - ...getUserDetails(kicked[i]), + ...getUserDetails(client), ...{ cmd: 'onlineAdd', channel: destChannel, // @todo Multichannel }, }, { channel: destChannel }); - } + }); - // Move all kicked clients to the new channel - for (let i = 0; i < kicked.length; i += 1) { + // move all kicked clients to the new channel + kicked.forEach((client) => { // @todo multi-channel update - kicked[i].channel = destChannel; + client.channel = destChannel; server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` - text: `${kicked[i].nick} was banished to ?${destChannel}`, + cmd: 'info', + text: `${client.nick} was banished to ?${destChannel}`, + id: Info.Mod.KICKED_DETAILED, channel: socket.channel, // @todo Multichannel }, { channel: socket.channel, level: isChannelModerator }); - console.log(`${socket.nick} [${socket.trip}] kicked ${kicked[i].nick} in ${socket.channel} to ${destChannel} `); - } + console.log(`${socket.nick} [${socket.trip}] kicked ${client.nick} in ${socket.channel} to ${destChannel} `); + }); // broadcast client leave event - for (let i = 0, j = kicked.length; i < j; i += 1) { + kicked.forEach((client) => { server.broadcast({ cmd: 'onlineRemove', - userid: kicked[i].userid, - nick: kicked[i].nick, + userid: client.userid, + nick: client.nick, channel: socket.channel, // @todo Multichannel }, { channel: socket.channel }); - } + }); // publicly broadcast kick event server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Kicked ${kicked.map((k) => k.nick).join(', ')}`, + id: Info.Mod.KICKED, channel: socket.channel, // @todo Multichannel }, { channel: socket.channel, level: (level) => isChannelModerator(level) }); @@ -163,13 +162,12 @@ export function runKickCheck({ if (payload.text.startsWith('/kick ')) { const input = payload.text.split(' '); - // If there is no nick parameter const nick = input[1]; if (!nick || !nick.replace(/[^a-zA-Z0-9_]/g, '')) { server.reply({ cmd: 'warn', text: 'Failed to kick: Missing name. Refer to `/help kick` for instructions on how to use this command.', - id: Errors.Global.UNKNOWN_USER, // this is wrong #lazydev + id: Errors.Kick.MISSING_NICK, channel: socket.channel, // @todo Multichannel }, socket); @@ -207,5 +205,6 @@ export const info = { description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings', usage: ` API: { cmd: 'kick', nick: '', to: '' } + API: { cmd: 'kick', userid: , to: '' } Text: /kick `, }; diff --git a/commands/mod/lockroom.js b/commands/mod/lockroom.js index a53f38e..a90e056 100644 --- a/commands/mod/lockroom.js +++ b/commands/mod/lockroom.js @@ -3,16 +3,17 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Locks the channel - * @version 1.0.0 + * @version 1.1.0 * @description Locks a channel preventing default levels from joining * @module lockroom */ import { - isTrustedUser, isModerator, + isChannelModerator, verifyNickname, getUserPerms, + levels, } from '../utility/_UAC.js'; import { upgradeLegacyJoin, @@ -20,6 +21,7 @@ import { } from '../utility/_LegacyFunctions.js'; import { Errors, + Info, } from '../utility/_Constants.js'; import { canJoinChannel, @@ -69,41 +71,74 @@ export async function init(core) { export async function run({ core, server, socket, payload, }) { + if (typeof socket.channel !== 'string') { // @todo Multichannel + return false; // silently fail + } + // increase rate limit chance and ignore if not admin or mod - if (!isModerator(socket.level)) { + if (!isChannelModerator(socket.level)) { return server.police.frisk(socket, 10); } - let targetChannel; + const targetChannel = socket.channel; - if (typeof payload.channel !== 'string') { - if (typeof socket.channel !== 'string') { // @todo Multichannel - return false; // silently fail - } - - targetChannel = socket.channel; - } else { - targetChannel = payload.channel; - } - - if (core.locked[targetChannel]) { + if (typeof core.locked[targetChannel] !== 'undefined' && core.locked[targetChannel] !== false) { return server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'warn', text: 'Channel is already locked.', - channel: socket.channel, // @todo Multichannel + id: Errors.Global.INVALID_DATA, + channel: targetChannel, // @todo Multichannel }, socket); } - // apply lock flag to channel list - core.locked[targetChannel] = true; + let lockLevel = socket.level; + if (typeof payload.level !== 'undefined') { + if (typeof payload.level === 'string') { + if (typeof levels[payload.level] === 'number') { + lockLevel = levels[payload.level]; + } + } else if (typeof payload.level === 'number') { + if (lockLevel > 1) { + lockLevel = payload.level; + } + } else { + return server.reply({ + cmd: 'warn', + text: `Expected "level" to be a number or string label: ${Object.keys(levels).join(', ')}`, + id: Errors.LockRoom.LEVEL_REQUIRED, + channel: targetChannel, // @todo Multichannel + }, socket); + } + } + + if (lockLevel > socket.level) { + return server.reply({ + cmd: 'warn', + text: `Target level too high (${lockLevel}). You may only lock up to ${socket.level}`, + id: Errors.LockRoom.LEVEL_TOO_HIGH, + channel: targetChannel, // @todo Multichannel + }, socket); + } + + core.locked[targetChannel] = lockLevel; // inform mods server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` - text: `Channel: ?${targetChannel} lock enabled by [${socket.trip}]${socket.nick}`, + cmd: 'info', + text: `Channel: ?${targetChannel} locked to ${lockLevel} by [${socket.trip}]${socket.nick}`, + id: Info.Mod.LOCKED_DETAILED, + channel: targetChannel, // @todo Multichannel + }, { channel: targetChannel, level: isChannelModerator }); + + server.broadcast({ + cmd: 'info', + text: `Channel: ?${targetChannel} locked to ${lockLevel} by [${socket.trip}]${socket.nick}`, + id: Info.Mod.LOCKED_GLOBAL_NOTIFY, channel: false, // @todo Multichannel, false for global info }, { level: isModerator }); + console.log(`Channel: ?${targetChannel} locked to ${lockLevel} by [${socket.trip}]${socket.nick}`); + return true; } @@ -169,7 +204,7 @@ export function whisperCheck({ * string = error */ export function chatCheck({ - socket, payload, + core, server, socket, payload, }) { if (socket.channel === 'purgatory') { if (isModerator(socket.level)) { @@ -179,6 +214,32 @@ export function chatCheck({ return false; } + if (typeof payload.text !== 'string') { + return false; + } + + if (payload.text.startsWith('/lockroom')) { + const [, levelArg] = payload.text.split(' '); + + const newPayload = { + cmd: 'lockroom', + }; + + if (levelArg) { + const parsedLevel = Number(levelArg); + newPayload.level = !Number.isNaN(parsedLevel) ? parsedLevel : levelArg; + } + + run({ + core, + server, + socket, + payload: newPayload, + }); + + return false; + } + return payload; } @@ -214,14 +275,14 @@ export function joinCheck({ core, server, socket, payload, }) { // check if target channel is locked - if (typeof core.locked[payload.channel] === 'undefined' || core.locked[payload.channel] !== true) { + if (typeof core.locked[payload.channel] === 'undefined' || core.locked[payload.channel] === false) { if (payload.channel !== 'purgatory') { return payload; } } // `join` is the legacy entry point, check if it needs to be upgraded - if (typeof socket.hcProtocol === 'undefined') { + if (typeof socket.hcProtocol === 'undefined' || socket.hcProtocol === 1) { payload = upgradeLegacyJoin(server, socket, payload); } @@ -278,8 +339,8 @@ export function joinCheck({ }; // check if trip is allowed - if (userInfo.uType === 'user') { - if (userInfo.trip == null || isTrustedUser(level) === false) { + if (!isModerator(userInfo.level)) { + if (core.locked[channel] > userInfo.level) { const origNick = userInfo.nick; const origChannel = payload.channel; @@ -296,15 +357,17 @@ export function joinCheck({ setTimeout(() => { server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: danteQuotes[Math.floor(Math.random() * danteQuotes.length)], + id: Info.Core.PURGATORY_QUOTE, channel: 'purgatory', // @todo Multichannel }, socket); }, 100); server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${payload.nick} is: ${origNick}\ntrip: ${userInfo.trip || 'none'}\ntried to join: ?${origChannel}\nhash: ${userInfo.hash}`, + id: Info.Core.PURGATORY_NOTIFY, channel: 'purgatory', // @todo Multichannel, false for global info }, { channel: 'purgatory', level: isModerator }); } @@ -327,5 +390,6 @@ export const info = { category: 'moderators', description: 'Locks a channel preventing default levels from joining', usage: ` - API: { cmd: 'lockroom', channel: '' }`, + API: { cmd: 'lockroom', channel: '', level: } + Text: /lockroom`, }; diff --git a/commands/mod/speak.js b/commands/mod/speak.js index 9803c54..480c3e1 100644 --- a/commands/mod/speak.js +++ b/commands/mod/speak.js @@ -3,7 +3,7 @@ /** * @author OpSimple ( https://github.com/OpSimple ) * @summary Unmuzzle a user - * @version 1.0.0 + * @version 1.1.0 * @description Pardon a dumb user to be able to speak again * @module speak */ @@ -13,6 +13,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; /** @@ -56,8 +57,9 @@ export async function run({ core.muzzledHashes = {}; return server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${socket.nick} unmuzzled all users`, + id: Info.Mod.UNMUZZLED_ALL, channel: false, // @todo Multichannel, false for global }, { level: isModerator }); } @@ -65,8 +67,9 @@ export async function run({ core.muzzledHashes = {}; return server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${socket.nick} unmuzzled all users`, + id: Info.Mod.UNMUZZLED_ALL, channel: false, // @todo Multichannel, false for global }, { level: isModerator }); } @@ -83,8 +86,9 @@ export async function run({ // notify mods server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${socket.nick}#${socket.trip} unmuzzled : ${target}`, + id: Info.Mod.UNMUZZLED_DETAILED, channel: false, // @todo Multichannel, false for global }, { level: isModerator }); diff --git a/commands/mod/unban.js b/commands/mod/unban.js index 9679e71..c9ea6c2 100644 --- a/commands/mod/unban.js +++ b/commands/mod/unban.js @@ -1,7 +1,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Unban a user - * @version 1.0.0 + * @version 1.1.0 * @description Un-bans target user by ip or hash * @module unban */ @@ -11,6 +11,7 @@ import { } from '../utility/_UAC.js'; import { Errors, + Info, } from '../utility/_Constants.js'; /** @@ -59,15 +60,17 @@ export async function run({ // reply with success server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Unbanned ${target}`, + id: Info.Mod.UNBANNED, channel: socket.channel, // @todo Multichannel }, socket); // notify mods server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${socket.nick}#${socket.trip} unbanned: ${target}`, + id: Info.Mod.UNBANNED_DETAILED, channel: false, // @todo Multichannel, false for global }, { level: isModerator }); diff --git a/commands/mod/unbanall.js b/commands/mod/unbanall.js index 4856437..3b5601f 100644 --- a/commands/mod/unbanall.js +++ b/commands/mod/unbanall.js @@ -1,7 +1,7 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Released them from the void - * @version 1.0.0 + * @version 1.1.0 * @description Clears all banned ip addresses * @module unbanall */ @@ -9,6 +9,9 @@ import { isModerator, } from '../utility/_UAC.js'; +import { + Info, +} from '../utility/_Constants.js'; /** * Executes when invoked by a remote client @@ -31,15 +34,17 @@ export async function run({ core, server, socket }) { // reply with success server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: 'Unbanned all ip addresses', + id: Info.Mod.UNBANNED_ALL, channel: socket.channel, // @todo Multichannel }, socket); // notify mods server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `${socket.nick}#${socket.trip} unbanned all ip addresses`, + id: Info.Mod.UNBANNED_ALL_DETAILED, channel: false, // @todo Multichannel, false for global }, { level: isModerator }); diff --git a/commands/mod/unlockroom.js b/commands/mod/unlockroom.js index fa2843b..e610058 100644 --- a/commands/mod/unlockroom.js +++ b/commands/mod/unlockroom.js @@ -3,14 +3,18 @@ /** * @author Marzavec ( https://github.com/marzavec ) * @summary Unlock target channel - * @version 1.0.0 + * @version 1.1.0 * @description Unlocks a channel allowing anyone to join * @module unlockroom */ import { - isModerator, + isChannelModerator, } from '../utility/_UAC.js'; +import { + Errors, + Info, +} from '../utility/_Constants.js'; /** * Automatically executes once after server is ready @@ -31,46 +35,89 @@ export async function init(core) { * @return {void} */ export async function run({ - core, server, socket, payload, + core, server, socket, }) { // increase rate limit chance and ignore if not admin or mod - if (!isModerator(socket.level)) { + if (!isChannelModerator(socket.level)) { return server.police.frisk(socket, 10); } - let targetChannel; + const targetChannel = socket.channel; - if (typeof payload.channel !== 'string') { - if (typeof socket.channel !== 'string') { // @todo Multichannel - return false; // silently fail - } - - targetChannel = socket.channel; - } else { - targetChannel = payload.channel; + if (typeof core.locked[targetChannel] === 'undefined' || core.locked[targetChannel] === false) { + return server.reply({ + cmd: 'warn', + text: 'Channel is not locked.', + id: Errors.Global.INVALID_DATA, + channel: targetChannel, // @todo Multichannel + }, socket); } - if (!core.locked[targetChannel]) { + if (core.locked[targetChannel] > socket.level) { return server.reply({ - cmd: 'info', // @todo Add numeric info code as `id` - text: 'Channel is not locked.', - channel: socket.channel, // @todo Multichannel + cmd: 'warn', + text: `Level ${core.locked[targetChannel]} required, you are level ${socket.level}`, + id: Errors.LockRoom.LEVEL_REQUIRED, + channel: targetChannel, // @todo Multichannel }, socket); } core.locked[targetChannel] = false; server.broadcast({ - cmd: 'info', // @todo Add numeric info code as `id` + cmd: 'info', text: `Channel: ?${targetChannel} unlocked by [${socket.trip}]${socket.nick}`, - channel: targetChannel, // @todo Multichannel, false for global info - }, { channel: targetChannel, level: isModerator }); + id: Info.Mod.UNLOCKED_DETAILED, + channel: targetChannel, // @todo Multichannel + }, { channel: targetChannel, level: isChannelModerator }); - console.log(`Channel: ?${targetChannel} unlocked by [${socket.trip}]${socket.nick} in ${socket.channel}`); + console.log(`Channel: ?${targetChannel} unlocked by [${socket.trip}]${socket.nick}`); return true; } +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server environment object + * @public + * @return {void} + */ +export function initHooks(server) { + server.registerHook('in', 'chat', this.chatCheck.bind(this), 4); +} + +/** + * Executes every time an incoming chat command is invoked; + * hook incoming chat commands, reject them if the channel is 'purgatory' + * @param {Object} env - Environment object with references to core, server, socket & payload + * @public + * @return {(Object|boolean|string)} Object = same/altered payload, + * false = suppress action, + * string = error + */ +export function chatCheck({ + core, server, socket, payload, +}) { + if (typeof payload.text !== 'string') { + return false; + } + + if (payload.text.startsWith('/unlockroom')) { + this.run({ + core, + server, + socket, + payload: { + cmd: 'unlockroom', + }, + }); + + return false; + } + + return payload; +} + /** * Module meta information * @public diff --git a/commands/utility/_Constants.js b/commands/utility/_Constants.js index b1b5f69..816655b 100644 --- a/commands/utility/_Constants.js +++ b/commands/utility/_Constants.js @@ -10,7 +10,7 @@ * Internal version, used mainly for debugging * @typedef {object} CodebaseVersion */ -export const CodebaseVersion = '2.2.25b'; +export const CodebaseVersion = '2.2.3b'; /* Base error ranges */ const GlobalErrors = 10; @@ -34,6 +34,9 @@ const ForceColorErrors = WhisperErrors + 10; const ForceFlairErrors = ForceColorErrors + 10; const UsersErrors = ForceFlairErrors + 10; const HackRequest = UsersErrors + 10; +const KickErrors = HackRequest + 10; +const LockRoomErrors = KickErrors + 10; +const WalletErrors = LockRoomErrors + 10; /** * Holds the numeric id values for each error type @@ -47,6 +50,9 @@ export const Errors = { INTERNAL_ERROR: GlobalErrors + 4, MISSING_TRIPCODE: GlobalErrors + 5, UNKNOWN_CMD: GlobalErrors + 6, + INVALID_PAYLOAD: GlobalErrors + 7, + LOGIN_REQUIRED: GlobalErrors + 8, + INVALID_DATA: GlobalErrors + 9, }, Captcha: { @@ -149,6 +155,93 @@ export const Errors = { TOO_LONG: HackRequest + 3, BAD_URL: HackRequest + 4, }, + + Kick: { + MISSING_NICK: KickErrors + 1, + }, + + LockRoom: { + LEVEL_TOO_HIGH: LockRoomErrors + 1, + LEVEL_REQUIRED: LockRoomErrors + 2, + }, + + Wallet: { + INVALID_AMOUNT: WalletErrors + 1, + MISSING_AMOUNT: WalletErrors + 2, + }, +}; + +/* Base Info Ranges */ +const InfoStart = 1000; // Start high to avoid collision +const AdminInfo = InfoStart + 100; +const ModInfo = AdminInfo + 100; +const CoreInfo = ModInfo + 100; +const CaptchaInfo = CoreInfo + 100; +const WalletInfo = CaptchaInfo + 100; + +/** + * Holds the numeric id values for each info type + * @typedef {object} Info + */ +export const Info = { + Admin: { + YOU_ARE_MOD: AdminInfo + 1, + MOD_ADDED: AdminInfo + 2, + MOD_ADDED_BROADCAST: AdminInfo + 3, + BOMB_STATUS: AdminInfo + 4, + USER_LIST: AdminInfo + 5, + RELOAD_STATUS: AdminInfo + 6, + YOU_ARE_USER: AdminInfo + 7, + MOD_REMOVED: AdminInfo + 8, + MOD_REMOVED_BROADCAST: AdminInfo + 9, + CONFIG_SAVED: AdminInfo + 10, + SHOUT: AdminInfo + 11, + }, + + Mod: { + BANNED: ModInfo + 1, + BANNED_DETAILED: ModInfo + 2, + MUZZLED_DETAILED: ModInfo + 3, + KICKED_DETAILED: ModInfo + 4, + KICKED: ModInfo + 5, + LOCKED_DETAILED: ModInfo + 6, + LOCKED_GLOBAL_NOTIFY: ModInfo + 7, + UNMUZZLED_ALL: ModInfo + 8, + UNMUZZLED_DETAILED: ModInfo + 9, + UNBANNED: ModInfo + 10, + UNBANNED_DETAILED: ModInfo + 11, + UNBANNED_ALL: ModInfo + 12, + UNBANNED_ALL_DETAILED: ModInfo + 13, + UNLOCKED_DETAILED: ModInfo + 14, + UWUIFY_ENABLED: ModInfo + 15, + UWUIFY_DISABLED: ModInfo + 16, + }, + + Core: { + NICK_CHANGED: CoreInfo + 1, + MY_HASH: CoreInfo + 2, + HELP_TEXT: CoreInfo + 3, + MOTD: CoreInfo + 4, + STATS_FULL: CoreInfo + 5, + STATS_BASIC: CoreInfo + 6, + PURGATORY_QUOTE: CoreInfo + 7, + PURGATORY_NOTIFY: CoreInfo + 8, + }, + + Captcha: { + NOT_ENABLED: CaptchaInfo + 1, + DISABLED: CaptchaInfo + 2, + ALREADY_ENABLED: CaptchaInfo + 3, + ENABLED: CaptchaInfo + 4, + }, + + Wallet: { + DISCONNECTED: WalletInfo + 1, + ADDRESS_REQUESTED: WalletInfo + 2, + TX_RELAYED: WalletInfo + 3, + VIEWED: WalletInfo + 4, + CONNECTED: WalletInfo + 5, + }, }; /** @@ -182,13 +275,14 @@ export const SystemMOTDs = [ 'Protip: Use /getchannels anytime to see a list of public channels', 'Protip: You can do ==/help== or ==/help command==', 'Protip: Privately message with: /whisper @name The message', + 'Protip: A moderator can lock a channel with: /lockroom', ]; /** * Maximum length of a channels MOTD string * @typedef {object} MaxMOTDLength */ -export const MaxMOTDLength = 250; +export const MaxMOTDLength = 500; /** * Maximum number of specialized trip levels, per channel diff --git a/commands/utility/_LegacyFunctions.js b/commands/utility/_LegacyFunctions.js index bb9f518..18ce41b 100644 --- a/commands/utility/_LegacyFunctions.js +++ b/commands/utility/_LegacyFunctions.js @@ -24,10 +24,15 @@ import { export function upgradeLegacyJoin(server, socket, payload) { const newPayload = payload; + // this is why we can't have nice things + if (typeof payload.nick === 'undefined' || !payload.nick) { + payload.nick = `scarmiglione_${Math.floor(Math.random() * 99999)}`; + } + // `join` is the legacy entry point, so apply protocol version socket.hcProtocol = 1; - // these would have been applied in the `session` module, apply it now + // these would have been applied in the `session` module, apply them now socket.hash = server.getSocketHash(socket); socket.isBot = false; socket.color = false; diff --git a/commands/utility/_Text.js b/commands/utility/_Text.js index 308ad63..53cecf6 100644 --- a/commands/utility/_Text.js +++ b/commands/utility/_Text.js @@ -2,8 +2,9 @@ /** * @author MinusGix ( https://github.com/MinusGix ) + * @author Marzavec ( https://github.com/marzavec ) * @summary General string helper functions - * @version v1.0.0 + * @version v1.1.0 * @description A library of several commonly used string functions * @module Text */ @@ -29,3 +30,11 @@ export const parseText = (text) => { return sanitizedText; }; + +/** + * Validate a string as a valid hex color string + * @param {string} color - Color string to validate + * @public + * @return {boolean} + */ +export const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); diff --git a/commands/wallet/disconnectwallet.js b/commands/wallet/disconnectwallet.js new file mode 100644 index 0000000..b58a541 --- /dev/null +++ b/commands/wallet/disconnectwallet.js @@ -0,0 +1,59 @@ +/** + * @author Marzavec + * @summary Disconnect a user's wallet + * @version 1.0.0 + * @description Removes wallet session data and resets user state + * @module disconnectwallet + */ + +import { + Errors, + Info, +} from '../utility/_Constants.js'; + +/** + * Executes when invoked by a remote client + * @param {Object} env - Environment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + server, socket, +}) { + // Check if wallet exists + if (typeof socket.wallet === 'undefined') { + return server.reply({ + cmd: 'warn', + text: 'No wallet currently connected', + id: Errors.Global.LOGIN_REQUIRED, + channel: socket.channel, + }, socket); + } + + const oldAddress = socket.wallet.address; + delete socket.wallet; + + return server.reply({ + cmd: 'info', + text: `Wallet disconnected (${oldAddress.slice(0, 4)}...${oldAddress.slice(-4)})`, + id: Info.Wallet.DISCONNECTED, + channel: socket.channel, + }, socket); +} + +/** + * Module meta information + * @public + * @typedef {Object} disconnectwallet/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'disconnectwallet', + category: 'wallet', + description: 'Disconnects the currently attached Solana wallet', + usage: ` + API: { cmd: 'disconnectwallet' }`, +}; diff --git a/commands/wallet/getwallet.js b/commands/wallet/getwallet.js new file mode 100644 index 0000000..24ca2bb --- /dev/null +++ b/commands/wallet/getwallet.js @@ -0,0 +1,117 @@ +/** + * @author Marzavec + * @summary Retrieve a user's wallet address + * @version 1.0.0 + * @description Checks if a target user has a connected wallet and returns the address + * @module getwallet + */ + +import { + Errors, + Info, +} from '../utility/_Constants.js'; +import { + findUser, +} from '../utility/_Channels.js'; + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + server, socket, payload, +}) { + // must be in a channel to run this command + if (typeof socket.channel === 'undefined') { + return server.police.frisk(socket, 1); + } + + server.police.frisk(socket, 2); + + let targetUser = null; + + if (typeof payload.userid === 'number') { + targetUser = findUser( + server, + { + channel: socket.channel, + userid: payload.userid, + }, + ); + } else if (typeof payload.nick === 'string') { + targetUser = findUser( + server, + { + channel: socket.channel, + nick: payload.nick, + }, + ); + } else { + return server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, + }, socket); + } + + if (!targetUser) { + return server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, + }, socket); + } + + if (typeof targetUser.wallet !== 'object' || typeof targetUser.wallet.address !== 'string') { + return server.reply({ + cmd: 'warn', + text: `@${targetUser.nick} has not connected a wallet`, + id: Errors.Global.INVALID_DATA, + channel: socket.channel, + }, socket); + } + + server.send({ + cmd: 'info', + text: `${socket.nick} requested your wallet address`, + id: Info.Wallet.ADDRESS_REQUESTED, + channel: socket.channel, + }, targetUser); + + return server.reply({ + cmd: 'walletInfo', + userid: targetUser.userid, + nick: targetUser.nick, + address: targetUser.wallet.address, + channel: socket.channel, + }, socket); +} + +/** + * The following payload properties are required to invoke this module: + * "userid" OR "nick" + * @public + * @typedef {Array} getwallet/requiredData + */ +// export const requiredData = ['userid']; + +/** + * Module meta information + * @public + * @typedef {Object} getwallet/info + * @property {string} name - Module command name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'getwallet', + category: 'wallet', + description: 'Retrieves the public wallet address of a specific user', + usage: ` + API: { cmd: 'getwallet', userid: } + API: { cmd: 'getwallet', nick: }`, +}; diff --git a/commands/wallet/relaytx.js b/commands/wallet/relaytx.js new file mode 100644 index 0000000..a190083 --- /dev/null +++ b/commands/wallet/relaytx.js @@ -0,0 +1,144 @@ +/** + * @author Marzavec + * @summary Relay a transaction to another user for signing + * @version 1.0.0 + * @description Accepts a base64 transaction and forwards it to a target user to sign + * @module relaytx + */ + +import { + Errors, + Info, +} from '../utility/_Constants.js'; +import { + findUser, +} from '../utility/_Channels.js'; + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + server, socket, payload, +}) { + // must be in a channel to run this command + if (typeof socket.channel === 'undefined') { + return server.police.frisk(socket, 1); + } + + server.police.frisk(socket, 2); + + if (typeof socket.wallet !== 'object' || typeof socket.wallet.address !== 'string') { + return server.reply({ + cmd: 'warn', + text: 'You must connect a wallet first', + id: Errors.Global.LOGIN_REQUIRED, + channel: socket.channel, + }, socket); + } + + if (typeof payload.tx !== 'string' || payload.tx.length === 0) { + return server.reply({ + cmd: 'warn', + text: 'Missing or invalid transaction data', + id: Errors.Global.INVALID_DATA, + channel: socket.channel, + }, socket); + } + + let targetUser = null; + + if (typeof payload.userid === 'number') { + targetUser = findUser( + server, + { + channel: socket.channel, + userid: payload.userid, + }, + ); + } else if (typeof payload.nick === 'string') { + targetUser = findUser( + server, + { + channel: socket.channel, + nick: payload.nick, + }, + ); + } else { + return server.reply({ + cmd: 'warn', + text: 'You must specify a target user by nick or userid', + id: Errors.Global.INVALID_DATA, + channel: socket.channel, + }, socket); + } + + if (!targetUser) { + return server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, + }, socket); + } + + if (targetUser.userid === socket.userid) { + return server.reply({ + cmd: 'warn', + text: 'You cannot relay transactions to yourself', + id: Errors.Global.INVALID_DATA, + channel: socket.channel, + }, socket); + } + + if (typeof targetUser.wallet !== 'object' || typeof targetUser.wallet.address !== 'string') { + return server.reply({ + cmd: 'warn', + text: `@${targetUser.nick} does not have a connected wallet`, + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, + }, socket); + } + + server.reply({ + cmd: 'signTransaction', + tx: payload.tx, + type: '3RD_PARTY_TRANSFER', + from: socket.nick, + channel: socket.channel, + }, targetUser); + + return server.reply({ + cmd: 'info', + text: `TX sent to @${targetUser.nick}`, + id: Info.Wallet.TX_RELAYED, + channel: socket.channel, + }, socket); +} + +/** + * The following payload properties are required to invoke this module: + * "tx", and either "userid" or "nick" + * @public + * @typedef {Array} relaytx/requiredData + */ +export const requiredData = ['tx']; + +/** + * Module meta information + * @public + * @typedef {Object} relaytx/info + * @property {string} name - Module command name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'relaytx', + category: 'wallet', + description: 'Relays a base64 transaction to a target user for signature', + usage: ` + API: { cmd: 'relaytx', tx: , userid: } + API: { cmd: 'relaytx', tx: , nick: }`, +}; diff --git a/commands/wallet/sendsol.js b/commands/wallet/sendsol.js new file mode 100644 index 0000000..8754b4b --- /dev/null +++ b/commands/wallet/sendsol.js @@ -0,0 +1,307 @@ +/** + * @author Marzavec + * @summary Allow a Solana transfer + * @version 1.0.0 + * @description Builds a transaction for a Solana transfer + * @module sendsol + */ + +import { + PublicKey, + Transaction, + SystemProgram, + ComputeBudgetProgram, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; +import { createSolanaRpc } from '@solana/kit'; + +import { + Errors, + Info, +} from '../utility/_Constants.js'; +import { + findUser, +} from '../utility/_Channels.js'; +// import { Buffer } from 'buffer'; + +const RPC_URL = 'https://solana-rpc.parafi.tech'; +const SERVER_WALLET = 'HACkoKCBiLiWjuVf4S4gTbFqJohVC6VkacBEBTtUCHat'; + +/** + * Automatically executes once after server is ready or after a hot-reload + * Ensures the shared Solana RPC client is initialized in the core environment + * @param {Object} core - Reference to core environment object + * @public + * @return {void} + */ +export async function init(core) { + if (typeof core.solanaRPC === 'undefined') { + core.solanaRPC = createSolanaRpc(RPC_URL); + } +} + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + core, server, socket, payload, +}) { + // must be in a channel to run this command + if (typeof socket.channel === 'undefined') { + return server.police.frisk(socket, 1); + } + + server.police.frisk(socket, 8); + + // client must have a confirmed wallet + if (typeof socket.wallet !== 'object' || typeof socket.wallet.address !== 'string') { + return server.send({ + cmd: 'warn', + text: 'You must connect a wallet first', + id: Errors.Global.LOGIN_REQUIRED, + channel: socket.channel, // @todo Multichannel + }, socket); + } + + if (typeof payload.amount !== 'number' || payload.amount <= 0) { + return server.reply({ + cmd: 'warn', + text: 'Invalid amount', + id: Errors.Wallet.INVALID_AMOUNT, + channel: socket.channel, // @todo Multichannel + }, socket); + } + + let targetUser = null; + + if (typeof payload.userid === 'number') { + targetUser = findUser( + server, + { + channel: socket.channel, + userid: payload.userid, + }, + ); + } else if (typeof payload.nick === 'string') { + targetUser = findUser( + server, + { + channel: socket.channel, + nick: payload.nick, + }, + ); + } else { + return server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel + }, socket); + } + + if (!targetUser) { + return server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel + }, socket); + } + + if (targetUser.userid === socket.userid) { + return server.reply({ + cmd: 'warn', + text: 'You cannot relay transactions to yourself', + id: Errors.Global.INVALID_DATA, + channel: socket.channel, + }, socket); + } + + // target user must have a confirmed wallet + if (typeof targetUser.wallet !== 'object' || typeof targetUser.wallet.address !== 'string') { + return server.send({ + cmd: 'warn', + text: `@${targetUser.nick} must connect a wallet first`, + id: Errors.Global.LOGIN_REQUIRED, + channel: socket.channel, // @todo Multichannel + }, socket); + } + + server.send({ + cmd: 'info', + text: `${socket.nick} viewed your wallet`, + id: Info.Wallet.VIEWED, + channel: socket.channel, // @todo Multichannel + }, targetUser); + + const senderPubkey = new PublicKey(socket.wallet.address); + const recipientPubkey = new PublicKey(targetUser.wallet.address); + const SERVER_ADDRESS = new PublicKey(SERVER_WALLET); + + const mainAmountLamports = Math.floor(payload.amount * LAMPORTS_PER_SOL); + + const feePercentage = 0.01; + const feeAmountLamports = Math.floor(mainAmountLamports * feePercentage); + + if (mainAmountLamports < 1 || feeAmountLamports < 1) { + return server.reply({ + cmd: 'warn', + text: 'Transfer amount too low to cover required fees', + id: Errors.Wallet.INVALID_AMOUNT, + channel: socket.channel, + }, socket); + } + + const transaction = new Transaction(); + + transaction.add( + ComputeBudgetProgram.setComputeUnitLimit({ units: 300000 }), + ); + + transaction.add( + ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 100000 }), + ); + + transaction.add( + SystemProgram.transfer({ + fromPubkey: senderPubkey, + toPubkey: recipientPubkey, + lamports: mainAmountLamports, + }), + ); + + transaction.add( + SystemProgram.transfer({ + fromPubkey: senderPubkey, + toPubkey: SERVER_ADDRESS, + lamports: feeAmountLamports, + }), + ); + + const rpcResponse = await core.solanaRPC.getLatestBlockhash().send(); + const latestBlockhash = rpcResponse.value; + + if (!latestBlockhash || !latestBlockhash.blockhash) { + return server.reply({ + cmd: 'warn', + text: 'RPC error, try again later', + id: Errors.Global.INTERNAL_ERROR, + channel: socket.channel, + }, socket); + } + + transaction.feePayer = senderPubkey; + transaction.recentBlockhash = latestBlockhash.blockhash; + + const serializedTx = transaction.serialize({ + requireAllSignatures: false, + verifySignatures: false, + }); + + const base64Tx = serializedTx.toString('base64'); + + return server.reply({ + cmd: 'signTransaction', + tx: base64Tx, + type: 'STANDARD_TRANSFER', + from: false, + channel: socket.channel, + }, socket); +} + +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server environment object + * @public + * @return {void} + */ +export function initHooks(server) { + server.registerHook('in', 'chat', this.runSendSolCheck.bind(this), 29); +} + +/** + * Executes every time an incoming chat command is invoked + * @param {Object} env - Environment object with references to core, server, socket & payload + * @public + * @return {(Object|boolean|string)} Object = same/altered payload, + * false = suppress action, + * string = error + */ +export function runSendSolCheck({ + core, server, socket, payload, +}) { + if (typeof payload.text !== 'string') { + return false; + } + + if (payload.text.startsWith('/sendsol ')) { + const input = payload.text.split(' '); + + const nick = input[1]; + if (!nick || !nick.replace(/[^a-zA-Z0-9_]/g, '')) { + server.reply({ + cmd: 'warn', + text: 'Failed to send sol: Missing name. Refer to `/help sendsol` for instructions on how to use this command.', + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel + }, socket); + + return false; + } + + const amount = Number(input[2]); + if (!amount || Number.isNaN(amount)) { + server.reply({ + cmd: 'warn', + text: 'Failed to send sol: Missing amount. Refer to `/help sendsol` for instructions on how to use this command.', + id: Errors.Wallet.INVALID_AMOUNT, + channel: socket.channel, // @todo Multichannel + }, socket); + + return false; + } + + this.run({ + core, + server, + socket, + payload: { + cmd: 'sendsol', + nick: nick.replace(/[^a-zA-Z0-9_]/g, ''), + amount, + }, + }); + + return false; + } + + return payload; +} + +/** + * The following payload properties are required to invoke this module: + * "userid", "amount" + * @public + * @typedef {Array} sendsol/requiredData + */ +export const requiredData = ['userid', 'amount']; + +/** + * Module meta information + * @public + * @typedef {Object} sendsol/info + * @property {string} name - Module command name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'sendsol', + category: 'wallet', + description: 'Constructs a Solana transaction to send funds to another user', + usage: ` + API: { cmd: 'sendsol', userid: , amount: } + Text: /sendsol @nick 23`, +}; diff --git a/commands/wallet/signsiw.js b/commands/wallet/signsiw.js new file mode 100644 index 0000000..813dcd7 --- /dev/null +++ b/commands/wallet/signsiw.js @@ -0,0 +1,249 @@ +/** + * @author Marzavec + * @summary Finalize a siw + * @version 1.0.0 + * @description Finalize a siw, check for NFT ownership, and sync permissions + * @module signsiw + */ + +import nacl from 'tweetnacl'; +import bs58 from 'bs58'; +import { PublicKey } from '@solana/web3.js'; +import { BorshCoder } from '@coral-xyz/anchor'; +import { createSolanaRpc } from '@solana/kit'; + +import { + levels, + getAppearance, + getUserDetails, +} from '../utility/_UAC.js'; + +import { + getChannelSettings, +} from '../utility/_Channels.js'; + +import { + Info, +} from '../utility/_Constants.js'; + +const RPC_URL = 'https://api.devnet.solana.com'; +const PROGRAM_ID = new PublicKey('HACkoKCBiLiWjuVf4S4gTbFqJohVC6VkacBEBTtUCHat'); // @todo +const IDL = { + address: 'HACkoKCBiLiWjuVf4S4gTbFqJohVC6VkacBEBTtUCHat', // @todo + metadata: { name: 'hackchat_sc', version: '0.1.0', spec: '0.1.0' }, + accounts: [ + { + name: 'ChannelState', + discriminator: [74, 132, 141, 196, 64, 52, 83, 136], + }, + ], + types: [ + { + name: 'ChannelState', + type: { + kind: 'struct', + fields: [ + { name: 'channel_name', type: 'string' }, + { name: 'owner_nft_mint', type: 'pubkey' }, + { name: 'owner_wallet', type: 'pubkey' }, + { name: 'moderator_trips', type: { vec: { array: ['u8', 6] } } }, + { name: 'bump', type: 'u8' }, + ], + }, + }, + ], +}; + +/** + * Automatically executes once after server is ready or after a hot-reload + * @param {Object} core - Reference to core environment object + * @public + * @return {void} + */ +export async function init(core) { + if (typeof core.solanaRPC === 'undefined') { + core.solanaRPC = createSolanaRpc(RPC_URL); + } + + // core.hackchatCoder = new BorshCoder(IDL); +} + +/** + * Checks Blockchain PDA for permissions + * @param {string} channelName - The name of the channel (e.g., "general") + * @param {string} walletAddress - The user's verified wallet address + * @param {string} userTrip - The user's current trip code (if any) + * @param {Object} core - Core environment (for RPC and Coder) + * @returns {Promise} - Returns the new level (number) or null if no perms found + */ +async function checkChainPermissions(channelName, walletAddress, userTrip, core) { + try { + const [pda] = PublicKey.findProgramAddressSync( + [Buffer.from('channel'), Buffer.from(channelName)], + PROGRAM_ID, + ); + + const accountInfo = await core.solanaRPC.getAccountInfo(pda); + + if (!accountInfo) { + return null; + } + + const accountData = core.hackchatCoder.accounts.decode( + 'ChannelState', + accountInfo.data, + ); + + if (accountData.ownerWallet.toString() === walletAddress) { + return levels.channelOwner; + } + + if (userTrip && accountData.moderatorTrips) { + const tripBuffer = Buffer.from(userTrip); + + const isMod = accountData.moderatorTrips.some((modTripBytes) => { + const modTripBuffer = Buffer.from(modTripBytes); + return modTripBuffer.equals(tripBuffer); + }); + + if (isMod) { + return levels.channelModerator; + } + } + + return null; + } catch (err) { + console.error('Error checking chain permissions:', err); + return null; + } +} + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + core, server, socket, payload, +}) { + // must be in a channel to run this command + if (typeof socket.channel === 'undefined') { + return server.police.frisk(socket, 1); + } + + if (typeof socket.siwMsg === 'undefined' || typeof socket.siwAddress === 'undefined') { + return false; + } + + if (typeof payload.signature !== 'string' || typeof payload.signedMessage !== 'string') { + return false; + } + + if (payload.signedMessage !== socket.siwMsg) { + return false; + } + + const now = new Date(); + if (!socket.siwExpiry || socket.siwExpiry < now) { + return false; + } + + const tempSiwAddress = socket.siwAddress; + + socket.siwMsg = undefined; + socket.siwAddress = undefined; + socket.siwExpiry = undefined; + + const messageBytes = new TextEncoder().encode(payload.signedMessage); + const publicKeyBytes = bs58.decode(tempSiwAddress); + const signatureBytes = bs58.decode(payload.signature); + + let isVerified = false; + try { + isVerified = nacl.sign.detached.verify( + messageBytes, + signatureBytes, + publicKeyBytes, + ); + } catch (e) { + return false; + } + + if (isVerified) { + socket.wallet = {}; + socket.wallet.address = tempSiwAddress; + + let replyText = `Now connected to: ${tempSiwAddress}`; + + const channelSettings = getChannelSettings(core.appConfig.data, socket.channel); + + let newLevel = null; + + if (!channelSettings.owned) { + /* newLevel = await checkChainPermissions( + socket.channel, + tempSiwAddress, + socket.trip, + core, + ); */ + } + + // only update if the new level is higher than what they currently have + if (newLevel !== null && newLevel > socket.level) { + socket.level = newLevel; + + const { color, flair } = getAppearance(newLevel); + socket.color = color; + socket.flair = flair; + + server.broadcast({ + ...getUserDetails(socket), + ...{ + cmd: 'updateUser', + channel: socket.channel, + }, + }, { channel: socket.channel }); + + if (newLevel === levels.channelOwner) { + replyText += ' You are the verified owner of this channel'; + } else if (newLevel === levels.channelModerator) { + replyText += ' You are a verified moderator of this channel'; + } + } + + return server.reply({ + cmd: 'info', + text: replyText, + id: Info.Wallet.CONNECTED, + channel: socket.channel, + }, socket); + } + + return false; +} + +/** + * The following payload properties are required to invoke this module: + * "signature", "signedMessage" + * @public + * @typedef {Array} signsiw/requiredData + */ +export const requiredData = ['signature', 'signedMessage']; + +/** + * Module meta information + * @public + * @typedef {Object} signsiw/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'signsiw', + category: 'wallet', + description: 'Verifies the wallet signature and syncs on-chain channel permissions', + usage: ` + API: { cmd: 'signsiw', signature: '', signedMessage: '' }`, +}; diff --git a/commands/wallet/siw.js b/commands/wallet/siw.js new file mode 100644 index 0000000..771f006 --- /dev/null +++ b/commands/wallet/siw.js @@ -0,0 +1,181 @@ +/** + * @author Marzavec + * @summary Allow a siw + * @version 1.0.0 + * @description Initiates a Sign-In-With-Solana request + * @module siw + */ + +import crypto from 'crypto'; + +const solanaAddressRegex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/; +const isValidSolanaAddress = (address) => solanaAddressRegex.test(address); + +const getMessage = (locale, address, nonce, expires) => { + const now = new Date(); + let header = 'hack.chat wants you to sign in with your Solana account:'; + let body = 'This action will authenticate your session and grant you access to restricted features.'; + const footer = `Version: 1 +Chain ID: solana:mainnet +Nonce: ${nonce} +Issued At: ${now.toISOString()} +Expiration Time: ${expires.toISOString()}`; + + // @todo + switch (locale) { + case 'ar': + header = ''; + body = ''; + break; + case 'bn': + header = ''; + body = ''; + break; + case 'cn': + header = ''; + body = ''; + break; + case 'de': + header = ''; + body = ''; + break; + case 'el': + header = ''; + body = ''; + break; + case 'es': + header = ''; + body = ''; + break; + case 'fa': + header = ''; + body = ''; + break; + case 'fi': + header = ''; + body = ''; + break; + case 'fr': + header = ''; + body = ''; + break; + case 'hi': + header = ''; + body = ''; + break; + case 'id': + header = ''; + body = ''; + break; + case 'it': + header = ''; + body = ''; + break; + case 'ja': + header = ''; + body = ''; + break; + case 'pt': + header = ''; + body = ''; + break; + case 'ru': + header = ''; + body = ''; + break; + case 'tr': + header = ''; + body = ''; + break; + case 'zh': + header = ''; + body = ''; + break; + default: + break; + } + + return `${header} +${address} + +${body} + +${footer}`; +}; + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + server, socket, payload, +}) { + // must be in a channel to run this command + if (typeof socket.channel === 'undefined') { + return server.police.frisk(socket, 1); + } + + if (typeof payload.address !== 'string') { + return false; + } + + if (!isValidSolanaAddress(payload.address)) { + return false; + } + + if (typeof payload.wallet !== 'string' || payload.wallet.length > 64) { + return false; + } + + /* if (typeof payload.locale !== 'string' || payload.locale.length > 4) { + return false; + } */ + + const expires = new Date(); + expires.setMinutes(expires.getMinutes() + 5); + const nonceBuffer = crypto.randomBytes(16); + const nonce = nonceBuffer.toString('hex'); + + const message = getMessage( + /* payload.locale, */ 'en', + payload.address, + nonce, + expires, + ); + + socket.siwMsg = message; + socket.siwAddress = payload.address; + socket.siwExpiry = expires; + + return server.reply({ + cmd: 'signMessage', + wallet: payload.wallet, + message, + }, socket); +} + +/** + * The following payload properties are required to invoke this module: + * "address", "locale", "wallet" + * @public + * @typedef {Array} siw/requiredData + */ +export const requiredData = ['address', /* 'locale', */ 'wallet']; + +/** + * Module meta information + * @public + * @typedef {Object} siw/info + * @property {string} name - Module command name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'siw', + category: 'wallet', + description: 'Initiates a Solana wallet login request', + usage: ` + API: { cmd: 'siw', address: '', wallet: '' }`, +}; diff --git a/main.mjs b/main.mjs index ced0820..21069e3 100644 --- a/main.mjs +++ b/main.mjs @@ -57,8 +57,6 @@ setInterval(() => { purgeInactiveChannels(server.appConfig.data); }, ChannelCheckInterval); -// @todo create storage management job - // start the server server.init(); diff --git a/package-lock.json b/package-lock.json index 11c99e8..22b7aa1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,13 +10,20 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "@coral-xyz/anchor": "^0.32.1", + "@solana/kit": "^5.1.0", + "@solana/web3.js": "^1.98.4", "ascii-captcha": "^0.0.3", + "bs58": "^6.0.0", "enquirer": "^2.3.6", "hackchat-server": "^2.3.2", "http-server": "^14.1.0", "jsonwebtoken": "^9.0.2", "lowdb": "^3.0.0", - "pm2": "^5.3.0" + "markdown-escape": "^2.0.0", + "pm2": "^5.3.0", + "tweetnacl": "^1.0.3", + "uwuify": "^1.0.1" }, "devDependencies": { "c8": "^7.11.0", @@ -459,12 +466,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -533,6 +538,91 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@coral-xyz/anchor": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.32.1.tgz", + "integrity": "sha512-zAyxFtfeje2FbMA1wzgcdVs7Hng/MijPKpRijoySPCicnvcTQs/+dnPZ/cR+LcXM9v9UYSyW81uRNYZtN5G4yg==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/anchor-errors": "^0.31.1", + "@coral-xyz/borsh": "^0.31.1", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.69.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=17" + } + }, + "node_modules/@coral-xyz/anchor-errors": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz", + "integrity": "sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/@coral-xyz/anchor/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@coral-xyz/anchor/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/@coral-xyz/anchor/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@coral-xyz/anchor/node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/@coral-xyz/borsh": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz", + "integrity": "sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.69.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.1.0.tgz", @@ -850,6 +940,33 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1001,6 +1118,894 @@ "debug": "^4.3.1" } }, + "node_modules/@solana/accounts": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-5.1.0.tgz", + "integrity": "sha512-Q1KzykCrl/YjLUH2RXF8vPq65U/ehAV2SHZicPbZ0jvgQUU6X1+Eca+0ilxA9xH8srYn3YTVDyEs/LYdfbY/2A==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/rpc-spec": "5.1.0", + "@solana/rpc-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/addresses": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-5.1.0.tgz", + "integrity": "sha512-X84qSZLgve9YeYsyxGI49WnfEre53tdFu4x9/4oULBgoj8d0A+P9VGLYzmRJ0YFYKRcZG7U4u3MQpI5uLZ1AsQ==", + "license": "MIT", + "dependencies": { + "@solana/assertions": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/nominal-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/assertions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-5.1.0.tgz", + "integrity": "sha512-5But2wyxuvGXMIOnD0jBMQ9yq1QQF2LSK3IbIRSkAkXbD3DS6O2tRvKUHNhogd+BpkPyCGOQHBycezgnxmStlg==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "license": "MIT", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/codecs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-5.1.0.tgz", + "integrity": "sha512-krSuf/E2Sa/4oASZ/jb/5KGUG58m1/bQdLrKvBnoAFhYj7zZf+8V4UqHGTV5n2NCQfmMyORsg9n2saKjkUzo8w==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/options": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-5.1.0.tgz", + "integrity": "sha512-vDwi03mxWeWCS5Il6BCdNdifYdOoHVz97YOmbWGIt45b77Ivu5NUYeSD2+ccl6fSw8eYQ6QaqqKXMjbSfsXv4g==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-data-structures": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-5.1.0.tgz", + "integrity": "sha512-ftAwL/jsurFrk9kFVhkTLdQ8fGZ8I0PcbVH+V1a0dIP2aKDofGePvK0XbwZE/ohizC9gEIZxyBX5IgRKk5PXyg==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-5.1.0.tgz", + "integrity": "sha512-Ea5/9yjDNOrDZcI40UGzzi6Aq1JNsmzM4m5pOk6Xb3JRZ0YdKOv/MwuCqb6jRgzZ7SQjHhkfGL43kHLJA++bOw==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "5.1.0", + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-strings": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-5.1.0.tgz", + "integrity": "sha512-014xwl5T/3VnGW0gceizF47DUs5EURRtgGmbWIR5+Z32yxgQ6hT9Zl0atZbL268RHbUQ03/J8Ush1StQgy7sfQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": ">=5.3.3" + }, + "peerDependenciesMeta": { + "fastestsmallesttextencoderdecoder": { + "optional": true + } + } + }, + "node_modules/@solana/errors": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-5.1.0.tgz", + "integrity": "sha512-JlTyekErWa6Fdcwu1Hrh+jZxjM4YxyorGCFDRVZlmHZFkp5N00DWKcYnSGZrTF8E6ZZEP9pfS2XwM8y7p7HPww==", + "license": "MIT", + "dependencies": { + "chalk": "5.6.2", + "commander": "14.0.2" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/errors/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/errors/node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@solana/fast-stable-stringify": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-5.1.0.tgz", + "integrity": "sha512-ACZo7cH/5EXsBmruw/0gU2/PXL2l4aET0YpL93H6QEaZwEAICFD8cLkj20nBcfLTf4srEiuKtwuSDeONTWIulw==", + "license": "MIT", + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/functional": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-5.1.0.tgz", + "integrity": "sha512-R6jacWU0Gr+j49lTDp+FSECBolqw2Gq7JlC22rI0JkcxJiiAlp3G80v6zAYq0FkHzxZbjyR6//JYUXSwliem5g==", + "license": "MIT", + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/instruction-plans": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/instruction-plans/-/instruction-plans-5.1.0.tgz", + "integrity": "sha512-friMgHt0z5jQlCyyTDXfwAMYjCAagI7QYR+hLWB/BmvSuRpai0ddToWbWJoqrNRM312xZ+Oy/qjC3+Ftzi0DLA==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/promises": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/instructions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-5.1.0.tgz", + "integrity": "sha512-fkwpUwwqk5K14T/kZDnCrfeR0kww49HBx+BK8xdSeJx+bt4QTwAHa9YeOkGhGrHEFVEJEUf8FKoxxTzZzJZtKQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "5.1.0", + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/keys": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-5.1.0.tgz", + "integrity": "sha512-ma4zTTuSOmtTCvATHMfUGNTw0Vqah/6XPe1VmLc66ohwXMI3yqatX1FQPXgDZozr15SvLAesfs7/bgl2TRoe9w==", + "license": "MIT", + "dependencies": { + "@solana/assertions": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/nominal-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/kit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-5.1.0.tgz", + "integrity": "sha512-oNQRzI0+mGWmXy05psO0J7r9Boy8PF7LH5H0Y9Jxvs10AbG4oSOBtyj20EccsRrr+jkqLw42fqb/4rNuASfvsA==", + "license": "MIT", + "dependencies": { + "@solana/accounts": "5.1.0", + "@solana/addresses": "5.1.0", + "@solana/codecs": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/instruction-plans": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/offchain-messages": "5.1.0", + "@solana/programs": "5.1.0", + "@solana/rpc": "5.1.0", + "@solana/rpc-parsed-types": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/rpc-subscriptions": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/signers": "5.1.0", + "@solana/sysvars": "5.1.0", + "@solana/transaction-confirmation": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/nominal-types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-5.1.0.tgz", + "integrity": "sha512-+4Cm+SpK+D811i9giqv4Up93ZlmUcZfLDHkSH24F4in61+Y2TKA+XKuRtKhNytQMmqCfbvJZ9MHFaIeZw5g+Bg==", + "license": "MIT", + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/offchain-messages": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/offchain-messages/-/offchain-messages-5.1.0.tgz", + "integrity": "sha512-6FUXjiIJprjWa7y/T4E3rUb3HKi3P5zpBweBEwDflEEJ/QlieWUw7xlGAOvZ1eF3Wi+6LfcrdtZOwIkuv6o9Sg==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/nominal-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/options": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-5.1.0.tgz", + "integrity": "sha512-PqgfALd0yhK+QFaYIbRFTV6hBpiy5xwdu07zSw1RLoNvt1sg+MRsRFDk9R8ZdEdiM69PY/cKiClVSjpNzLLcJg==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/programs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-5.1.0.tgz", + "integrity": "sha512-zAghXyRGixWNcarShlrnpjMD2115BZTF9JMLIcgkCYDOwjDPFIB/Y0hwDCH87N5uSjzlgkDpxKEL4ILewoZTRQ==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/promises": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-5.1.0.tgz", + "integrity": "sha512-LU9wwS1PvGc/It610dclfq+JCuUEZSIWjvaF0+sqMP7QCk12Uz7MK2m9TtvLcjTvvKTIrucglRZP6qKroWRqGg==", + "license": "MIT", + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-5.1.0.tgz", + "integrity": "sha512-j+ByLxFCoHWw9TnsGzkAVMFUfBDIUE53nIosJAYEsERpImD2mjwc33uDE6YXLKoaKRoYO4tc7IUzkKY1fQp/CA==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0", + "@solana/fast-stable-stringify": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/rpc-api": "5.1.0", + "@solana/rpc-spec": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/rpc-transformers": "5.1.0", + "@solana/rpc-transport-http": "5.1.0", + "@solana/rpc-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-5.1.0.tgz", + "integrity": "sha512-eI1tY0i3gmih1C65gFECYbfPRpHEYqFp+9IKjpknZtYpQIe9BqBKSpfYpGiCAbKdN/TMadBNPOzdK15ewhkkvQ==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/rpc-parsed-types": "5.1.0", + "@solana/rpc-spec": "5.1.0", + "@solana/rpc-transformers": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-parsed-types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-5.1.0.tgz", + "integrity": "sha512-ZJoXHNItALMNa1zmGrNnIh96RBlc9GpIqoaZkdE14mAQ7gWe7Oc0ejYavUeSCmcL0wZcvIFh50AsfVxrHr4+2Q==", + "license": "MIT", + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-spec": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-5.1.0.tgz", + "integrity": "sha512-y8B6fUWA1EBKXUsNo6b9EiFcQPsaJREPLlcIDbo4b6TucQNwvl7FHfpf1VHJL64SkI/WE69i2WEkiOJYjmLO0A==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0", + "@solana/rpc-spec-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-spec-types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-5.1.0.tgz", + "integrity": "sha512-B8/WyjmHpC34vXtAmTpZyPwRCm7WwoSkmjBcBouaaY1uilJ9+Wp2nptbq2cJyWairOoMSoI7v5kvvnrJuquq4Q==", + "license": "MIT", + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-subscriptions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-5.1.0.tgz", + "integrity": "sha512-u/mafVzBbdqvYDD7x/98T5/5xk4Bl2C/90TaHiKx7FmutVC/H4QsritPTY0v9JG1dOVWbgIfUgfZ0C0DPkiYnA==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0", + "@solana/fast-stable-stringify": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/promises": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/rpc-subscriptions-api": "5.1.0", + "@solana/rpc-subscriptions-channel-websocket": "5.1.0", + "@solana/rpc-subscriptions-spec": "5.1.0", + "@solana/rpc-transformers": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/subscribable": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-subscriptions-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-5.1.0.tgz", + "integrity": "sha512-84e2AsgqAGiVloW3G4RzpHPkInknu3rEuFPut2/69eq3Ab97TiTz2s5kc9gJpprtGM+xbgnIfeuGqr5F+2bXQA==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/rpc-subscriptions-spec": "5.1.0", + "@solana/rpc-transformers": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-subscriptions-channel-websocket": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-5.1.0.tgz", + "integrity": "sha512-FzAEmHzXtlckNn7T/1dzDS7r5HmekYPstrtZKjDcVxuGMVBUkZTnb69t7EJvKNuKw1wYZEUd0EEegtC2K/9dZA==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/rpc-subscriptions-spec": "5.1.0", + "@solana/subscribable": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3", + "ws": "^8.18.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + } + } + }, + "node_modules/@solana/rpc-subscriptions-spec": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-5.1.0.tgz", + "integrity": "sha512-ORfjKtainnYisql6z4YsXByVwY8/rWsedVWn5oe/V7Og9LyetTM7hwJ8FbUdRDZwyLlUrI0cEE1aG+3ma/8tPw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0", + "@solana/promises": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/subscribable": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-transformers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-5.1.0.tgz", + "integrity": "sha512-6v93xi/ewGS/xEiSktNQ0bh0Uiv1/q9nR5oiFMn3BiAJRC+FdMRMxCjp6H+/Tua7wdhpClaPKrZYBQHoIp59tw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/nominal-types": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/rpc-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-transport-http": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-5.1.0.tgz", + "integrity": "sha512-XoGX+2n/iXzoGb3Xrltbx8avnzp15vCfCGXuZpQWFL+xUg3P4CGl217XyDGjS5VxuUml+f/30xzWl18RaAIEcw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0", + "@solana/rpc-spec": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "undici-types": "^7.16.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-5.1.0.tgz", + "integrity": "sha512-Rnpt5BuHQvnULPNXUC/yRqB+7iPbon95CSCeyRvPj5tJ4fx2JibvX3s/UEoud5vC+kRjPi/R0BGJ8XFvd3eDWg==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/nominal-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/signers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-5.1.0.tgz", + "integrity": "sha512-B8xO0SGN1ZWYfJROL+da3id279qNbXbXoqud+AuT5gur51RrS4YhNkTQ6khVbGtAOpPMAhkoZN0jnfCC1r33jQ==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/nominal-types": "5.1.0", + "@solana/offchain-messages": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/subscribable": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-5.1.0.tgz", + "integrity": "sha512-OeW5AJwKzHh18+PIPtghuuPJTmEep2Mhb3Lsrq4alas4fibmMGkr39z1HXxVF6l6e2lu/YGhHIDtuhouWmY7ow==", + "license": "MIT", + "dependencies": { + "@solana/errors": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/sysvars": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-5.1.0.tgz", + "integrity": "sha512-FJ9YIsLTAaajnOrYEYn54znstXJsvKndRhyCrlyiAEN1IXHw5HtZHploLF3ZZ78b7YU3uv3tFJMziXFBwPOn4Q==", + "license": "MIT", + "dependencies": { + "@solana/accounts": "5.1.0", + "@solana/codecs": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/rpc-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/transaction-confirmation": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-5.1.0.tgz", + "integrity": "sha512-6HnL0uH8tWZXJVuaoeTbCQp/FS11Bsc4GSlq+k0N21GdhTbFuqBhsxlAYWbzPWs9+/kYRGHqqXvBPCReWxT7BA==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/promises": "5.1.0", + "@solana/rpc": "5.1.0", + "@solana/rpc-subscriptions": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/transaction-messages": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-5.1.0.tgz", + "integrity": "sha512-9rNV2YJhd85WIMvnwa/vUY4xUw3ZTU17jP1KDo/fFZWk55a0ov0ATJJPyC5HAR1i6hT1cmJzGH/UHhnD9m/Q3w==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/nominal-types": "5.1.0", + "@solana/rpc-types": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/transactions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-5.1.0.tgz", + "integrity": "sha512-06JwSPtz+38ozNgpysAXS2eTMPQCufIisXB6K88X8J4GF8ziqs4nkq0BpXAXn+MpZTkuMt+JeW2RxP3HKhXe5g==", + "license": "MIT", + "dependencies": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/nominal-types": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/transaction-messages": "5.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz", + "integrity": "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@solana/web3.js/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/web3.js/node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@solana/web3.js/node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/helpers/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -1015,6 +2020,15 @@ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -1027,6 +2041,27 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -1060,6 +2095,18 @@ "node": ">= 6.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -1261,6 +2308,32 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base-x": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", + "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -1299,11 +2372,46 @@ "node": ">= 0.8.0" } }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT" + }, "node_modules/bodec": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", "integrity": "sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==" }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/borsh/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/borsh/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1356,6 +2464,39 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -1366,6 +2507,29 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "license": "MIT", + "engines": { + "node": ">=4.5" + } + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/c8": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.0.tgz", @@ -1754,6 +2918,15 @@ "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==" }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1876,6 +3049,18 @@ "node": ">= 14" } }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/didyoumean2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/didyoumean2/-/didyoumean2-4.2.0.tgz", @@ -2005,6 +3190,21 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2373,6 +3573,14 @@ "follow-redirects": "^1.14.0" } }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2396,6 +3604,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT" + }, "node_modules/fast-url-parser": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", @@ -2985,6 +4199,15 @@ "node": ">= 6" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2996,6 +4219,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -3365,6 +4608,15 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -3485,6 +4737,68 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jayson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", + "integrity": "sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==", + "license": "MIT", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/jayson/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/jayson/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/js-git": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", @@ -3551,8 +4865,7 @@ "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "optional": true + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, "node_modules/json5": { "version": "1.0.2", @@ -3788,6 +5101,12 @@ "semver": "bin/semver.js" } }, + "node_modules/markdown-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-escape/-/markdown-escape-2.0.0.tgz", + "integrity": "sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==", + "license": "MIT" + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -4134,10 +5453,10 @@ } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -4153,6 +5472,18 @@ } } }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -5199,11 +6530,6 @@ "node": ">=8.10.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -5301,6 +6627,53 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rpc-websockets": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.2.tgz", + "integrity": "sha512-VuW2xJDnl1k8n8kjbdRSWawPRkwaVqUQNjE1TdeTawf0y0abGhtVJFTXCLfgpgGDBkO/Fj6kny8Dc/nvOW78MA==", + "license": "LGPL-3.0-only", + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^8.3.4", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/rpc-websockets/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/run-series": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", @@ -5545,6 +6918,12 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause" + }, "node_modules/stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -5554,6 +6933,15 @@ "stubs": "^3.0.0" } }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5661,6 +7049,12 @@ "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", "dev": true }, + "node_modules/superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5749,6 +7143,11 @@ "node": ">=8" } }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5776,11 +7175,16 @@ "node": ">=8.0" } }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "node_modules/tsconfig-paths": { "version": "3.12.0", @@ -5808,6 +7212,12 @@ "node": ">= 0.8.0" } }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "license": "Unlicense" + }, "node_modules/tx2": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tx2/-/tx2-1.0.5.tgz", @@ -5859,6 +7269,20 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -5874,6 +7298,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, "node_modules/union": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", @@ -5916,6 +7346,20 @@ "fast-url-parser": "^1.1.3" } }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -5926,6 +7370,26 @@ "uuid": "bin/uuid" } }, + "node_modules/uwuifier": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/uwuifier/-/uwuifier-2.0.4.tgz", + "integrity": "sha512-6enYpIJOMtfkn1VTDm/vTb15jV7g63jyQWXwCyM7jAru8qTValSgu61qJbUXGHGOifsTmw+XVR6Lf4f2pjA0IA==", + "license": "ISC", + "engines": { + "npm": "*", + "pnpm": "please-use-npm", + "yarn": "please-use-npm" + } + }, + "node_modules/uwuify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uwuify/-/uwuify-1.0.1.tgz", + "integrity": "sha512-RrRNPGBVDSY4NmdKee9Dg4koaroAPa5ip324TjuHc9Abf3Jz0h75Rw5xvGRTvlR5ysOXNT+Qh2UZW5vaUdwNeQ==", + "license": "GPL-3.0", + "dependencies": { + "uwuifier": "^2.0.2" + } + }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -5972,8 +7436,7 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "node_modules/whatwg-encoding": { "version": "2.0.0", @@ -6001,7 +7464,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -6564,12 +8026,9 @@ "dev": true }, "@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==" }, "@babel/template": { "version": "7.22.15", @@ -6625,6 +8084,68 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@coral-xyz/anchor": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.32.1.tgz", + "integrity": "sha512-zAyxFtfeje2FbMA1wzgcdVs7Hng/MijPKpRijoySPCicnvcTQs/+dnPZ/cR+LcXM9v9UYSyW81uRNYZtN5G4yg==", + "requires": { + "@coral-xyz/anchor-errors": "^0.31.1", + "@coral-xyz/borsh": "^0.31.1", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.69.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "dependencies": { + "base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "requires": { + "base-x": "^3.0.2" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + } + } + }, + "@coral-xyz/anchor-errors": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz", + "integrity": "sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ==" + }, + "@coral-xyz/borsh": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz", + "integrity": "sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw==", + "requires": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + } + }, "@eslint/eslintrc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.1.0.tgz", @@ -6857,6 +8378,19 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "requires": { + "@noble/hashes": "1.8.0" + } + }, + "@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==" + }, "@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -6966,6 +8500,566 @@ "debug": "^4.3.1" } }, + "@solana/accounts": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-5.1.0.tgz", + "integrity": "sha512-Q1KzykCrl/YjLUH2RXF8vPq65U/ehAV2SHZicPbZ0jvgQUU6X1+Eca+0ilxA9xH8srYn3YTVDyEs/LYdfbY/2A==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/rpc-spec": "5.1.0", + "@solana/rpc-types": "5.1.0" + } + }, + "@solana/addresses": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-5.1.0.tgz", + "integrity": "sha512-X84qSZLgve9YeYsyxGI49WnfEre53tdFu4x9/4oULBgoj8d0A+P9VGLYzmRJ0YFYKRcZG7U4u3MQpI5uLZ1AsQ==", + "requires": { + "@solana/assertions": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/nominal-types": "5.1.0" + } + }, + "@solana/assertions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-5.1.0.tgz", + "integrity": "sha512-5But2wyxuvGXMIOnD0jBMQ9yq1QQF2LSK3IbIRSkAkXbD3DS6O2tRvKUHNhogd+BpkPyCGOQHBycezgnxmStlg==", + "requires": { + "@solana/errors": "5.1.0" + } + }, + "@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "requires": { + "buffer": "~6.0.3" + } + }, + "@solana/codecs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-5.1.0.tgz", + "integrity": "sha512-krSuf/E2Sa/4oASZ/jb/5KGUG58m1/bQdLrKvBnoAFhYj7zZf+8V4UqHGTV5n2NCQfmMyORsg9n2saKjkUzo8w==", + "requires": { + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/options": "5.1.0" + } + }, + "@solana/codecs-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-5.1.0.tgz", + "integrity": "sha512-vDwi03mxWeWCS5Il6BCdNdifYdOoHVz97YOmbWGIt45b77Ivu5NUYeSD2+ccl6fSw8eYQ6QaqqKXMjbSfsXv4g==", + "requires": { + "@solana/errors": "5.1.0" + } + }, + "@solana/codecs-data-structures": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-5.1.0.tgz", + "integrity": "sha512-ftAwL/jsurFrk9kFVhkTLdQ8fGZ8I0PcbVH+V1a0dIP2aKDofGePvK0XbwZE/ohizC9gEIZxyBX5IgRKk5PXyg==", + "requires": { + "@solana/codecs-core": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/errors": "5.1.0" + } + }, + "@solana/codecs-numbers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-5.1.0.tgz", + "integrity": "sha512-Ea5/9yjDNOrDZcI40UGzzi6Aq1JNsmzM4m5pOk6Xb3JRZ0YdKOv/MwuCqb6jRgzZ7SQjHhkfGL43kHLJA++bOw==", + "requires": { + "@solana/codecs-core": "5.1.0", + "@solana/errors": "5.1.0" + } + }, + "@solana/codecs-strings": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-5.1.0.tgz", + "integrity": "sha512-014xwl5T/3VnGW0gceizF47DUs5EURRtgGmbWIR5+Z32yxgQ6hT9Zl0atZbL268RHbUQ03/J8Ush1StQgy7sfQ==", + "requires": { + "@solana/codecs-core": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/errors": "5.1.0" + } + }, + "@solana/errors": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-5.1.0.tgz", + "integrity": "sha512-JlTyekErWa6Fdcwu1Hrh+jZxjM4YxyorGCFDRVZlmHZFkp5N00DWKcYnSGZrTF8E6ZZEP9pfS2XwM8y7p7HPww==", + "requires": { + "chalk": "5.6.2", + "commander": "14.0.2" + }, + "dependencies": { + "chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==" + }, + "commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==" + } + } + }, + "@solana/fast-stable-stringify": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-5.1.0.tgz", + "integrity": "sha512-ACZo7cH/5EXsBmruw/0gU2/PXL2l4aET0YpL93H6QEaZwEAICFD8cLkj20nBcfLTf4srEiuKtwuSDeONTWIulw==", + "requires": {} + }, + "@solana/functional": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-5.1.0.tgz", + "integrity": "sha512-R6jacWU0Gr+j49lTDp+FSECBolqw2Gq7JlC22rI0JkcxJiiAlp3G80v6zAYq0FkHzxZbjyR6//JYUXSwliem5g==", + "requires": {} + }, + "@solana/instruction-plans": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/instruction-plans/-/instruction-plans-5.1.0.tgz", + "integrity": "sha512-friMgHt0z5jQlCyyTDXfwAMYjCAagI7QYR+hLWB/BmvSuRpai0ddToWbWJoqrNRM312xZ+Oy/qjC3+Ftzi0DLA==", + "requires": { + "@solana/errors": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/promises": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + } + }, + "@solana/instructions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-5.1.0.tgz", + "integrity": "sha512-fkwpUwwqk5K14T/kZDnCrfeR0kww49HBx+BK8xdSeJx+bt4QTwAHa9YeOkGhGrHEFVEJEUf8FKoxxTzZzJZtKQ==", + "requires": { + "@solana/codecs-core": "5.1.0", + "@solana/errors": "5.1.0" + } + }, + "@solana/keys": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-5.1.0.tgz", + "integrity": "sha512-ma4zTTuSOmtTCvATHMfUGNTw0Vqah/6XPe1VmLc66ohwXMI3yqatX1FQPXgDZozr15SvLAesfs7/bgl2TRoe9w==", + "requires": { + "@solana/assertions": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/nominal-types": "5.1.0" + } + }, + "@solana/kit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-5.1.0.tgz", + "integrity": "sha512-oNQRzI0+mGWmXy05psO0J7r9Boy8PF7LH5H0Y9Jxvs10AbG4oSOBtyj20EccsRrr+jkqLw42fqb/4rNuASfvsA==", + "requires": { + "@solana/accounts": "5.1.0", + "@solana/addresses": "5.1.0", + "@solana/codecs": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/instruction-plans": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/offchain-messages": "5.1.0", + "@solana/programs": "5.1.0", + "@solana/rpc": "5.1.0", + "@solana/rpc-parsed-types": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/rpc-subscriptions": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/signers": "5.1.0", + "@solana/sysvars": "5.1.0", + "@solana/transaction-confirmation": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + } + }, + "@solana/nominal-types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-5.1.0.tgz", + "integrity": "sha512-+4Cm+SpK+D811i9giqv4Up93ZlmUcZfLDHkSH24F4in61+Y2TKA+XKuRtKhNytQMmqCfbvJZ9MHFaIeZw5g+Bg==", + "requires": {} + }, + "@solana/offchain-messages": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/offchain-messages/-/offchain-messages-5.1.0.tgz", + "integrity": "sha512-6FUXjiIJprjWa7y/T4E3rUb3HKi3P5zpBweBEwDflEEJ/QlieWUw7xlGAOvZ1eF3Wi+6LfcrdtZOwIkuv6o9Sg==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/nominal-types": "5.1.0" + } + }, + "@solana/options": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-5.1.0.tgz", + "integrity": "sha512-PqgfALd0yhK+QFaYIbRFTV6hBpiy5xwdu07zSw1RLoNvt1sg+MRsRFDk9R8ZdEdiM69PY/cKiClVSjpNzLLcJg==", + "requires": { + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0" + } + }, + "@solana/programs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-5.1.0.tgz", + "integrity": "sha512-zAghXyRGixWNcarShlrnpjMD2115BZTF9JMLIcgkCYDOwjDPFIB/Y0hwDCH87N5uSjzlgkDpxKEL4ILewoZTRQ==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/errors": "5.1.0" + } + }, + "@solana/promises": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-5.1.0.tgz", + "integrity": "sha512-LU9wwS1PvGc/It610dclfq+JCuUEZSIWjvaF0+sqMP7QCk12Uz7MK2m9TtvLcjTvvKTIrucglRZP6qKroWRqGg==", + "requires": {} + }, + "@solana/rpc": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-5.1.0.tgz", + "integrity": "sha512-j+ByLxFCoHWw9TnsGzkAVMFUfBDIUE53nIosJAYEsERpImD2mjwc33uDE6YXLKoaKRoYO4tc7IUzkKY1fQp/CA==", + "requires": { + "@solana/errors": "5.1.0", + "@solana/fast-stable-stringify": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/rpc-api": "5.1.0", + "@solana/rpc-spec": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/rpc-transformers": "5.1.0", + "@solana/rpc-transport-http": "5.1.0", + "@solana/rpc-types": "5.1.0" + } + }, + "@solana/rpc-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-5.1.0.tgz", + "integrity": "sha512-eI1tY0i3gmih1C65gFECYbfPRpHEYqFp+9IKjpknZtYpQIe9BqBKSpfYpGiCAbKdN/TMadBNPOzdK15ewhkkvQ==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/rpc-parsed-types": "5.1.0", + "@solana/rpc-spec": "5.1.0", + "@solana/rpc-transformers": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + } + }, + "@solana/rpc-parsed-types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-5.1.0.tgz", + "integrity": "sha512-ZJoXHNItALMNa1zmGrNnIh96RBlc9GpIqoaZkdE14mAQ7gWe7Oc0ejYavUeSCmcL0wZcvIFh50AsfVxrHr4+2Q==", + "requires": {} + }, + "@solana/rpc-spec": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-5.1.0.tgz", + "integrity": "sha512-y8B6fUWA1EBKXUsNo6b9EiFcQPsaJREPLlcIDbo4b6TucQNwvl7FHfpf1VHJL64SkI/WE69i2WEkiOJYjmLO0A==", + "requires": { + "@solana/errors": "5.1.0", + "@solana/rpc-spec-types": "5.1.0" + } + }, + "@solana/rpc-spec-types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-5.1.0.tgz", + "integrity": "sha512-B8/WyjmHpC34vXtAmTpZyPwRCm7WwoSkmjBcBouaaY1uilJ9+Wp2nptbq2cJyWairOoMSoI7v5kvvnrJuquq4Q==", + "requires": {} + }, + "@solana/rpc-subscriptions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-5.1.0.tgz", + "integrity": "sha512-u/mafVzBbdqvYDD7x/98T5/5xk4Bl2C/90TaHiKx7FmutVC/H4QsritPTY0v9JG1dOVWbgIfUgfZ0C0DPkiYnA==", + "requires": { + "@solana/errors": "5.1.0", + "@solana/fast-stable-stringify": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/promises": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/rpc-subscriptions-api": "5.1.0", + "@solana/rpc-subscriptions-channel-websocket": "5.1.0", + "@solana/rpc-subscriptions-spec": "5.1.0", + "@solana/rpc-transformers": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/subscribable": "5.1.0" + } + }, + "@solana/rpc-subscriptions-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-5.1.0.tgz", + "integrity": "sha512-84e2AsgqAGiVloW3G4RzpHPkInknu3rEuFPut2/69eq3Ab97TiTz2s5kc9gJpprtGM+xbgnIfeuGqr5F+2bXQA==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/rpc-subscriptions-spec": "5.1.0", + "@solana/rpc-transformers": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + } + }, + "@solana/rpc-subscriptions-channel-websocket": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-5.1.0.tgz", + "integrity": "sha512-FzAEmHzXtlckNn7T/1dzDS7r5HmekYPstrtZKjDcVxuGMVBUkZTnb69t7EJvKNuKw1wYZEUd0EEegtC2K/9dZA==", + "requires": { + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/rpc-subscriptions-spec": "5.1.0", + "@solana/subscribable": "5.1.0" + } + }, + "@solana/rpc-subscriptions-spec": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-5.1.0.tgz", + "integrity": "sha512-ORfjKtainnYisql6z4YsXByVwY8/rWsedVWn5oe/V7Og9LyetTM7hwJ8FbUdRDZwyLlUrI0cEE1aG+3ma/8tPw==", + "requires": { + "@solana/errors": "5.1.0", + "@solana/promises": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/subscribable": "5.1.0" + } + }, + "@solana/rpc-transformers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-5.1.0.tgz", + "integrity": "sha512-6v93xi/ewGS/xEiSktNQ0bh0Uiv1/q9nR5oiFMn3BiAJRC+FdMRMxCjp6H+/Tua7wdhpClaPKrZYBQHoIp59tw==", + "requires": { + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/nominal-types": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "@solana/rpc-types": "5.1.0" + } + }, + "@solana/rpc-transport-http": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-5.1.0.tgz", + "integrity": "sha512-XoGX+2n/iXzoGb3Xrltbx8avnzp15vCfCGXuZpQWFL+xUg3P4CGl217XyDGjS5VxuUml+f/30xzWl18RaAIEcw==", + "requires": { + "@solana/errors": "5.1.0", + "@solana/rpc-spec": "5.1.0", + "@solana/rpc-spec-types": "5.1.0", + "undici-types": "^7.16.0" + } + }, + "@solana/rpc-types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-5.1.0.tgz", + "integrity": "sha512-Rnpt5BuHQvnULPNXUC/yRqB+7iPbon95CSCeyRvPj5tJ4fx2JibvX3s/UEoud5vC+kRjPi/R0BGJ8XFvd3eDWg==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/nominal-types": "5.1.0" + } + }, + "@solana/signers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-5.1.0.tgz", + "integrity": "sha512-B8xO0SGN1ZWYfJROL+da3id279qNbXbXoqud+AuT5gur51RrS4YhNkTQ6khVbGtAOpPMAhkoZN0jnfCC1r33jQ==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/nominal-types": "5.1.0", + "@solana/offchain-messages": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + } + }, + "@solana/subscribable": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-5.1.0.tgz", + "integrity": "sha512-OeW5AJwKzHh18+PIPtghuuPJTmEep2Mhb3Lsrq4alas4fibmMGkr39z1HXxVF6l6e2lu/YGhHIDtuhouWmY7ow==", + "requires": { + "@solana/errors": "5.1.0" + } + }, + "@solana/sysvars": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-5.1.0.tgz", + "integrity": "sha512-FJ9YIsLTAaajnOrYEYn54znstXJsvKndRhyCrlyiAEN1IXHw5HtZHploLF3ZZ78b7YU3uv3tFJMziXFBwPOn4Q==", + "requires": { + "@solana/accounts": "5.1.0", + "@solana/codecs": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/rpc-types": "5.1.0" + } + }, + "@solana/transaction-confirmation": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-5.1.0.tgz", + "integrity": "sha512-6HnL0uH8tWZXJVuaoeTbCQp/FS11Bsc4GSlq+k0N21GdhTbFuqBhsxlAYWbzPWs9+/kYRGHqqXvBPCReWxT7BA==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/promises": "5.1.0", + "@solana/rpc": "5.1.0", + "@solana/rpc-subscriptions": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/transaction-messages": "5.1.0", + "@solana/transactions": "5.1.0" + } + }, + "@solana/transaction-messages": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-5.1.0.tgz", + "integrity": "sha512-9rNV2YJhd85WIMvnwa/vUY4xUw3ZTU17jP1KDo/fFZWk55a0ov0ATJJPyC5HAR1i6hT1cmJzGH/UHhnD9m/Q3w==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/nominal-types": "5.1.0", + "@solana/rpc-types": "5.1.0" + } + }, + "@solana/transactions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-5.1.0.tgz", + "integrity": "sha512-06JwSPtz+38ozNgpysAXS2eTMPQCufIisXB6K88X8J4GF8ziqs4nkq0BpXAXn+MpZTkuMt+JeW2RxP3HKhXe5g==", + "requires": { + "@solana/addresses": "5.1.0", + "@solana/codecs-core": "5.1.0", + "@solana/codecs-data-structures": "5.1.0", + "@solana/codecs-numbers": "5.1.0", + "@solana/codecs-strings": "5.1.0", + "@solana/errors": "5.1.0", + "@solana/functional": "5.1.0", + "@solana/instructions": "5.1.0", + "@solana/keys": "5.1.0", + "@solana/nominal-types": "5.1.0", + "@solana/rpc-types": "5.1.0", + "@solana/transaction-messages": "5.1.0" + } + }, + "@solana/web3.js": { + "version": "1.98.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz", + "integrity": "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==", + "requires": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + }, + "dependencies": { + "@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "requires": { + "@solana/errors": "2.3.0" + } + }, + "@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "requires": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + } + }, + "@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "requires": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + } + }, + "base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "requires": { + "base-x": "^3.0.2" + } + }, + "chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==" + }, + "commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==" + }, + "superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==" + } + } + }, + "@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "requires": { + "tslib": "^2.8.0" + }, + "dependencies": { + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + } + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -6977,6 +9071,14 @@ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" }, + "@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "requires": { + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -6989,6 +9091,24 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" + }, + "@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "requires": { + "@types/node": "*" + } + }, "acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -7011,6 +9131,14 @@ "debug": "4" } }, + "agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "requires": { + "humanize-ms": "^1.2.1" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -7167,6 +9295,16 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "base-x": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", + "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -7190,11 +9328,44 @@ "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", "integrity": "sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=" }, + "bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==" + }, "bodec": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", "integrity": "sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==" }, + "borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "requires": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + }, + "dependencies": { + "base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "requires": { + "base-x": "^3.0.2" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -7232,6 +9403,23 @@ "picocolors": "^1.0.0" } }, + "bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "requires": { + "base-x": "^5.0.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -7242,6 +9430,20 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==" + }, + "bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, "c8": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.0.tgz", @@ -7533,6 +9735,14 @@ "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==" }, + "cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "requires": { + "node-fetch": "^2.7.0" + } + }, "cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -7624,6 +9834,11 @@ "esprima": "^4.0.1" } }, + "delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==" + }, "didyoumean2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/didyoumean2/-/didyoumean2-4.2.0.tgz", @@ -7727,6 +9942,19 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "requires": { + "es6-promise": "^4.0.3" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -8011,6 +10239,11 @@ "follow-redirects": "^1.14.0" } }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8034,6 +10267,11 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" + }, "fast-url-parser": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", @@ -8444,6 +10682,14 @@ "debug": "4" } }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "requires": { + "ms": "^2.0.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -8452,6 +10698,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -8704,6 +10955,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "requires": {} + }, "istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -8796,6 +11053,43 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "jayson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", + "integrity": "sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==", + "requires": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "requires": {} + } + } + }, "js-git": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", @@ -8854,8 +11148,7 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "optional": true + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, "json5": { "version": "1.0.2", @@ -9047,6 +11340,11 @@ } } }, + "markdown-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-escape/-/markdown-escape-2.0.0.tgz", + "integrity": "sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==" + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -9280,14 +11578,19 @@ "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==" }, "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "requires": { "whatwg-url": "^5.0.0" } }, + "node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "optional": true + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -10080,11 +12383,6 @@ "picomatch": "^2.2.1" } }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -10151,6 +12449,42 @@ "glob": "^7.1.3" } }, + "rpc-websockets": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.2.tgz", + "integrity": "sha512-VuW2xJDnl1k8n8kjbdRSWawPRkwaVqUQNjE1TdeTawf0y0abGhtVJFTXCLfgpgGDBkO/Fj6kny8Dc/nvOW78MA==", + "requires": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^8.3.4", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "bufferutil": "^4.0.1", + "eventemitter3": "^5.0.1", + "utf-8-validate": "^5.0.2", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "dependencies": { + "@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "requires": { + "@types/node": "*" + } + }, + "eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, "run-series": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", @@ -10330,6 +12664,11 @@ "resolved": "https://registry.npmjs.org/steno/-/steno-2.1.0.tgz", "integrity": "sha512-mauOsiaqTNGFkWqIfwcm3y/fq+qKKaIWf1vf3ocOuTdco9XoHCO2AGF1gFYXuZFSWuP38Q8LBHBGJv2KnJSXyA==" }, + "stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==" + }, "stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -10339,6 +12678,14 @@ "stubs": "^3.0.0" } }, + "stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "requires": { + "stream-chain": "^2.2.5" + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -10415,6 +12762,11 @@ "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", "dev": true }, + "superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==" + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10466,6 +12818,11 @@ "minimatch": "^3.0.4" } }, + "text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -10486,11 +12843,15 @@ "is-number": "^7.0.0" } }, + "toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "tsconfig-paths": { "version": "3.12.0", @@ -10514,6 +12875,11 @@ "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", "integrity": "sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==" }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "tx2": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tx2/-/tx2-1.0.5.tgz", @@ -10553,6 +12919,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "peer": true + }, "unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -10565,6 +12937,11 @@ "which-boxed-primitive": "^1.0.2" } }, + "undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==" + }, "union": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", @@ -10601,12 +12978,34 @@ "fast-url-parser": "^1.1.3" } }, + "utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, + "uwuifier": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/uwuifier/-/uwuifier-2.0.4.tgz", + "integrity": "sha512-6enYpIJOMtfkn1VTDm/vTb15jV7g63jyQWXwCyM7jAru8qTValSgu61qJbUXGHGOifsTmw+XVR6Lf4f2pjA0IA==" + }, + "uwuify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uwuify/-/uwuify-1.0.1.tgz", + "integrity": "sha512-RrRNPGBVDSY4NmdKee9Dg4koaroAPa5ip324TjuHc9Abf3Jz0h75Rw5xvGRTvlR5ysOXNT+Qh2UZW5vaUdwNeQ==", + "requires": { + "uwuifier": "^2.0.2" + } + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -10646,8 +13045,7 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "whatwg-encoding": { "version": "2.0.0", @@ -10671,7 +13069,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" diff --git a/package.json b/package.json index 12c760f..1364728 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,20 @@ "author": "marzavec", "license": "MIT", "dependencies": { + "@coral-xyz/anchor": "^0.32.1", + "@solana/kit": "^5.1.0", + "@solana/web3.js": "^1.98.4", "ascii-captcha": "^0.0.3", + "bs58": "^6.0.0", "enquirer": "^2.3.6", "hackchat-server": "^2.3.2", "http-server": "^14.1.0", "jsonwebtoken": "^9.0.2", "lowdb": "^3.0.0", - "pm2": "^5.3.0" + "markdown-escape": "^2.0.0", + "pm2": "^5.3.0", + "tweetnacl": "^1.0.3", + "uwuify": "^1.0.1" }, "devDependencies": { "c8": "^7.11.0", diff --git a/test/mockImports.js b/test/mockImports.js index 5b9627b..ff1715a 100644 --- a/test/mockImports.js +++ b/test/mockImports.js @@ -62,7 +62,7 @@ const mocks = { } }, }, - + configManager: { save: () => true, }, @@ -80,7 +80,7 @@ const mocks = { if (typeof filterObj.level === 'function') { filterObj.level(); } - + return true; }, send: () => true,