From d33e1d4184f90907ac4ba357815c869dd84cb4c7 Mon Sep 17 00:00:00 2001 From: Max Leiter <8675906+MaxLeiter@users.noreply.github.com> Date: Sun, 12 Apr 2026 06:30:56 -0700 Subject: [PATCH 1/2] Remove sqlite3 dependency; use built-in node:sqlite (#5055) https://www.npmjs.com/package/sqlite3 is deprecated and Node 22 (#5041) lets us use the builtin `node:sqlite` package (although it is experimental) most changes are a result of the native module being synchronous relies on #5041 (now merged) Closes https://github.com/thelounge/thelounge/issues/5033 --- package.json | 3 - server/client.ts | 20 +- server/command-line/storage.ts | 36 +- server/models/chan.ts | 71 ++-- server/plugins/messageStorage/sqlite.ts | 355 +++++++---------- server/plugins/messageStorage/text.ts | 35 +- server/plugins/messageStorage/types.d.ts | 14 +- server/server.ts | 4 +- server/storageCleaner.ts | 17 +- test/plugins/sqlite.ts | 198 ++++------ yarn.lock | 474 +---------------------- 11 files changed, 316 insertions(+), 911 deletions(-) diff --git a/package.json b/package.json index b3cafea7..fb720242 100644 --- a/package.json +++ b/package.json @@ -84,9 +84,6 @@ "web-push": "3.4.5", "yarn": "1.22.22" }, - "optionalDependencies": { - "sqlite3": "6.0.1" - }, "devDependencies": { "@babel/core": "7.17.10", "@babel/plugin-transform-runtime": "7.18.2", diff --git a/server/client.ts b/server/client.ts index f2f12594..4c0f42eb 100644 --- a/server/client.ts +++ b/server/client.ts @@ -150,7 +150,11 @@ class Client { } for (const messageStorage of client.messageStorage) { - messageStorage.enable().catch((e) => log.error(e)); + try { + messageStorage.enable(); + } catch (e: any) { + log.error(e); + } } } @@ -645,11 +649,15 @@ class Client { } for (const messageStorage of this.messageStorage) { - messageStorage.deleteChannel(target.network, target.chan).catch((e) => log.error(e)); + try { + messageStorage.deleteChannel(target.network, target.chan); + } catch (e: any) { + log.error(e); + } } } - async search(query: SearchQuery): Promise { + search(query: SearchQuery): SearchResponse { if (!this.messageProvider?.isEnabled) { return { ...query, @@ -778,7 +786,11 @@ class Client { }); for (const messageStorage of this.messageStorage) { - messageStorage.close().catch((e) => log.error(e)); + try { + messageStorage.close(); + } catch (e: any) { + log.error(e); + } } } diff --git a/server/command-line/storage.ts b/server/command-line/storage.ts index 3f9184b2..35782d7e 100644 --- a/server/command-line/storage.ts +++ b/server/command-line/storage.ts @@ -15,10 +15,12 @@ program .description("Migrate message storage where needed") .on("--help", Utils.extraHelp) .action(function (user) { - runMigrations(user).catch((err) => { + try { + runMigrations(user); + } catch (err: any) { log.error(err.toString()); process.exit(1); - }); + } }); program @@ -27,13 +29,15 @@ program .description("Delete messages from the DB based on the storage policy") .on("--help", Utils.extraHelp) .action(function (user) { - runCleaning(user).catch((err) => { + try { + runCleaning(user); + } catch (err: any) { log.error(err.toString()); process.exit(1); - }); + } }); -async function runMigrations(user?: string) { +function runMigrations(user?: string) { const manager = new ClientManager(); const users = manager.getUsers(); @@ -46,14 +50,14 @@ async function runMigrations(user?: string) { } for (const name of users) { - await migrateUser(manager, name); + migrateUser(manager, name); // if any migration fails we blow up, // chances are the rest won't complete either } } // runs sqlite migrations for a user, which must exist -async function migrateUser(manager: ClientManager, user: string) { +function migrateUser(manager: ClientManager, user: string) { log.info("handling user", user); if (!isUserLogEnabled(manager, user)) { @@ -62,8 +66,8 @@ async function migrateUser(manager: ClientManager, user: string) { } const sqlite = new SqliteMessageStorage(user); - await sqlite.enable(); // enable runs migrations - await sqlite.close(); + sqlite.enable(); + sqlite.close(); log.info("user", user, "migrated successfully"); } @@ -78,7 +82,7 @@ function isUserLogEnabled(manager: ClientManager, user: string): boolean { return conf.log; } -async function runCleaning(user: string) { +function runCleaning(user: string) { const manager = new ClientManager(); const users = manager.getUsers(); @@ -91,13 +95,13 @@ async function runCleaning(user: string) { } for (const name of users) { - await cleanUser(manager, name); + cleanUser(manager, name); // if any migration fails we blow up, // chances are the rest won't complete either } } -async function cleanUser(manager: ClientManager, user: string) { +function cleanUser(manager: ClientManager, user: string) { log.info("handling user", user); if (!isUserLogEnabled(manager, user)) { @@ -106,17 +110,17 @@ async function cleanUser(manager: ClientManager, user: string) { } const sqlite = new SqliteMessageStorage(user); - await sqlite.enable(); + sqlite.enable(); const cleaner = new StorageCleaner(sqlite); - const num_deleted = await cleaner.runDeletesNoLimit(); + const num_deleted = cleaner.runDeletesNoLimit(); log.info(`deleted ${num_deleted} messages`); log.info("running a vacuum now, this might take a while"); if (num_deleted > 0) { - await sqlite.vacuum(); + sqlite.vacuum(); } - await sqlite.close(); + sqlite.close(); log.info(`cleaning messages for ${user} has been successful`); } diff --git a/server/models/chan.ts b/server/models/chan.ts index 7ed0e805..4dd83842 100644 --- a/server/models/chan.ts +++ b/server/models/chan.ts @@ -261,7 +261,11 @@ class Chan { } for (const messageStorage of client.messageStorage) { - messageStorage.index(target.network, targetChannel, msg).catch((e) => log.error(e)); + try { + messageStorage.index(target.network, targetChannel, msg); + } catch (e: any) { + log.error(e); + } } } @@ -288,38 +292,41 @@ class Chan { return; } - client.messageProvider - .getMessages(network, this, () => client.idMsg++) - .then((messages) => { - if (messages.length === 0) { - if (network.irc!.network.cap.isEnabled("znc.in/playback")) { - requestZncPlayback(this, network, 0); - } - - return; - } - - this.messages = messages.concat(this.messages); - - if (!this.firstUnread) { - this.firstUnread = messages[messages.length - 1].id; - } - - client.emit("more", { - chan: this.id, - messages: messages.slice(-100), - totalMessages: messages.length, - }); - - if (network.irc!.network.cap.isEnabled("znc.in/playback")) { - const from = Math.floor(messages[messages.length - 1].time.getTime() / 1000); - - requestZncPlayback(this, network, from); - } - }) - .catch((err: Error) => - log.error(`Failed to load messages for ${client.name}: ${err.toString()}`) + try { + const messages = client.messageProvider.getMessages( + network, + this, + () => client.idMsg++ ); + + if (messages.length === 0) { + if (network.irc!.network.cap.isEnabled("znc.in/playback")) { + requestZncPlayback(this, network, 0); + } + + return; + } + + this.messages = messages.concat(this.messages); + + if (!this.firstUnread) { + this.firstUnread = messages[messages.length - 1].id; + } + + client.emit("more", { + chan: this.id, + messages: messages.slice(-100), + totalMessages: messages.length, + }); + + if (network.irc!.network.cap.isEnabled("znc.in/playback")) { + const from = Math.floor(messages[messages.length - 1].time.getTime() / 1000); + + requestZncPlayback(this, network, from); + } + } catch (err: any) { + log.error(`Failed to load messages for ${client.name}: ${err.toString()}`); + } } isLoggable() { diff --git a/server/plugins/messageStorage/sqlite.ts b/server/plugins/messageStorage/sqlite.ts index f4865e13..64de434a 100644 --- a/server/plugins/messageStorage/sqlite.ts +++ b/server/plugins/messageStorage/sqlite.ts @@ -1,8 +1,8 @@ -import type {Database} from "sqlite3"; +import {DatabaseSync} from "node:sqlite"; import log from "../../log"; import path from "path"; -import fs from "fs/promises"; +import {mkdirSync} from "fs"; import Config from "../../config"; import Msg, {Message} from "../../models/msg"; import Chan, {Channel} from "../../models/chan"; @@ -11,19 +11,6 @@ import type {SearchableMessageStorage, DeletionRequest} from "./types"; import Network from "../../models/network"; import {SearchQuery, SearchResponse} from "../../../shared/types/storage"; -// TODO; type -let sqlite3: any; - -try { - sqlite3 = require("sqlite3"); -} catch (e: any) { - Config.values.messageStorage = Config.values.messageStorage.filter((item) => item !== "sqlite"); - - log.error( - "Unable to load sqlite3 module. See https://github.com/mapbox/node-sqlite3/wiki/Binaries" - ); -} - type Migration = {version: number; stmts: string[]}; type Rollback = {version: number; rollback_forbidden?: boolean; stmts: string[]}; @@ -103,35 +90,21 @@ export const rollbacks: Rollback[] = [ }, ]; -class Deferred { - resolve!: () => void; - promise: Promise; - - constructor() { - this.promise = new Promise((resolve) => { - this.resolve = resolve; - }); - } -} - class SqliteMessageStorage implements SearchableMessageStorage { isEnabled: boolean; - database!: Database; - initDone: Deferred; + database!: DatabaseSync; userName: string; constructor(userName: string) { this.userName = userName; this.isEnabled = false; - this.initDone = new Deferred(); } - async _enable(connection_string: string) { - this.database = new sqlite3.Database(connection_string); + _enable(connection_string: string) { + this.database = new DatabaseSync(connection_string); try { - await this.run_pragmas(); // must be done outside of a transaction - await this.run_migrations(); + this.run_migrations(); } catch (e) { this.isEnabled = false; throw Helper.catch_to_error("Migration failed", e); @@ -140,46 +113,35 @@ class SqliteMessageStorage implements SearchableMessageStorage { this.isEnabled = true; } - async enable() { + enable() { const logsPath = Config.getUserLogsPath(); const sqlitePath = path.join(logsPath, `${this.userName}.sqlite3`); - - try { - await fs.mkdir(logsPath, {recursive: true}); - } catch (e) { - throw Helper.catch_to_error("Unable to create logs directory", e); - } - - try { - await this._enable(sqlitePath); - } finally { - this.initDone.resolve(); // unblock the instance methods - } + mkdirSync(logsPath, {recursive: true}); + this._enable(sqlitePath); } - async setup_new_db() { + setup_new_db() { for (const stmt of schema) { - await this.serialize_run(stmt); + this.database.exec(stmt); } - await this.serialize_run( - "INSERT INTO options (name, value) VALUES ('schema_version', ?)", - currentSchemaVersion.toString() - ); + this.database + .prepare("INSERT INTO options (name, value) VALUES ('schema_version', ?)") + .run(currentSchemaVersion.toString()); } - async current_version(): Promise { - const have_options = await this.serialize_get( - "select 1 from sqlite_master where type = 'table' and name = 'options'" - ); + current_version(): number { + const have_options = this.database + .prepare("select 1 from sqlite_master where type = 'table' and name = 'options'") + .get(); if (!have_options) { return 0; } - const version = await this.serialize_get( - "SELECT value FROM options WHERE name = 'schema_version'" - ); + const version = this.database + .prepare("SELECT value FROM options WHERE name = 'schema_version'") + .get() as {value: string} | undefined; if (version === undefined) { // technically shouldn't happen, means something created a schema but didn't populate it @@ -191,14 +153,13 @@ class SqliteMessageStorage implements SearchableMessageStorage { return storedSchemaVersion; } - async update_version_in_db() { - return this.serialize_run( - "UPDATE options SET value = ? WHERE name = 'schema_version'", - currentSchemaVersion.toString() - ); + update_version_in_db() { + this.database + .prepare("UPDATE options SET value = ? WHERE name = 'schema_version'") + .run(currentSchemaVersion.toString()); } - async _run_migrations(dbVersion: number) { + _run_migrations(dbVersion: number) { log.info( `sqlite messages schema version is out of date (${dbVersion} < ${currentSchemaVersion}). Running migrations.` ); @@ -206,18 +167,14 @@ class SqliteMessageStorage implements SearchableMessageStorage { const to_execute = necessaryMigrations(dbVersion); for (const stmt of to_execute.map((m) => m.stmts).flat()) { - await this.serialize_run(stmt); + this.database.exec(stmt); } - await this.update_version_in_db(); + this.update_version_in_db(); } - async run_pragmas() { - await this.serialize_run("PRAGMA foreign_keys = ON;"); - } - - async run_migrations() { - const version = await this.current_version(); + run_migrations() { + const version = this.current_version(); if (version > currentSchemaVersion) { throw `sqlite messages schema version is higher than expected (${version} > ${currentSchemaVersion}). Is The Lounge out of date?`; @@ -225,58 +182,54 @@ class SqliteMessageStorage implements SearchableMessageStorage { return; // nothing to do } - await this.serialize_run("BEGIN EXCLUSIVE TRANSACTION"); + this.database.exec("BEGIN EXCLUSIVE TRANSACTION"); try { if (version === 0) { - await this.setup_new_db(); + this.setup_new_db(); } else { - await this._run_migrations(version); + this._run_migrations(version); } - await this.insert_rollback_since(version); + this.insert_rollback_since(version); } catch (err) { - await this.serialize_run("ROLLBACK"); + this.database.exec("ROLLBACK"); throw err; } - await this.serialize_run("COMMIT"); - await this.serialize_run("VACUUM"); + this.database.exec("COMMIT"); + this.database.exec("VACUUM"); } // helper method that vacuums the db, meant to be used by migration related cli commands - async vacuum() { - await this.serialize_run("VACUUM"); + vacuum() { + this.database.exec("VACUUM"); } - async close() { + close() { if (!this.isEnabled) { return; } this.isEnabled = false; - - return new Promise((resolve, reject) => { - this.database.close((err) => { - if (err) { - reject(`Failed to close sqlite database: ${err.message}`); - return; - } - - resolve(); - }); - }); + this.database.close(); } - async fetch_rollbacks(since_version: number) { - const res = await this.serialize_fetchall( - `select version, rollback_forbidden, statement - from rollback_steps - join migrations on migrations.id=rollback_steps.migration_id - where version > ? - order by version desc, step asc`, - since_version - ); + fetch_rollbacks(since_version: number): Rollback[] { + const res = this.database + .prepare( + `select version, rollback_forbidden, statement + from rollback_steps + join migrations on migrations.id=rollback_steps.migration_id + where version > ? + order by version desc, step asc` + ) + .all(since_version) as { + version: number; + rollback_forbidden: number; + statement: string; + }[]; + const result: Rollback[] = []; // convert to Rollback[] @@ -298,12 +251,12 @@ class SqliteMessageStorage implements SearchableMessageStorage { return result; } - async delete_migrations_older_than(version: number) { - return this.serialize_run("delete from migrations where migrations.version > ?", version); + delete_migrations_older_than(version: number) { + this.database.prepare("delete from migrations where migrations.version > ?").run(version); } - async _downgrade_to(version: number) { - const _rollbacks = await this.fetch_rollbacks(version); + _downgrade_to(version: number): number { + const _rollbacks = this.fetch_rollbacks(version); if (_rollbacks.length === 0) { return version; @@ -317,72 +270,69 @@ class SqliteMessageStorage implements SearchableMessageStorage { for (const rollback of _rollbacks) { for (const stmt of rollback.stmts) { - await this.serialize_run(stmt); + this.database.exec(stmt); } } - await this.delete_migrations_older_than(version); - await this.update_version_in_db(); + this.delete_migrations_older_than(version); + this.update_version_in_db(); return version; } - async downgrade_to(version: number) { + downgrade_to(version: number): number { if (version <= 0) { throw Error(`${version} is not a valid version to downgrade to`); } - await this.serialize_run("BEGIN EXCLUSIVE TRANSACTION"); + this.database.exec("BEGIN EXCLUSIVE TRANSACTION"); let new_version: number; try { - new_version = await this._downgrade_to(version); + new_version = this._downgrade_to(version); } catch (err) { - await this.serialize_run("ROLLBACK"); + this.database.exec("ROLLBACK"); throw err; } - await this.serialize_run("COMMIT"); + this.database.exec("COMMIT"); return new_version; } - async downgrade() { - const res = await this.downgrade_to(currentSchemaVersion); - return res; + downgrade() { + return this.downgrade_to(currentSchemaVersion); } - async insert_rollback_since(version: number) { + insert_rollback_since(version: number) { const missing = newRollbacks(version); for (const rollback of missing) { - const migration = await this.serialize_get( - `insert into migrations - (version, rollback_forbidden) - values (?, ?) - returning id`, - rollback.version, - rollback.rollback_forbidden || 0 - ); + const migration = this.database + .prepare( + `insert into migrations + (version, rollback_forbidden) + values (?, ?) + returning id` + ) + .get(rollback.version, rollback.rollback_forbidden ? 1 : 0) as {id: number}; + + let step = 0; for (const stmt of rollback.stmts) { - let step = 0; - await this.serialize_run( - `insert into rollback_steps - (migration_id, step, statement) - values (?, ?, ?)`, - migration.id, - step, - stmt - ); + this.database + .prepare( + `insert into rollback_steps + (migration_id, step, statement) + values (?, ?, ?)` + ) + .run(migration.id, step, stmt); step++; } } } - async index(network: Network, channel: Chan, msg: Msg) { - await this.initDone.promise; - + index(network: Network, channel: Chan, msg: Msg) { if (!this.isEnabled) { return; } @@ -398,38 +348,30 @@ class SqliteMessageStorage implements SearchableMessageStorage { return newMsg; }, {}); - await this.serialize_run( - "INSERT INTO messages(network, channel, time, type, msg) VALUES(?, ?, ?, ?, ?)", - - network.uuid, - channel.name.toLowerCase(), - msg.time.getTime(), - msg.type, - JSON.stringify(clonedMsg) - ); + this.database + .prepare( + "INSERT INTO messages(network, channel, time, type, msg) VALUES(?, ?, ?, ?, ?)" + ) + .run( + network.uuid, + channel.name.toLowerCase(), + msg.time.getTime(), + msg.type, + JSON.stringify(clonedMsg) + ); } - async deleteChannel(network: Network, channel: Channel) { - await this.initDone.promise; - + deleteChannel(network: Network, channel: Channel) { if (!this.isEnabled) { return; } - await this.serialize_run( - "DELETE FROM messages WHERE network = ? AND channel = ?", - network.uuid, - channel.name.toLowerCase() - ); + this.database + .prepare("DELETE FROM messages WHERE network = ? AND channel = ?") + .run(network.uuid, channel.name.toLowerCase()); } - async getMessages( - network: Network, - channel: Channel, - nextID: () => number - ): Promise { - await this.initDone.promise; - + getMessages(network: Network, channel: Channel, nextID: () => number): Message[] { if (!this.isEnabled || Config.values.maxHistory === 0) { return []; } @@ -437,14 +379,17 @@ class SqliteMessageStorage implements SearchableMessageStorage { // If unlimited history is specified, load 100k messages const limit = Config.values.maxHistory < 0 ? 100000 : Config.values.maxHistory; - const rows = await this.serialize_fetchall( - "SELECT msg, type, time FROM messages WHERE network = ? AND channel = ? ORDER BY time DESC LIMIT ?", - network.uuid, - channel.name.toLowerCase(), - limit - ); + const rows = this.database + .prepare( + "SELECT msg, type, time FROM messages WHERE network = ? AND channel = ? ORDER BY time DESC LIMIT ?" + ) + .all(network.uuid, channel.name.toLowerCase(), limit) as { + msg: string; + type: string; + time: number; + }[]; - return rows.reverse().map((row: any): Message => { + return rows.reverse().map((row): Message => { const msg = JSON.parse(row.msg); msg.time = row.time; msg.type = row.type; @@ -456,9 +401,7 @@ class SqliteMessageStorage implements SearchableMessageStorage { }); } - async search(query: SearchQuery): Promise { - await this.initDone.promise; - + search(query: SearchQuery): SearchResponse { if (!this.isEnabled) { // this should never be hit as messageProvider is checked in client.search() throw new Error( @@ -471,7 +414,7 @@ class SqliteMessageStorage implements SearchableMessageStorage { let select = "SELECT msg, type, time, network, channel FROM messages WHERE type = 'message' AND json_extract(msg, '$.text') LIKE ? ESCAPE '@'"; - const params: any[] = [`%${escapedSearchTerm}%`]; + const params: (string | number)[] = [`%${escapedSearchTerm}%`]; if (query.networkUuid) { select += " AND network = ? "; @@ -489,15 +432,21 @@ class SqliteMessageStorage implements SearchableMessageStorage { params.push(maxResults); params.push(query.offset); - const rows = await this.serialize_fetchall(select, ...params); + const rows = this.database.prepare(select).all(...params) as { + msg: string; + type: string; + time: number; + network: string; + channel: string; + }[]; + return { ...query, results: parseSearchRowsToMessages(query.offset, rows).reverse(), }; } - async deleteMessages(req: DeletionRequest): Promise { - await this.initDone.promise; + deleteMessages(req: DeletionRequest): number { let sql = "delete from messages where id in (select id from messages where\n"; // We roughly get a timestamp from N days before. @@ -520,61 +469,19 @@ class SqliteMessageStorage implements SearchableMessageStorage { sql += `limit ${req.limit}\n`; sql += ")"; - return this.serialize_run(sql); + return this.database.prepare(sql).run().changes as number; } canProvideMessages() { return this.isEnabled; } - - private serialize_run(stmt: string, ...params: any[]): Promise { - return new Promise((resolve, reject) => { - this.database.serialize(() => { - this.database.run(stmt, params, function (err) { - if (err) { - reject(err); - return; - } - - resolve(this.changes); // number of affected rows, `this` is re-bound by sqlite3 - }); - }); - }); - } - - private serialize_fetchall(stmt: string, ...params: any[]): Promise { - return new Promise((resolve, reject) => { - this.database.serialize(() => { - this.database.all(stmt, params, (err, rows) => { - if (err) { - reject(err); - return; - } - - resolve(rows); - }); - }); - }); - } - - private serialize_get(stmt: string, ...params: any[]): Promise { - return new Promise((resolve, reject) => { - this.database.serialize(() => { - this.database.get(stmt, params, (err, row) => { - if (err) { - reject(err); - return; - } - - resolve(row); - }); - }); - }); - } } // TODO: type any -function parseSearchRowsToMessages(id: number, rows: any[]) { +function parseSearchRowsToMessages( + id: number, + rows: {msg: string; type: string; time: number; network: string; channel: string}[] +) { const messages: Msg[] = []; for (const row of rows) { diff --git a/server/plugins/messageStorage/text.ts b/server/plugins/messageStorage/text.ts index 20ca8ac9..02c3c56e 100644 --- a/server/plugins/messageStorage/text.ts +++ b/server/plugins/messageStorage/text.ts @@ -1,5 +1,4 @@ -/* eslint-disable @typescript-eslint/restrict-template-expressions */ -import fs from "fs/promises"; +import {mkdirSync, appendFileSync} from "fs"; import path from "path"; import filenamify from "filenamify"; @@ -19,17 +18,15 @@ class TextFileMessageStorage implements MessageStorage { this.isEnabled = false; } - // eslint-disable-next-line @typescript-eslint/require-await - async enable() { + enable() { this.isEnabled = true; } - // eslint-disable-next-line @typescript-eslint/require-await - async close() { + close() { this.isEnabled = false; } - async index(network: Network, channel: Channel, msg: Message) { + index(network: Network, channel: Channel, msg: Message) { if (!this.isEnabled) { return; } @@ -40,11 +37,7 @@ class TextFileMessageStorage implements MessageStorage { TextFileMessageStorage.getNetworkFolderName(network) ); - try { - await fs.mkdir(logPath, {recursive: true}); - } catch (e) { - throw new Error(`Unable to create logs directory: ${e}`); - } + mkdirSync(logPath, {recursive: true}); let line = `[${msg.time.toISOString()}] `; @@ -102,25 +95,21 @@ class TextFileMessageStorage implements MessageStorage { line += "\n"; - try { - await fs.appendFile( - path.join(logPath, TextFileMessageStorage.getChannelFileName(channel)), - line - ); - } catch (e) { - throw new Error(`Failed to write user log: ${e}`); - } + appendFileSync( + path.join(logPath, TextFileMessageStorage.getChannelFileName(channel)), + line + ); } - async deleteChannel() { + deleteChannel() { // Not implemented for text log files } - getMessages() { + getMessages(): Message[] { // Not implemented for text log files // They do not contain enough data to fully re-create message objects // Use sqlite storage instead - return Promise.resolve([]); + return []; } canProvideMessages() { diff --git a/server/plugins/messageStorage/types.d.ts b/server/plugins/messageStorage/types.d.ts index 3b20035e..e0741031 100644 --- a/server/plugins/messageStorage/types.d.ts +++ b/server/plugins/messageStorage/types.d.ts @@ -1,5 +1,3 @@ -import type {Database} from "sqlite3"; - import {Channel} from "../../models/channel"; import {Message} from "../../models/message"; import {Network} from "../../models/network"; @@ -16,20 +14,20 @@ export type DeletionRequest = { interface MessageStorage { isEnabled: boolean; - enable(): Promise; + enable(): void; - close(): Promise; + close(): void; - index(network: Network, channel: Channel, msg: Message): Promise; + index(network: Network, channel: Channel, msg: Message): void; - deleteChannel(network: Network, channel: Channel): Promise; + deleteChannel(network: Network, channel: Channel): void; - getMessages(network: Network, channel: Channel, nextID: () => number): Promise; + getMessages(network: Network, channel: Channel, nextID: () => number): Message[]; canProvideMessages(): boolean; } -type SearchFunction = (query: SearchQuery) => Promise; +type SearchFunction = (query: SearchQuery) => SearchResponse; export interface SearchableMessageStorage extends MessageStorage { search: SearchFunction; diff --git a/server/server.ts b/server/server.ts index 4d63bfad..70a7d56e 100644 --- a/server/server.ts +++ b/server/server.ts @@ -760,8 +760,8 @@ function initializeClient( socket.emit("setting:all", clientSettings); }); - socket.on("search", async (query) => { - const results = await client.search(query); + socket.on("search", (query) => { + const results = client.search(query); socket.emit("search:results", results); }); diff --git a/server/storageCleaner.ts b/server/storageCleaner.ts index 067452d7..8d40141b 100644 --- a/server/storageCleaner.ts +++ b/server/storageCleaner.ts @@ -61,7 +61,7 @@ export class StorageCleaner { }; } - async runDeletesNoLimit(): Promise { + runDeletesNoLimit(): number { if (!Config.values.storagePolicy.enabled) { // this is meant to be used by cli tools, so we guard against this throw new Error("storage policy is disabled"); @@ -69,11 +69,10 @@ export class StorageCleaner { const req = this.genDeletionRequest(); req.limit = -1; // unlimited - const num_deleted = await this.db.deleteMessages(req); - return num_deleted; + return this.db.deleteMessages(req); } - private async runDeletes() { + private runDeletes() { if (this.isStopped) { return; } @@ -89,7 +88,7 @@ export class StorageCleaner { let num_deleted = 0; try { - num_deleted = await this.db.deleteMessages(req); + num_deleted = this.db.deleteMessages(req); this.errCount = 0; // reset when it works } catch (err: any) { this.errCount++; @@ -115,13 +114,13 @@ export class StorageCleaner { } private schedule(ms: number) { - const self = this; - this.ticker = setTimeout(() => { - self.runDeletes().catch((err) => { + try { + this.runDeletes(); + } catch (err) { log.error("storageCleaner: unexpected failure"); throw err; - }); + } }, ms); } diff --git a/test/plugins/sqlite.ts b/test/plugins/sqlite.ts index 06d2b199..27e4c09e 100644 --- a/test/plugins/sqlite.ts +++ b/test/plugins/sqlite.ts @@ -11,7 +11,7 @@ import MessageStorage, { necessaryMigrations, rollbacks, } from "../../server/plugins/messageStorage/sqlite"; -import sqlite3 from "sqlite3"; +import {DatabaseSync} from "node:sqlite"; import {DeletionRequest} from "../../server/plugins/messageStorage/types"; const orig_schema = [ @@ -50,44 +50,26 @@ const v1_dummy_messages = [ ]; describe("SQLite migrations", function () { - let db: sqlite3.Database; + let db: DatabaseSync; - function serialize_run(stmt: string, ...params: any[]): Promise { - return new Promise((resolve, reject) => { - db.serialize(() => { - db.run(stmt, params, (err) => { - if (err) { - reject(err); - return; - } - - resolve(); - }); - }); - }); - } - - before(async function () { - db = new sqlite3.Database(":memory:"); + before(function () { + db = new DatabaseSync(":memory:"); for (const stmt of orig_schema) { - await serialize_run(stmt); + db.exec(stmt); } + const insert = db.prepare( + "INSERT INTO messages(network, channel, time, type, msg) VALUES(?, ?, ?, ?, ?)" + ); + for (const msg of v1_dummy_messages) { - await serialize_run( - "INSERT INTO messages(network, channel, time, type, msg) VALUES(?, ?, ?, ?, ?)", - msg.network, - msg.channel, - msg.time, - msg.type, - msg.msg - ); + insert.run(msg.network, msg.channel, msg.time, msg.type, msg.msg); } }); - after(function (done) { - db.close(done); + after(function () { + db.close(); }); it("has a down migration for every migration", function () { @@ -97,20 +79,20 @@ describe("SQLite migrations", function () { ); }); - it("has working up-migrations", async function () { + it("has working up-migrations", function () { const to_execute = necessaryMigrations(v1_schema_version); expect(to_execute.length).to.eq(migrations.length); - await serialize_run("BEGIN EXCLUSIVE TRANSACTION"); + db.exec("BEGIN EXCLUSIVE TRANSACTION"); for (const stmt of to_execute.map((m) => m.stmts).flat()) { - await serialize_run(stmt); + db.exec(stmt); } - await serialize_run("COMMIT TRANSACTION"); + db.exec("COMMIT TRANSACTION"); }); - it("has working down-migrations", async function () { - await serialize_run("BEGIN EXCLUSIVE TRANSACTION"); + it("has working down-migrations", function () { + db.exec("BEGIN EXCLUSIVE TRANSACTION"); for (const rollback of rollbacks.slice().reverse()) { if (rollback.rollback_forbidden) { @@ -120,35 +102,34 @@ describe("SQLite migrations", function () { } for (const stmt of rollback.stmts) { - await serialize_run(stmt); + db.exec(stmt); } } - await serialize_run("COMMIT TRANSACTION"); + db.exec("COMMIT TRANSACTION"); }); }); describe("SQLite unit tests", function () { let store: MessageStorage; - beforeEach(async function () { + beforeEach(function () { store = new MessageStorage("testUser"); - await store._enable(":memory:"); - store.initDone.resolve(); + store._enable(":memory:"); }); - afterEach(async function () { - await store.close(); + afterEach(function () { + store.close(); }); - it("deletes messages when asked to", async function () { + it("deletes messages when asked to", function () { const baseDate = new Date(); const net = {uuid: "testnet"} as any; const chan = {name: "#channel"} as any; for (let i = 0; i < 14; ++i) { - await store.index( + store.index( net, chan, new Msg({ @@ -165,29 +146,29 @@ describe("SQLite unit tests", function () { olderThanDays: 2, }; - let deleted = await store.deleteMessages(delReq); + let deleted = store.deleteMessages(delReq); expect(deleted).to.equal(limit, "number of deleted messages doesn't match"); let id = 0; - let messages = await store.getMessages(net, chan, () => id++); + let messages = store.getMessages(net, chan, () => id++); expect(messages.find((m) => m.text === "msg 13")).to.be.undefined; // oldest gets deleted first // let's test if it properly cleans now delReq.limit = 100; - deleted = await store.deleteMessages(delReq); + deleted = store.deleteMessages(delReq); expect(deleted).to.equal(11, "number of deleted messages doesn't match"); - messages = await store.getMessages(net, chan, () => id++); + messages = store.getMessages(net, chan, () => id++); expect(messages.map((m) => m.text)).to.have.ordered.members(["msg 1", "msg 0"]); }); - it("deletes only the types it should", async function () { + it("deletes only the types it should", function () { const baseDate = new Date(); const net = {uuid: "testnet"} as any; const chan = {name: "#channel"} as any; for (let i = 0; i < 6; ++i) { - await store.index( + store.index( net, chan, new Msg({ @@ -211,11 +192,11 @@ describe("SQLite unit tests", function () { olderThanDays: 0, }; - let deleted = await store.deleteMessages(delReq); + let deleted = store.deleteMessages(delReq); expect(deleted).to.equal(3, "number of deleted messages doesn't match"); let id = 0; - let messages = await store.getMessages(net, chan, () => id++); + let messages = store.getMessages(net, chan, () => id++); expect(messages.map((m) => m.type)).to.have.ordered.members([ MessageType.MESSAGE, MessageType.PART, @@ -227,9 +208,9 @@ describe("SQLite unit tests", function () { MessageType.PART, MessageType.MESSAGE, ]; - deleted = await store.deleteMessages(delReq); + deleted = store.deleteMessages(delReq); expect(deleted).to.equal(2, "number of deleted messages doesn't match"); - messages = await store.getMessages(net, chan, () => id++); + messages = store.getMessages(net, chan, () => id++); expect(messages.map((m) => m.type)).to.have.ordered.members([MessageType.AWAY]); }); }); @@ -242,36 +223,6 @@ describe("SQLite Message Storage", function () { const expectedPath = path.join(Config.getHomePath(), "logs", "testUser.sqlite3"); let store: MessageStorage; - function db_get_one(stmt: string, ...params: any[]): Promise { - return new Promise((resolve, reject) => { - store.database.serialize(() => { - store.database.get(stmt, params, (err, row) => { - if (err) { - reject(err); - return; - } - - resolve(row); - }); - }); - }); - } - - function db_get_mult(stmt: string, ...params: any[]): Promise { - return new Promise((resolve, reject) => { - store.database.serialize(() => { - store.database.all(stmt, params, (err, rows) => { - if (err) { - reject(err); - return; - } - - resolve(rows); - }); - }); - }); - } - before(function (done) { store = new MessageStorage("testUser"); @@ -290,36 +241,37 @@ describe("SQLite Message Storage", function () { fs.rmdir(path.join(Config.getHomePath(), "logs"), done); }); - it("should create database file", async function () { + it("should create database file", function () { expect(store.isEnabled).to.be.false; expect(fs.existsSync(expectedPath)).to.be.false; - await store.enable(); + store.enable(); expect(store.isEnabled).to.be.true; }); - it("should resolve an empty array when disabled", async function () { + it("should resolve an empty array when disabled", function () { store.isEnabled = false; - const messages = await store.getMessages(null as any, null as any, null as any); + const messages = store.getMessages(null as any, null as any, null as any); expect(messages).to.be.empty; store.isEnabled = true; }); - it("should insert schema version to options table", async function () { - const row = await db_get_one("SELECT value FROM options WHERE name = 'schema_version'"); + it("should insert schema version to options table", function () { + const row = store.database + .prepare("SELECT value FROM options WHERE name = 'schema_version'") + .get() as {value: string}; expect(row.value).to.equal(currentSchemaVersion.toString()); }); - it("should insert migrations", async function () { - const row = await db_get_one( - "SELECT id, version FROM migrations WHERE version = ?", - currentSchemaVersion - ); + it("should insert migrations", function () { + const row = store.database + .prepare("SELECT id, version FROM migrations WHERE version = ?") + .get(currentSchemaVersion) as {id: number; version: number} | undefined; expect(row).to.not.be.undefined; }); - it("should store a message", async function () { - await store.index( + it("should store a message", function () { + store.index( { uuid: "this-is-a-network-guid", } as any, @@ -333,9 +285,9 @@ describe("SQLite Message Storage", function () { ); }); - it("should retrieve previously stored message", async function () { + it("should retrieve previously stored message", function () { let msgid = 0; - const messages = await store.getMessages( + const messages = store.getMessages( { uuid: "this-is-a-network-guid", } as any, @@ -351,14 +303,14 @@ describe("SQLite Message Storage", function () { expect(msg.time.getTime()).to.equal(123456789); }); - it("should retrieve latest LIMIT messages in order", async function () { + it("should retrieve latest LIMIT messages in order", function () { const originalMaxHistory = Config.values.maxHistory; try { Config.values.maxHistory = 2; for (let i = 0; i < 200; ++i) { - await store.index( + store.index( {uuid: "retrieval-order-test-network"} as any, {name: "#channel"} as any, new Msg({ @@ -369,7 +321,7 @@ describe("SQLite Message Storage", function () { } let msgId = 0; - const messages = await store.getMessages( + const messages = store.getMessages( {uuid: "retrieval-order-test-network"} as any, {name: "#channel"} as any, () => msgId++ @@ -381,13 +333,13 @@ describe("SQLite Message Storage", function () { } }); - it("should search messages", async function () { + it("should search messages", function () { const originalMaxHistory = Config.values.maxHistory; try { Config.values.maxHistory = 2; - const search = await store.search({ + const search = store.search({ searchTerm: "msg", networkUuid: "retrieval-order-test-network", channelName: "", @@ -406,9 +358,9 @@ describe("SQLite Message Storage", function () { } }); - it("should search messages with escaped wildcards", async function () { - async function assertResults(query: string, expected: string[]) { - const search = await store.search({ + it("should search messages with escaped wildcards", function () { + function assertResults(query: string, expected: string[]) { + const search = store.search({ searchTerm: query, networkUuid: "this-is-a-network-guid2", channelName: "", @@ -422,7 +374,7 @@ describe("SQLite Message Storage", function () { try { Config.values.maxHistory = 3; - await store.index( + store.index( {uuid: "this-is-a-network-guid2"} as any, {name: "#channel"} as any, new Msg({ @@ -431,7 +383,7 @@ describe("SQLite Message Storage", function () { } as any) ); - await store.index( + store.index( {uuid: "this-is-a-network-guid2"} as any, {name: "#channel"} as any, new Msg({ @@ -440,7 +392,7 @@ describe("SQLite Message Storage", function () { } as any) ); - await store.index( + store.index( {uuid: "this-is-a-network-guid2"} as any, {name: "#channel"} as any, new Msg({ @@ -449,20 +401,20 @@ describe("SQLite Message Storage", function () { } as any) ); - await assertResults("foo", ["foo % bar _ baz", "foo bar x baz"]); - await assertResults("%", ["foo % bar _ baz"]); - await assertResults("foo % bar ", ["foo % bar _ baz"]); - await assertResults("_", ["foo % bar _ baz"]); - await assertResults("bar _ baz", ["foo % bar _ baz"]); - await assertResults("%%", []); - await assertResults("@%", []); - await assertResults("@", ["bar @ baz"]); + assertResults("foo", ["foo % bar _ baz", "foo bar x baz"]); + assertResults("%", ["foo % bar _ baz"]); + assertResults("foo % bar ", ["foo % bar _ baz"]); + assertResults("_", ["foo % bar _ baz"]); + assertResults("bar _ baz", ["foo % bar _ baz"]); + assertResults("%%", []); + assertResults("@%", []); + assertResults("@", ["bar @ baz"]); } finally { Config.values.maxHistory = originalMaxHistory; } }); - it("should be able to downgrade", async function () { + it("should be able to downgrade", function () { for (const rollback of rollbacks.slice().reverse()) { if (rollback.rollback_forbidden) { throw Error( @@ -470,13 +422,13 @@ describe("SQLite Message Storage", function () { ); } - const new_version = await store.downgrade_to(rollback.version); + const new_version = store.downgrade_to(rollback.version); expect(new_version).to.equal(rollback.version); } }); - it("should close database", async function () { - await store.close(); + it("should close database", function () { + store.close(); expect(fs.existsSync(expectedPath)).to.be.true; }); }); diff --git a/yarn.lock b/yarn.lock index 28a70bcf..61536450 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1265,11 +1265,6 @@ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz#ecda5712b61ac852c760d8b3c79c96adca5554e5" integrity sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg== -"@gar/promise-retry@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@gar/promise-retry/-/promise-retry-1.0.3.tgz#65e726428e794bc4453948e0a41e6de4215ce8b0" - integrity sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA== - "@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -1301,13 +1296,6 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@isaacs/fs-minipass@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" - integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== - dependencies: - minipass "^7.0.4" - "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -1608,29 +1596,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@npmcli/agent@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-4.0.0.tgz#2bb2b1c0a170940511554a7986ae2a8be9fedcce" - integrity sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA== - dependencies: - agent-base "^7.1.0" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.1" - lru-cache "^11.2.1" - socks-proxy-agent "^8.0.3" - -"@npmcli/fs@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-5.0.0.tgz#674619771907342b3d1ac197aaf1deeb657e3539" - integrity sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og== - dependencies: - semver "^7.3.5" - -"@npmcli/redact@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/redact/-/redact-4.0.0.tgz#c91121e02b7559a997614a2c1057cd7fc67608c4" - integrity sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q== - "@one-ini/wasm@0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323" @@ -2667,11 +2632,6 @@ abbrev@^2.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== -abbrev@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-4.0.0.tgz#ec933f0e27b6cd60e89b5c6b2a304af42209bb05" - integrity sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA== - abstract-logging@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" @@ -2727,11 +2687,6 @@ agent-base@6: dependencies: debug "4" -agent-base@^7.1.0, agent-base@^7.1.2: - version "7.1.4" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8" - integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== - aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -3029,11 +2984,6 @@ balanced-match@^2.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== -balanced-match@^4.0.2: - version "4.0.4" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" - integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== - base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -3059,22 +3009,6 @@ big.js@^5.2.2: resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bl@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - bn.js@^4.0.0: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" @@ -3125,13 +3059,6 @@ brace-expansion@^2.0.2: dependencies: balanced-match "^1.0.0" -brace-expansion@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.5.tgz#dcc3a37116b79f3e1b46db994ced5d570e930fdb" - integrity sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ== - dependencies: - balanced-match "^4.0.2" - braces@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -3175,14 +3102,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -3196,22 +3115,6 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cacache@^20.0.1: - version "20.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-20.0.4.tgz#9b547dc3db0c1f87cba6dbbff91fb17181b4bbb1" - integrity sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA== - dependencies: - "@npmcli/fs" "^5.0.0" - fs-minipass "^3.0.0" - glob "^13.0.0" - lru-cache "^11.1.0" - minipass "^7.0.3" - minipass-collect "^2.0.1" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - p-map "^7.0.2" - ssri "^13.0.0" - cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" @@ -3374,16 +3277,6 @@ chokidar@^4.0.1: dependencies: readdirp "^4.0.1" -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - -chownr@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" - integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== - chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -3943,11 +3836,6 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-libc@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" - integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== - diff@^4.0.1, diff@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -4114,13 +4002,6 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -end-of-stream@^1.4.1: - version "1.4.5" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" - integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== - dependencies: - once "^1.4.0" - engine.io-client@~6.2.1: version "6.2.3" resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.2.3.tgz#a8cbdab003162529db85e9de31575097f6d29458" @@ -4179,7 +4060,7 @@ entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== -env-paths@^2.2.0, env-paths@^2.2.1: +env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== @@ -4594,16 +4475,6 @@ execall@^2.0.0: dependencies: clone-regexp "^2.1.0" -expand-template@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" - integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== - -exponential-backoff@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz#51cf92c1c0493c766053f9d3abee4434c244d2f6" - integrity sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA== - express@4.20.0: version "4.20.0" resolved "https://registry.yarnpkg.com/express/-/express-4.20.0.tgz#f1d08e591fcec770c07be4767af8eb9bcfd67c48" @@ -4715,11 +4586,6 @@ file-type@16.5.4: strtok3 "^6.2.4" token-types "^4.1.1" -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - filename-reserved-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" @@ -4858,11 +4724,6 @@ fromentries@^1.2.0: resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a" integrity sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg== -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - fs-extra@^10.0.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -4872,13 +4733,6 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-minipass@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" - integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== - dependencies: - minipass "^7.0.3" - fs-monkey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" @@ -4978,11 +4832,6 @@ get-tsconfig@^4.7.5: dependencies: resolve-pkg-maps "^1.0.0" -github-from-package@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" - integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== - glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -5030,15 +4879,6 @@ glob@^10.4.5: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^13.0.0: - version "13.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d" - integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw== - dependencies: - minimatch "^10.2.2" - minipass "^7.1.3" - path-scurry "^2.0.2" - glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -5150,7 +4990,7 @@ graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -graceful-fs@^4.2.11, graceful-fs@^4.2.6: +graceful-fs@^4.2.11: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -5281,11 +5121,6 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-cache-semantics@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" - integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== - http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -5297,14 +5132,6 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" -http-proxy-agent@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" - integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== - dependencies: - agent-base "^7.1.0" - debug "^4.3.4" - http2-wrapper@^1.0.0-beta.5.2: version "1.0.3" resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" @@ -5328,14 +5155,6 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.1: - version "7.0.6" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" - integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== - dependencies: - agent-base "^7.1.2" - debug "4" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -5360,19 +5179,12 @@ iconv-lite@0.6.3, iconv-lite@^0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -iconv-lite@^0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e" - integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5434,7 +5246,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -5713,11 +5525,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isexe@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-4.0.0.tgz#48f6576af8e87a18feb796b7ed5e2e5903b43dca" - integrity sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw== - isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" @@ -6122,11 +5929,6 @@ lru-cache@^10.2.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== -lru-cache@^11.0.0, lru-cache@^11.1.0, lru-cache@^11.2.1: - version "11.3.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.3.3.tgz#d6c633c2a9657760fd30594d8d98da65330d9d78" - integrity sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ== - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -6153,24 +5955,6 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -make-fetch-happen@^15.0.0: - version "15.0.5" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-15.0.5.tgz#b0e3dd53d487b2733e4ea232c2bebf1bd16afb03" - integrity sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg== - dependencies: - "@gar/promise-retry" "^1.0.0" - "@npmcli/agent" "^4.0.0" - "@npmcli/redact" "^4.0.0" - cacache "^20.0.1" - http-cache-semantics "^4.1.1" - minipass "^7.0.2" - minipass-fetch "^5.0.0" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^1.0.0" - proc-log "^6.0.0" - ssri "^13.0.0" - map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -6348,13 +6132,6 @@ minimatch@9.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^10.2.2: - version "10.2.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.5.tgz#bd48687a0be38ed2961399105600f832095861d1" - integrity sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg== - dependencies: - brace-expansion "^5.0.5" - minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -6390,79 +6167,16 @@ minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -minimist@^1.2.3: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -minipass-collect@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863" - integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw== - dependencies: - minipass "^7.0.3" - -minipass-fetch@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-5.0.2.tgz#3973a605ddfd8abb865e50d6fc634853c8239729" - integrity sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ== - dependencies: - minipass "^7.0.3" - minipass-sized "^2.0.0" - minizlib "^3.0.1" - optionalDependencies: - iconv-lite "^0.7.2" - -minipass-flush@^1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.7.tgz#145c383d5ae294b36030aa80d4e872d08bebcb73" - integrity sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA== - dependencies: - minipass "^3.0.0" - -minipass-pipeline@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" - integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== - dependencies: - minipass "^3.0.0" - -minipass-sized@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-2.0.0.tgz#2228ee97e3f74f6b22ba6d1319addb7621534306" - integrity sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA== - dependencies: - minipass "^7.1.2" - -minipass@^3.0.0: - version "3.3.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" - integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== - dependencies: - yallist "^4.0.0" - "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4: version "7.1.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.0.tgz#b545f84af94e567386770159302ca113469c80b8" integrity sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig== -minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.2, minipass@^7.1.3: +minipass@^7.1.2: version "7.1.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== -minizlib@^3.0.1, minizlib@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.1.0.tgz#6ad76c3a8f10227c9b51d1c9ac8e30b27f5a251c" - integrity sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw== - dependencies: - minipass "^7.1.2" - -mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - mocha@11.7.5: version "11.7.5" resolved "https://registry.yarnpkg.com/mocha/-/mocha-11.7.5.tgz#58f5bbfa5e0211ce7e5ee6128107cefc2515a627" @@ -6546,11 +6260,6 @@ nanoid@^3.3.7: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== -napi-build-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-2.0.0.tgz#13c22c0187fcfccce1461844136372a47ddc027e" - integrity sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -6561,11 +6270,6 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -negotiator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" - integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== - neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -6598,44 +6302,16 @@ nise@^5.1.1: just-extend "^4.0.2" path-to-regexp "^1.7.0" -node-abi@^3.3.0: - version "3.89.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.89.0.tgz#eea98bf89d4534743bbbf2defa9f4f9bd3bdccfd" - integrity sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA== - dependencies: - semver "^7.3.5" - node-abort-controller@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.0.1.tgz#f91fa50b1dee3f909afabb7e261b1e1d6b0cb74e" integrity sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw== -node-addon-api@^8.0.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.7.0.tgz#f64f8413456ecbe900221305a3f883c37666473f" - integrity sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA== - node-forge@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-gyp@12.x: - version "12.2.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-12.2.0.tgz#ff73f6f509e33d8b7e768f889ffc9738ad117b07" - integrity sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ== - dependencies: - env-paths "^2.2.0" - exponential-backoff "^3.1.1" - graceful-fs "^4.2.6" - make-fetch-happen "^15.0.0" - nopt "^9.0.0" - proc-log "^6.0.0" - semver "^7.3.5" - tar "^7.5.4" - tinyglobby "^0.2.12" - which "^6.0.0" - node-preload@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" @@ -6660,13 +6336,6 @@ nopt@^7.2.0: dependencies: abbrev "^2.0.0" -nopt@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-9.0.0.tgz#6bff0836b2964d24508b6b41b5a9a49c4f4a1f96" - integrity sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw== - dependencies: - abbrev "^4.0.0" - normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -6887,11 +6556,6 @@ p-map@^3.0.0: dependencies: aggregate-error "^3.0.0" -p-map@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-7.0.4.tgz#b81814255f542e252d5729dca4d66e5ec14935b8" - integrity sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ== - p-try@^2.0.0, p-try@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -7015,14 +6679,6 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-scurry@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85" - integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg== - dependencies: - lru-cache "^11.0.0" - minipass "^7.1.2" - path-to-regexp@0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" @@ -7655,24 +7311,6 @@ postcss@^8.4.40: picocolors "^1.1.1" source-map-js "^1.2.1" -prebuild-install@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.3.tgz#d630abad2b147443f20a212917beae68b8092eec" - integrity sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug== - dependencies: - detect-libc "^2.0.0" - expand-template "^2.0.3" - github-from-package "0.0.0" - minimist "^1.2.3" - mkdirp-classic "^0.5.3" - napi-build-utils "^2.0.0" - node-abi "^3.3.0" - pump "^3.0.0" - rc "^1.2.7" - simple-get "^4.0.0" - tar-fs "^2.0.0" - tunnel-agent "^0.6.0" - precond@0.2: version "0.2.3" resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" @@ -7712,11 +7350,6 @@ primer-tooltips@2.0.0: dependencies: primer-support "5.0.0" -proc-log@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-6.1.0.tgz#18519482a37d5198e231133a70144a50f21f0215" - integrity sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ== - process-on-spawn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" @@ -7801,7 +7434,7 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -rc@1.2.8, rc@^1.2.7, rc@^1.2.8: +rc@1.2.8, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -7861,7 +7494,7 @@ read@1.0.7: dependencies: mute-stream "~0.0.4" -readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0: +readable-stream@^3.5.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -8337,20 +7970,6 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" - integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== - -simple-get@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" - integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== - dependencies: - decompress-response "^6.0.0" - once "^1.3.1" - simple-concat "^1.0.0" - sinon@13.0.2: version "13.0.2" resolved "https://registry.yarnpkg.com/sinon/-/sinon-13.0.2.tgz#c6a8ddd655dc1415bbdc5ebf0e5b287806850c3a" @@ -8439,15 +8058,6 @@ socket.io@4.6.2: socket.io-adapter "~2.5.2" socket.io-parser "~4.2.4" -socks-proxy-agent@^8.0.3: - version "8.0.5" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee" - integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw== - dependencies: - agent-base "^7.1.2" - debug "^4.3.4" - socks "^2.8.3" - socks@^2.8.3: version "2.8.3" resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" @@ -8547,25 +8157,6 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -sqlite3@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-6.0.1.tgz#c0956e7834931c406b283c87b66771c847a6abfc" - integrity sha512-X0czUUMG2tmSqJpEQa3tCuZSHKIx8PwM53vLZzKp/o6Rpy25fiVfjdbnZ988M8+O3ZWR1ih0K255VumCb3MAnQ== - dependencies: - bindings "^1.5.0" - node-addon-api "^8.0.0" - prebuild-install "^7.1.3" - tar "^7.5.10" - optionalDependencies: - node-gyp "12.x" - -ssri@^13.0.0: - version "13.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-13.0.1.tgz#2d8946614d33f4d0c84946bb370dce7a9379fd18" - integrity sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ== - dependencies: - minipass "^7.0.3" - stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" @@ -8867,38 +8458,6 @@ tapable@^2.3.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.2.tgz#86755feabad08d82a26b891db044808c6ad00f15" integrity sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA== -tar-fs@^2.0.0: - version "2.1.4" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.4.tgz#800824dbf4ef06ded9afea4acafe71c67c76b930" - integrity sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - -tar-stream@^2.1.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - -tar@^7.5.10, tar@^7.5.4: - version "7.5.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.13.tgz#0d214ed56781a26edc313581c0e2d929ceeb866d" - integrity sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng== - dependencies: - "@isaacs/fs-minipass" "^4.0.0" - chownr "^3.0.0" - minipass "^7.1.2" - minizlib "^3.1.0" - yallist "^5.0.0" - terser-webpack-plugin@^5.1.3: version "5.3.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz#8033db876dd5875487213e87c627bca323e5ed90" @@ -9084,13 +8643,6 @@ tsx@4.21.0: optionalDependencies: fsevents "~2.3.3" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -9623,13 +9175,6 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -which@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/which/-/which-6.0.1.tgz#021642443a198fb93b784a5606721cb18cfcbfce" - integrity sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg== - dependencies: - isexe "^4.0.0" - wildcard@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" @@ -9748,11 +9293,6 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yallist@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" - integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== - yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" From 2a92ec0e0393ee4127b68689cbb3735ed356e32f Mon Sep 17 00:00:00 2001 From: Max Leiter <8675906+MaxLeiter@users.noreply.github.com> Date: Sun, 12 Apr 2026 09:25:28 -0700 Subject: [PATCH 2/2] fix: hide Account settings tab on public instance, sometimes hide General (#5063) on public TL instances like the demo, this is what the account and general tabs look like in Firefox: | General | Account | |--------|--------| | image | image | 1. we should just always hide account if mode is public, its useless 2. if file uploads are off, there's nothing to show in General except the native app install, which i figure is fine/not really necessary for public instances (and isn't supported by Firefox, hence the blankness) --- client/components/Settings/Navigation.vue | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/client/components/Settings/Navigation.vue b/client/components/Settings/Navigation.vue index 1b8c5f39..327419c5 100644 --- a/client/components/Settings/Navigation.vue +++ b/client/components/Settings/Navigation.vue @@ -3,10 +3,10 @@ @@ -93,11 +93,18 @@