Add overlays to outlook command
273
data/commands.json
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "subscribe",
|
||||||
|
"description": "Subscribe to a weather.im room",
|
||||||
|
"default_member_permissions": 0,
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "room",
|
||||||
|
"description": "The room/WFO you want to subscribe to",
|
||||||
|
"type": 3,
|
||||||
|
"required": true,
|
||||||
|
"autocomplete": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "message",
|
||||||
|
"description": "Custom message to send when alert is sent",
|
||||||
|
"type": 3,
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "setmessage",
|
||||||
|
"description": "Set a custom message for a room",
|
||||||
|
"default_member_permissions": 0,
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "room",
|
||||||
|
"description": "The room/WFO you want to set a message for",
|
||||||
|
"type": 3,
|
||||||
|
"required": true,
|
||||||
|
"autocomplete": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "message",
|
||||||
|
"description": "Custom message to send when alert is sent",
|
||||||
|
"type": 3,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unsubscribe",
|
||||||
|
"description": "Unsubscribe from a weather.im room",
|
||||||
|
"default_member_permissions": 0,
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "room",
|
||||||
|
"description": "The room/WFO you want to unsubscribe from",
|
||||||
|
"type": 3,
|
||||||
|
"required": true,
|
||||||
|
"autocomplete": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "list",
|
||||||
|
"description": "List all subscribed rooms for this channel",
|
||||||
|
"default_member_permissions": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "about",
|
||||||
|
"description": "About this bot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rooms",
|
||||||
|
"description": "List all available rooms"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "setupall",
|
||||||
|
"description": "[OWNER ONLY] Setup channels in a category for all rooms",
|
||||||
|
"default_member_permissions": 0,
|
||||||
|
"type": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "support",
|
||||||
|
"description": "Get support for the bot",
|
||||||
|
"type": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "usersubscribe",
|
||||||
|
"description": "Subscribe to alerts for a room",
|
||||||
|
"type": 1,
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "room",
|
||||||
|
"description": "The room/WFO you want to subscribe to",
|
||||||
|
"type": 3,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "filter",
|
||||||
|
"description": "Filter for the alert",
|
||||||
|
"type": 3,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "minpriority",
|
||||||
|
"description": "Minimum priority to alert for",
|
||||||
|
"type": 4,
|
||||||
|
"required": false,
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"name": "Any",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Minimum",
|
||||||
|
"value": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Low",
|
||||||
|
"value": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Normal",
|
||||||
|
"value": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "High",
|
||||||
|
"value": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Very High",
|
||||||
|
"value": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "filterevt",
|
||||||
|
"description": "Filter for event type",
|
||||||
|
"type": 3,
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "userunsubscribe",
|
||||||
|
"description": "Unsubscribe from alerts for a room",
|
||||||
|
"type": 1,
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "room",
|
||||||
|
"description": "The room/WFO you want to unsubscribe from",
|
||||||
|
"type": 3,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "userlist",
|
||||||
|
"description": "List all subscribed alerts for this user",
|
||||||
|
"type": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "outlook",
|
||||||
|
"description": "Get day 1-8 storm or fire outlook from the SPC",
|
||||||
|
"type": 1,
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "day",
|
||||||
|
"description": "Day of outlook",
|
||||||
|
"type": 4,
|
||||||
|
"required": true,
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"name": "Day 1",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Day 2",
|
||||||
|
"value": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Day 3",
|
||||||
|
"value": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Day 4",
|
||||||
|
"value": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Day 5",
|
||||||
|
"value": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Day 6",
|
||||||
|
"value": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Day 7",
|
||||||
|
"value": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Day 8",
|
||||||
|
"value": 7
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"description": "Type of outlook",
|
||||||
|
"type": 3,
|
||||||
|
"required": true,
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"name": "Fire",
|
||||||
|
"value": "fire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Convective",
|
||||||
|
"value": "convective"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "population_overlay",
|
||||||
|
"description": "Whether to add the population overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "city_overlay",
|
||||||
|
"description": "Whether to add the city name overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cwa_overlay",
|
||||||
|
"description": "Whether to add the County Warning Area overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rfc_overlay",
|
||||||
|
"description": "Whether to add the River Forecast Center overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "interstate_overlay",
|
||||||
|
"description": "Whether to add the interstate overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "county_overlay",
|
||||||
|
"description": "Whether to add the county lines overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tribal_overlay",
|
||||||
|
"description": "Whether to add the tribal lands overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "artcc_overlay",
|
||||||
|
"description": "Whether to add the Air Route Traffic Control Centers overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fema_overlay",
|
||||||
|
"description": "Whether to add the FEMA regions overlay",
|
||||||
|
"type": 5,
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"storm": [
|
"convective": [
|
||||||
"https://www.spc.noaa.gov/products/outlook/day1otlk.gif",
|
"https://www.spc.noaa.gov/products/outlook/day1otlk.gif",
|
||||||
"https://www.spc.noaa.gov/products/outlook/day2otlk.gif",
|
"https://www.spc.noaa.gov/products/outlook/day2otlk.gif",
|
||||||
"https://www.spc.noaa.gov/products/outlook/day3otlk.gif",
|
"https://www.spc.noaa.gov/products/outlook/day3otlk.gif",
|
||||||
|
|
BIN
images/overlays/artcc.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
images/overlays/city.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/overlays/county.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
images/overlays/cwa.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
images/overlays/fema.png
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
images/overlays/interstate.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
images/overlays/population.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
images/overlays/rfc.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
images/overlays/tribal.png
Normal file
After Width: | Height: | Size: 34 KiB |
300
index.js
|
@ -5,6 +5,7 @@ const wfos = require("./data/wfos.json");
|
||||||
const blacklist = require("./data/blacklist.json");
|
const blacklist = require("./data/blacklist.json");
|
||||||
const events = require("./data/events.json");
|
const events = require("./data/events.json");
|
||||||
const outlookURLs = require("./data/outlook.json");
|
const outlookURLs = require("./data/outlook.json");
|
||||||
|
const Jimp = require("jimp");
|
||||||
const { client, xml } = require("@xmpp/client");
|
const { client, xml } = require("@xmpp/client");
|
||||||
const fetch = require("node-fetch");
|
const fetch = require("node-fetch");
|
||||||
const html = require("html-entities")
|
const html = require("html-entities")
|
||||||
|
@ -546,226 +547,7 @@ discord.on('ready', async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Do slash command stuff
|
// Do slash command stuff
|
||||||
const commands = [
|
commands = require("./data/commands.json");
|
||||||
{
|
|
||||||
"name": "subscribe",
|
|
||||||
"description": "Subscribe to a weather.im room",
|
|
||||||
"default_member_permissions": 0,
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "room",
|
|
||||||
"description": "The room/WFO you want to subscribe to",
|
|
||||||
"type": 3,
|
|
||||||
"required": true,
|
|
||||||
"autocomplete": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "message",
|
|
||||||
"description": "Custom message to send when alert is sent",
|
|
||||||
"type": 3,
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "setmessage",
|
|
||||||
"description": "Set a custom message for a room",
|
|
||||||
"default_member_permissions": 0,
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "room",
|
|
||||||
"description": "The room/WFO you want to set a message for",
|
|
||||||
"type": 3,
|
|
||||||
"required": true,
|
|
||||||
"autocomplete": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "message",
|
|
||||||
"description": "Custom message to send when alert is sent",
|
|
||||||
"type": 3,
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "unsubscribe",
|
|
||||||
"description": "Unsubscribe from a weather.im room",
|
|
||||||
"default_member_permissions": 0,
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "room",
|
|
||||||
"description": "The room/WFO you want to unsubscribe from",
|
|
||||||
"type": 3,
|
|
||||||
"required": true,
|
|
||||||
"autocomplete": false
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "list",
|
|
||||||
"description": "List all subscribed rooms for this channel",
|
|
||||||
"default_member_permissions": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "about",
|
|
||||||
"description": "About this bot"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "rooms",
|
|
||||||
"description": "List all available rooms"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "setupall",
|
|
||||||
"description": "[OWNER ONLY] Setup channels in a category for all rooms",
|
|
||||||
"default_member_permissions": 0,
|
|
||||||
"type": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "support",
|
|
||||||
"description": "Get support for the bot",
|
|
||||||
"type": 1
|
|
||||||
},
|
|
||||||
// User alert commands
|
|
||||||
{
|
|
||||||
"name": "usersubscribe",
|
|
||||||
"description": "Subscribe to alerts for a room",
|
|
||||||
"type": 1,
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "room",
|
|
||||||
"description": "The room/WFO you want to subscribe to",
|
|
||||||
"type": 3,
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "filter",
|
|
||||||
"description": "Filter for the alert",
|
|
||||||
"type": 3,
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "minpriority",
|
|
||||||
"description": "Minimum priority to alert for",
|
|
||||||
"type": 4,
|
|
||||||
"required": false,
|
|
||||||
"choices": [
|
|
||||||
{
|
|
||||||
"name": "Any",
|
|
||||||
"value": 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Minimum",
|
|
||||||
"value": 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Low",
|
|
||||||
"value": 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Normal",
|
|
||||||
"value": 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "High",
|
|
||||||
"value": 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Very High",
|
|
||||||
"value": 5,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "filterevt",
|
|
||||||
"description": "Filter for event type",
|
|
||||||
"type": 3,
|
|
||||||
"required": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userunsubscribe",
|
|
||||||
"description": "Unsubscribe from alerts for a room",
|
|
||||||
"type": 1,
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "room",
|
|
||||||
"description": "The room/WFO you want to unsubscribe from",
|
|
||||||
"type": 3,
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "userlist",
|
|
||||||
"description": "List all subscribed alerts for this user",
|
|
||||||
"type": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "outlook",
|
|
||||||
"description": "Get day 1-8 storm or fire outlook from the SPC",
|
|
||||||
"type": 1,
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "day",
|
|
||||||
"description": "Day of outlook",
|
|
||||||
"type": 4,
|
|
||||||
"required": true,
|
|
||||||
"choices": [
|
|
||||||
{
|
|
||||||
"name": "Day 1",
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Day 2",
|
|
||||||
"value": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Day 3",
|
|
||||||
"value": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Day 4",
|
|
||||||
"value": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Day 5",
|
|
||||||
"value": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Day 6",
|
|
||||||
"value": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Day 7",
|
|
||||||
"value": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Day 8",
|
|
||||||
"value": 7
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "type",
|
|
||||||
"description": "Type of outlook",
|
|
||||||
"type": 3,
|
|
||||||
"required": true,
|
|
||||||
"choices": [
|
|
||||||
{
|
|
||||||
"name": "Fire",
|
|
||||||
"value": "fire"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Storm",
|
|
||||||
"value": "storm"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
if (config.broadcastify.enabled) {
|
if (config.broadcastify.enabled) {
|
||||||
// Add commands to join vc, leave vc, and play stream
|
// Add commands to join vc, leave vc, and play stream
|
||||||
|
@ -1232,26 +1014,74 @@ discord.on("interactionCreate", async (interaction) => {
|
||||||
interaction.editReply({ content: "Failed to get outlook", ephemeral: true });
|
interaction.editReply({ content: "Failed to get outlook", ephemeral: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// debug log toLocalString of timestamps
|
|
||||||
console.log(issued.toLocaleString());
|
|
||||||
// Returns image, send embed with image as attachment (we need to bypass discord cache)
|
|
||||||
res.buffer().then(async (buffer) => {
|
res.buffer().then(async (buffer) => {
|
||||||
interaction.editReply({
|
// Check all overlays and add them to image as selected using Jimp
|
||||||
embeds: [{
|
overlays = ["population", "city", "cwa", "rfc", "interstate", "county", "tribal", "artcc", "fema"]
|
||||||
title: `${toTitleCase(type)} Outlook Day ${day + 1}`,
|
await Jimp.read(buffer).then((image) => {
|
||||||
image: {
|
outImg = image;
|
||||||
url: `attachment://${type}_${day}.png`
|
cnt = 0;
|
||||||
},
|
sendMsg = setTimeout(() => {
|
||||||
color: 0x00ff00
|
interaction.editReply({
|
||||||
}],
|
embeds: [{
|
||||||
files: [{
|
title: `${toTitleCase(type)} Outlook Day ${day + 1}`,
|
||||||
attachment: buffer,
|
image: {
|
||||||
name: `${type}_${day}.png`
|
url: `attachment://${type}_${day}.png`
|
||||||
}]
|
},
|
||||||
|
color: 0x00ff00
|
||||||
|
}],
|
||||||
|
files: [{
|
||||||
|
attachment: buffer,
|
||||||
|
name: `${type}_${day}.png`
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}, 150)
|
||||||
|
overlays.forEach((overlay) => {
|
||||||
|
if (interaction.options.getBoolean(`${overlay}_overlay`)) {
|
||||||
|
clearTimeout(sendMsg);
|
||||||
|
Jimp.read(`./images/overlays/${overlay}.png`).then((overlayImage) => {
|
||||||
|
outImg.composite(overlayImage, 0, 0);
|
||||||
|
sendMsg = setTimeout(() => {
|
||||||
|
outImg.getBufferAsync(Jimp.MIME_PNG).then((buffer) => {
|
||||||
|
interaction.editReply({
|
||||||
|
embeds: [{
|
||||||
|
title: `${toTitleCase(type)} Outlook Day ${day + 1}`,
|
||||||
|
image: {
|
||||||
|
url: `attachment://${type}_${day}.png`
|
||||||
|
},
|
||||||
|
color: 0x00ff00
|
||||||
|
}],
|
||||||
|
files: [{
|
||||||
|
attachment: buffer,
|
||||||
|
name: `${type}_${day}.png`
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 150)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// interaction.editReply({
|
||||||
|
// embeds: [{
|
||||||
|
// title: `${toTitleCase(type)} Outlook Day ${day + 1}`,
|
||||||
|
// image: {
|
||||||
|
// url: `attachment://${type}_${day}.png`
|
||||||
|
// },
|
||||||
|
// color: 0x00ff00
|
||||||
|
// }],
|
||||||
|
// files: [{
|
||||||
|
// attachment: buffer,
|
||||||
|
// name: `${type}_${day}.png`
|
||||||
|
// }]
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
interaction.editReply({ content: "Failed to get outlook", ephemeral: true });
|
interaction.editReply({ content: "Failed to get outlook", ephemeral: true });
|
||||||
|
console.log(`${colors.red("[ERROR]")} Failed to get outlook: ${err.message}`);
|
||||||
|
console.error(err);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"discord.js": "^14.15.2",
|
"discord.js": "^14.15.2",
|
||||||
"html-entities": "^2.5.2",
|
"html-entities": "^2.5.2",
|
||||||
|
"jimp": "^0.22.12",
|
||||||
"sodium": "^3.0.2",
|
"sodium": "^3.0.2",
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
|
|