diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2539227 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.git +.vscode +node_modules +app/node_modules +.env +.env.* diff --git a/.env.example b/.env.example index 09a7979..a67735b 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,16 @@ CLIENT_ID=VOTRE_BOT_CLIENT_ID CLIENT_SECRET=VOTRE_BOT_CLIENT_SECRET REDIRECT_URI=https://lazybot.arthurp.fr/auth/discord/callback +NODE_ENV=development PORT=3000 BOT_TOKEN=VOTRE_BOT_TOKEN SESSION_SECRET=UN_SECRET_LONG_ET_UNIQUE -DB_PATH=database.sqlite +POSTGRES_HOST=db +POSTGRES_PORT=5432 +POSTGRES_DB=lazybot +POSTGRES_USER=lazybot +POSTGRES_PASSWORD=change_me +POSTGRES_DATA_PATH=./data/postgres +DATABASE_URL=postgresql://lazybot:change_me@db:5432/lazybot OWNER=VOTRE_ID_UTILISATEUR URL=https://lazybot.arthurp.fr diff --git a/.gitignore b/.gitignore index 1dd490c..b335118 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,9 @@ web_modules/ .env.* !.env.example +# Docker volumes +data/postgres/ + # parcel-bundler cache (https://parceljs.org/) .cache .parcel-cache diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b85248b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM node:20-bookworm-slim AS development +WORKDIR /app +COPY app/package*.json ./ +RUN npm install +COPY app/ ./ +CMD ["node", "server.js"] + +FROM node:20-bookworm-slim AS production +ENV NODE_ENV=production +WORKDIR /app +COPY app/package*.json ./ +RUN npm install --omit=dev && npm cache clean --force +COPY app/ ./ +CMD ["node", "server.js"] diff --git a/README.md b/README.md index 1125456..038ca63 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Site officiel: https://lazybot.arthurp.fr - Node.js - Discord.js -- SQLite +- PostgreSQL - Docker et Docker Compose ## Installation @@ -40,15 +40,41 @@ cp .env.example .env CLIENT_ID=VOTRE_BOT_CLIENT_ID CLIENT_SECRET=VOTRE_BOT_CLIENT_SECRET REDIRECT_URI=https://lazybot.arthurp.fr/auth/discord/callback +NODE_ENV=production PORT=3000 BOT_TOKEN=VOTRE_TOKEN_BOT SESSION_SECRET=UN_SECRET_LONG_ET_UNIQUE -DB_PATH=database.sqlite +POSTGRES_HOST=db +POSTGRES_PORT=5432 +POSTGRES_DB=lazybot +POSTGRES_USER=lazybot +POSTGRES_PASSWORD=change_me +POSTGRES_DATA_PATH=./data/postgres +DATABASE_URL=postgresql://lazybot:change_me@db:5432/lazybot OWNER=VOTRE_ID_UTILISATEUR URL=https://lazybot.arthurp.fr ``` -4. Lancer avec Docker +Variables d'environnement prises en charge: + +- CLIENT_ID +- CLIENT_SECRET +- REDIRECT_URI +- NODE_ENV +- PORT +- BOT_TOKEN +- SESSION_SECRET +- POSTGRES_HOST +- POSTGRES_PORT +- POSTGRES_DB +- POSTGRES_USER +- POSTGRES_PASSWORD +- POSTGRES_DATA_PATH +- DATABASE_URL +- OWNER +- URL + +4. Lancer ```bash docker compose up -d --build @@ -56,6 +82,26 @@ docker compose up -d --build Le dashboard est ensuite disponible sur `http://localhost:3000`. +## Exemples de profils + +Exemple developpement (.env): + +```env +NODE_ENV=development +PORT=3002 +POSTGRES_DATA_PATH=./data/postgres/dev +URL=http://localhost:3002 +``` + +Exemple production (.env): + +```env +NODE_ENV=production +PORT=3000 +POSTGRES_DATA_PATH=./data/postgres +URL=https://lazybot.arthurp.fr +``` + ## Securite avant publication - Ne jamais versionner `.env` diff --git a/app/db.js b/app/db.js index 5f4faa5..9ad2691 100644 --- a/app/db.js +++ b/app/db.js @@ -1,34 +1,29 @@ -const sqlite3 = require("sqlite3").verbose(); -const path = require("path"); +const { Pool } = require("pg"); -const db = new sqlite3.Database( - path.join(__dirname, process.env.DB_PATH || "database.sqlite"), - err => { - if (err) console.error("Erreur DB:", err); - else console.log("DB SQLite connectée"); - } -); +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, + host: process.env.POSTGRES_HOST, + port: process.env.POSTGRES_PORT ? Number(process.env.POSTGRES_PORT) : undefined, + user: process.env.POSTGRES_USER, + password: process.env.POSTGRES_PASSWORD, + database: process.env.POSTGRES_DB, +}); -db.getAsync = (sql, params = []) => { - return new Promise((resolve, reject) => { - db.get(sql, params, (err, row) => { - if (err) reject(err); - else resolve(row); - }); - }); -}; +const TABLES_WITH_ID = new Set([ + "shop_items", + "user_inventory", + "stats_channels", + "user_activity_stats", + "username_history", + "nickname_history", + "antiraid_warnings", + "warnings", + "scheduled_messages", + "role_panels", + "role_panel_buttons", +]); -db.allAsync = (sql, params = []) => { - return new Promise((resolve, reject) => { - db.all(sql, params, (err, rows) => { - if (err) reject(err); - else resolve(rows); - }); - }); -}; - -// Création de la table si elle n'existe pas -db.exec(` +const schemaSql = ` CREATE TABLE IF NOT EXISTS welcome_config ( guild_id TEXT PRIMARY KEY, channel_id TEXT, @@ -106,7 +101,7 @@ db.exec(` user_id TEXT NOT NULL, xp INTEGER NOT NULL, level INTEGER NOT NULL, - last_xp_message_timestamp INTEGER, + last_xp_message_timestamp BIGINT, PRIMARY KEY (guild_id, user_id) ); @@ -155,32 +150,32 @@ db.exec(` user_id TEXT NOT NULL, balance INTEGER NOT NULL DEFAULT 0, bank INTEGER NOT NULL DEFAULT 0, - last_daily_timestamp INTEGER, - last_work_timestamp INTEGER, - last_crime_timestamp INTEGER, - last_steal_timestamp INTEGER, - last_message_money_timestamp INTEGER, + last_daily_timestamp BIGINT, + last_work_timestamp BIGINT, + last_crime_timestamp BIGINT, + last_steal_timestamp BIGINT, + last_message_money_timestamp BIGINT, PRIMARY KEY (guild_id, user_id) ); CREATE TABLE IF NOT EXISTS shop_items ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, name TEXT NOT NULL, description TEXT, price INTEGER NOT NULL, role_id TEXT, stock INTEGER DEFAULT -1, - created_at INTEGER NOT NULL + created_at BIGINT NOT NULL ); CREATE TABLE IF NOT EXISTS user_inventory ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, user_id TEXT NOT NULL, - item_id INTEGER NOT NULL, + item_id BIGINT NOT NULL, quantity INTEGER NOT NULL DEFAULT 1, - purchased_at INTEGER NOT NULL, + purchased_at BIGINT NOT NULL, FOREIGN KEY (item_id) REFERENCES shop_items(id) ); @@ -196,7 +191,7 @@ db.exec(` channel_id TEXT PRIMARY KEY, guild_id TEXT NOT NULL, owner_id TEXT NOT NULL, - created_at INTEGER NOT NULL + created_at BIGINT NOT NULL ); CREATE TABLE IF NOT EXISTS counting_config ( @@ -208,7 +203,7 @@ db.exec(` ); CREATE TABLE IF NOT EXISTS stats_channels ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, channel_id TEXT NOT NULL, stat_type TEXT NOT NULL, @@ -218,7 +213,7 @@ db.exec(` ); CREATE TABLE IF NOT EXISTS user_activity_stats ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, user_id TEXT NOT NULL, stat_type TEXT NOT NULL, @@ -230,7 +225,7 @@ db.exec(` CREATE TABLE IF NOT EXISTS voice_sessions ( guild_id TEXT NOT NULL, user_id TEXT NOT NULL, - join_timestamp INTEGER NOT NULL, + join_timestamp BIGINT NOT NULL, PRIMARY KEY(guild_id, user_id) ); @@ -259,21 +254,21 @@ db.exec(` ); CREATE TABLE IF NOT EXISTS username_history ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, user_id TEXT NOT NULL, username TEXT NOT NULL, display_name TEXT, - changed_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) + changed_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW())::BIGINT) ); CREATE INDEX IF NOT EXISTS idx_username_history_user ON username_history(user_id, changed_at DESC); CREATE TABLE IF NOT EXISTS nickname_history ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, user_id TEXT NOT NULL, nickname TEXT, - changed_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) + changed_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW())::BIGINT) ); CREATE INDEX IF NOT EXISTS idx_nickname_history_user ON nickname_history(guild_id, user_id, changed_at DESC); @@ -282,23 +277,20 @@ db.exec(` guild_id TEXT PRIMARY KEY, enabled INTEGER NOT NULL DEFAULT 0, log_channel_id TEXT, - - -- Anti-link + antilink_enabled INTEGER NOT NULL DEFAULT 0, antilink_action TEXT NOT NULL DEFAULT 'delete', antilink_whitelist_domains TEXT DEFAULT '[]', antilink_exclude_channels TEXT DEFAULT '[]', antilink_exclude_roles TEXT DEFAULT '[]', antilink_warn_message TEXT DEFAULT '⚠️ Les liens ne sont pas autorisés ici.', - - -- Anti-invite (liens Discord) + antiinvite_enabled INTEGER NOT NULL DEFAULT 0, antiinvite_action TEXT NOT NULL DEFAULT 'delete', antiinvite_allow_own_server INTEGER NOT NULL DEFAULT 1, antiinvite_exclude_channels TEXT DEFAULT '[]', antiinvite_exclude_roles TEXT DEFAULT '[]', - - -- Anti-spam + antispam_enabled INTEGER NOT NULL DEFAULT 0, antispam_action TEXT NOT NULL DEFAULT 'mute', antispam_max_messages INTEGER NOT NULL DEFAULT 5, @@ -306,59 +298,51 @@ db.exec(` antispam_mute_duration_minutes INTEGER NOT NULL DEFAULT 10, antispam_exclude_channels TEXT DEFAULT '[]', antispam_exclude_roles TEXT DEFAULT '[]', - - -- Anti-duplicate (messages identiques) + antidupe_enabled INTEGER NOT NULL DEFAULT 0, antidupe_action TEXT NOT NULL DEFAULT 'delete', antidupe_max_duplicates INTEGER NOT NULL DEFAULT 3, antidupe_interval_seconds INTEGER NOT NULL DEFAULT 60, antidupe_exclude_channels TEXT DEFAULT '[]', antidupe_exclude_roles TEXT DEFAULT '[]', - - -- Anti-mass mention + antimention_enabled INTEGER NOT NULL DEFAULT 0, antimention_action TEXT NOT NULL DEFAULT 'delete', antimention_max_mentions INTEGER NOT NULL DEFAULT 5, antimention_exclude_channels TEXT DEFAULT '[]', antimention_exclude_roles TEXT DEFAULT '[]', - - -- Anti-mass emoji + antiemoji_enabled INTEGER NOT NULL DEFAULT 0, antiemoji_action TEXT NOT NULL DEFAULT 'delete', antiemoji_max_emojis INTEGER NOT NULL DEFAULT 10, antiemoji_exclude_channels TEXT DEFAULT '[]', antiemoji_exclude_roles TEXT DEFAULT '[]', - - -- Anti-caps (majuscules) + anticaps_enabled INTEGER NOT NULL DEFAULT 0, anticaps_action TEXT NOT NULL DEFAULT 'delete', anticaps_max_percent INTEGER NOT NULL DEFAULT 70, anticaps_min_length INTEGER NOT NULL DEFAULT 10, anticaps_exclude_channels TEXT DEFAULT '[]', anticaps_exclude_roles TEXT DEFAULT '[]', - - -- Anti-bot join + antibot_enabled INTEGER NOT NULL DEFAULT 0, antibot_action TEXT NOT NULL DEFAULT 'kick', antibot_min_account_age_days INTEGER NOT NULL DEFAULT 7, antibot_no_avatar_action INTEGER NOT NULL DEFAULT 0, antibot_suspicious_name_action INTEGER NOT NULL DEFAULT 0, - - -- Anti-mass join (raid de comptes) + antimassj_enabled INTEGER NOT NULL DEFAULT 0, antimassj_action TEXT NOT NULL DEFAULT 'kick', antimassj_max_joins INTEGER NOT NULL DEFAULT 10, antimassj_interval_seconds INTEGER NOT NULL DEFAULT 10, antimassj_lockdown_duration_minutes INTEGER NOT NULL DEFAULT 5, - - -- Anti-newline spam + antinewline_enabled INTEGER NOT NULL DEFAULT 0, antinewline_action TEXT NOT NULL DEFAULT 'delete', antinewline_max_lines INTEGER NOT NULL DEFAULT 15, antinewline_exclude_channels TEXT DEFAULT '[]', antinewline_exclude_roles TEXT DEFAULT '[]', - - -- Anti-badwords (gros mots) + antibadwords_enabled INTEGER NOT NULL DEFAULT 0, antibadwords_action TEXT NOT NULL DEFAULT 'delete', antibadwords_words TEXT DEFAULT '[]', @@ -368,29 +352,27 @@ db.exec(` ); CREATE TABLE IF NOT EXISTS antiraid_warnings ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, user_id TEXT NOT NULL, warning_type TEXT NOT NULL, - warned_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) + warned_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW())::BIGINT) ); CREATE INDEX IF NOT EXISTS idx_antiraid_warnings ON antiraid_warnings(guild_id, user_id, warning_type, warned_at); - -- Table des warns utilisateurs CREATE TABLE IF NOT EXISTS warnings ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, user_id TEXT NOT NULL, moderator_id TEXT NOT NULL, reason TEXT NOT NULL, source TEXT DEFAULT 'manual', - created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) + created_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW())::BIGINT) ); CREATE INDEX IF NOT EXISTS idx_warnings ON warnings(guild_id, user_id, created_at DESC); - -- Configuration des sanctions automatiques par warns CREATE TABLE IF NOT EXISTS warnings_config ( guild_id TEXT PRIMARY KEY, enabled INTEGER NOT NULL DEFAULT 0, @@ -411,7 +393,7 @@ db.exec(` ); CREATE TABLE IF NOT EXISTS scheduled_messages ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, channel_id TEXT NOT NULL, message_content TEXT NOT NULL, @@ -427,15 +409,14 @@ db.exec(` force_send INTEGER NOT NULL DEFAULT 1, delete_previous INTEGER NOT NULL DEFAULT 0, enabled INTEGER NOT NULL DEFAULT 1, - last_sent_at INTEGER, + last_sent_at BIGINT, last_message_id TEXT, - last_channel_activity INTEGER, - created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) + last_channel_activity BIGINT, + created_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW())::BIGINT) ); - -- Système de rôles par boutons CREATE TABLE IF NOT EXISTS role_panels ( - id INTEGER PRIMARY KEY AUTOINCREMENT, + id BIGSERIAL PRIMARY KEY, guild_id TEXT NOT NULL, channel_id TEXT NOT NULL, message_id TEXT, @@ -449,12 +430,12 @@ db.exec(` exclusive INTEGER NOT NULL DEFAULT 0, required_role_id TEXT, enabled INTEGER NOT NULL DEFAULT 1, - created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) + created_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW())::BIGINT) ); CREATE TABLE IF NOT EXISTS role_panel_buttons ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - panel_id INTEGER NOT NULL, + id BIGSERIAL PRIMARY KEY, + panel_id BIGINT NOT NULL, role_id TEXT NOT NULL, label TEXT NOT NULL, emoji TEXT, @@ -463,60 +444,181 @@ db.exec(` enabled INTEGER NOT NULL DEFAULT 1, FOREIGN KEY (panel_id) REFERENCES role_panels(id) ON DELETE CASCADE ); -`); -// Migration: Ajouter les nouvelles colonnes pour welcome/goodbye si elles n'existent pas -const migrateWelcomeGoodbye = () => { - // Colonnes à ajouter pour welcome_config - const welcomeColumns = [ - { name: 'message_type', sql: "ALTER TABLE welcome_config ADD COLUMN message_type TEXT NOT NULL DEFAULT 'embed'" }, - { name: 'embed_title', sql: "ALTER TABLE welcome_config ADD COLUMN embed_title TEXT" }, - { name: 'embed_description', sql: "ALTER TABLE welcome_config ADD COLUMN embed_description TEXT" }, - { name: 'embed_color', sql: "ALTER TABLE welcome_config ADD COLUMN embed_color TEXT DEFAULT '#57F287'" }, - { name: 'embed_thumbnail', sql: "ALTER TABLE welcome_config ADD COLUMN embed_thumbnail INTEGER NOT NULL DEFAULT 1" }, - { name: 'embed_footer', sql: "ALTER TABLE welcome_config ADD COLUMN embed_footer TEXT" }, - { name: 'image_enabled', sql: "ALTER TABLE welcome_config ADD COLUMN image_enabled INTEGER NOT NULL DEFAULT 0" }, - { name: 'image_gradient', sql: "ALTER TABLE welcome_config ADD COLUMN image_gradient TEXT DEFAULT 'purple'" }, - { name: 'image_title', sql: "ALTER TABLE welcome_config ADD COLUMN image_title TEXT" }, - { name: 'image_subtitle', sql: "ALTER TABLE welcome_config ADD COLUMN image_subtitle TEXT" }, - { name: 'image_show_member_count', sql: "ALTER TABLE welcome_config ADD COLUMN image_show_member_count INTEGER NOT NULL DEFAULT 1" } - ]; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS message_type TEXT NOT NULL DEFAULT 'embed'; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS embed_title TEXT; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS embed_description TEXT; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS embed_color TEXT DEFAULT '#57F287'; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS embed_thumbnail INTEGER NOT NULL DEFAULT 1; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS embed_footer TEXT; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS image_enabled INTEGER NOT NULL DEFAULT 0; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS image_gradient TEXT DEFAULT 'purple'; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS image_title TEXT; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS image_subtitle TEXT; + ALTER TABLE IF EXISTS welcome_config ADD COLUMN IF NOT EXISTS image_show_member_count INTEGER NOT NULL DEFAULT 1; - // Colonnes à ajouter pour goodbye_config - const goodbyeColumns = [ - { name: 'message_type', sql: "ALTER TABLE goodbye_config ADD COLUMN message_type TEXT NOT NULL DEFAULT 'embed'" }, - { name: 'embed_title', sql: "ALTER TABLE goodbye_config ADD COLUMN embed_title TEXT" }, - { name: 'embed_description', sql: "ALTER TABLE goodbye_config ADD COLUMN embed_description TEXT" }, - { name: 'embed_color', sql: "ALTER TABLE goodbye_config ADD COLUMN embed_color TEXT DEFAULT '#ED4245'" }, - { name: 'embed_thumbnail', sql: "ALTER TABLE goodbye_config ADD COLUMN embed_thumbnail INTEGER NOT NULL DEFAULT 1" }, - { name: 'embed_footer', sql: "ALTER TABLE goodbye_config ADD COLUMN embed_footer TEXT" }, - { name: 'image_enabled', sql: "ALTER TABLE goodbye_config ADD COLUMN image_enabled INTEGER NOT NULL DEFAULT 0" }, - { name: 'image_gradient', sql: "ALTER TABLE goodbye_config ADD COLUMN image_gradient TEXT DEFAULT 'red'" }, - { name: 'image_title', sql: "ALTER TABLE goodbye_config ADD COLUMN image_title TEXT" }, - { name: 'image_subtitle', sql: "ALTER TABLE goodbye_config ADD COLUMN image_subtitle TEXT" }, - { name: 'image_show_member_count', sql: "ALTER TABLE goodbye_config ADD COLUMN image_show_member_count INTEGER NOT NULL DEFAULT 1" } - ]; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS message_type TEXT NOT NULL DEFAULT 'embed'; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS embed_title TEXT; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS embed_description TEXT; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS embed_color TEXT DEFAULT '#ED4245'; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS embed_thumbnail INTEGER NOT NULL DEFAULT 1; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS embed_footer TEXT; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS image_enabled INTEGER NOT NULL DEFAULT 0; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS image_gradient TEXT DEFAULT 'red'; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS image_title TEXT; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS image_subtitle TEXT; + ALTER TABLE IF EXISTS goodbye_config ADD COLUMN IF NOT EXISTS image_show_member_count INTEGER NOT NULL DEFAULT 1; +`; - // Exécuter les migrations pour welcome_config - welcomeColumns.forEach(col => { - db.run(col.sql, (err) => { - if (err && !err.message.includes('duplicate column')) { - // Ignorer les erreurs de colonnes dupliquées +function convertPlaceholders(sql) { + let index = 1; + let out = ""; + let inSingleQuote = false; + + for (let i = 0; i < sql.length; i += 1) { + const char = sql[i]; + + if (char === "'") { + if (inSingleQuote && sql[i + 1] === "'") { + out += "''"; + i += 1; + continue; } - }); - }); + inSingleQuote = !inSingleQuote; + out += char; + continue; + } - // Exécuter les migrations pour goodbye_config - goodbyeColumns.forEach(col => { - db.run(col.sql, (err) => { - if (err && !err.message.includes('duplicate column')) { - // Ignorer les erreurs de colonnes dupliquées - } - }); - }); + if (!inSingleQuote && char === "?") { + out += `$${index}`; + index += 1; + continue; + } + + out += char; + } + + return out; +} + +function normalizeArgs(params, callback) { + if (typeof params === "function") { + return { params: [], callback: params }; + } + return { params: Array.isArray(params) ? params : [], callback }; +} + +function maybeAddReturningId(sql) { + if (/\breturning\b/i.test(sql)) { + return sql; + } + + const match = sql.match(/^\s*INSERT\s+INTO\s+([A-Za-z_][A-Za-z0-9_]*)/i); + if (!match) { + return sql; + } + + const tableName = match[1].toLowerCase(); + if (!TABLES_WITH_ID.has(tableName)) { + return sql; + } + + return `${sql.trim()} RETURNING id`; +} + +const db = { + async exec(sql, callback) { + try { + await pool.query(sql); + if (callback) callback(null); + } catch (err) { + if (callback) callback(err); + else throw err; + } + }, + + run(sql, params, callback) { + const normalized = normalizeArgs(params, callback); + const sqlWithReturning = maybeAddReturningId(convertPlaceholders(sql)); + + pool + .query(sqlWithReturning, normalized.params) + .then((result) => { + const stmt = { + lastID: result.rows[0] ? result.rows[0].id : undefined, + changes: result.rowCount, + }; + + if (normalized.callback) { + normalized.callback.call(stmt, null); + } + }) + .catch((err) => { + if (normalized.callback) { + normalized.callback.call({ lastID: undefined, changes: 0 }, err); + return; + } + console.error("Erreur SQL (run):", err); + }); + }, + + get(sql, params, callback) { + const normalized = normalizeArgs(params, callback); + + pool + .query(convertPlaceholders(sql), normalized.params) + .then((result) => { + if (normalized.callback) { + normalized.callback(null, result.rows[0]); + } + }) + .catch((err) => { + if (normalized.callback) { + normalized.callback(err, undefined); + return; + } + console.error("Erreur SQL (get):", err); + }); + }, + + all(sql, params, callback) { + const normalized = normalizeArgs(params, callback); + + pool + .query(convertPlaceholders(sql), normalized.params) + .then((result) => { + if (normalized.callback) { + normalized.callback(null, result.rows); + } + }) + .catch((err) => { + if (normalized.callback) { + normalized.callback(err, []); + return; + } + console.error("Erreur SQL (all):", err); + }); + }, + + getAsync(sql, params = []) { + return pool.query(convertPlaceholders(sql), params).then((result) => result.rows[0]); + }, + + allAsync(sql, params = []) { + return pool.query(convertPlaceholders(sql), params).then((result) => result.rows); + }, + + pool, }; -// Exécuter la migration -migrateWelcomeGoodbye(); +(async () => { + try { + await pool.query("SELECT 1"); + console.log("DB PostgreSQL connectee"); + await pool.query(schemaSql); + } catch (err) { + console.error("Erreur DB:", err); + } +})(); module.exports = db; diff --git a/app/events/voiceStateUpdate.js b/app/events/voiceStateUpdate.js index e38b56d..7d6d28a 100644 --- a/app/events/voiceStateUpdate.js +++ b/app/events/voiceStateUpdate.js @@ -238,8 +238,9 @@ async function trackVoiceTime(guildId, userId, oldState, newState) { if (newState.channelId && !oldState.channelId) { // Save join timestamp db.run( - `INSERT OR REPLACE INTO voice_sessions (guild_id, user_id, join_timestamp) - VALUES (?, ?, ?)`, + `INSERT INTO voice_sessions (guild_id, user_id, join_timestamp) + VALUES (?, ?, ?) + ON CONFLICT (guild_id, user_id) DO UPDATE SET join_timestamp = EXCLUDED.join_timestamp`, [guildId, userId, Date.now()] ); } diff --git a/app/package-lock.json b/app/package-lock.json index c376139..9aabe45 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -11,13 +11,13 @@ "dependencies": { "canvas": "^3.2.1", "chartjs-node-canvas": "^4.1.6", - "connect-sqlite3": "^0.9.16", + "connect-pg-simple": "^10.0.0", "cross-fetch": "^4.1.0", "discord.js": "^14.25.1", "dotenv": "^17.2.3", "express": "^5.2.1", "express-session": "^1.18.2", - "sqlite3": "^5.1.7" + "pg": "^8.16.3" } }, "node_modules/@discordjs/builders": { @@ -150,13 +150,6 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "license": "MIT", - "optional": true - }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -225,32 +218,6 @@ "set-blocking": "^2.0.0" } }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "license": "MIT", - "optional": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@sapphire/async-queue": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz", @@ -284,16 +251,6 @@ "npm": ">=7.0.0" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/@types/node": { "version": "25.0.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.8.tgz", @@ -353,33 +310,6 @@ "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", - "optional": true, - "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", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "license": "MIT", - "optional": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -395,21 +325,6 @@ "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", "license": "ISC" }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -436,15 +351,6 @@ ], "license": "MIT" }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -523,36 +429,6 @@ "node": ">= 0.8" } }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -675,16 +551,6 @@ "node": ">=10" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" - } - }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -700,15 +566,16 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, - "node_modules/connect-sqlite3": { - "version": "0.9.16", - "resolved": "https://registry.npmjs.org/connect-sqlite3/-/connect-sqlite3-0.9.16.tgz", - "integrity": "sha512-2gqo0QmcBBL8p8+eqpBETn7RgM/PaoKvpQGl8PfjEgwlr0VuMYNMxRJRrRCo3KR3fxMYeSsCw2tGNG0JKN9Nvg==", + "node_modules/connect-pg-simple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/connect-pg-simple/-/connect-pg-simple-10.0.0.tgz", + "integrity": "sha512-pBGVazlqiMrackzCr0eKhn4LO5trJXsOX0nQoey9wCOayh80MYtThCbq8eoLsjpiWgiok/h+1/uti9/2/Una8A==", + "license": "MIT", "dependencies": { - "sqlite3": "^5.0.2" + "pg": "^8.12.0" }, "engines": { - "node": ">=0.4.x" + "node": "^18.18.0 || ^20.9.0 || >=22.0.0" } }, "node_modules/console-control-strings": { @@ -920,6 +787,7 @@ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -930,6 +798,7 @@ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -946,23 +815,6 @@ "once": "^1.4.0" } }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "license": "MIT", - "optional": true - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -1106,12 +958,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" - }, "node_modules/finalhandler": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", @@ -1184,27 +1030,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -1281,13 +1106,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC", - "optional": true - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -1318,13 +1136,6 @@ "node": ">= 0.4" } }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "license": "BSD-2-Clause", - "optional": true - }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", @@ -1345,21 +1156,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "license": "MIT", - "optional": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -1373,16 +1169,6 @@ "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", - "optional": true, - "dependencies": { - "ms": "^2.0.0" - } - }, "node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", @@ -1419,33 +1205,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "license": "ISC", - "optional": true - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1469,16 +1228,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "license": "ISC" }, - "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1497,26 +1246,12 @@ "node": ">=8" } }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "license": "MIT", - "optional": true - }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC", - "optional": true - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1529,19 +1264,6 @@ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", "license": "MIT" }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/magic-bytes.js": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.12.1.tgz", @@ -1572,44 +1294,6 @@ "semver": "bin/semver.js" } }, - "node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "license": "ISC", - "optional": true, - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1710,76 +1394,6 @@ "node": ">=8" } }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "license": "MIT", - "optional": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -1876,31 +1490,6 @@ } } }, - "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "license": "MIT", - "optional": true, - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -1916,23 +1505,6 @@ "node": ">=6" } }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1984,22 +1556,6 @@ "wrappy": "1" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2028,6 +1584,134 @@ "url": "https://opencollective.com/express" } }, + "node_modules/pg": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.12.0", + "pg-pool": "^3.13.0", + "pg-protocol": "^1.13.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", + "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", + "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", @@ -2054,27 +1738,6 @@ "node": ">=10" } }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "license": "ISC", - "optional": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "license": "MIT", - "optional": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2175,16 +1838,6 @@ "node": ">= 6" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -2435,82 +2088,13 @@ "simple-concat": "^1.0.0" } }, - "node_modules/smart-buffer": { + "node_modules/split2": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "license": "MIT", - "optional": true, - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/sqlite3": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", - "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^7.0.0", - "prebuild-install": "^7.1.1", - "tar": "^6.1.11" - }, - "optionalDependencies": { - "node-gyp": "8.x" - }, - "peerDependencies": { - "node-gyp": "8.x" - }, - "peerDependenciesMeta": { - "node-gyp": { - "optional": true - } - } - }, - "node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.1.1" - }, "engines": { - "node": ">= 8" + "node": ">= 10.x" } }, "node_modules/statuses": { @@ -2706,26 +2290,6 @@ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "license": "ISC", - "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2766,22 +2330,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "optional": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -2818,6 +2366,15 @@ } } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/app/package.json b/app/package.json index 3678381..a9fd371 100644 --- a/app/package.json +++ b/app/package.json @@ -25,12 +25,12 @@ "dependencies": { "canvas": "^3.2.1", "chartjs-node-canvas": "^4.1.6", - "connect-sqlite3": "^0.9.16", + "connect-pg-simple": "^10.0.0", "cross-fetch": "^4.1.0", "discord.js": "^14.25.1", "dotenv": "^17.2.3", "express": "^5.2.1", "express-session": "^1.18.2", - "sqlite3": "^5.1.7" + "pg": "^8.16.3" } } diff --git a/app/public/privacy.html b/app/public/privacy.html index 4c3683a..baf665e 100644 --- a/app/public/privacy.html +++ b/app/public/privacy.html @@ -85,7 +85,7 @@

4. Stockage et sécurité