Compare commits

..

9 Commits

Author SHA1 Message Date
aad8c3c50f haha
All checks were successful
Build and Push Docker Image / build (push) Successful in 22s
2026-04-01 22:36:35 -04:00
f47028b5f5 command to say
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m27s
2026-04-01 22:30:42 -04:00
ae2046185c add x.com to loop of links
All checks were successful
Build and Push Docker Image / build (push) Successful in 41s
2026-03-26 19:58:39 -04:00
42db857a98 whoops
All checks were successful
Build and Push Docker Image / build (push) Successful in 20s
2026-03-14 19:13:38 -04:00
5b24cf324f actually get profile picture rotation
All checks were successful
Build and Push Docker Image / build (push) Successful in 48s
discord.js was outdated and it was making the client token reset every time i set a pfp,
so this was taking forever to figure out because i dont understand packages
2026-03-11 23:27:36 -04:00
b8880f9a17 automagically build docker?
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m31s
2026-03-11 13:25:39 -04:00
b34d1281f2 better readme 2026-03-11 13:25:32 -04:00
95777bb389 accept discord token as env
we only really need that to function anyway, other things like jellyfin will
just not do anything and we have default value for avatar reset.
2026-03-11 13:25:15 -04:00
81c5e916dc better docker 2026-03-11 13:22:09 -04:00
13 changed files with 307 additions and 78 deletions

View File

@@ -1,3 +1,7 @@
docker-compose.yml
node_modules
.git
config.json
.gitea
state.json
config.json
avatars

View File

@@ -0,0 +1,36 @@
name: Build and Push Docker Image
on:
push:
branches: [ main, cmdsay ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Registry
uses: docker/login-action@v2
with:
registry: git.cesium.one
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build Docker Image
run: |
# Build the image with the commit hash tag
docker build -t git.cesium.one/kira/cockinator:cmdsay .
- name: Push Docker Images
env:
BRANCH_NAME: ${{ github.ref_name }}
SHORT_HASH: ${{ github.sha }}
run: |
docker push git.cesium.one/kira/cockinator:cmdsay
- name: Log out from registry
if: always()
run: docker logout git.cesium.one

3
.gitignore vendored
View File

@@ -141,4 +141,5 @@ dist
*.code-workspace
config.json
state.json
state.json
avatars/

View File

@@ -1,6 +1,6 @@
FROM node:25
RUN mkdir -p /usr/scr/bot
WORKDIR /usr/src/bot
COPY . /usr/src/bot
FROM node:25-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
CMD ["node", "index.js"]
COPY . .
CMD ["node", "index.js"]

View File

@@ -1,3 +1,42 @@
# girl cock inator
its docker compose, copy the default to `docker-compose.yml` and put a discord token in and start the container and it works i hope
it finds twitter links and turns them into girlcock links for better embed
## easiest way
docker image published at `git.cesium.one/kira/cockinator:latest` only needs `DISCORD` passed as a variable with your token
### examples
`docker run -e "DISCORD=TOKEN_HERE" git.cesium.one/kira/cockinator:latest`
```yml
services:
bot:
restart: unless-stopped
image: git.cesium.one/kira/cockinator
environment:
- DISCORD=TOKEN_HERE
```
## easy way
this also works in not docker with regular node.js, and pass it the `DISCORD` variable however you like
`npm i && DISCORD=TOKEN_HERE node index.js`
## other ways
you can build the image yourself with `docker build . -t cockinator` to then run with `docker run cockinator`
you can also build the image with docker-compose, by replacing `image: git.cesium.one/kira/cockinator` with `build: .`
## the config file
for the full functionality of the bot, you can copy `config.json.default` to `config.json` and fill it in.
it'll need to be in the main directory, and for docker that means mounting it as a volume with `-v ./config.json:/app/config.json`
## profile picture rotation
it'll take everything in ./avatars and shuffle them before rotating through them. this can also be mounted for docker with `-v ./avatars:/app/avatars`

View File

@@ -1,5 +1,8 @@
let config = {}
try { config = require('../config.json'); }
catch { config.jellyfin = null; }
const { SlashCommandBuilder } = require('discord.js');
const config = require('../config.json');
const { createClient } = require('../lib/jellyfin');
async function sendChunked(interaction, content) {
@@ -73,7 +76,10 @@ module.exports = {
),
async execute(interaction) {
if (!config.jellyfin.users.includes(interaction.user.id)) {
if (!config.jellyfin) {
interaction.reply({ content: 'This bot is not configured with a Jellyfin instance.', flags: 64 });
return;
} else if (!config.jellyfin.users.includes(interaction.user.id)) {
interaction.reply({ content: 'You are not authorized to use this command.', flags: 64 });
return;
} else if (interaction.channel.type !== 1) {
@@ -187,4 +193,4 @@ module.exports = {
await interaction.editReply(`Error fetching from Jellyfin: ${err.message}`);
}
},
};
};

20
commands/say.js Normal file
View File

@@ -0,0 +1,20 @@
const { SlashCommandBuilder } = require('discord.js');
const config = require('../config.json');
module.exports = {
data: new SlashCommandBuilder()
.setName('say')
.setDescription('speak on behalf of cockinator')
.addStringOption(option =>
option.setName('message')
.setDescription('The message to say')
.setRequired(true)
),
async execute(interaction) {
if (!config.parentsAndOrGuardians.includes(interaction.member.id)) {
return interaction.reply({ content: 'noe :(', ephemeral: true });
}
const message = interaction.options.getString('message');
await interaction.reply({ content: message });
},
};

View File

@@ -1,6 +1,8 @@
{
"token": "bot token go here",
"status": "looking for x.com links",
"avatarDir": "./avatars",
"avatarInterval": "24h",
"parentsAndOrGuardians": [
"230659159450845195",
"297983197990354944"

View File

@@ -2,5 +2,11 @@ services:
bot:
restart: unless-stopped
build: .
volumes:
- ./config.json:/usr/src/bot/config.json
environment:
- DISCORD=TOKEN_HERE
# volumes:
# Uncomment the config for advanced configuration like Jellyfin.
# - ./config.json:/app/config.json
# Uncomment avatars for an avatars folder it can rotate through.
# - ./avatars:/app/avatars

View File

@@ -1,4 +1,14 @@
const config = require('./config.json');
let config = {};
try {
config = require('./config.json');
} catch {
if (process.env.DISCORD && process.env.DISCORD != "TOKEN_HERE") {
config.token = process.env.DISCORD;
} else {
console.error("FATAL: Discord token required. Either pass it as an environment variable \"DISCORD\", or fill out config.json.default.");
process.exit(1);
}
}
// the basic discord setup stuff yoinked from their guide
const { Client, Events, GatewayIntentBits, Partials, ActivityType, MessageFlags, Collection } = require('discord.js');
const client = new Client({
@@ -17,6 +27,8 @@ const client = new Client({
]
});
const avatarRotation = require('./lib/avatarRotation');
// build the button below the message that swaps the URL
const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const swapRow = new ActionRowBuilder()
@@ -41,11 +53,10 @@ function swapify(url) {
const girlcockRegex = /https?:\/\/girlcockx\.com\/(.*?)\/status\/(\d+)/;
const fxtwitterRegex = /https?:\/\/fxtwitter\.com\/(.*?)\/status\/(\d+)/;
const fixupxRegex = /https?:\/\/fixupx\.com\/(.*?)\/status\/(\d+)/;
const twitterRegex = /https?:\/\/x\.com\/(.*?)\/status\/(\d+)/;
if (url.match(girlcockRegex)) return convertURL(url, girlcockRegex, "fxtwitter.com");
if (url.match(fxtwitterRegex)) return convertURL(url, fxtwitterRegex, "fixupx.com");
if (url.match(fixupxRegex)) return convertURL(url, fixupxRegex, "girlcockx.com");
// if we got this far, somethings not right but we'll try twitter before giving up
const twitterRegex = /https?:\/\/x\.com\/(.*?)\/status\/(\d+)/;
if (url.match(fixupxRegex)) return convertURL(url, fixupxRegex, "x.com");
if (url.match(twitterRegex)) return convertURL(url, twitterRegex, "girlcockx.com");
return url; // give up, we'll just return the original URL
}
@@ -68,6 +79,7 @@ client.on(Events.InteractionCreate, async interaction => {
client.once(Events.ClientReady, readyClient => {
console.log(`Discord: Connected as ${readyClient.user.tag}`);
client.user.setActivity(config.status, { type: ActivityType.Custom });
avatarRotation.start(client, config);
});
client.login(config.token);

96
lib/avatarRotation.js Normal file
View File

@@ -0,0 +1,96 @@
// this entire file is Opus 4.6 sorry
const fs = require('fs');
const path = require('path');
const IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.webp'];
const DEFAULT_INTERVAL = '24h';
const DEFAULT_DIR = './avatars';
/** Parse an interval string like "24h" or "30m" into milliseconds */
function parseInterval(str) {
const match = String(str).match(/^(\d+)\s*(h|m)$/i);
if (!match) {
console.warn(`Avatars: Invalid interval "${str}", falling back to ${DEFAULT_INTERVAL}`);
return parseInterval(DEFAULT_INTERVAL);
}
const value = parseInt(match[1], 10);
const unit = match[2].toLowerCase();
return unit === 'h' ? value * 60 * 60 * 1000 : value * 60 * 1000;
}
/** Scan the directory and return an array of image file paths */
function scanAvatars(dir) {
try {
return fs.readdirSync(dir)
.filter(f => IMAGE_EXTENSIONS.includes(path.extname(f).toLowerCase()))
.map(f => path.join(dir, f));
} catch (err) {
console.warn(`Avatars: Could not read directory "${dir}": ${err.message}`);
return [];
}
}
/** Pick a random avatar and set it on the client */
async function setRandomAvatar(client, avatars) {
if (!avatars.length) {
console.warn('Avatars: No images found, skipping avatar change');
return;
}
const pick = avatars[Math.floor(Math.random() * avatars.length)];
try {
await client.user.setAvatar(pick);
console.log(`Avatars: Changed to ${path.basename(pick)}`);
} catch (err) {
console.error(`Avatars: Failed to set avatar: ${err.message}`);
}
}
/**
* Start the avatar rotation system.
* @param {import('discord.js').Client} client - The Discord client (must be ready)
* @param {object} config - Bot config object
*/
function start(client, config = {}) {
const avatarDir = path.resolve(config.avatarDir || DEFAULT_DIR);
const intervalMs = parseInterval(config.avatarInterval || DEFAULT_INTERVAL);
// ensure the directory exists
if (!fs.existsSync(avatarDir)) {
console.warn(`Avatars: Directory "${avatarDir}" does not exist, avatar rotation disabled`);
return;
}
let avatars = scanAvatars(avatarDir);
console.log(`Avatars: Found ${avatars.length} image(s) in ${avatarDir}`);
console.log(`Avatars: Rotation interval set to ${config.avatarInterval || DEFAULT_INTERVAL}`);
// set one immediately on boot
setRandomAvatar(client, avatars);
// rotate on the configured interval
setInterval(() => {
avatars = scanAvatars(avatarDir); // re-scan in case watcher missed something
setRandomAvatar(client, avatars);
}, intervalMs);
// live-watch the folder for changes
let debounceTimer = null;
try {
fs.watch(avatarDir, (eventType, filename) => {
if (debounceTimer) clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
const updated = scanAvatars(avatarDir);
if (updated.length !== avatars.length) {
console.log(`Avatars: Folder changed, now ${updated.length} image(s)`);
}
avatars = updated;
}, 500); // 500ms debounce
});
console.log(`Avatars: Watching "${avatarDir}" for changes`);
} catch (err) {
console.warn(`Avatars: Could not watch directory: ${err.message}`);
}
}
module.exports = { start };

127
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"discord.js": "^14.18.0",
"discord.js": "^14.25.1",
"fs": "^0.0.1-security"
},
"devDependencies": {
@@ -18,15 +18,15 @@
}
},
"node_modules/@discordjs/builders": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.10.1.tgz",
"integrity": "sha512-OWo1fY4ztL1/M/DUyRPShB4d/EzVfuUvPTRRHRIt/YxBrUYSz0a+JicD5F5zHFoNs2oTuWavxCOVFV1UljHTng==",
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.13.1.tgz",
"integrity": "sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/formatters": "^0.6.0",
"@discordjs/util": "^1.1.1",
"@discordjs/formatters": "^0.6.2",
"@discordjs/util": "^1.2.0",
"@sapphire/shapeshift": "^4.0.0",
"discord-api-types": "^0.37.119",
"discord-api-types": "^0.38.33",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.4",
"tslib": "^2.6.3"
@@ -48,12 +48,12 @@
}
},
"node_modules/@discordjs/formatters": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.0.tgz",
"integrity": "sha512-YIruKw4UILt/ivO4uISmrGq2GdMY6EkoTtD0oS0GvkJFRZbTSdPhzYiUILbJ/QslsvC9H9nTgGgnarnIl4jMfw==",
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.2.tgz",
"integrity": "sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==",
"license": "Apache-2.0",
"dependencies": {
"discord-api-types": "^0.37.114"
"discord-api-types": "^0.38.33"
},
"engines": {
"node": ">=16.11.0"
@@ -63,9 +63,9 @@
}
},
"node_modules/@discordjs/rest": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.3.tgz",
"integrity": "sha512-+SO4RKvWsM+y8uFHgYQrcTl/3+cY02uQOH7/7bKbVZsTfrfpoE62o5p+mmV+s7FVhTX82/kQUGGbu4YlV60RtA==",
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.6.0.tgz",
"integrity": "sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/collection": "^2.1.1",
@@ -73,10 +73,10 @@
"@sapphire/async-queue": "^1.5.3",
"@sapphire/snowflake": "^3.5.3",
"@vladfrangu/async_event_emitter": "^2.4.6",
"discord-api-types": "^0.37.119",
"discord-api-types": "^0.38.16",
"magic-bytes.js": "^1.10.0",
"tslib": "^2.6.3",
"undici": "6.21.1"
"undici": "6.21.3"
},
"engines": {
"node": ">=18"
@@ -98,10 +98,13 @@
}
},
"node_modules/@discordjs/util": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz",
"integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.2.0.tgz",
"integrity": "sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==",
"license": "Apache-2.0",
"dependencies": {
"discord-api-types": "^0.38.33"
},
"engines": {
"node": ">=18"
},
@@ -110,18 +113,18 @@
}
},
"node_modules/@discordjs/ws": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.1.tgz",
"integrity": "sha512-PBvenhZG56a6tMWF/f4P6f4GxZKJTBG95n7aiGSPTnodmz4N5g60t79rSIAq7ywMbv8A4jFtexMruH+oe51aQQ==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz",
"integrity": "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/collection": "^2.1.0",
"@discordjs/rest": "^2.4.3",
"@discordjs/rest": "^2.5.1",
"@discordjs/util": "^1.1.0",
"@sapphire/async-queue": "^1.5.2",
"@types/ws": "^8.5.10",
"@vladfrangu/async_event_emitter": "^2.2.4",
"discord-api-types": "^0.37.119",
"discord-api-types": "^0.38.1",
"tslib": "^2.6.2",
"ws": "^8.17.0"
},
@@ -409,12 +412,12 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.14.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz",
"integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==",
"version": "25.4.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.4.0.tgz",
"integrity": "sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
"undici-types": "~7.18.0"
}
},
"node_modules/@types/ws": {
@@ -427,9 +430,9 @@
}
},
"node_modules/@vladfrangu/async_event_emitter": {
"version": "2.4.6",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz",
"integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==",
"version": "2.4.7",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.7.tgz",
"integrity": "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
@@ -612,29 +615,33 @@
"license": "MIT"
},
"node_modules/discord-api-types": {
"version": "0.37.119",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.119.tgz",
"integrity": "sha512-WasbGFXEB+VQWXlo6IpW3oUv73Yuau1Ig4AZF/m13tXcTKnMpc/mHjpztIlz4+BM9FG9BHQkEXiPto3bKduQUg==",
"license": "MIT"
"version": "0.38.42",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.42.tgz",
"integrity": "sha512-qs1kya7S84r5RR8m9kgttywGrmmoHaRifU1askAoi+wkoSefLpZP6aGXusjNw5b0jD3zOg3LTwUa3Tf2iHIceQ==",
"license": "MIT",
"workspaces": [
"scripts/actions/documentation"
]
},
"node_modules/discord.js": {
"version": "14.18.0",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.18.0.tgz",
"integrity": "sha512-SvU5kVUvwunQhN2/+0t55QW/1EHfB1lp0TtLZUSXVHDmyHTrdOj5LRKdR0zLcybaA15F+NtdWuWmGOX9lE+CAw==",
"version": "14.25.1",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.25.1.tgz",
"integrity": "sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/builders": "^1.10.1",
"@discordjs/builders": "^1.13.0",
"@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.6.0",
"@discordjs/rest": "^2.4.3",
"@discordjs/util": "^1.1.1",
"@discordjs/ws": "^1.2.1",
"@discordjs/formatters": "^0.6.2",
"@discordjs/rest": "^2.6.0",
"@discordjs/util": "^1.2.0",
"@discordjs/ws": "^1.2.3",
"@sapphire/snowflake": "3.5.3",
"discord-api-types": "^0.37.119",
"discord-api-types": "^0.38.33",
"fast-deep-equal": "3.1.3",
"lodash.snakecase": "4.1.1",
"magic-bytes.js": "^1.10.0",
"tslib": "^2.6.3",
"undici": "6.21.1"
"undici": "6.21.3"
},
"engines": {
"node": ">=18"
@@ -1066,9 +1073,9 @@
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
"node_modules/lodash.merge": {
@@ -1085,9 +1092,9 @@
"license": "MIT"
},
"node_modules/magic-bytes.js": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz",
"integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==",
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.13.0.tgz",
"integrity": "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==",
"license": "MIT"
},
"node_modules/minimatch": {
@@ -1305,18 +1312,18 @@
}
},
"node_modules/undici": {
"version": "6.21.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz",
"integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==",
"version": "6.21.3",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
"integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==",
"license": "MIT",
"engines": {
"node": ">=18.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
"license": "MIT"
},
"node_modules/uri-js": {
@@ -1356,9 +1363,9 @@
}
},
"node_modules/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"

View File

@@ -17,7 +17,7 @@
"homepage": "https://github.com/CesiumCs/tornbot#readme",
"description": "",
"dependencies": {
"discord.js": "^14.18.0",
"discord.js": "^14.25.1",
"fs": "^0.0.1-security"
},
"devDependencies": {