From 71f377ac18205e734d30303471fcc5831a77b4c8 Mon Sep 17 00:00:00 2001 From: sky Date: Sat, 7 Feb 2026 14:45:30 -0500 Subject: [PATCH] new game stuff, analytics --- accounts/profile.js | 2 +- ai.js | 12 +-- database.js | 10 ++- edu/index.html | 192 ----------------------------------------- edu/script.js | 65 -------------- edu/style.css | 185 --------------------------------------- games/flashpoint.js | 2 + games/osu.js | 13 +++ html/ai.html | 76 +++++++--------- html/login.html | 6 +- html/profile.html | 2 +- html/profile_404.html | 2 +- html/profile_ban.html | 2 +- html/profile_edit.html | 2 +- html/register.html | 2 +- html/reset.html | 2 +- html/users.html | 4 +- html/users.html.old | 2 +- index.js | 44 +++++----- package-lock.json | 81 +++++++++-------- 20 files changed, 144 insertions(+), 562 deletions(-) delete mode 100644 edu/index.html delete mode 100644 edu/script.js delete mode 100644 edu/style.css create mode 100644 games/flashpoint.js create mode 100644 games/osu.js diff --git a/accounts/profile.js b/accounts/profile.js index 7435ab1..c8f26a2 100755 --- a/accounts/profile.js +++ b/accounts/profile.js @@ -271,7 +271,7 @@ async function generateAccountPage(name, cookie, admin) { } let modifiedHTML = rawProfileHTML; - console.log(userData.music); + // console.log(userData.music); let songData = JSON.parse(userData.music) || false; modifiedHTML = modifiedHTML.replaceAll("{{ name }}", sanitizeHtml(userData.name, allowNone)); modifiedHTML = modifiedHTML.replaceAll("{{ join_date }}", dayjs(userData.createdAt).fromNow()); diff --git a/ai.js b/ai.js index 9fb4397..b8fae50 100755 --- a/ai.js +++ b/ai.js @@ -1,21 +1,23 @@ import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; -import { generateText } from 'ai'; +import { generateText, streamText } from 'ai'; const model = createOpenAICompatible({ name: 'model', apiKey: process.env.OPENAI_API_KEY, baseURL: process.env.OPENAI_BASE_URL, - includeUsage: true, // Include usage information in streaming responses + includeUsage: true, }); async function callAI(chatHistory) { - console.log("call ai called") - let { text } = await generateText({ + // TODO: add proper checking for chat + // realistically, just trust whats given, just make sure that the only roles are user and assistant + let { text } = streamText({ model: model(process.env.OPENAI_MODEL), system: "You are Zen, a helpful AI assistant built by Selenite. Your response should be accurate without hallucination." + "Over the course of conversation, adapt to the user's tone and preferences. Try to match the user's vibe, tone, and generally how they are speaking. You want the conversation to feel natural. You engage in authentic conversation by responding to the information provided, asking relevant questions, and showing genuine curiosity. If natural, use information you know about the user to personalize your responses and ask a follow up question.", messages: chatHistory }); - console.log(text); + return text.toTextStreamResponse(); } + export { callAI }; \ No newline at end of file diff --git a/database.js b/database.js index 4b23914..9036c89 100755 --- a/database.js +++ b/database.js @@ -6,12 +6,14 @@ if(!await (Bun.file(process.env.DATA_PATH)).exists()) { } const accs = new Database(`${process.env.DATA_PATH}/accounts.sqlite`, { create: true }); +const top = new Database(`${process.env.DATA_PATH}/games.sqlite`, { create: true }); // const infdb = new Database(`${process.env.DATA_PATH}/infinitecraft.sqlite`); // const friends = new Database(`${process.env.DATA_PATH}/friends.sqlite`); // const polytrack = new Database(`${process.env.DATA_PATH}/polytrack.sqlite`); // const ai_chats = new Database(`${process.env.DATA_PATH}/ai_chats.sqlite`); accs.exec("PRAGMA journal_mode = WAL;"); +top.exec("PRAGMA journal_mode = WAL;"); // infdb.exec("PRAGMA journal_mode = WAL;"); // friends.exec("PRAGMA journal_mode = WAL;"); // polytrack.exec("PRAGMA journal_mode = WAL;"); @@ -46,5 +48,11 @@ createAccountQuery+=`)` // console.log(createAccountQuery) accs.query(createAccountQuery).run(); +let topGamesQuery = `CREATE TABLE IF NOT EXISTS "stats" ( + "game" TEXT PRIMARY KEY, + "plays" INTEGER DEFAULT 0 +);` +top.query(topGamesQuery).run(); + // export { accs, infdb, friends, polytrack, ai_chats }; -export { accs }; \ No newline at end of file +export { accs, top }; \ No newline at end of file diff --git a/edu/index.html b/edu/index.html deleted file mode 100644 index 28ac386..0000000 --- a/edu/index.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - - - Open Learning Hub - - - -
-
-

Open Learning Hub

-

Your gateway to free educational resources across the web.

-
-
- -
-
-

💡 Tip of the Day

-

Loading tip...

- -
- -
-

Educational Resources

-
- - - - - - - - -
- -
- -
-

freeCodeCamp

-

Learn to code for free with interactive lessons and projects.

- Visit Site -
-
-

MDN Web Docs

-

Resources for developers, by developers. The bible of web dev.

- Visit Site -
-
-

GitHub

-

The world's largest platform for software development and version control.

- Visit Site -
-
-

The Odin Project

-

A full stack curriculum that is free and supported by a passionate open source community.

- Visit Site -
- - -
-

NASA

-

Explore the universe with images, videos, and news from NASA.

- Visit Site -
-
-

National Geographic

-

World leader in geography, cartography and exploration.

- Visit Site -
-
-

Nature

-

Leading international weekly journal of science.

- Visit Site -
- - -
-

Khan Academy

-

Free, world-class education for anyone, anywhere.

- Visit Site -
-
-

Wolfram MathWorld

-

The web's most extensive mathematics resource.

- Visit Site -
-
-

Desmos

-

Beautiful, free online graphing calculator.

- Visit Site -
- - -
-

Project Gutenberg

-

A library of over 60,000 free eBooks.

- Visit Site -
-
-

Smithsonian

-

Official website of the Smithsonian Institution.

- Visit Site -
-
-

Internet Archive

-

Non-profit library of millions of free books, movies, software, and music.

- Visit Site -
- - -
-

Duolingo

-

The world's most popular way to learn a language. It's 100% free.

- Visit Site -
-
-

BBC Languages

-

Archived but excellent resources for learning 40 languages.

- Visit Site -
- - -
-

Coursera

-

Build skills with courses, certificates, and degrees online from world-class universities.

- Visit Site -
-
-

edX

-

Access 2000+ free online courses from 140 leading institutions worldwide.

- Visit Site -
-
-

MIT OpenCourseWare

-

A web-based publication of virtually all MIT course content.

- Visit Site -
- - -
-

Anki

-

Powerful, intelligent flashcards. Remembering things just became much easier.

- Visit Site -
-
-

Notion

-

The all-in-one workspace for your notes, tasks, wikis, and databases.

- Visit Site -
-
-

Pomofocus

-

A customizable Pomodoro timer that works on desktop & mobile browser.

- Visit Site -
-
-
- -
-

🚀 Learning Paths

-
-
-

For Beginners

-

Start with Khan Academy to build a strong foundation in Math and Science. Then, try Duolingo for a new language.

-
-
-

For Career Switchers

-

Dive into freeCodeCamp or The Odin Project (add this!) to learn web development. Supplement with CS50 on edX.

-
-
-

For Lifelong Learners

-

Explore Project Gutenberg for classics, TED Talks for inspiration, and Coursera for specific interests.

-
-
-
-
- - - - - - diff --git a/edu/script.js b/edu/script.js deleted file mode 100644 index c40d842..0000000 --- a/edu/script.js +++ /dev/null @@ -1,65 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - // --- Tip of the Day Logic --- - const tips = [ - "Spaced repetition is a learning technique that incorporates increasing intervals of time between subsequent review of previously learned material.", - "The Pomodoro Technique uses a timer to break down work into intervals, traditionally 25 minutes in length, separated by short breaks.", - "Teaching someone else is one of the best ways to learn a new concept (The Feynman Technique).", - "Sleep is crucial for memory consolidation. Pulling an all-nighter is often counterproductive.", - "Active recall (testing yourself) is far more effective than passive re-reading.", - "Interleaving practice (mixing different subjects or topics) improves long-term retention compared to blocked practice.", - "Exercise increases blood flow to the brain and can improve cognitive performance.", - "Setting specific, measurable goals (SMART goals) helps maintain motivation.", - "Taking handwritten notes can improve conceptual understanding better than typing.", - "Mnemonic devices like acronyms or rhymes can help encode information into long-term memory." - ]; - - const tipElement = document.getElementById('daily-tip'); - const newTipBtn = document.getElementById('new-tip-btn'); - - function showRandomTip() { - const randomIndex = Math.floor(Math.random() * tips.length); - tipElement.textContent = tips[randomIndex]; - - // Add a subtle animation effect - tipElement.style.opacity = 0; - setTimeout(() => { - tipElement.style.opacity = 1; - }, 50); - } - - if (newTipBtn) { - newTipBtn.addEventListener('click', showRandomTip); - } - - // Show initial tip - if (tipElement) { - showRandomTip(); - tipElement.style.transition = "opacity 0.5s ease-in-out"; - } - - - // --- Filtering Logic --- - const filterBtns = document.querySelectorAll('.filter-btn'); - const cards = document.querySelectorAll('.card'); - - filterBtns.forEach(btn => { - btn.addEventListener('click', () => { - // Remove active class from all buttons - filterBtns.forEach(b => b.classList.remove('active')); - // Add active class to clicked button - btn.classList.add('active'); - - const filterValue = btn.getAttribute('data-filter'); - - cards.forEach(card => { - if (filterValue === 'all' || card.getAttribute('data-category') === filterValue) { - card.style.display = 'flex'; - // Add animation for appearing elements - card.style.animation = 'fadeIn 0.5s ease-in-out'; - } else { - card.style.display = 'none'; - } - }); - }); - }); -}); diff --git a/edu/style.css b/edu/style.css deleted file mode 100644 index 80b910d..0000000 --- a/edu/style.css +++ /dev/null @@ -1,185 +0,0 @@ -:root { - --primary-color: #2c3e50; - --secondary-color: #3498db; - --accent-color: #e74c3c; - --bg-color: #f4f4f4; - --card-bg: #ffffff; - --text-color: #333; -} - -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - line-height: 1.6; - background-color: var(--bg-color); - color: var(--text-color); -} - -.container { - max-width: 1100px; - margin: 0 auto; - padding: 0 20px; -} - -header { - background-color: var(--primary-color); - color: white; - padding: 2rem 0; - text-align: center; - margin-bottom: 2rem; -} - -header h1 { - font-size: 2.5rem; - margin-bottom: 0.5rem; -} - -section { - margin-bottom: 3rem; -} - -h2 { - color: var(--primary-color); - border-bottom: 2px solid var(--secondary-color); - padding-bottom: 0.5rem; - margin-bottom: 1.5rem; - display: inline-block; -} - -/* Tip Section */ -#tip-section { - background-color: var(--card-bg); - padding: 1.5rem; - border-radius: 8px; - box-shadow: 0 2px 5px rgba(0,0,0,0.1); - border-left: 5px solid var(--accent-color); -} - -#new-tip-btn { - background-color: var(--secondary-color); - color: white; - border: none; - padding: 8px 16px; - border-radius: 4px; - cursor: pointer; - margin-top: 1rem; - transition: background 0.3s; -} - -#new-tip-btn:hover { - background-color: #2980b9; -} - -/* Filter Controls */ -.filter-controls { - margin-bottom: 1.5rem; - display: flex; - gap: 10px; - flex-wrap: wrap; -} - -.filter-btn { - background: transparent; - border: 2px solid var(--secondary-color); - color: var(--secondary-color); - padding: 6px 12px; - border-radius: 20px; - cursor: pointer; - font-weight: bold; - transition: all 0.3s; -} - -.filter-btn:hover, .filter-btn.active { - background-color: var(--secondary-color); - color: white; -} - -/* Resource Grid */ -.resource-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 20px; -} - -.card { - background-color: var(--card-bg); - padding: 1.5rem; - border-radius: 8px; - box-shadow: 0 2px 5px rgba(0,0,0,0.1); - transition: transform 0.2s; - display: flex; - flex-direction: column; -} - -.card:hover { - transform: translateY(-5px); -} - -.card h3 { - margin-bottom: 0.5rem; - color: var(--primary-color); -} - -.card p { - flex-grow: 1; - margin-bottom: 1rem; - color: #666; -} - -.card a { - display: inline-block; - text-decoration: none; - color: var(--secondary-color); - font-weight: bold; -} - -.card a:hover { - text-decoration: underline; -} - -footer { - text-align: center; - padding: 2rem 0; - margin-top: 2rem; - color: #777; - border-top: 1px solid #ddd; -} - -@keyframes fadeIn { - from { opacity: 0; transform: translateY(10px); } - to { opacity: 1; transform: translateY(0); } -} - -@media (max-width: 600px) { - header h1 { - font-size: 2rem; - } - - .resource-grid { - grid-template-columns: 1fr; - } -} - -/* Learning Paths */ -.paths-container { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 20px; -} - -.path-card { - background-color: #e8f4f8; - padding: 1.5rem; - border-radius: 8px; - border-left: 4px solid var(--secondary-color); -} - -.path-card h3 { - color: var(--primary-color); - margin-bottom: 0.5rem; -} diff --git a/games/flashpoint.js b/games/flashpoint.js new file mode 100644 index 0000000..8185e95 --- /dev/null +++ b/games/flashpoint.js @@ -0,0 +1,2 @@ +let searchURL = function(query) {return `https://db-api.unstable.life/search?filter=true&fields=id,title,developer,publisher,platform,library,tags,originalDescription,dateAdded,dateModified&smartSearch=${query}`} +let imagesURL = function(uuid) {return `https://infinity.unstable.life/images/Logos/c2/af/${uuid}.png?type=jpg`} \ No newline at end of file diff --git a/games/osu.js b/games/osu.js new file mode 100644 index 0000000..800140b --- /dev/null +++ b/games/osu.js @@ -0,0 +1,13 @@ +async function minoProxy(req, res) { + + let baseurl = ((req.url.startsWith("/api") && !req.url.startsWith("/api/v2")) || req.url.includes(".ttf") || req.url.startsWith("/skin/")) ? "https://webosumania.com" : "https://catboy.best" + let data = await fetch(baseurl + req.url); + + res.status(data.status); + res.setHeader("Content-Type", data.headers.get("content-type")); + for await (const chunk of data.body) { + res.write(chunk) + } + res.end(); +} +export { minoProxy }; \ No newline at end of file diff --git a/html/ai.html b/html/ai.html index 573f417..b13fec9 100755 --- a/html/ai.html +++ b/html/ai.html @@ -5,60 +5,46 @@ https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> - - + + - + - - - + + + - AI | Selenite + Selenite + - -
- Home - Bookmarklets - Games - Apps - Settings - Open Blank - -
- -
-

AI Chat Bot

-

Powered by Groq.

-

Messages are logged for quality assurance. Don't type any personal information.

- -
-
-
-
- -
-
-
- + +

ai

+ +

diff --git a/html/login.html b/html/login.html index dff6967..27b24f8 100755 --- a/html/login.html +++ b/html/login.html @@ -7,7 +7,7 @@ - + @@ -41,11 +41,11 @@ }) ).json(); if (data.success == true) { - console.log("Token: ", data.token); + // console.log("Token: ", data.token); document.cookie = `token=${data.token}; expires=${new Date(new Date().setMonth(new Date().getMonth() + 6)).toUTCString()}; path=/;`; location.href = "/u/"; } else { - console.log("Error: ", data.reason); + // console.log("Error: ", data.reason); document.getElementById("title").innerText = "Failed to login"; document.getElementById("reason").innerText = data.reason; document.getElementById("popup").style.display = "flex"; diff --git a/html/profile.html b/html/profile.html index 8432e25..ac79f50 100755 --- a/html/profile.html +++ b/html/profile.html @@ -24,7 +24,7 @@ - + diff --git a/html/profile_404.html b/html/profile_404.html index 13a8861..d41c25e 100755 --- a/html/profile_404.html +++ b/html/profile_404.html @@ -13,7 +13,7 @@ - + diff --git a/html/profile_ban.html b/html/profile_ban.html index 5c58b85..6f3bc9f 100755 --- a/html/profile_ban.html +++ b/html/profile_ban.html @@ -13,7 +13,7 @@ - + diff --git a/html/profile_edit.html b/html/profile_edit.html index a063298..db7b8a4 100755 --- a/html/profile_edit.html +++ b/html/profile_edit.html @@ -24,7 +24,7 @@ - + diff --git a/html/register.html b/html/register.html index 2e5da6b..c7a12a5 100755 --- a/html/register.html +++ b/html/register.html @@ -9,7 +9,7 @@ - + diff --git a/html/reset.html b/html/reset.html index 86a6f43..0aa45e8 100755 --- a/html/reset.html +++ b/html/reset.html @@ -7,7 +7,7 @@ - + diff --git a/html/users.html b/html/users.html index bdf1c02..ead7a04 100644 --- a/html/users.html +++ b/html/users.html @@ -24,7 +24,7 @@ - + - + diff --git a/index.js b/index.js index 7094cf0..60bf8c2 100755 --- a/index.js +++ b/index.js @@ -8,9 +8,10 @@ import path, { dirname } from "node:path"; import mime from "mime-types"; import compression from "compression"; // import { accs, infdb, polytrack } from "./database.js"; -import { accs } from "./database.js"; +import { accs, top } from "./database.js"; import { } from "./accounts/friend.js"; import { findClientID, search, download } from "./accounts/music.js"; +import { minoProxy } from "./games/osu.js"; import { banUser, removeAccount, verifyCookie, getUserFromCookie, createAccount, resetPassword, loginAccount, addBadge } from "./accounts/manage.js"; import { } from "./accounts/misc.js"; import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdmin, retrieveData } from "./accounts/profile.js"; @@ -21,18 +22,6 @@ import chokidar from 'chokidar'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -let recatters = JSON.parse(await fs.readFile("./data/recats.json")); -const watcher = chokidar.watch('./data/recats.json', { - persistent: true, - awaitWriteFinish: { - stabilityThreshold: 500, - pollInterval: 100 - } -}); -watcher.on('change', async (event, filePath) => { - recatters = JSON.parse(await fs.readFile("./data/recats.json")); -}); - await findClientID(); setInterval(async () => { await findClientID(); @@ -42,14 +31,6 @@ const port = process.env.PORT || 3000; const app = express(); -let recatFolder = express.static("./edu", { extensions: ["html"] }); -app.use((req, res, next) => { - if(recatters.includes(req.hostname)) { - return recatFolder(req, res, next); - } - next(); -}); - // why the fuck does this have to exist? app.use("/resources/semag/hotline-miami/", (req,res,next) => { if(req.method == "HEAD") { @@ -57,6 +38,9 @@ app.use("/resources/semag/hotline-miami/", (req,res,next) => { } next(); }); + + +app.use("/osu/", await minoProxy) app.use("/resources/semag/portal/", (req,res,next) => { res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); @@ -193,6 +177,22 @@ app.post("/api/account/upload", async (req, res, next) => { } }); +app.post("/api/analytics/game", async (req, res) => { + if(req.body && req.body.path.length < 16) { + const query = top.prepare(` + INSERT INTO stats (game, plays) + VALUES ($id, 1) + ON CONFLICT(game) DO UPDATE SET plays = plays + 1 + RETURNING * + `); + query.get({ $id: req.body.path }); + res.send(200); + return; + } + res.send(400); + return; +}) + app.post("/api/ai/sendMessage", async (req, res) => { // take in chat id and message // stream back reply @@ -284,7 +284,7 @@ app.use("/api/account/load", async (req, res, next) => { }); app.use("/api/getUsers", async (req, res, next) => { - console.log(req.query) + // console.log(req.query) let status = await getUsers(req.query.page, req.query.query); res.status(200).send(status); }); diff --git a/package-lock.json b/package-lock.json index c92d3d0..c29d4d3 100755 --- a/package-lock.json +++ b/package-lock.json @@ -637,23 +637,27 @@ } }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", - "debug": "^4.4.0", + "debug": "^4.4.3", "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/body-parser/node_modules/debug": { @@ -1477,31 +1481,39 @@ } }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ieee754": { @@ -1881,9 +1893,9 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -1914,18 +1926,18 @@ } }, "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, "node_modules/readdirp": { @@ -2007,7 +2019,8 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/sanitize-html": { "version": "2.17.0", @@ -2250,9 +2263,9 @@ } }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8"