From 008d8d8f5c3d761552d0a27953261f0a77ed9916 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 13 Apr 2024 21:30:38 +0900 Subject: [PATCH 01/22] docs: update changelog --- docs/changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index f0076197bc..85f13c6238 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -8,6 +8,9 @@ Critical security updates are indicated by the :warning: icon. ## Unreleased - Add "Media" tab to user page +- Improve federation and rendering of mathematical expressions +- Remove donor information from the web client + - See also: https://info.firefish.dev/notes/9s1n283sb10rh869 - Fix bugs ## [v20240405](https://firefish.dev/firefish/firefish/-/merge_requests/10733/commits) From 5ba88f3d6f005c895528399504daddbfa7cba9d0 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 13 Apr 2024 21:34:20 +0900 Subject: [PATCH 02/22] v20240413 --- docs/api-change.md | 2 +- docs/changelog.md | 2 +- docs/notice-for-admins.md | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api-change.md b/docs/api-change.md index e788b3d637..f3ed584c32 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -2,7 +2,7 @@ Breaking changes are indicated by the :warning: icon. -## Unreleased +## v20240413 - :warning: Removed `patrons` endpoint. diff --git a/docs/changelog.md b/docs/changelog.md index 85f13c6238..a818e09835 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,7 +5,7 @@ Critical security updates are indicated by the :warning: icon. - Server administrators should check [notice-for-admins.md](./notice-for-admins.md) as well. - Third-party client/bot developers may want to check [api-change.md](./api-change.md) as well. -## Unreleased +## [v20240413](https://firefish.dev/firefish/firefish/-/merge_requests/10741/commits) - Add "Media" tab to user page - Improve federation and rendering of mathematical expressions diff --git a/docs/notice-for-admins.md b/docs/notice-for-admins.md index c22b1da0aa..9bff40a65c 100644 --- a/docs/notice-for-admins.md +++ b/docs/notice-for-admins.md @@ -2,7 +2,7 @@ You can skip intermediate versions when upgrading from an old version, but please read the notices and follow the instructions for each intermediate version before [upgrading](./upgrade.md). -## Unreleased +## v20240413 ### For all users diff --git a/package.json b/package.json index bff235df6e..a7bb0a5cc1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firefish", - "version": "20240405", + "version": "20240413", "repository": { "type": "git", "url": "https://firefish.dev/firefish/firefish.git" From aea6659d0bee60b5930155fc3e9eda7cd167b3c8 Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 14 Apr 2024 02:35:25 +0900 Subject: [PATCH 03/22] fix: workaround the issue that profile pages don't load if the version is older than 20240212 (v20240212 is vulnerable btw) --- patrons.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 patrons.json diff --git a/patrons.json b/patrons.json new file mode 100644 index 0000000000..cbbeacfdc9 --- /dev/null +++ b/patrons.json @@ -0,0 +1,4 @@ +{ + "patrons": [], + "sponsors": [] +} From 19b45866c804ab0667b26acfa7a84c5c1151874c Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 14 Apr 2024 13:35:35 +0900 Subject: [PATCH 04/22] docs: update packages/README.md --- packages/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/README.md b/packages/README.md index 56356ec2d0..6637462910 100644 --- a/packages/README.md +++ b/packages/README.md @@ -4,6 +4,7 @@ This directory contains all of the packages Firefish uses. - `backend`: Main backend code written in TypeScript for NodeJS - `backend-rs`: Backend code written in Rust, bound to NodeJS by [NAPI-RS](https://napi.rs/) +- `macro-rs`: Procedural macros for backend-rs - `client`: Web interface written in Vue3 and TypeScript - `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript - `firefish-js`: TypeScript SDK for both backend and client From baa57d7c173433f4b30f949fd1246960afebb7a0 Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 14 Apr 2024 13:38:44 +0900 Subject: [PATCH 05/22] dev: add rust-analyzer to recommended VSCode extensitons --- .vscode/extensions.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0083604d44..de0385be2a 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -12,6 +12,7 @@ "esbenp.prettier-vscode", "redhat.vscode-yaml", "yoavbls.pretty-ts-errors", - "biomejs.biome" + "biomejs.biome", + "rust-lang.rust-analyzer" ] } From 70aa3704ef27932ef0d3da543f169c0099f103bb Mon Sep 17 00:00:00 2001 From: sup39 Date: Sun, 14 Apr 2024 14:41:01 +0900 Subject: [PATCH 06/22] refactor (backend): port password hashing/verification to backend-rs Co-authored-by: naskya --- Cargo.lock | 92 ++++++++++++++++++- Cargo.toml | 2 + packages/backend-rs/Cargo.toml | 2 + packages/backend-rs/index.d.ts | 3 + packages/backend-rs/index.js | 5 +- packages/backend-rs/src/misc/mod.rs | 1 + packages/backend-rs/src/misc/password.rs | 69 ++++++++++++++ packages/backend/package.json | 3 - packages/backend/src/misc/password.ts | 20 ---- .../backend/src/server/api/common/signup.ts | 5 +- .../api/endpoints/admin/reset-password.ts | 6 +- .../server/api/endpoints/i/2fa/key-done.ts | 6 +- .../api/endpoints/i/2fa/register-key.ts | 7 +- .../server/api/endpoints/i/2fa/register.ts | 6 +- .../server/api/endpoints/i/2fa/remove-key.ts | 6 +- .../server/api/endpoints/i/2fa/unregister.ts | 6 +- .../server/api/endpoints/i/change-password.ts | 6 +- .../server/api/endpoints/i/delete-account.ts | 6 +- .../api/endpoints/i/regenerate-token.ts | 6 +- .../server/api/endpoints/i/update-email.ts | 6 +- .../server/api/endpoints/reset-password.ts | 4 +- .../backend/src/server/api/private/signin.ts | 16 ++-- .../backend/src/server/api/private/signup.ts | 6 +- .../src/services/create-system-user.ts | 5 +- pnpm-lock.yaml | 38 +------- 25 files changed, 214 insertions(+), 118 deletions(-) create mode 100644 packages/backend-rs/src/misc/password.rs delete mode 100644 packages/backend/src/misc/password.ts diff --git a/Cargo.lock b/Cargo.lock index 93c475fa0b..6552351a3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,6 +132,18 @@ version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -190,8 +202,10 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" name = "backend-rs" version = "0.0.0" dependencies = [ + "argon2", "async-trait", "basen", + "bcrypt", "cfg-if", "chrono", "cuid2", @@ -238,6 +252,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "base64ct" version = "1.6.0" @@ -250,6 +270,19 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dbe4bb73fd931c4d1aaf53b35d1286c8a948ad00ec92c8e3c856f15fd027f43" +[[package]] +name = "bcrypt" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7" +dependencies = [ + "base64 0.22.0", + "blowfish", + "getrandom", + "subtle", + "zeroize", +] + [[package]] name = "bigdecimal" version = "0.3.1" @@ -303,6 +336,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -312,6 +354,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "borsh" version = "1.4.0" @@ -415,6 +467,16 @@ dependencies = [ "windows-targets 0.52.4", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.4" @@ -1075,6 +1137,15 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -1122,7 +1193,7 @@ checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978" dependencies = [ "ahash 0.8.11", "anyhow", - "base64", + "base64 0.21.7", "bytecount", "clap", "fancy-regex", @@ -1559,6 +1630,17 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.14" @@ -1801,7 +1883,7 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -1947,7 +2029,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", ] [[package]] @@ -2398,7 +2480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", - "base64", + "base64 0.21.7", "bigdecimal", "bitflags 2.5.0", "byteorder", @@ -2445,7 +2527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", - "base64", + "base64 0.21.7", "bigdecimal", "bitflags 2.5.0", "byteorder", diff --git a/Cargo.toml b/Cargo.toml index f7ba12d884..1a72cb2c5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,10 @@ napi = { version = "2.16.2", default-features = false } napi-derive = "2.16.2" napi-build = "2.1.2" +argon2 = "0.5.3" async-trait = "0.1.80" basen = "0.1.0" +bcrypt = "0.15.1" cfg-if = "1.0.0" chrono = "0.4.37" convert_case = "0.6.0" diff --git a/packages/backend-rs/Cargo.toml b/packages/backend-rs/Cargo.toml index 783f630942..235fcc8706 100644 --- a/packages/backend-rs/Cargo.toml +++ b/packages/backend-rs/Cargo.toml @@ -17,8 +17,10 @@ macro_rs = { workspace = true } napi = { workspace = true, optional = true, default-features = false, features = ["napi9", "tokio_rt", "chrono_date", "serde-json"] } napi-derive = { workspace = true, optional = true } +argon2 = { workspace = true, features = ["std"] } async-trait = { workspace = true } basen = { workspace = true } +bcrypt = { workspace = true } cfg-if = { workspace = true } chrono = { workspace = true } cuid2 = { workspace = true } diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 617bedf5b9..f2830dcac3 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -135,6 +135,9 @@ export function toPuny(host: string): string export function toMastodonId(firefishId: string): string | null export function fromMastodonId(mastodonId: string): string | null export function nyaify(text: string, lang?: string | undefined | null): string +export function hashPassword(password: string): string +export function verifyPassword(password: string, hash: string): boolean +export function isOldPasswordAlgorithm(hash: string): boolean export interface AbuseUserReport { id: string createdAt: Date diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index f2942a9aa5..af9a293bbb 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, toMastodonId, fromMastodonId, nyaify, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding +const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, toMastodonId, fromMastodonId, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding module.exports.readServerConfig = readServerConfig module.exports.stringToAcct = stringToAcct @@ -324,6 +324,9 @@ module.exports.toPuny = toPuny module.exports.toMastodonId = toMastodonId module.exports.fromMastodonId = fromMastodonId module.exports.nyaify = nyaify +module.exports.hashPassword = hashPassword +module.exports.verifyPassword = verifyPassword +module.exports.isOldPasswordAlgorithm = isOldPasswordAlgorithm module.exports.AntennaSrcEnum = AntennaSrcEnum module.exports.MutedNoteReasonEnum = MutedNoteReasonEnum module.exports.NoteVisibilityEnum = NoteVisibilityEnum diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index 701e35a4eb..6eda4e449e 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -3,3 +3,4 @@ pub mod check_word_mute; pub mod convert_host; pub mod mastodon_id; pub mod nyaify; +pub mod password; diff --git a/packages/backend-rs/src/misc/password.rs b/packages/backend-rs/src/misc/password.rs new file mode 100644 index 0000000000..b21ff73499 --- /dev/null +++ b/packages/backend-rs/src/misc/password.rs @@ -0,0 +1,69 @@ +use argon2::{ + password_hash, + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; + +#[crate::export] +pub fn hash_password(password: &str) -> Result { + let salt = SaltString::generate(&mut OsRng); + Ok(Argon2::default() + .hash_password(password.as_bytes(), &salt)? + .to_string()) +} + +#[derive(thiserror::Error, Debug)] +pub enum VerifyError { + #[error("An error occured while bcrypt verification: {0}")] + BcryptError(#[from] bcrypt::BcryptError), + #[error("Invalid argon2 password hash: {0}")] + InvalidArgon2Hash(#[from] password_hash::Error), + #[error("An error occured while argon2 verification: {0}")] + Argon2Error(#[from] argon2::Error), +} + +#[crate::export] +pub fn verify_password(password: &str, hash: &str) -> Result { + if is_old_password_algorithm(hash) { + Ok(bcrypt::verify(password, hash)?) + } else { + let parsed_hash = PasswordHash::new(hash)?; + Ok(Argon2::default() + .verify_password(password.as_bytes(), &parsed_hash) + .is_ok()) + } +} + +#[inline] +#[crate::export] +pub fn is_old_password_algorithm(hash: &str) -> bool { + // bcrypt hashes start with $2[ab]$ + hash.starts_with("$2") +} + +#[cfg(test)] +mod unit_test { + use super::{hash_password, is_old_password_algorithm, verify_password}; + + #[test] + fn verify_password_test() { + let password = "omWc*%sD^fn7o2cXmc9e2QasBdrbRuhNB*gx!J5"; + + let hash = hash_password(password).unwrap(); + assert!(verify_password(password, hash.as_str()).unwrap()); + + let argon2_hash = "$argon2id$v=19$m=19456,t=2,p=1$jty3puDFd4ENv/lgHn3ROQ$kRHDdEoVv2rruvnF731E74NxnYlvj5FMgePdGIIq3Jk"; + let argon2_invalid_hash = "$argon2id$v=19$m=19456,t=2,p=1$jty3puDFd4ENv/lgHn3ROQ$kRHDdEoVv2rruvnF731E74NxnYlvj4FMgePdGIIq3Jk"; + let bcrypt_hash = "$2a$12$WzUc.20jgbHmQjUMqTr8vOhKqYbS1BUvubapv/GLjCK1IN.h4e4la"; + let bcrypt_invalid_hash = "$2a$12$WzUc.20jgbHmQjUMqTr7vOhKqYbS1BUvubapv/GLjCK1IN.h4e4la"; + + assert!(!is_old_password_algorithm(argon2_hash)); + assert!(is_old_password_algorithm(bcrypt_hash)); + + assert!(verify_password(password, argon2_hash).unwrap()); + assert!(verify_password(password, bcrypt_hash).unwrap()); + + assert!(!verify_password(password, argon2_invalid_hash).unwrap()); + assert!(!verify_password(password, bcrypt_invalid_hash).unwrap()); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index 5382f1d361..5dbf7cad64 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -37,11 +37,9 @@ "adm-zip": "0.5.10", "ajv": "8.12.0", "archiver": "7.0.1", - "argon2": "^0.40.1", "aws-sdk": "2.1597.0", "axios": "^1.6.8", "backend-rs": "workspace:*", - "bcryptjs": "2.4.3", "blurhash": "2.0.5", "bull": "4.12.2", "cacheable-lookup": "TheEssem/cacheable-lookup", @@ -130,7 +128,6 @@ "@swc/cli": "0.3.12", "@swc/core": "1.4.13", "@types/adm-zip": "^0.5.5", - "@types/bcryptjs": "2.4.6", "@types/color-convert": "^2.0.3", "@types/content-disposition": "^0.5.8", "@types/escape-regexp": "0.0.3", diff --git a/packages/backend/src/misc/password.ts b/packages/backend/src/misc/password.ts deleted file mode 100644 index c63f89f5c9..0000000000 --- a/packages/backend/src/misc/password.ts +++ /dev/null @@ -1,20 +0,0 @@ -import bcrypt from "bcryptjs"; -import * as argon2 from "argon2"; - -export async function hashPassword(password: string): Promise { - return argon2.hash(password); -} - -export async function comparePassword( - password: string, - hash: string, -): Promise { - if (isOldAlgorithm(hash)) return bcrypt.compare(password, hash); - - return argon2.verify(hash, password); -} - -export function isOldAlgorithm(hash: string): boolean { - // bcrypt hashes start with $2[ab]$ - return hash.startsWith("$2"); -} diff --git a/packages/backend/src/server/api/common/signup.ts b/packages/backend/src/server/api/common/signup.ts index a267baf9c0..58b88b7d02 100644 --- a/packages/backend/src/server/api/common/signup.ts +++ b/packages/backend/src/server/api/common/signup.ts @@ -4,12 +4,11 @@ import { User } from "@/models/entities/user.js"; import { Users, UsedUsernames } from "@/models/index.js"; import { UserProfile } from "@/models/entities/user-profile.js"; import { IsNull } from "typeorm"; -import { genId, toPuny } from "backend-rs"; +import { genId, hashPassword, toPuny } from "backend-rs"; import { UserKeypair } from "@/models/entities/user-keypair.js"; import { UsedUsername } from "@/models/entities/used-username.js"; import { db } from "@/db/postgre.js"; import config from "@/config/index.js"; -import { hashPassword } from "@/misc/password.js"; export async function signup(opts: { username: User["username"]; @@ -40,7 +39,7 @@ export async function signup(opts: { } // Generate hash of password - hash = await hashPassword(password); + hash = hashPassword(password); } // Generate secret diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index 5fbed130e6..ace0b581d7 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -1,8 +1,7 @@ import define from "@/server/api/define.js"; -// import bcrypt from "bcryptjs"; import rndstr from "rndstr"; import { Users, UserProfiles } from "@/models/index.js"; -import { hashPassword } from "@/misc/password.js"; +import { hashPassword } from "backend-rs"; export const meta = { tags: ["admin"], @@ -48,8 +47,7 @@ export default define(meta, paramDef, async (ps) => { const passwd = rndstr("a-zA-Z0-9", 8); // Generate hash of password - // const hash = bcrypt.hashSync(passwd); - const hash = await hashPassword(passwd); + const hash = hashPassword(passwd); await UserProfiles.update( { diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index 0e52dd0d78..6c99217e7d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -9,7 +9,7 @@ import { import config from "@/config/index.js"; import { procedures, hash } from "@/server/api/2fa.js"; import { publishMainStream } from "@/services/stream.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8")); @@ -40,8 +40,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index b275b5705d..4991e8fc90 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -2,9 +2,8 @@ import define from "@/server/api/define.js"; import { UserProfiles, AttestationChallenges } from "@/models/index.js"; import { promisify } from "node:util"; import * as crypto from "node:crypto"; -import { genId } from "backend-rs"; +import { genId, verifyPassword } from "backend-rs"; import { hash } from "@/server/api/2fa.js"; -import { comparePassword } from "@/misc/password.js"; const randomBytes = promisify(crypto.randomBytes); @@ -25,8 +24,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts index 52e1df39f4..c0e6137d5d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts @@ -3,7 +3,7 @@ import * as QRCode from "qrcode"; import config from "@/config/index.js"; import { UserProfiles } from "@/models/index.js"; import define from "@/server/api/define.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -22,8 +22,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts index 0cdf8780ef..4259d8f70d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts @@ -1,4 +1,4 @@ -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; import define from "@/server/api/define.js"; import { UserProfiles, UserSecurityKeys, Users } from "@/models/index.js"; import { publishMainStream } from "@/services/stream.js"; @@ -21,8 +21,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts index c4e78eecb5..240ff2b34e 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts @@ -1,7 +1,7 @@ import { publishMainStream } from "@/services/stream.js"; import define from "@/server/api/define.js"; import { Users, UserProfiles } from "@/models/index.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -20,8 +20,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/change-password.ts b/packages/backend/src/server/api/endpoints/i/change-password.ts index b0dc8bba60..1634676748 100644 --- a/packages/backend/src/server/api/endpoints/i/change-password.ts +++ b/packages/backend/src/server/api/endpoints/i/change-password.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { UserProfiles } from "@/models/index.js"; -import { hashPassword, comparePassword } from "@/misc/password.js"; +import { hashPassword, verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -20,8 +20,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.currentPassword, profile.password!); + // Compare passwords + const same = verifyPassword(ps.currentPassword, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/delete-account.ts b/packages/backend/src/server/api/endpoints/i/delete-account.ts index 606cde82e1..538798261d 100644 --- a/packages/backend/src/server/api/endpoints/i/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/i/delete-account.ts @@ -1,7 +1,7 @@ import { UserProfiles, Users } from "@/models/index.js"; import { deleteAccount } from "@/services/delete-account.js"; import define from "@/server/api/define.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -24,8 +24,8 @@ export default define(meta, paramDef, async (ps, user) => { return; } - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts index c1b4325adb..fd3023ab7a 100644 --- a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts +++ b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts @@ -6,7 +6,7 @@ import { import generateUserToken from "@/server/api/common/generate-native-user-token.js"; import define from "@/server/api/define.js"; import { Users, UserProfiles } from "@/models/index.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -28,8 +28,8 @@ export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new Error("incorrect password"); diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts index a48252ed1a..234127f584 100644 --- a/packages/backend/src/server/api/endpoints/i/update-email.ts +++ b/packages/backend/src/server/api/endpoints/i/update-email.ts @@ -7,7 +7,7 @@ import { sendEmail } from "@/services/send-email.js"; import { ApiError } from "@/server/api/error.js"; import { validateEmailForAccount } from "@/services/validate-email-for-account.js"; import { HOUR } from "@/const.js"; -import { comparePassword } from "@/misc/password.js"; +import { verifyPassword } from "backend-rs"; export const meta = { requireCredential: true, @@ -46,8 +46,8 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(ps.password, profile.password!); + // Compare passwords + const same = verifyPassword(ps.password, profile.password!); if (!same) { throw new ApiError(meta.errors.incorrectPassword); diff --git a/packages/backend/src/server/api/endpoints/reset-password.ts b/packages/backend/src/server/api/endpoints/reset-password.ts index ff5c8d987f..b69b1b17d3 100644 --- a/packages/backend/src/server/api/endpoints/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/reset-password.ts @@ -1,6 +1,6 @@ import { UserProfiles, PasswordResetRequests } from "@/models/index.js"; import define from "@/server/api/define.js"; -import { hashPassword } from "@/misc/password.js"; +import { hashPassword } from "backend-rs"; export const meta = { tags: ["reset password"], @@ -32,7 +32,7 @@ export default define(meta, paramDef, async (ps, user) => { } // Generate hash of password - const hash = await hashPassword(ps.password); + const hash = hashPassword(ps.password); await UserProfiles.update(req.userId, { password: hash, diff --git a/packages/backend/src/server/api/private/signin.ts b/packages/backend/src/server/api/private/signin.ts index 8692b01ad1..a7eb623062 100644 --- a/packages/backend/src/server/api/private/signin.ts +++ b/packages/backend/src/server/api/private/signin.ts @@ -10,12 +10,12 @@ import { AttestationChallenges, } from "@/models/index.js"; import type { ILocalUser } from "@/models/entities/user.js"; -import { genId } from "backend-rs"; import { - comparePassword, + genId, hashPassword, - isOldAlgorithm, -} from "@/misc/password.js"; + isOldPasswordAlgorithm, + verifyPassword, +} from "backend-rs"; import { verifyLogin, hash } from "@/server/api/2fa.js"; import { randomBytes } from "node:crypto"; import { IsNull } from "typeorm"; @@ -91,11 +91,11 @@ export default async (ctx: Koa.Context) => { const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - // Compare password - const same = await comparePassword(password, profile.password!); + // Compare passwords + const same = verifyPassword(password, profile.password!); - if (same && isOldAlgorithm(profile.password!)) { - profile.password = await hashPassword(password); + if (same && isOldPasswordAlgorithm(profile.password!)) { + profile.password = hashPassword(password); await UserProfiles.save(profile); } diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts index 8179300884..64b5c57337 100644 --- a/packages/backend/src/server/api/private/signup.ts +++ b/packages/backend/src/server/api/private/signup.ts @@ -6,10 +6,8 @@ import { Users, RegistrationTickets, UserPendings } from "@/models/index.js"; import { signup } from "@/server/api/common/signup.js"; import config from "@/config/index.js"; import { sendEmail } from "@/services/send-email.js"; -import { genId } from "backend-rs"; +import { genId, hashPassword } from "backend-rs"; import { validateEmailForAccount } from "@/services/validate-email-for-account.js"; -import { hashPassword } from "@/misc/password.js"; -import { inspect } from "node:util"; export default async (ctx: Koa.Context) => { const body = ctx.request.body; @@ -85,7 +83,7 @@ export default async (ctx: Koa.Context) => { const code = rndstr("a-z0-9", 16); // Generate hash of password - const hash = await hashPassword(password); + const hash = hashPassword(password); await UserPendings.insert({ id: genId(), diff --git a/packages/backend/src/services/create-system-user.ts b/packages/backend/src/services/create-system-user.ts index 345de7ad17..802c59b288 100644 --- a/packages/backend/src/services/create-system-user.ts +++ b/packages/backend/src/services/create-system-user.ts @@ -4,17 +4,16 @@ import { genRsaKeyPair } from "@/misc/gen-key-pair.js"; import { User } from "@/models/entities/user.js"; import { UserProfile } from "@/models/entities/user-profile.js"; import { IsNull } from "typeorm"; -import { genId } from "backend-rs"; +import { genId, hashPassword } from "backend-rs"; import { UserKeypair } from "@/models/entities/user-keypair.js"; import { UsedUsername } from "@/models/entities/used-username.js"; import { db } from "@/db/postgre.js"; -import { hashPassword } from "@/misc/password.js"; export async function createSystemUser(username: string) { const password = uuid(); // Generate hash of password - const hash = await hashPassword(password); + const hash = hashPassword(password); // Generate secret const secret = generateNativeUserToken(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 192b5f95e5..02b473ddce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -99,9 +99,6 @@ importers: archiver: specifier: 7.0.1 version: 7.0.1 - argon2: - specifier: ^0.40.1 - version: 0.40.1 aws-sdk: specifier: 2.1597.0 version: 2.1597.0 @@ -111,9 +108,6 @@ importers: backend-rs: specifier: workspace:* version: link:../backend-rs - bcryptjs: - specifier: 2.4.3 - version: 2.4.3 blurhash: specifier: 2.0.5 version: 2.0.5 @@ -377,9 +371,6 @@ importers: '@types/adm-zip': specifier: ^0.5.5 version: 0.5.5 - '@types/bcryptjs': - specifier: 2.4.6 - version: 2.4.6 '@types/color-convert': specifier: ^2.0.3 version: 2.0.3 @@ -3294,11 +3285,6 @@ packages: sshpk: 1.17.0 dev: false - /@phc/format@1.0.0: - resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} - engines: {node: '>=10'} - dev: false - /@phosphor-icons/web@2.1.1: resolution: {integrity: sha512-QjrfbItu5Rb2i37GzsKxmrRHfZPTVk3oXSPBnQ2+oACDbQRWGAeB0AsvZw263n1nFouQuff+khOCtRbrc6+k+A==} dev: true @@ -3831,10 +3817,6 @@ packages: '@babel/types': 7.23.0 dev: true - /@types/bcryptjs@2.4.6: - resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==} - dev: true - /@types/body-parser@1.19.2: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: @@ -5358,16 +5340,6 @@ packages: /arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - /argon2@0.40.1: - resolution: {integrity: sha512-DjtHDwd7pm12qeWyfihHoM8Bn5vGcgH6sKwgPqwNYroRmxlrzadHEvMyuvQxN/V8YSyRRKD5x6ito09q1e9OyA==} - engines: {node: '>=16.17.0'} - requiresBuild: true - dependencies: - '@phc/format': 1.0.0 - node-addon-api: 7.1.0 - node-gyp-build: 4.8.0 - dev: false - /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -5893,10 +5865,6 @@ packages: tweetnacl: 0.14.5 dev: false - /bcryptjs@2.4.3: - resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} - dev: false - /bin-check@4.1.0: resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==} engines: {node: '>=4'} @@ -13029,11 +12997,6 @@ packages: dev: true optional: true - /node-addon-api@7.1.0: - resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} - engines: {node: ^16 || ^18 || >= 20} - dev: false - /node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -13083,6 +13046,7 @@ packages: /node-gyp-build@4.8.0: resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} hasBin: true + dev: true /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} From ceca260c922f40318279cf2871da3a8f718ae4df Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 14 Apr 2024 14:53:25 +0900 Subject: [PATCH 07/22] refactor (backend): port convert-milliseconds to backend-rs --- packages/backend-rs/index.d.ts | 2 + packages/backend-rs/index.js | 3 +- .../src/misc/format_milliseconds.rs | 46 +++++++++++++++++++ packages/backend-rs/src/misc/mod.rs | 1 + .../backend/src/misc/convert-milliseconds.ts | 17 ------- packages/backend/src/server/api/limiter.ts | 4 +- 6 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 packages/backend-rs/src/misc/format_milliseconds.rs delete mode 100644 packages/backend/src/misc/convert-milliseconds.ts diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index f2830dcac3..d3bb13164a 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -132,6 +132,8 @@ export function isSelfHost(host?: string | undefined | null): boolean export function isSameOrigin(uri: string): boolean export function extractHost(uri: string): string export function toPuny(host: string): string +/** Convert milliseconds to a human readable string */ +export function formatMilliseconds(milliseconds: number): string export function toMastodonId(firefishId: string): string | null export function fromMastodonId(mastodonId: string): string | null export function nyaify(text: string, lang?: string | undefined | null): string diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index af9a293bbb..6fbfe9414d 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, toMastodonId, fromMastodonId, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding +const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, formatMilliseconds, toMastodonId, fromMastodonId, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding module.exports.readServerConfig = readServerConfig module.exports.stringToAcct = stringToAcct @@ -321,6 +321,7 @@ module.exports.isSelfHost = isSelfHost module.exports.isSameOrigin = isSameOrigin module.exports.extractHost = extractHost module.exports.toPuny = toPuny +module.exports.formatMilliseconds = formatMilliseconds module.exports.toMastodonId = toMastodonId module.exports.fromMastodonId = fromMastodonId module.exports.nyaify = nyaify diff --git a/packages/backend-rs/src/misc/format_milliseconds.rs b/packages/backend-rs/src/misc/format_milliseconds.rs new file mode 100644 index 0000000000..dfa8df6f62 --- /dev/null +++ b/packages/backend-rs/src/misc/format_milliseconds.rs @@ -0,0 +1,46 @@ +/// Convert milliseconds to a human readable string +#[crate::export] +pub fn format_milliseconds(milliseconds: u32) -> String { + let mut seconds = milliseconds / 1000; + let mut minutes = seconds / 60; + let mut hours = minutes / 60; + let days = hours / 24; + + seconds %= 60; + minutes %= 60; + hours %= 24; + + let mut buf: Vec = vec![]; + + if days > 0 { + buf.push(format!("{} day(s)", days)); + } + if hours > 0 { + buf.push(format!("{} hour(s)", hours)); + } + if minutes > 0 { + buf.push(format!("{} minute(s)", minutes)); + } + if seconds > 0 { + buf.push(format!("{} second(s)", seconds)); + } + + buf.join(", ") +} + +#[cfg(test)] +mod unit_test { + use super::format_milliseconds; + use pretty_assertions::assert_eq; + + #[test] + fn format_milliseconds_test() { + assert_eq!(format_milliseconds(1000), "1 second(s)"); + assert_eq!(format_milliseconds(1387938), "23 minute(s), 7 second(s)"); + assert_eq!(format_milliseconds(34200457), "9 hour(s), 30 minute(s)"); + assert_eq!( + format_milliseconds(998244353), + "11 day(s), 13 hour(s), 17 minute(s), 24 second(s)" + ); + } +} diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index 6eda4e449e..d5a84e56a1 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -1,6 +1,7 @@ pub mod acct; pub mod check_word_mute; pub mod convert_host; +pub mod format_milliseconds; pub mod mastodon_id; pub mod nyaify; pub mod password; diff --git a/packages/backend/src/misc/convert-milliseconds.ts b/packages/backend/src/misc/convert-milliseconds.ts deleted file mode 100644 index d8c163ffda..0000000000 --- a/packages/backend/src/misc/convert-milliseconds.ts +++ /dev/null @@ -1,17 +0,0 @@ -export function convertMilliseconds(ms: number) { - let seconds = Math.round(ms / 1000); - let minutes = Math.round(seconds / 60); - let hours = Math.round(minutes / 60); - const days = Math.round(hours / 24); - seconds %= 60; - minutes %= 60; - hours %= 24; - - const result = []; - if (days > 0) result.push(`${days} day(s)`); - if (hours > 0) result.push(`${hours} hour(s)`); - if (minutes > 0) result.push(`${minutes} minute(s)`); - if (seconds > 0) result.push(`${seconds} second(s)`); - - return result.join(", "); -} diff --git a/packages/backend/src/server/api/limiter.ts b/packages/backend/src/server/api/limiter.ts index f03f8754cf..d4a9353ade 100644 --- a/packages/backend/src/server/api/limiter.ts +++ b/packages/backend/src/server/api/limiter.ts @@ -2,7 +2,7 @@ import Limiter from "ratelimiter"; import Logger from "@/services/logger.js"; import { redisClient } from "@/db/redis.js"; import type { IEndpointMeta } from "./endpoints.js"; -import { convertMilliseconds } from "@/misc/convert-milliseconds.js"; +import { formatMilliseconds } from "backend-rs"; const logger = new Logger("limiter"); @@ -78,7 +78,7 @@ export const limiter = ( if (info.remaining === 0) { reject({ message: "RATE_LIMIT_EXCEEDED", - remainingTime: convertMilliseconds(info.resetMs - Date.now()), + remainingTime: formatMilliseconds(info.resetMs - Date.now()), }); } else { ok(); From b71da18b032d3cf6a6593e648c9fe9ac04726f29 Mon Sep 17 00:00:00 2001 From: sup39 Date: Sun, 14 Apr 2024 20:16:22 +0900 Subject: [PATCH 08/22] refactor (backend): port fetch-meta to backend-rs Co-authored-by: naskya --- packages/backend-rs/index.d.ts | 13 +++ packages/backend-rs/index.js | 4 +- packages/backend-rs/src/misc/meta.rs | 83 +++++++++++++++++++ packages/backend-rs/src/misc/mod.rs | 1 + packages/backend/src/daemons/server-stats.ts | 4 +- packages/backend/src/misc/fetch-meta.ts | 72 ---------------- .../backend/src/misc/fetch-proxy-account.ts | 4 +- packages/backend/src/misc/reaction-lib.ts | 6 +- .../backend/src/misc/should-block-instance.ts | 6 +- .../backend/src/misc/skipped-instances.ts | 4 +- packages/backend/src/misc/translate.ts | 4 +- .../backend/src/queue/processors/inbox.ts | 4 +- .../src/remote/activitypub/check-fetch.ts | 6 +- .../src/remote/activitypub/models/image.ts | 4 +- .../src/remote/activitypub/resolver.ts | 4 +- packages/backend/src/server/activitypub.ts | 21 +++-- .../src/server/activitypub/featured.ts | 4 +- .../src/server/activitypub/followers.ts | 4 +- .../src/server/activitypub/following.ts | 4 +- .../backend/src/server/activitypub/outbox.ts | 4 +- .../backend/src/server/api/api-handler.ts | 4 +- packages/backend/src/server/api/call.ts | 4 +- .../src/server/api/endpoints/admin/meta.ts | 4 +- .../src/server/api/endpoints/custom-motd.ts | 4 +- .../api/endpoints/custom-splash-icons.ts | 4 +- .../backend/src/server/api/endpoints/drive.ts | 4 +- .../api/endpoints/drive/files/create.ts | 4 +- .../api/endpoints/federation/instances.ts | 6 +- .../server/api/endpoints/hashtags/trend.ts | 4 +- .../server/api/endpoints/i/import-posts.ts | 4 +- .../backend/src/server/api/endpoints/meta.ts | 4 +- .../api/endpoints/notes/global-timeline.ts | 4 +- .../api/endpoints/notes/hybrid-timeline.ts | 4 +- .../api/endpoints/notes/local-timeline.ts | 4 +- .../endpoints/notes/recommended-timeline.ts | 4 +- .../src/server/api/endpoints/pinned-users.ts | 4 +- .../api/endpoints/recommended-instances.ts | 4 +- .../src/server/api/endpoints/server-info.ts | 4 +- .../src/server/api/endpoints/sw/register.ts | 4 +- .../api/endpoints/users/report-abuse.ts | 4 +- .../src/server/api/mastodon/endpoints/meta.ts | 4 +- .../server/api/mastodon/endpoints/status.ts | 7 +- .../backend/src/server/api/private/signup.ts | 5 +- .../api/stream/channels/global-timeline.ts | 5 +- .../api/stream/channels/hybrid-timeline.ts | 5 +- .../api/stream/channels/local-timeline.ts | 5 +- .../stream/channels/recommended-timeline.ts | 7 +- packages/backend/src/server/index.ts | 4 +- packages/backend/src/server/nodeinfo.ts | 4 +- packages/backend/src/server/web/index.ts | 21 +++-- packages/backend/src/server/web/manifest.ts | 4 +- .../backend/src/server/web/url-preview.ts | 4 +- .../backend/src/services/drive/add-file.ts | 10 +-- .../backend/src/services/drive/delete-file.ts | 4 +- .../backend/src/services/push-notification.ts | 4 +- packages/backend/src/services/send-email.ts | 4 +- .../services/validate-email-for-account.ts | 4 +- 57 files changed, 229 insertions(+), 210 deletions(-) create mode 100644 packages/backend-rs/src/misc/meta.rs delete mode 100644 packages/backend/src/misc/fetch-meta.ts diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index d3bb13164a..3770056d8f 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -136,6 +136,19 @@ export function toPuny(host: string): string export function formatMilliseconds(milliseconds: number): string export function toMastodonId(firefishId: string): string | null export function fromMastodonId(mastodonId: string): string | null +export function fetchMeta(useCache: boolean): Promise +export interface PugArgs { + img: string | null + title: string + instanceName: string + desc: string | null + icon: string | null + splashIcon: string | null + themeColor: string | null + randomMotd: string + privateMode: boolean | null +} +export function metaToPugArgs(meta: Meta): PugArgs export function nyaify(text: string, lang?: string | undefined | null): string export function hashPassword(password: string): string export function verifyPassword(password: string, hash: string): boolean diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 6fbfe9414d..363c858e4a 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, formatMilliseconds, toMastodonId, fromMastodonId, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding +const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding module.exports.readServerConfig = readServerConfig module.exports.stringToAcct = stringToAcct @@ -324,6 +324,8 @@ module.exports.toPuny = toPuny module.exports.formatMilliseconds = formatMilliseconds module.exports.toMastodonId = toMastodonId module.exports.fromMastodonId = fromMastodonId +module.exports.fetchMeta = fetchMeta +module.exports.metaToPugArgs = metaToPugArgs module.exports.nyaify = nyaify module.exports.hashPassword = hashPassword module.exports.verifyPassword = verifyPassword diff --git a/packages/backend-rs/src/misc/meta.rs b/packages/backend-rs/src/misc/meta.rs new file mode 100644 index 0000000000..5aed617038 --- /dev/null +++ b/packages/backend-rs/src/misc/meta.rs @@ -0,0 +1,83 @@ +use crate::database::db_conn; +use crate::model::entity::meta; +use rand::prelude::*; +use sea_orm::{prelude::*, ActiveValue}; +use std::sync::Mutex; + +type Meta = meta::Model; + +static CACHE: Mutex> = Mutex::new(None); +fn update_cache(meta: &Meta) { + let _ = CACHE.lock().map(|mut cache| *cache = Some(meta.clone())); +} + +#[crate::export] +pub async fn fetch_meta(use_cache: bool) -> Result { + // try using cache + if use_cache { + if let Some(cache) = CACHE.lock().ok().and_then(|cache| cache.clone()) { + return Ok(cache); + } + } + + // try fetching from db + let db = db_conn().await?; + let meta = meta::Entity::find().one(db).await?; + if let Some(meta) = meta { + update_cache(&meta); + return Ok(meta); + } + + // create a new meta object and insert into db + let meta = meta::Entity::insert(meta::ActiveModel { + id: ActiveValue::Set("x".to_owned()), + ..Default::default() + }) + .exec_with_returning(db) + .await?; + update_cache(&meta); + Ok(meta) +} + +#[crate::export(object)] +pub struct PugArgs { + pub img: Option, + pub title: String, + pub instance_name: String, + pub desc: Option, + pub icon: Option, + pub splash_icon: Option, + pub theme_color: Option, + pub random_motd: String, + pub private_mode: Option, +} + +#[crate::export] +pub fn meta_to_pug_args(meta: Meta) -> PugArgs { + let mut rng = rand::thread_rng(); + + let splash_icon = meta + .custom_splash_icons + .choose(&mut rng) + .map(|s| s.to_owned()) + .or_else(|| meta.icon_url.to_owned()); + + let random_motd = meta + .custom_motd + .choose(&mut rng) + .map(|s| s.to_owned()) + .unwrap_or_else(|| "Loading...".to_owned()); + + let name = meta.name.unwrap_or_else(|| "Firefish".to_owned()); + PugArgs { + img: meta.banner_url, + title: name.clone(), + instance_name: name.clone(), + desc: meta.description, + icon: meta.icon_url, + splash_icon, + theme_color: meta.theme_color, + random_motd, + private_mode: meta.private_mode, + } +} diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index d5a84e56a1..7f99a67324 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -3,5 +3,6 @@ pub mod check_word_mute; pub mod convert_host; pub mod format_milliseconds; pub mod mastodon_id; +pub mod meta; pub mod nyaify; pub mod password; diff --git a/packages/backend/src/daemons/server-stats.ts b/packages/backend/src/daemons/server-stats.ts index 58a9b1491b..92265ecba7 100644 --- a/packages/backend/src/daemons/server-stats.ts +++ b/packages/backend/src/daemons/server-stats.ts @@ -1,7 +1,7 @@ import si from "systeminformation"; import Xev from "xev"; import * as osUtils from "os-utils"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; const ev = new Xev(); @@ -20,7 +20,7 @@ export default function () { ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length || 50)); }); - fetchMeta().then((meta) => { + fetchMeta(true).then((meta) => { if (!meta.enableServerMachineStats) return; }); diff --git a/packages/backend/src/misc/fetch-meta.ts b/packages/backend/src/misc/fetch-meta.ts deleted file mode 100644 index fdc978b5a3..0000000000 --- a/packages/backend/src/misc/fetch-meta.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { db } from "@/db/postgre.js"; -import { Meta } from "@/models/entities/meta.js"; - -let cache: Meta; - -export function metaToPugArgs(meta: Meta): object { - let motd = ["Loading..."]; - if (meta.customMotd.length > 0) { - motd = meta.customMotd; - } - let splashIconUrl = meta.iconUrl; - if (meta.customSplashIcons.length > 0) { - splashIconUrl = - meta.customSplashIcons[ - Math.floor(Math.random() * meta.customSplashIcons.length) - ]; - } - - return { - img: meta.bannerUrl, - title: meta.name || "Firefish", - instanceName: meta.name || "Firefish", - desc: meta.description, - icon: meta.iconUrl, - splashIcon: splashIconUrl, - themeColor: meta.themeColor, - randomMOTD: motd[Math.floor(Math.random() * motd.length)], - privateMode: meta.privateMode, - }; -} - -export async function fetchMeta(noCache = false): Promise { - if (!noCache && cache) return cache; - - return await db.transaction(async (transactionalEntityManager) => { - // New IDs are prioritized because multiple records may have been created due to past bugs. - const metas = await transactionalEntityManager.find(Meta, { - order: { - id: "DESC", - }, - }); - - const meta = metas[0]; - - if (meta) { - cache = meta; - return meta; - } else { - // If fetchMeta is called at the same time when meta is empty, this part may be called at the same time, so use fail-safe upsert. - const saved = await transactionalEntityManager - .upsert( - Meta, - { - id: "x", - }, - ["id"], - ) - .then((x) => - transactionalEntityManager.findOneByOrFail(Meta, x.identifiers[0]), - ); - - cache = saved; - return saved; - } - }); -} - -setInterval(() => { - fetchMeta(true).then((meta) => { - cache = meta; - }); -}, 1000 * 10); diff --git a/packages/backend/src/misc/fetch-proxy-account.ts b/packages/backend/src/misc/fetch-proxy-account.ts index a277db6fb9..8d015da25d 100644 --- a/packages/backend/src/misc/fetch-proxy-account.ts +++ b/packages/backend/src/misc/fetch-proxy-account.ts @@ -1,9 +1,9 @@ -import { fetchMeta } from "./fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { ILocalUser } from "@/models/entities/user.js"; import { Users } from "@/models/index.js"; export async function fetchProxyAccount(): Promise { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.proxyAccountId == null) return null; return (await Users.findOneByOrFail({ id: meta.proxyAccountId, diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts index 4304d3b9e1..691d9743c8 100644 --- a/packages/backend/src/misc/reaction-lib.ts +++ b/packages/backend/src/misc/reaction-lib.ts @@ -1,5 +1,5 @@ import { emojiRegex } from "./emoji-regex.js"; -import { fetchMeta } from "./fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Emojis } from "@/models/index.js"; import { toPuny } from "backend-rs"; import { IsNull } from "typeorm"; @@ -21,7 +21,7 @@ export async function toDbReaction( reaction?: string | null, reacterHost?: string | null, ): Promise { - if (!reaction) return (await fetchMeta()).defaultReaction; + if (!reaction) return (await fetchMeta(true)).defaultReaction; reacterHost = reacterHost == null ? null : toPuny(reacterHost); @@ -45,7 +45,7 @@ export async function toDbReaction( if (emoji) return reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; } - return (await fetchMeta()).defaultReaction; + return (await fetchMeta(true)).defaultReaction; } type DecodedReaction = { diff --git a/packages/backend/src/misc/should-block-instance.ts b/packages/backend/src/misc/should-block-instance.ts index 35ed307931..465be41f2a 100644 --- a/packages/backend/src/misc/should-block-instance.ts +++ b/packages/backend/src/misc/should-block-instance.ts @@ -1,4 +1,4 @@ -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { Instance } from "@/models/entities/instance.js"; import type { Meta } from "@/models/entities/meta.js"; @@ -13,7 +13,7 @@ export async function shouldBlockInstance( host: Instance["host"], meta?: Meta, ): Promise { - const { blockedHosts } = meta ?? (await fetchMeta()); + const { blockedHosts } = meta ?? (await fetchMeta(true)); return blockedHosts.some( (blockedHost) => host === blockedHost || host.endsWith(`.${blockedHost}`), ); @@ -30,7 +30,7 @@ export async function shouldSilenceInstance( host: Instance["host"], meta?: Meta, ): Promise { - const { silencedHosts } = meta ?? (await fetchMeta()); + const { silencedHosts } = meta ?? (await fetchMeta(true)); return silencedHosts.some( (silencedHost) => host === silencedHost || host.endsWith(`.${silencedHost}`), diff --git a/packages/backend/src/misc/skipped-instances.ts b/packages/backend/src/misc/skipped-instances.ts index 785393022a..14b26a3032 100644 --- a/packages/backend/src/misc/skipped-instances.ts +++ b/packages/backend/src/misc/skipped-instances.ts @@ -1,5 +1,5 @@ import { Brackets } from "typeorm"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Instances } from "@/models/index.js"; import type { Instance } from "@/models/entities/instance.js"; import { DAY } from "@/const.js"; @@ -19,7 +19,7 @@ export async function skippedInstances( hosts: Instance["host"][], ): Promise { // first check for blocked instances since that info may already be in memory - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const shouldSkip = await Promise.all( hosts.map((host) => shouldBlockInstance(host, meta)), ); diff --git a/packages/backend/src/misc/translate.ts b/packages/backend/src/misc/translate.ts index e622171ec6..3395ce93be 100644 --- a/packages/backend/src/misc/translate.ts +++ b/packages/backend/src/misc/translate.ts @@ -1,7 +1,7 @@ import fetch from "node-fetch"; import { Converter } from "opencc-js"; import { getAgentByUrl } from "@/misc/fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { PostLanguage } from "@/misc/langmap"; import * as deepl from "deepl-node"; @@ -26,7 +26,7 @@ export async function translate( from: PostLanguage | null, to: PostLanguage, ) { - const instance = await fetchMeta(); + const instance = await fetchMeta(true); if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) { throw Error("No translator is set up on this server."); diff --git a/packages/backend/src/queue/processors/inbox.ts b/packages/backend/src/queue/processors/inbox.ts index 46f9939a41..0ea72306b6 100644 --- a/packages/backend/src/queue/processors/inbox.ts +++ b/packages/backend/src/queue/processors/inbox.ts @@ -5,7 +5,7 @@ import perform from "@/remote/activitypub/perform.js"; import Logger from "@/services/logger.js"; import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js"; import { Instances } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { toPuny, extractHost } from "backend-rs"; import { getApId } from "@/remote/activitypub/type.js"; import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; @@ -41,7 +41,7 @@ export default async (job: Bull.Job): Promise => { const host = toPuny(new URL(signature.keyId).hostname); // interrupt if blocked - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (await shouldBlockInstance(host, meta)) { return `Blocked request: ${host}`; } diff --git a/packages/backend/src/remote/activitypub/check-fetch.ts b/packages/backend/src/remote/activitypub/check-fetch.ts index c0d40278ee..12ea63a931 100644 --- a/packages/backend/src/remote/activitypub/check-fetch.ts +++ b/packages/backend/src/remote/activitypub/check-fetch.ts @@ -1,7 +1,7 @@ import { URL } from "url"; import httpSignature, { IParsedSignature } from "@peertube/http-signature"; import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { toPuny } from "backend-rs"; import DbResolver from "@/remote/activitypub/db-resolver.js"; import { getApId } from "@/remote/activitypub/type.js"; @@ -12,7 +12,7 @@ import type { UserPublickey } from "@/models/entities/user-publickey.js"; import { verify } from "node:crypto"; export async function hasSignature(req: IncomingMessage): Promise { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const required = meta.secureMode || meta.privateMode; try { @@ -27,7 +27,7 @@ export async function hasSignature(req: IncomingMessage): Promise { } export async function checkFetch(req: IncomingMessage): Promise { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { if (req.headers.host !== config.host) return 400; diff --git a/packages/backend/src/remote/activitypub/models/image.ts b/packages/backend/src/remote/activitypub/models/image.ts index 2cf0c6c152..e2072a963a 100644 --- a/packages/backend/src/remote/activitypub/models/image.ts +++ b/packages/backend/src/remote/activitypub/models/image.ts @@ -1,7 +1,7 @@ import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; import type { CacheableRemoteUser } from "@/models/entities/user.js"; import Resolver from "../resolver.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { apLogger } from "../logger.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import { DriveFiles } from "@/models/index.js"; @@ -34,7 +34,7 @@ export async function createImage( logger.info(`Creating the Image: ${image.url}`); - const instance = await fetchMeta(); + const instance = await fetchMeta(true); let file = await uploadFromUrl({ url: image.url, diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts index 973f12cdc2..79b7962b72 100644 --- a/packages/backend/src/remote/activitypub/resolver.ts +++ b/packages/backend/src/remote/activitypub/resolver.ts @@ -1,7 +1,7 @@ import config from "@/config/index.js"; import type { ILocalUser } from "@/models/entities/user.js"; import { getInstanceActor } from "@/services/instance-actor.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { extractHost, isSelfHost } from "backend-rs"; import { apGet } from "./request.js"; import type { IObject, ICollection, IOrderedCollection } from "./type.js"; @@ -100,7 +100,7 @@ export default class Resolver { return await this.resolveLocal(value); } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (await shouldBlockInstance(host, meta)) { throw new Error("Instance is blocked"); } diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index 7e5fb5a281..00c8a6babe 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -9,7 +9,7 @@ import renderKey from "@/remote/activitypub/renderer/key.js"; import { renderPerson } from "@/remote/activitypub/renderer/person.js"; import renderEmoji from "@/remote/activitypub/renderer/emoji.js"; import { inbox as processInbox } from "@/queue/index.js"; -import { isSelfHost } from "backend-rs"; +import { fetchMeta, isSelfHost } from "backend-rs"; import { Notes, Users, @@ -25,7 +25,6 @@ import { getSignatureUser, } from "@/remote/activitypub/check-fetch.js"; import { getInstanceActor } from "@/services/instance-actor.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; import renderFollow from "@/remote/activitypub/renderer/follow.js"; import Featured from "./activitypub/featured.js"; import Following from "./activitypub/following.js"; @@ -238,7 +237,7 @@ router.get("/notes/:note", async (ctx, next) => { ctx.body = renderActivity(await renderNote(note, false)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -268,7 +267,7 @@ router.get("/notes/:note/activity", async (ctx) => { } ctx.body = renderActivity(await packActivity(note)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -323,7 +322,7 @@ router.get("/users/:user/publickey", async (ctx) => { if (Users.isLocalUser(user)) { ctx.body = renderActivity(renderKey(user, keypair)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -343,7 +342,7 @@ async function userInfo(ctx: Router.RouterContext, user: User | null) { } ctx.body = renderActivity(await renderPerson(user as ILocalUser)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -426,8 +425,8 @@ router.get("/emojis/:emoji", async (ctx) => { return; } - ctx.body = renderActivity(await renderEmoji(emoji)); - const meta = await fetchMeta(); + ctx.body = renderActivity(renderEmoji(emoji)); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -459,7 +458,7 @@ router.get("/likes/:like", async (ctx) => { } ctx.body = renderActivity(await renderLike(reaction, note)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -497,7 +496,7 @@ router.get( } ctx.body = renderActivity(renderFollow(follower, followee)); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { @@ -540,7 +539,7 @@ router.get("/follows/:followRequestId", async (ctx: Router.RouterContext) => { return; } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/activitypub/featured.ts b/packages/backend/src/server/activitypub/featured.ts index 464a7f769d..e7ea6f238e 100644 --- a/packages/backend/src/server/activitypub/featured.ts +++ b/packages/backend/src/server/activitypub/featured.ts @@ -5,7 +5,7 @@ import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-colle import renderNote from "@/remote/activitypub/renderer/note.js"; import { Users, Notes, UserNotePinings } from "@/models/index.js"; import { checkFetch } from "@/remote/activitypub/check-fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { setResponseType } from "../activitypub.js"; import type Router from "@koa/router"; @@ -57,7 +57,7 @@ export default async (ctx: Router.RouterContext) => { ctx.body = renderActivity(rendered); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/activitypub/followers.ts b/packages/backend/src/server/activitypub/followers.ts index 3c9e5fa201..576a672d6d 100644 --- a/packages/backend/src/server/activitypub/followers.ts +++ b/packages/backend/src/server/activitypub/followers.ts @@ -8,7 +8,7 @@ import renderFollowUser from "@/remote/activitypub/renderer/follow-user.js"; import { Users, Followings, UserProfiles } from "@/models/index.js"; import type { Following } from "@/models/entities/following.js"; import { checkFetch } from "@/remote/activitypub/check-fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { setResponseType } from "../activitypub.js"; import type { FindOptionsWhere } from "typeorm"; import type Router from "@koa/router"; @@ -110,7 +110,7 @@ export default async (ctx: Router.RouterContext) => { ctx.body = renderActivity(rendered); setResponseType(ctx); } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/activitypub/following.ts b/packages/backend/src/server/activitypub/following.ts index cfbe985911..76b4e79716 100644 --- a/packages/backend/src/server/activitypub/following.ts +++ b/packages/backend/src/server/activitypub/following.ts @@ -8,7 +8,7 @@ import renderFollowUser from "@/remote/activitypub/renderer/follow-user.js"; import { Users, Followings, UserProfiles } from "@/models/index.js"; import type { Following } from "@/models/entities/following.js"; import { checkFetch } from "@/remote/activitypub/check-fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { setResponseType } from "../activitypub.js"; import type { FindOptionsWhere } from "typeorm"; import type Router from "@koa/router"; @@ -110,7 +110,7 @@ export default async (ctx: Router.RouterContext) => { ctx.body = renderActivity(rendered); setResponseType(ctx); } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index 53aa6f4ad5..305102cf12 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -11,7 +11,7 @@ import * as url from "@/prelude/url.js"; import { Users, Notes } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; import { checkFetch } from "@/remote/activitypub/check-fetch.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { makePaginationQuery } from "../api/common/make-pagination-query.js"; import { setResponseType } from "../activitypub.js"; import type Router from "@koa/router"; @@ -117,7 +117,7 @@ export default async (ctx: Router.RouterContext) => { setResponseType(ctx); } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.secureMode || meta.privateMode) { ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); } else { diff --git a/packages/backend/src/server/api/api-handler.ts b/packages/backend/src/server/api/api-handler.ts index 620b754f30..5e65636427 100644 --- a/packages/backend/src/server/api/api-handler.ts +++ b/packages/backend/src/server/api/api-handler.ts @@ -2,7 +2,7 @@ import type Koa from "koa"; import type { User } from "@/models/entities/user.js"; import { UserIps } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { IEndpoint } from "./endpoints.js"; import authenticate, { AuthenticationError } from "./authenticate.js"; import call from "./call.js"; @@ -84,7 +84,7 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => // Log IP if (user) { - fetchMeta().then((meta) => { + fetchMeta(true).then((meta) => { if (!meta.enableIpLogging) return; const ip = ctx.ip; const ips = userIpHistories.get(user.id); diff --git a/packages/backend/src/server/api/call.ts b/packages/backend/src/server/api/call.ts index 2faef7b0e8..3107156a9b 100644 --- a/packages/backend/src/server/api/call.ts +++ b/packages/backend/src/server/api/call.ts @@ -10,7 +10,7 @@ import endpoints from "./endpoints.js"; import compatibility from "./compatibility.js"; import { ApiError } from "./error.js"; import { apiLogger } from "./logger.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; const accessDenied = { message: "Access denied.", @@ -117,7 +117,7 @@ export default async ( } // private mode - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( meta.privateMode && ep.meta.requireCredentialPrivateMode && diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index a22fbab8f1..c7731c6c81 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -1,5 +1,5 @@ import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js"; import define from "@/server/api/define.js"; @@ -466,7 +466,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); return { maintainerName: instance.maintainerName, diff --git a/packages/backend/src/server/api/endpoints/custom-motd.ts b/packages/backend/src/server/api/endpoints/custom-motd.ts index 2939355b94..ac1012258d 100644 --- a/packages/backend/src/server/api/endpoints/custom-motd.ts +++ b/packages/backend/src/server/api/endpoints/custom-motd.ts @@ -1,5 +1,5 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import define from "@/server/api/define.js"; export const meta = { @@ -27,7 +27,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const motd = await Promise.all(meta.customMotd.map((x) => x)); return motd; }); diff --git a/packages/backend/src/server/api/endpoints/custom-splash-icons.ts b/packages/backend/src/server/api/endpoints/custom-splash-icons.ts index f63a1b9600..4eb35aa3e5 100644 --- a/packages/backend/src/server/api/endpoints/custom-splash-icons.ts +++ b/packages/backend/src/server/api/endpoints/custom-splash-icons.ts @@ -1,5 +1,5 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import define from "@/server/api/define.js"; export const meta = { @@ -27,7 +27,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const icons = await Promise.all(meta.customSplashIcons.map((x) => x)); return icons; }); diff --git a/packages/backend/src/server/api/endpoints/drive.ts b/packages/backend/src/server/api/endpoints/drive.ts index 164e7b8f93..c04f219a9b 100644 --- a/packages/backend/src/server/api/endpoints/drive.ts +++ b/packages/backend/src/server/api/endpoints/drive.ts @@ -1,4 +1,4 @@ -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { DriveFiles } from "@/models/index.js"; import define from "@/server/api/define.js"; @@ -35,7 +35,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); // Calculate drive usage const usage = await DriveFiles.calcDriveUsageOf(user.id); diff --git a/packages/backend/src/server/api/endpoints/drive/files/create.ts b/packages/backend/src/server/api/endpoints/drive/files/create.ts index a3e3fafa2f..44e388a9bd 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/create.ts @@ -2,7 +2,7 @@ import { addFile } from "@/services/drive/add-file.js"; import { DriveFiles } from "@/models/index.js"; import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js"; import { IdentifiableError } from "@/misc/identifiable-error.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { MINUTE } from "@/const.js"; import define from "@/server/api/define.js"; import { apiLogger } from "@/server/api/logger.js"; @@ -96,7 +96,7 @@ export default define( name = null; } - const instanceMeta = await fetchMeta(); + const instanceMeta = await fetchMeta(true); try { // Create file diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 27a6dabb49..8c021d0e65 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Instances } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; export const meta = { @@ -101,7 +101,7 @@ export default define(meta, paramDef, async (ps, me) => { } if (typeof ps.blocked === "boolean") { - const meta = await fetchMeta(true); + const meta = await fetchMeta(false); if (ps.blocked) { if (meta.blockedHosts.length === 0) { return []; @@ -117,7 +117,7 @@ export default define(meta, paramDef, async (ps, me) => { } if (typeof ps.silenced === "boolean") { - const meta = await fetchMeta(true); + const meta = await fetchMeta(false); if (ps.silenced) { if (meta.silencedHosts.length === 0) { return []; diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index fe8bba95fd..9d31445a42 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -1,6 +1,6 @@ import { Brackets } from "typeorm"; import define from "@/server/api/define.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Notes } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; import { safeForSql } from "@/misc/safe-for-sql.js"; @@ -67,7 +67,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); const hiddenTags = instance.hiddenTags.map((t) => normalizeForSearch(t)); const now = new Date(); // 5分単位で丸めた現在日時 diff --git a/packages/backend/src/server/api/endpoints/i/import-posts.ts b/packages/backend/src/server/api/endpoints/i/import-posts.ts index b8b52be98f..225306ebc5 100644 --- a/packages/backend/src/server/api/endpoints/i/import-posts.ts +++ b/packages/backend/src/server/api/endpoints/i/import-posts.ts @@ -3,7 +3,7 @@ import { createImportPostsJob } from "@/queue/index.js"; import { ApiError } from "@/server/api/error.js"; import { DriveFiles } from "@/models/index.js"; import { DAY } from "@/const.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; export const meta = { secure: true, @@ -45,7 +45,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOneBy({ id: ps.fileId }); - const instanceMeta = await fetchMeta(); + const instanceMeta = await fetchMeta(true); if (instanceMeta.experimentalFeatures?.postImports === false) throw new ApiError(meta.errors.importsDisabled); diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 2a674b52c3..31677ee2ef 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -1,7 +1,7 @@ import JSON5 from "json5"; import { IsNull, MoreThan } from "typeorm"; import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Ads, Emojis, Users } from "@/models/index.js"; import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js"; import define from "@/server/api/define.js"; @@ -398,7 +398,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, me) => { - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); const emojis = await Emojis.find({ where: { diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index 142b380f71..476375dc0b 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -1,4 +1,4 @@ -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Notes } from "@/models/index.js"; import { activeUsersChart } from "@/services/chart/index.js"; import define from "@/server/api/define.js"; @@ -64,7 +64,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const m = await fetchMeta(); + const m = await fetchMeta(true); if (m.disableGlobalTimeline) { if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.gtlDisabled); diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index c9800f2e1f..e6ab910040 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -1,5 +1,5 @@ import { Brackets } from "typeorm"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Followings, Notes } from "@/models/index.js"; import { activeUsersChart } from "@/services/chart/index.js"; import define from "@/server/api/define.js"; @@ -71,7 +71,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const m = await fetchMeta(); + const m = await fetchMeta(true); if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { throw new ApiError(meta.errors.stlDisabled); } diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index b9cb68c2a0..2a99c1236c 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -1,5 +1,5 @@ import { Brackets } from "typeorm"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Notes } from "@/models/index.js"; import { activeUsersChart } from "@/services/chart/index.js"; import define from "@/server/api/define.js"; @@ -74,7 +74,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const m = await fetchMeta(); + const m = await fetchMeta(true); if (m.disableLocalTimeline) { if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.ltlDisabled); diff --git a/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts b/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts index f71822f926..073a8f8569 100644 --- a/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/recommended-timeline.ts @@ -1,5 +1,5 @@ import { Brackets } from "typeorm"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Notes } from "@/models/index.js"; import { activeUsersChart } from "@/services/chart/index.js"; import define from "@/server/api/define.js"; @@ -74,7 +74,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const m = await fetchMeta(); + const m = await fetchMeta(true); if (m.disableRecommendedTimeline) { if (user == null || !(user.isAdmin || user.isModerator)) { throw new ApiError(meta.errors.rtlDisabled); diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index 6d6519e47b..325b54f350 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -1,6 +1,6 @@ import { IsNull } from "typeorm"; import { Users } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { stringToAcct } from "backend-rs"; import type { User } from "@/models/entities/user.js"; import define from "@/server/api/define.js"; @@ -31,7 +31,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, me) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const users = await Promise.all( meta.pinnedUsers diff --git a/packages/backend/src/server/api/endpoints/recommended-instances.ts b/packages/backend/src/server/api/endpoints/recommended-instances.ts index b235678428..5c5e267b2e 100644 --- a/packages/backend/src/server/api/endpoints/recommended-instances.ts +++ b/packages/backend/src/server/api/endpoints/recommended-instances.ts @@ -1,5 +1,5 @@ // import { IsNull } from 'typeorm'; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import define from "@/server/api/define.js"; export const meta = { @@ -27,7 +27,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async () => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const instances = await Promise.all(meta.recommendedInstances.map((x) => x)); return instances; }); diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index d3b6a08074..1a1ecad688 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -1,7 +1,7 @@ import * as os from "node:os"; import si from "systeminformation"; import define from "@/server/api/define.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; export const meta = { requireCredential: false, @@ -30,7 +30,7 @@ export default define(meta, paramDef, async () => { } } - const instanceMeta = await fetchMeta(); + const instanceMeta = await fetchMeta(true); if (!instanceMeta.enableServerMachineStats) { return { machine: "Not specified", diff --git a/packages/backend/src/server/api/endpoints/sw/register.ts b/packages/backend/src/server/api/endpoints/sw/register.ts index 528d3106e0..69b3f6779b 100644 --- a/packages/backend/src/server/api/endpoints/sw/register.ts +++ b/packages/backend/src/server/api/endpoints/sw/register.ts @@ -1,4 +1,4 @@ -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { genId } from "backend-rs"; import { SwSubscriptions } from "@/models/index.js"; import define from "@/server/api/define.js"; @@ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, me) => { publickey: ps.publickey, }); - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); // if already subscribed if (subscription != null) { diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index 1b43762cb6..fda4aa0bb8 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -4,7 +4,7 @@ import { publishAdminStream } from "@/services/stream.js"; import { AbuseUserReports, UserProfiles, Users } from "@/models/index.js"; import { genId } from "backend-rs"; import { sendEmail } from "@/services/send-email.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { getUser } from "@/server/api/common/getters.js"; import { ApiError } from "@/server/api/error.js"; import define from "@/server/api/define.js"; @@ -86,7 +86,7 @@ export default define(meta, paramDef, async (ps, me) => { ], }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); for (const moderator of moderators) { publishAdminStream(moderator.id, "newAbuseUserReport", { id: report.id, diff --git a/packages/backend/src/server/api/mastodon/endpoints/meta.ts b/packages/backend/src/server/api/mastodon/endpoints/meta.ts index fbad7d5ef4..5c304929a1 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/meta.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/meta.ts @@ -1,6 +1,6 @@ import { Entity } from "megalodon"; import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Users, Notes } from "@/models/index.js"; import { IsNull } from "typeorm"; import { MAX_NOTE_TEXT_LENGTH, FILE_TYPE_BROWSERSAFE } from "@/const.js"; @@ -10,7 +10,7 @@ export async function getInstance( contact: Entity.Account, ) { const [meta, totalUsers, totalStatuses] = await Promise.all([ - fetchMeta(), + fetchMeta(true), Users.count({ where: { host: IsNull() } }), Notes.count({ where: { userHost: IsNull() } }), ]); diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index 5e6c0edaae..5286c90fac 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -4,14 +4,13 @@ import { emojiRegexAtStartToEnd } from "@/misc/emoji-regex.js"; import querystring from "node:querystring"; import qs from "qs"; import { convertTimelinesArgsId, limitToInt } from "./timeline.js"; -import { fromMastodonId } from "backend-rs"; +import { fetchMeta, fromMastodonId } from "backend-rs"; import { convertAccount, convertAttachment, convertPoll, convertStatus, } from "../converters.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; import { apiLogger } from "@/server/api/logger.js"; import { inspect } from "node:util"; @@ -213,7 +212,7 @@ export function apiStatusMastodon(router: Router): void { router.post<{ Params: { id: string } }>( "/v1/statuses/:id/favourite", async (ctx) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); @@ -235,7 +234,7 @@ export function apiStatusMastodon(router: Router): void { router.post<{ Params: { id: string } }>( "/v1/statuses/:id/unfavourite", async (ctx) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts index 64b5c57337..5af5d65b50 100644 --- a/packages/backend/src/server/api/private/signup.ts +++ b/packages/backend/src/server/api/private/signup.ts @@ -1,18 +1,17 @@ import type Koa from "koa"; import rndstr from "rndstr"; -import { fetchMeta } from "@/misc/fetch-meta.js"; import { verifyHcaptcha, verifyRecaptcha } from "@/misc/captcha.js"; import { Users, RegistrationTickets, UserPendings } from "@/models/index.js"; import { signup } from "@/server/api/common/signup.js"; import config from "@/config/index.js"; import { sendEmail } from "@/services/send-email.js"; -import { genId, hashPassword } from "backend-rs"; +import { fetchMeta, genId, hashPassword } from "backend-rs"; import { validateEmailForAccount } from "@/services/validate-email-for-account.js"; export default async (ctx: Koa.Context) => { const body = ctx.request.body; - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); // Verify *Captcha // ただしテスト時はこの機構は障害となるため無効にする diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index 97295af57a..1760d5abf7 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -1,6 +1,5 @@ import Channel from "../channel.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { checkWordMute } from "backend-rs"; +import { checkWordMute, fetchMeta } from "backend-rs"; import { isInstanceMuted } from "@/misc/is-instance-muted.js"; import { isUserRelated } from "@/misc/is-user-related.js"; import type { Packed } from "@/misc/schema.js"; @@ -17,7 +16,7 @@ export default class extends Channel { } public async init(params: any) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.disableGlobalTimeline) { if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) return; diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 9052e7c2a5..5100a48efd 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -1,6 +1,5 @@ import Channel from "../channel.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { checkWordMute } from "backend-rs"; +import { checkWordMute, fetchMeta } from "backend-rs"; import { isUserRelated } from "@/misc/is-user-related.js"; import { isInstanceMuted } from "@/misc/is-instance-muted.js"; import type { Packed } from "@/misc/schema.js"; @@ -17,7 +16,7 @@ export default class extends Channel { } public async init(params: any) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( meta.disableLocalTimeline && !this.user!.isAdmin && diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index bd31c94f9d..2c9a38d677 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -1,6 +1,5 @@ import Channel from "../channel.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { checkWordMute } from "backend-rs"; +import { checkWordMute, fetchMeta } from "backend-rs"; import { isUserRelated } from "@/misc/is-user-related.js"; import type { Packed } from "@/misc/schema.js"; @@ -16,7 +15,7 @@ export default class extends Channel { } public async init(params: any) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.disableLocalTimeline) { if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) return; diff --git a/packages/backend/src/server/api/stream/channels/recommended-timeline.ts b/packages/backend/src/server/api/stream/channels/recommended-timeline.ts index 26c3cbfc68..5d0d6fc602 100644 --- a/packages/backend/src/server/api/stream/channels/recommended-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/recommended-timeline.ts @@ -1,6 +1,5 @@ import Channel from "../channel.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { checkWordMute } from "backend-rs"; +import { checkWordMute, fetchMeta } from "backend-rs"; import { isUserRelated } from "@/misc/is-user-related.js"; import { isInstanceMuted } from "@/misc/is-instance-muted.js"; import type { Packed } from "@/misc/schema.js"; @@ -17,7 +16,7 @@ export default class extends Channel { } public async init(params: any) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( meta.disableRecommendedTimeline && !this.user!.isAdmin && @@ -37,7 +36,7 @@ export default class extends Channel { // チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または // チャンネルの投稿ではなく、全体公開のローカルの投稿 または // フォローしているチャンネルの投稿 の場合だけ - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( !( note.user.host != null && diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 2a6dfdf674..6cf837b4ed 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -16,7 +16,7 @@ import { IsNull } from "typeorm"; import config from "@/config/index.js"; import Logger from "@/services/logger.js"; import { Users } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { genIdenticon } from "@/misc/gen-identicon.js"; import { createTemp } from "@/misc/create-temp.js"; import { stringToAcct } from "backend-rs"; @@ -126,7 +126,7 @@ router.get("/avatar/@:acct", async (ctx) => { }); router.get("/identicon/:x", async (ctx) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.enableIdenticonGeneration) { const [temp, cleanup] = await createTemp(); await genIdenticon(ctx.params.x, fs.createWriteStream(temp)); diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts index 1cb8eb1eaf..7359878b19 100644 --- a/packages/backend/src/server/nodeinfo.ts +++ b/packages/backend/src/server/nodeinfo.ts @@ -1,6 +1,6 @@ import Router from "@koa/router"; import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { Users, Notes } from "@/models/index.js"; import { IsNull, MoreThan } from "typeorm"; import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js"; @@ -27,7 +27,7 @@ const nodeinfo2 = async () => { const now = Date.now(); const [meta, total, activeHalfyear, activeMonth, localPosts] = await Promise.all([ - fetchMeta(true), + fetchMeta(false), Users.count({ where: { host: IsNull() } }), Users.count({ where: { diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index bb17cd279a..6473073370 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -10,13 +10,12 @@ import Router from "@koa/router"; import send from "koa-send"; import favicon from "koa-favicon"; import views from "@ladjs/koa-views"; -import sharp from "sharp"; import { createBullBoard } from "@bull-board/api"; import { BullAdapter } from "@bull-board/api/bullAdapter.js"; import { KoaAdapter } from "@bull-board/koa"; import { In, IsNull } from "typeorm"; -import { fetchMeta, metaToPugArgs } from "@/misc/fetch-meta.js"; +import { fetchMeta, metaToPugArgs } from "backend-rs"; import config from "@/config/index.js"; import { Users, @@ -326,7 +325,7 @@ const getFeed = async ( noRenotes: string, noReplies: string, ) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.privateMode) { return; } @@ -475,7 +474,7 @@ const userPage: Router.Middleware = async (ctx, next) => { } const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const me = profile.fields ? profile.fields .filter((filed) => filed.value?.match(/^https?:/)) @@ -524,7 +523,7 @@ router.get("/notes/:note", async (ctx, next) => { const profile = await UserProfiles.findOneByOrFail({ userId: note.userId, }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("note", { ...metaToPugArgs(meta), note: _note, @@ -558,7 +557,7 @@ router.get("/posts/:note", async (ctx, next) => { if (note) { const _note = await Notes.pack(note); const profile = await UserProfiles.findOneByOrFail({ userId: note.userId }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("note", { ...metaToPugArgs(meta), note: _note, @@ -596,7 +595,7 @@ router.get("/@:user/pages/:page", async (ctx, next) => { if (page) { const _page = await Pages.pack(page); const profile = await UserProfiles.findOneByOrFail({ userId: page.userId }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("page", { ...metaToPugArgs(meta), page: _page, @@ -628,7 +627,7 @@ router.get("/clips/:clip", async (ctx, next) => { if (clip) { const _clip = await Clips.pack(clip); const profile = await UserProfiles.findOneByOrFail({ userId: clip.userId }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("clip", { ...metaToPugArgs(meta), clip: _clip, @@ -653,7 +652,7 @@ router.get("/gallery/:post", async (ctx, next) => { if (post) { const _post = await GalleryPosts.pack(post); const profile = await UserProfiles.findOneByOrFail({ userId: post.userId }); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("gallery-post", { ...metaToPugArgs(meta), post: _post, @@ -679,7 +678,7 @@ router.get("/channels/:channel", async (ctx, next) => { if (channel) { const _channel = await Channels.pack(channel); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("channel", { ...metaToPugArgs(meta), channel: _channel, @@ -732,7 +731,7 @@ router.get("/api/v1/streaming", async (ctx) => { // Render base html for all requests router.get("(.*)", async (ctx) => { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); await ctx.render("base", { ...metaToPugArgs(meta), diff --git a/packages/backend/src/server/web/manifest.ts b/packages/backend/src/server/web/manifest.ts index bbcf639ffe..a4c615c7ab 100644 --- a/packages/backend/src/server/web/manifest.ts +++ b/packages/backend/src/server/web/manifest.ts @@ -1,5 +1,5 @@ import type Koa from "koa"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import config from "@/config/index.js"; import manifest from "./manifest.json" assert { type: "json" }; @@ -8,7 +8,7 @@ export const manifestHandler = async (ctx: Koa.Context) => { //const res = structuredClone(manifest); const res = JSON.parse(JSON.stringify(manifest)); - const instance = await fetchMeta(true); + const instance = await fetchMeta(false); res.short_name = instance.name || "Firefish"; res.name = instance.name || "Firefish"; diff --git a/packages/backend/src/server/web/url-preview.ts b/packages/backend/src/server/web/url-preview.ts index 07d3bf7f2c..f59f3f357a 100644 --- a/packages/backend/src/server/web/url-preview.ts +++ b/packages/backend/src/server/web/url-preview.ts @@ -1,6 +1,6 @@ import type Koa from "koa"; import summaly from "summaly"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import Logger from "@/services/logger.js"; import config from "@/config/index.js"; import { query } from "@/prelude/url.js"; @@ -22,7 +22,7 @@ export const urlPreviewHandler = async (ctx: Koa.Context) => { return; } - const meta = await fetchMeta(); + const meta = await fetchMeta(true); logger.info( meta.summalyProxy diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index 6320277eef..24ad9f8f02 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -6,7 +6,7 @@ import type S3 from "aws-sdk/clients/s3.js"; // TODO: migrate to SDK v3 import sharp from "sharp"; import { IsNull } from "typeorm"; import { publishMainStream, publishDriveStream } from "@/services/stream.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { contentDisposition } from "@/misc/content-disposition.js"; import { getFileInfo } from "@/misc/get-file-info.js"; import { @@ -77,7 +77,7 @@ async function save( // thunbnail, webpublic を必要なら生成 const alts = await generateAlts(path, type, !file.uri); - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if (meta.useObjectStorage) { //#region ObjectStorage params @@ -360,7 +360,7 @@ async function upload( if (type === "image/apng") type = "image/png"; if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = "application/octet-stream"; - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const params = { Bucket: meta.objectStorageBucket, @@ -495,7 +495,7 @@ export async function addFile({ const usage = await DriveFiles.calcDriveUsageOf(user); const u = await Users.findOneBy({ id: user.id }); - const instance = await fetchMeta(); + const instance = await fetchMeta(true); let driveCapacity = 1024 * 1024 * @@ -567,7 +567,7 @@ export async function addFile({ : null; const folder = await fetchFolder(); - const instance = await fetchMeta(); + const instance = await fetchMeta(true); let file = new DriveFile(); file.id = genId(); diff --git a/packages/backend/src/services/drive/delete-file.ts b/packages/backend/src/services/drive/delete-file.ts index 16c0219e71..b4b5580a1c 100644 --- a/packages/backend/src/services/drive/delete-file.ts +++ b/packages/backend/src/services/drive/delete-file.ts @@ -2,7 +2,7 @@ import type { DriveFile } from "@/models/entities/drive-file.js"; import { InternalStorage } from "./internal-storage.js"; import { DriveFiles } from "@/models/index.js"; import { createDeleteObjectStorageFileJob } from "@/queue/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import { getS3 } from "./s3.js"; import { v4 as uuid } from "uuid"; @@ -82,7 +82,7 @@ async function postProcess(file: DriveFile, isExpired = false) { } export async function deleteObjectStorageFile(key: string) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const s3 = getS3(meta); diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index 09749059a9..1a772ff9c5 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -1,7 +1,7 @@ import push from "web-push"; import config from "@/config/index.js"; import { SwSubscriptions } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import type { Packed } from "@/misc/schema.js"; import { getNoteSummary } from "@/misc/get-note-summary.js"; @@ -45,7 +45,7 @@ export async function pushNotification( type: T, body: pushNotificationsTypes[T], ) { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); if ( !meta.enableServiceWorker || diff --git a/packages/backend/src/services/send-email.ts b/packages/backend/src/services/send-email.ts index aa96cfc014..11a899d267 100644 --- a/packages/backend/src/services/send-email.ts +++ b/packages/backend/src/services/send-email.ts @@ -1,5 +1,5 @@ import * as nodemailer from "nodemailer"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; import Logger from "@/services/logger.js"; import config from "@/config/index.js"; import { inspect } from "node:util"; @@ -12,7 +12,7 @@ export async function sendEmail( html: string, text: string, ) { - const meta = await fetchMeta(true); + const meta = await fetchMeta(false); const iconUrl = `${config.url}/static-assets/mi-white.png`; const emailSettingUrl = `${config.url}/settings/email`; diff --git a/packages/backend/src/services/validate-email-for-account.ts b/packages/backend/src/services/validate-email-for-account.ts index 4d05afcc6d..5aa091a5ac 100644 --- a/packages/backend/src/services/validate-email-for-account.ts +++ b/packages/backend/src/services/validate-email-for-account.ts @@ -1,12 +1,12 @@ import { validate as validateEmail } from "deep-email-validator"; import { UserProfiles } from "@/models/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; +import { fetchMeta } from "backend-rs"; export async function validateEmailForAccount(emailAddress: string): Promise<{ available: boolean; reason: null | "used" | "format" | "disposable" | "mx" | "smtp"; }> { - const meta = await fetchMeta(); + const meta = await fetchMeta(true); const exist = await UserProfiles.countBy({ emailVerified: true, From fca48b2a816fcef6ad17ccb0c31a2c9a15c31e54 Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 14 Apr 2024 20:29:44 +0900 Subject: [PATCH 09/22] refactor (backend): port safe-for-sql, sql-like-escape to backend-rs --- packages/backend-rs/index.d.ts | 2 ++ packages/backend-rs/index.js | 4 ++- packages/backend-rs/src/misc/escape_sql.rs | 36 +++++++++++++++++++ packages/backend-rs/src/misc/mod.rs | 1 + packages/backend/src/misc/safe-for-sql.ts | 3 -- packages/backend/src/misc/sql-like-escape.ts | 3 -- .../api/endpoints/admin/emoji/list-remote.ts | 3 +- .../server/api/endpoints/admin/emoji/list.ts | 4 +-- .../server/api/endpoints/admin/show-users.ts | 2 +- .../server/api/endpoints/channels/search.ts | 2 +- .../api/endpoints/federation/instances.ts | 3 +- .../server/api/endpoints/hashtags/search.ts | 2 +- .../server/api/endpoints/hashtags/trend.ts | 3 +- .../api/endpoints/notes/search-by-tag.ts | 2 +- .../src/server/api/endpoints/notes/search.ts | 4 +-- .../users/search-by-username-and-host.ts | 2 +- .../src/server/api/endpoints/users/search.ts | 2 +- 17 files changed, 55 insertions(+), 23 deletions(-) create mode 100644 packages/backend-rs/src/misc/escape_sql.rs delete mode 100644 packages/backend/src/misc/safe-for-sql.ts delete mode 100644 packages/backend/src/misc/sql-like-escape.ts diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 3770056d8f..a9398aacc1 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -132,6 +132,8 @@ export function isSelfHost(host?: string | undefined | null): boolean export function isSameOrigin(uri: string): boolean export function extractHost(uri: string): string export function toPuny(host: string): string +export function sqlLikeEscape(src: string): string +export function safeForSql(src: string): boolean /** Convert milliseconds to a human readable string */ export function formatMilliseconds(milliseconds: number): string export function toMastodonId(firefishId: string): string | null diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 363c858e4a..7a404d6447 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding +const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding module.exports.readServerConfig = readServerConfig module.exports.stringToAcct = stringToAcct @@ -321,6 +321,8 @@ module.exports.isSelfHost = isSelfHost module.exports.isSameOrigin = isSameOrigin module.exports.extractHost = extractHost module.exports.toPuny = toPuny +module.exports.sqlLikeEscape = sqlLikeEscape +module.exports.safeForSql = safeForSql module.exports.formatMilliseconds = formatMilliseconds module.exports.toMastodonId = toMastodonId module.exports.fromMastodonId = fromMastodonId diff --git a/packages/backend-rs/src/misc/escape_sql.rs b/packages/backend-rs/src/misc/escape_sql.rs new file mode 100644 index 0000000000..c575e088ce --- /dev/null +++ b/packages/backend-rs/src/misc/escape_sql.rs @@ -0,0 +1,36 @@ +#[crate::export] +pub fn sql_like_escape(src: &str) -> String { + src.replace('%', r"\%").replace('_', r"\_") +} + +#[crate::export] +pub fn safe_for_sql(src: &str) -> bool { + !src.contains([ + '\0', '\x08', '\x09', '\x1a', '\n', '\r', '"', '\'', '\\', '%', + ]) +} + +#[cfg(test)] +mod unit_test { + use super::{safe_for_sql, sql_like_escape}; + use pretty_assertions::assert_eq; + + #[test] + fn sql_like_escape_test() { + assert_eq!(sql_like_escape(""), ""); + assert_eq!(sql_like_escape("abc"), "abc"); + assert_eq!(sql_like_escape("a%bc"), r"a\%bc"); + assert_eq!(sql_like_escape("a呼%吸bc"), r"a呼\%吸bc"); + assert_eq!(sql_like_escape("a呼%吸b%_c"), r"a呼\%吸b\%\_c"); + assert_eq!(sql_like_escape("_اللغة العربية"), r"\_اللغة العربية"); + } + + #[test] + fn safe_for_sql_test() { + assert!(safe_for_sql("123")); + assert!(safe_for_sql("人間")); + assert!(!safe_for_sql("人間\x09")); + assert!(!safe_for_sql("abc\ndef")); + assert!(!safe_for_sql("%something%")); + } +} diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index 7f99a67324..74a483ea51 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -1,6 +1,7 @@ pub mod acct; pub mod check_word_mute; pub mod convert_host; +pub mod escape_sql; pub mod format_milliseconds; pub mod mastodon_id; pub mod meta; diff --git a/packages/backend/src/misc/safe-for-sql.ts b/packages/backend/src/misc/safe-for-sql.ts deleted file mode 100644 index 02eb7f0a26..0000000000 --- a/packages/backend/src/misc/safe-for-sql.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function safeForSql(text: string): boolean { - return !/[\0\x08\x09\x1a\n\r"'\\\%]/g.test(text); -} diff --git a/packages/backend/src/misc/sql-like-escape.ts b/packages/backend/src/misc/sql-like-escape.ts deleted file mode 100644 index 453947d6ec..0000000000 --- a/packages/backend/src/misc/sql-like-escape.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function sqlLikeEscape(s: string) { - return s.replace(/([%_])/g, "\\$1"); -} diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index 5c3e19d9e0..9c7a5180d3 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -1,8 +1,7 @@ import define from "@/server/api/define.js"; import { Emojis } from "@/models/index.js"; -import { toPuny } from "backend-rs"; +import { sqlLikeEscape, toPuny } from "backend-rs"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; import { ApiError } from "@/server/api/error.js"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts index 434b679608..98a69090db 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts @@ -1,8 +1,8 @@ import define from "@/server/api/define.js"; import { Emojis } from "@/models/index.js"; -import { makePaginationQuery } from "../../../common/make-pagination-query.js"; +import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import type { Emoji } from "@/models/entities/emoji.js"; -//import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +//import { sqlLikeEscape } from "backend-rs"; import { ApiError } from "@/server/api/error.js"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index 1e6ebeda93..8a892c3606 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -1,6 +1,6 @@ import { Users } from "@/models/index.js"; import define from "@/server/api/define.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["admin"], diff --git a/packages/backend/src/server/api/endpoints/channels/search.ts b/packages/backend/src/server/api/endpoints/channels/search.ts index b2fab701c5..ed44250a37 100644 --- a/packages/backend/src/server/api/endpoints/channels/search.ts +++ b/packages/backend/src/server/api/endpoints/channels/search.ts @@ -2,7 +2,7 @@ import define from "@/server/api/define.js"; import { Brackets } from "typeorm"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import { Channels } from "@/models/index.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["channels"], diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 8c021d0e65..362ab098fb 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -1,7 +1,6 @@ import define from "@/server/api/define.js"; import { Instances } from "@/models/index.js"; -import { fetchMeta } from "backend-rs"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { fetchMeta, sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["federation"], diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts index 1dc1fb4922..8fb5b23f62 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/search.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts @@ -1,6 +1,6 @@ import define from "@/server/api/define.js"; import { Hashtags } from "@/models/index.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["hashtags"], diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index 9d31445a42..531a494248 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -1,9 +1,8 @@ import { Brackets } from "typeorm"; import define from "@/server/api/define.js"; -import { fetchMeta } from "backend-rs"; +import { fetchMeta, safeForSql } from "backend-rs"; import { Notes } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; -import { safeForSql } from "@/misc/safe-for-sql.js"; import { normalizeForSearch } from "@/misc/normalize-for-search.js"; /* diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index e87725e342..f449ea081a 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -1,6 +1,6 @@ import { Brackets } from "typeorm"; import { Notes } from "@/models/index.js"; -import { safeForSql } from "@/misc/safe-for-sql.js"; +import { safeForSql } from "backend-rs"; import { normalizeForSearch } from "@/misc/normalize-for-search.js"; import define from "@/server/api/define.js"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index b159a91944..f28208cba9 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -1,11 +1,11 @@ import { Notes } from "@/models/index.js"; -import { Note } from "@/models/entities/note.js"; +import type { Note } from "@/models/entities/note.js"; import define from "@/server/api/define.js"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js"; import { generateMutedUserQuery } from "@/server/api/common/generate-muted-user-query.js"; import { generateBlockedUserQuery } from "@/server/api/common/generate-block-query.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; import type { SelectQueryBuilder } from "typeorm"; export const meta = { diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index 517ef615b1..fe15ae18c0 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -2,7 +2,7 @@ import { Brackets } from "typeorm"; import { Followings, Users } from "@/models/index.js"; import type { User } from "@/models/entities/user.js"; import define from "@/server/api/define.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["users"], diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index a15a0feb4b..df0701709b 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -2,7 +2,7 @@ import { Brackets } from "typeorm"; import { UserProfiles, Users } from "@/models/index.js"; import type { User } from "@/models/entities/user.js"; import define from "@/server/api/define.js"; -import { sqlLikeEscape } from "@/misc/sql-like-escape.js"; +import { sqlLikeEscape } from "backend-rs"; export const meta = { tags: ["users"], From 21225f713716e72427c7cf05f0e55401e80cb2c9 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 15 Apr 2024 04:09:33 +0900 Subject: [PATCH 10/22] chore: update dependencies --- Cargo.lock | 81 +-- Cargo.toml | 2 +- package.json | 8 +- packages/backend/package.json | 12 +- packages/client/package.json | 6 +- pnpm-lock.yaml | 1132 +++++++++++++++++++-------------- 6 files changed, 727 insertions(+), 514 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6552351a3a..bc584faf24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,9 +59,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-tzdata" @@ -436,9 +436,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" [[package]] name = "cfg-if" @@ -464,7 +464,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -695,9 +695,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" dependencies = [ "serde", ] @@ -1246,7 +1246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1367,9 +1367,9 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9130fccc5f763cf2069b34a089a18f0d0883c66aceb81f2fad541a3d823c43" +checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" [[package]] name = "napi-derive" @@ -1421,9 +1421,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" dependencies = [ "num-bigint", "num-complex", @@ -3123,7 +3123,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -3141,7 +3141,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -3161,17 +3161,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -3182,9 +3183,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -3194,9 +3195,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -3206,9 +3207,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -3218,9 +3225,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -3230,9 +3237,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -3242,9 +3249,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -3254,9 +3261,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index 1a72cb2c5a..c9efe1f69a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ macro_rs = { path = "packages/macro-rs" } napi = { version = "2.16.2", default-features = false } napi-derive = "2.16.2" -napi-build = "2.1.2" +napi-build = "2.1.3" argon2 = "0.5.3" async-trait = "0.1.80" diff --git a/package.json b/package.json index a7bb0a5cc1..dd0766bc7b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "git", "url": "https://firefish.dev/firefish/firefish.git" }, - "packageManager": "pnpm@8.15.6", + "packageManager": "pnpm@8.15.7", "private": true, "scripts": { "rebuild": "pnpm run clean && pnpm run build", @@ -36,11 +36,11 @@ "clean-all": "pnpm run clean && pnpm run clean-cargo && pnpm run clean-npm" }, "dependencies": { - "js-yaml": "4.1.0", "gulp": "4.0.2", "gulp-cssnano": "2.1.3", "gulp-replace": "1.1.4", - "gulp-terser": "2.1.0" + "gulp-terser": "2.1.0", + "js-yaml": "4.1.0" }, "devDependencies": { "@biomejs/biome": "1.6.4", @@ -50,7 +50,7 @@ "@biomejs/cli-linux-x64": "^1.6.4", "@types/node": "20.12.7", "execa": "8.0.1", - "pnpm": "8.15.6", + "pnpm": "8.15.7", "typescript": "5.4.5" } } diff --git a/packages/backend/package.json b/packages/backend/package.json index 5dbf7cad64..bf435ec64b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -22,9 +22,9 @@ "@swc/core-android-arm64": "1.3.11" }, "dependencies": { - "@bull-board/api": "5.15.3", - "@bull-board/koa": "5.15.3", - "@bull-board/ui": "5.15.3", + "@bull-board/api": "5.15.5", + "@bull-board/koa": "5.15.5", + "@bull-board/ui": "5.15.5", "@discordapp/twemoji": "^15.0.3", "@koa/cors": "5.0.0", "@koa/multer": "3.0.2", @@ -37,7 +37,7 @@ "adm-zip": "0.5.10", "ajv": "8.12.0", "archiver": "7.0.1", - "aws-sdk": "2.1597.0", + "aws-sdk": "2.1599.0", "axios": "^1.6.8", "backend-rs": "workspace:*", "blurhash": "2.0.5", @@ -52,7 +52,7 @@ "date-fns": "3.6.0", "decompress": "^4.2.1", "deep-email-validator": "0.1.21", - "deepl-node": "1.12.0", + "deepl-node": "1.13.0", "escape-regexp": "0.0.1", "feed": "4.2.2", "file-type": "19.0.0", @@ -98,7 +98,7 @@ "punycode": "2.3.1", "pureimage": "0.4.13", "qrcode": "1.5.3", - "qs": "6.12.0", + "qs": "6.12.1", "random-seed": "0.3.0", "ratelimiter": "3.4.1", "redis-semaphore": "5.5.1", diff --git a/packages/client/package.json b/packages/client/package.json index 594f07c607..97a5f83ef7 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -67,9 +67,9 @@ "photoswipe": "5.4.3", "prismjs": "1.29.0", "punycode": "2.3.1", - "rollup": "4.14.1", + "rollup": "4.14.2", "s-age": "1.1.2", - "sass": "1.74.1", + "sass": "1.75.0", "seedrandom": "3.0.5", "stringz": "2.1.0", "swiper": "11.1.1", @@ -88,6 +88,6 @@ "vue-draggable-plus": "^0.4.0", "vue-plyr": "^7.0.0", "vue-prism-editor": "2.0.0-alpha.2", - "vue-tsc": "2.0.12" + "vue-tsc": "2.0.13" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 02b473ddce..53b6089f9c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,8 +46,8 @@ importers: specifier: 8.0.1 version: 8.0.1 pnpm: - specifier: 8.15.6 - version: 8.15.6 + specifier: 8.15.7 + version: 8.15.7 typescript: specifier: 5.4.5 version: 5.4.5 @@ -55,14 +55,14 @@ importers: packages/backend: dependencies: '@bull-board/api': - specifier: 5.15.3 - version: 5.15.3(@bull-board/ui@5.15.3) + specifier: 5.15.5 + version: 5.15.5(@bull-board/ui@5.15.5) '@bull-board/koa': - specifier: 5.15.3 - version: 5.15.3(@types/koa@2.15.0)(pug@3.0.2) + specifier: 5.15.5 + version: 5.15.5(@types/koa@2.15.0)(pug@3.0.2) '@bull-board/ui': - specifier: 5.15.3 - version: 5.15.3 + specifier: 5.15.5 + version: 5.15.5 '@discordapp/twemoji': specifier: ^15.0.3 version: 15.0.3 @@ -100,8 +100,8 @@ importers: specifier: 7.0.1 version: 7.0.1 aws-sdk: - specifier: 2.1597.0 - version: 2.1597.0 + specifier: 2.1599.0 + version: 2.1599.0 axios: specifier: ^1.6.8 version: 1.6.8 @@ -145,8 +145,8 @@ importers: specifier: 0.1.21 version: 0.1.21 deepl-node: - specifier: 1.12.0 - version: 1.12.0 + specifier: 1.13.0 + version: 1.13.0 escape-regexp: specifier: 0.0.1 version: 0.0.1 @@ -283,8 +283,8 @@ importers: specifier: 1.5.3 version: 1.5.3 qs: - specifier: 6.12.0 - version: 6.12.0 + specifier: 6.12.1 + version: 6.12.1 random-seed: specifier: 0.3.0 version: 0.3.0 @@ -547,22 +547,22 @@ importers: devDependencies: '@eslint-sets/eslint-config-vue3': specifier: ^5.12.0 - version: 5.12.0(@babel/core@7.23.2)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5) + version: 5.12.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) '@eslint-sets/eslint-config-vue3-ts': specifier: ^3.3.0 - version: 3.3.0(@babel/core@7.23.2)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5) + version: 3.3.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) '@phosphor-icons/web': specifier: ^2.1.1 version: 2.1.1 '@rollup/plugin-alias': specifier: 5.1.0 - version: 5.1.0(rollup@4.14.1) + version: 5.1.0(rollup@4.14.2) '@rollup/plugin-json': specifier: 6.1.0 - version: 6.1.0(rollup@4.14.1) + version: 6.1.0(rollup@4.14.2) '@rollup/pluginutils': specifier: ^5.1.0 - version: 5.1.0(rollup@4.14.1) + version: 5.1.0(rollup@4.14.2) '@syuilo/aiscript': specifier: 0.17.0 version: 0.17.0 @@ -658,7 +658,7 @@ importers: version: 3.0.12 eslint-plugin-file-progress: specifier: ^1.3.0 - version: 1.3.0(eslint@8.57.0) + version: 1.3.0(eslint@9.0.0) eventemitter3: specifier: 5.0.1 version: 5.0.1 @@ -711,14 +711,14 @@ importers: specifier: 2.3.1 version: 2.3.1 rollup: - specifier: 4.14.1 - version: 4.14.1 + specifier: 4.14.2 + version: 4.14.2 s-age: specifier: 1.1.2 version: 1.1.2 sass: - specifier: 1.74.1 - version: 1.74.1 + specifier: 1.75.0 + version: 1.75.0 seedrandom: specifier: 3.0.5 version: 3.0.5 @@ -757,7 +757,7 @@ importers: version: 9.0.1 vite: specifier: 5.2.8 - version: 5.2.8(@types/node@20.12.7)(sass@1.74.1) + version: 5.2.8(@types/node@20.12.7)(sass@1.75.0) vite-plugin-compression: specifier: ^0.5.1 version: 0.5.1(vite@5.2.8) @@ -766,7 +766,7 @@ importers: version: 3.4.21(typescript@5.4.5) vue-draggable-plus: specifier: ^0.4.0 - version: 0.4.0(@types/sortablejs@1.15.4) + version: 0.4.0(@types/sortablejs@1.15.8) vue-plyr: specifier: ^7.0.0 version: 7.0.0 @@ -774,8 +774,8 @@ importers: specifier: 2.0.0-alpha.2 version: 2.0.0-alpha.2(vue@3.4.21) vue-tsc: - specifier: 2.0.12 - version: 2.0.12(typescript@5.4.5) + specifier: 2.0.13 + version: 2.0.13(typescript@5.4.5) packages/firefish-js: dependencies: @@ -931,7 +931,7 @@ importers: version: 4.17.21 ts-jest: specifier: ^29.0.5 - version: 29.1.1(@babel/core@7.23.2)(jest@29.7.0)(typescript@4.9.4) + version: 29.1.1(@babel/core@7.24.4)(jest@29.7.0)(typescript@4.9.4) typedoc: specifier: ^0.23.24 version: 0.23.28(typescript@4.9.4) @@ -949,7 +949,7 @@ importers: version: 6.2.1 vite: specifier: 5.2.8 - version: 5.2.8(@types/node@20.12.7)(sass@1.74.1) + version: 5.2.8(@types/node@20.12.7)(sass@1.75.0) vite-plugin-compression: specifier: ^0.5.1 version: 0.5.1(vite@5.2.8) @@ -968,6 +968,14 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + dev: true + /@babel/code-frame@7.22.10: resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} engines: {node: '>=6.9.0'} @@ -983,6 +991,14 @@ packages: chalk: 2.4.2 dev: true + /@babel/code-frame@7.24.2: + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.2 + picocolors: 1.0.0 + dev: true + /@babel/compat-data@7.22.9: resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} engines: {node: '>=6.9.0'} @@ -992,6 +1008,11 @@ packages: engines: {node: '>=6.9.0'} dev: true + /@babel/compat-data@7.24.4: + resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/core@7.22.10: resolution: {integrity: sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==} engines: {node: '>=6.9.0'} @@ -1037,30 +1058,53 @@ packages: - supports-color dev: true - /@babel/eslint-parser@7.23.10(@babel/core@7.23.2)(eslint@8.57.0): + /@babel/core@7.24.4: + resolution: {integrity: sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.4 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) + '@babel/helpers': 7.24.4 + '@babel/parser': 7.24.4 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + convert-source-map: 2.0.0 + debug: 4.3.4(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/eslint-parser@7.23.10(@babel/core@7.24.4)(eslint@9.0.0): resolution: {integrity: sha512-3wSYDPZVnhseRnxRJH6ZVTNknBz76AEnyC+AYYhasjP3Yy23qz0ERR7Fcd2SHmYuSFJ2kY9gaaDd3vyqU09eSw==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: '@babel/core': ^7.11.0 eslint: ^7.5.0 || ^8.0.0 dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.24.4 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 8.57.0 + eslint: 9.0.0 eslint-visitor-keys: 2.1.0 semver: 6.3.1 dev: true - /@babel/eslint-parser@7.23.3(@babel/core@7.23.2)(eslint@8.57.0): + /@babel/eslint-parser@7.23.3(@babel/core@7.24.4)(eslint@9.0.0): resolution: {integrity: sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: '@babel/core': ^7.11.0 eslint: ^7.5.0 || ^8.0.0 dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.24.4 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 8.57.0 + eslint: 9.0.0 eslint-visitor-keys: 2.1.0 semver: 6.3.1 dev: true @@ -1084,6 +1128,16 @@ packages: jsesc: 2.5.2 dev: true + /@babel/generator@7.24.4: + resolution: {integrity: sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + dev: true + /@babel/helper-compilation-targets@7.22.10: resolution: {integrity: sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==} engines: {node: '>=6.9.0'} @@ -1105,6 +1159,17 @@ packages: semver: 6.3.1 dev: true + /@babel/helper-compilation-targets@7.23.6: + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.24.4 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.23.0 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + /@babel/helper-environment-visitor@7.22.20: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} @@ -1148,6 +1213,13 @@ packages: dependencies: '@babel/types': 7.23.0 + /@babel/helper-module-imports@7.24.3: + resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + dev: true + /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.10): resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} engines: {node: '>=6.9.0'} @@ -1175,6 +1247,20 @@ packages: '@babel/helper-validator-identifier': 7.22.20 dev: true + /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.4): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + /@babel/helper-plugin-utils@7.22.5: resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} @@ -1195,6 +1281,11 @@ packages: resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} + /@babel/helper-string-parser@7.24.1: + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} @@ -1212,6 +1303,11 @@ packages: resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} engines: {node: '>=6.9.0'} + /@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helpers@7.22.10: resolution: {integrity: sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==} engines: {node: '>=6.9.0'} @@ -1233,6 +1329,17 @@ packages: - supports-color dev: true + /@babel/helpers@7.24.4: + resolution: {integrity: sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/highlight@7.22.10: resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} engines: {node: '>=6.9.0'} @@ -1250,6 +1357,16 @@ packages: js-tokens: 4.0.0 dev: true + /@babel/highlight@7.24.2: + resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.0 + dev: true + /@babel/parser@7.22.10: resolution: {integrity: sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==} engines: {node: '>=6.0.0'} @@ -1272,6 +1389,14 @@ packages: '@babel/types': 7.23.0 dev: true + /@babel/parser@7.24.4: + resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.24.0 + dev: true + /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.22.10): resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} engines: {node: '>=6.9.0'} @@ -1457,6 +1582,15 @@ packages: '@babel/parser': 7.23.0 '@babel/types': 7.23.0 + /@babel/template@7.24.0: + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/parser': 7.24.4 + '@babel/types': 7.24.0 + dev: true + /@babel/traverse@7.22.10: resolution: {integrity: sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==} engines: {node: '>=6.9.0'} @@ -1492,6 +1626,24 @@ packages: - supports-color dev: true + /@babel/traverse@7.24.1: + resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.4 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.24.4 + '@babel/types': 7.24.0 + debug: 4.3.4(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types@7.22.10: resolution: {integrity: sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==} engines: {node: '>=6.9.0'} @@ -1508,6 +1660,15 @@ packages: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + /@babel/types@7.24.0: + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.1 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true @@ -1592,26 +1753,26 @@ packages: dev: true optional: true - /@bull-board/api@5.15.3(@bull-board/ui@5.15.3): - resolution: {integrity: sha512-tlEYOI6Hp0ZGozDCtKQEFgvzTKXj+drKStHJm86s1TcUZlsnMjzR0BUxu5CW6EB3tS3MtPLJH5RQCmUq0UEiiQ==} + /@bull-board/api@5.15.5(@bull-board/ui@5.15.5): + resolution: {integrity: sha512-s3x0f+0s4nwndBM+QSROMVKiDyE/vaaouQCsxRWOFqneLCkM+Ro2wF6fkhmFkZMjouoBbS8rCFGaIZ+8uttYtg==} peerDependencies: - '@bull-board/ui': 5.15.3 + '@bull-board/ui': 5.15.5 dependencies: - '@bull-board/ui': 5.15.3 + '@bull-board/ui': 5.15.5 redis-info: 3.1.0 dev: false - /@bull-board/koa@5.15.3(@types/koa@2.15.0)(pug@3.0.2): - resolution: {integrity: sha512-pgHdRcre8RJKwWqlMLFY1oj742hLtxVrHsT2s4k+Ribzmoj3bq1tgRHtu6m9TX7AyABBtcTfTo30NNbPPrYR7A==} + /@bull-board/koa@5.15.5(@types/koa@2.15.0)(pug@3.0.2): + resolution: {integrity: sha512-Kbmca8hKNW5wLpGM/H1RBm09bcdK+KWCsINUyDtp91bGwMRK0mhiqvjJLJpRohXXmtPTnnJDuVO9p1gYsbed3Q==} dependencies: - '@bull-board/api': 5.15.3(@bull-board/ui@5.15.3) - '@bull-board/ui': 5.15.3 - ejs: 3.1.9 + '@bull-board/api': 5.15.5(@bull-board/ui@5.15.5) + '@bull-board/ui': 5.15.5 + ejs: 3.1.10 koa: 2.15.3 koa-mount: 4.0.0 koa-router: 10.1.1 koa-static: 5.0.0 - koa-views: 7.0.2(@types/koa@2.15.0)(ejs@3.1.9)(pug@3.0.2) + koa-views: 7.0.2(@types/koa@2.15.0)(ejs@3.1.10)(pug@3.0.2) transitivePeerDependencies: - '@types/koa' - arc-templates @@ -1669,10 +1830,10 @@ packages: - whiskers dev: false - /@bull-board/ui@5.15.3: - resolution: {integrity: sha512-wCXk+s4cSszZe0p0sYYxZPLSKafFQNPsUypTvpAh3IC2p4fr6F/wUBGb1kBMspRkFC19l5yFCD5qPHVlAR0QKw==} + /@bull-board/ui@5.15.5: + resolution: {integrity: sha512-TSXgqBDI3ig6ez6yHArGzpwCuA/rhQewv0KOUAvPzssgX4HqfkatrV7gTuTM+XJe7/sLiXnBiryV7SRV0hgRMg==} dependencies: - '@bull-board/api': 5.15.3(@bull-board/ui@5.15.3) + '@bull-board/api': 5.15.5(@bull-board/ui@5.15.5) dev: false /@cbor-extract/cbor-extract-darwin-arm64@2.2.0: @@ -1841,8 +2002,8 @@ packages: universalify: 0.1.2 dev: false - /@emnapi/runtime@1.1.0: - resolution: {integrity: sha512-gCGlE0fJGWalfy+wbFApjhKn6uoSVvopru77IPyxNKkjkaiSx2HxDS7eOYSmo9dcMIhmmIvoxiC3N9TM1c3EaA==} + /@emnapi/runtime@1.1.1: + resolution: {integrity: sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==} requiresBuild: true dependencies: tslib: 2.6.2 @@ -2075,16 +2236,6 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - dependencies: - eslint: 8.57.0 - eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@9.0.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2105,29 +2256,29 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint-sets/eslint-config-basic@3.3.0(@babel/core@7.23.2)(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(prettier@3.2.5): + /@eslint-sets/eslint-config-basic@3.3.0(@babel/core@7.24.4)(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(prettier@3.2.5): resolution: {integrity: sha512-x5YH0CvZJxn19/5ehu188XaoLQpxOGlFiIuPHCN6FyONgrmriakT/cmIIBOJg2Vi/y1bn2xbhsgVNb00J3HyTg==} peerDependencies: eslint: '>=8.0.0' prettier: '>=2.0.0' dependencies: - '@babel/eslint-parser': 7.23.3(@babel/core@7.23.2)(eslint@8.57.0) - eslint: 8.57.0 - eslint-config-prettier: 8.9.0(eslint@8.57.0) - eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0) + '@babel/eslint-parser': 7.23.3(@babel/core@7.24.4)(eslint@9.0.0) + eslint: 9.0.0 + eslint-config-prettier: 8.9.0(eslint@9.0.0) + eslint-plugin-eslint-comments: 3.2.0(eslint@9.0.0) eslint-plugin-html: 7.1.0 - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) - eslint-plugin-jsonc: 2.10.0(eslint@8.57.0) - eslint-plugin-markdown: 3.0.1(eslint@8.57.0) - eslint-plugin-n: 15.7.0(eslint@8.57.0) - eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@8.57.0)(prettier@3.2.5) - eslint-plugin-promise: 5.2.0(eslint@8.57.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0) + eslint-plugin-jsonc: 2.10.0(eslint@9.0.0) + eslint-plugin-markdown: 3.0.1(eslint@9.0.0) + eslint-plugin-n: 15.7.0(eslint@9.0.0) + eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@9.0.0)(prettier@3.2.5) + eslint-plugin-promise: 5.2.0(eslint@9.0.0) eslint-plugin-tsdoc: 0.2.17 - eslint-plugin-unicorn: 45.0.2(eslint@8.57.0) - eslint-plugin-yml: 1.10.0(eslint@8.57.0) + eslint-plugin-unicorn: 45.0.2(eslint@9.0.0) + eslint-plugin-yml: 1.10.0(eslint@9.0.0) jsonc-eslint-parser: 2.3.0 prettier: 3.2.5 - vue-eslint-parser: 9.3.2(eslint@8.57.0) + vue-eslint-parser: 9.3.2(eslint@9.0.0) yaml-eslint-parser: 1.2.2 transitivePeerDependencies: - '@babel/core' @@ -2137,7 +2288,7 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-basic@5.12.0(@babel/core@7.23.2)(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-basic@5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-AgECfmJsiVOWKmvgjv780VuuoT9SE6PRgxGTtytHSfE9b9MAJjHxToVTKtD4UEKvocEGbg2EcwqGbff8cxDWKw==} peerDependencies: eslint: '>=7.4.0' @@ -2147,24 +2298,24 @@ packages: typescript: optional: true dependencies: - '@babel/eslint-parser': 7.23.10(@babel/core@7.23.2)(eslint@8.57.0) - eslint: 8.57.0 - eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0) + '@babel/eslint-parser': 7.23.10(@babel/core@7.24.4)(eslint@9.0.0) + eslint: 9.0.0 + eslint-config-prettier: 9.1.0(eslint@9.0.0) + eslint-plugin-eslint-comments: 3.2.0(eslint@9.0.0) eslint-plugin-html: 7.1.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0) - eslint-plugin-jsonc: 2.13.0(eslint@8.57.0) - eslint-plugin-markdown: 3.0.1(eslint@8.57.0) - eslint-plugin-n: 16.6.2(eslint@8.57.0) - eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) - eslint-plugin-promise: 6.1.1(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@9.0.0) + eslint-plugin-jsonc: 2.13.0(eslint@9.0.0) + eslint-plugin-markdown: 3.0.1(eslint@9.0.0) + eslint-plugin-n: 16.6.2(eslint@9.0.0) + eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.0.0)(prettier@3.2.5) + eslint-plugin-promise: 6.1.1(eslint@9.0.0) eslint-plugin-tsdoc: 0.2.17 - eslint-plugin-unicorn: 40.1.0(eslint@8.57.0) - eslint-plugin-yml: 1.12.2(eslint@8.57.0) + eslint-plugin-unicorn: 40.1.0(eslint@9.0.0) + eslint-plugin-yml: 1.12.2(eslint@9.0.0) jsonc-eslint-parser: 2.4.0 prettier: 3.2.5 typescript: 5.4.5 - vue-eslint-parser: 9.4.2(eslint@8.57.0) + vue-eslint-parser: 9.4.2(eslint@9.0.0) yaml-eslint-parser: 1.2.2 transitivePeerDependencies: - '@babel/core' @@ -2175,19 +2326,19 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-ts@3.3.0(@babel/core@7.23.2)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-ts@3.3.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-4Vj3KxYx16hmW6AyEv1mil0gVN8H3rdJt8TRWufbAj0ZN+EjwOPf3TqE7ASCYto/NpA8xWQY3NGm/og9Or/dDQ==} peerDependencies: eslint: '>=8.0.0' prettier: '>=2.0.0' typescript: '>=4.0.0' dependencies: - '@eslint-sets/eslint-config-basic': 3.3.0(@babel/core@7.23.2)(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(prettier@3.2.5) - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-config-prettier: 8.9.0(eslint@8.57.0) - eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@8.57.0)(prettier@3.2.5) + '@eslint-sets/eslint-config-basic': 3.3.0(@babel/core@7.24.4)(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(prettier@3.2.5) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) + eslint: 9.0.0 + eslint-config-prettier: 8.9.0(eslint@9.0.0) + eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@9.0.0)(prettier@3.2.5) eslint-plugin-tsdoc: 0.2.17 prettier: 3.2.5 typescript: 5.4.5 @@ -2198,7 +2349,7 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-ts@5.12.0(@babel/core@7.23.2)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-ts@5.12.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-7vOzV6qYv0SbA9W17m9lkG/Zv+qVeCcAbWEY1d9hUbBHx9Ip48kNMNVDrnh97zUORXGcmjxsZ81W2lC36Ox2pw==} peerDependencies: eslint: '>=7.4.0' @@ -2208,12 +2359,12 @@ packages: typescript: optional: true dependencies: - '@eslint-sets/eslint-config-basic': 5.12.0(@babel/core@7.23.2)(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5) - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) + '@eslint-sets/eslint-config-basic': 5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + eslint: 9.0.0 + eslint-config-prettier: 9.1.0(eslint@9.0.0) + eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.0.0)(prettier@3.2.5) eslint-plugin-tsdoc: 0.2.17 prettier: 3.2.5 typescript: 5.4.5 @@ -2225,26 +2376,26 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-vue3-ts@3.3.0(@babel/core@7.23.2)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-vue3-ts@3.3.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-KX3VFuS5U4FYKfZ6PABQjl54BMpNapNjYYe103Nm2Zy8y9zphDCBAARbhU97XNSvzkurve7HhJcsi9gXrWlGFA==} peerDependencies: eslint: '>=8.0.0' prettier: '>=2.0.0' typescript: '>=4.0.0' dependencies: - '@eslint-sets/eslint-config-ts': 3.3.0(@babel/core@7.23.2)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5) - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-config-prettier: 8.9.0(eslint@8.57.0) - eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@8.57.0)(prettier@3.2.5) + '@eslint-sets/eslint-config-ts': 3.3.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) + eslint: 9.0.0 + eslint-config-prettier: 8.9.0(eslint@9.0.0) + eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@9.0.0)(prettier@3.2.5) eslint-plugin-tsdoc: 0.2.17 eslint-plugin-vitest-globals: 1.4.0 - eslint-plugin-vue: 9.16.1(eslint@8.57.0) - eslint-plugin-vue-scoped-css: 2.5.0(eslint@8.57.0)(vue-eslint-parser@9.3.1) + eslint-plugin-vue: 9.16.1(eslint@9.0.0) + eslint-plugin-vue-scoped-css: 2.5.0(eslint@9.0.0)(vue-eslint-parser@9.3.1) prettier: 3.2.5 typescript: 5.4.5 - vue-eslint-parser: 9.3.1(eslint@8.57.0) + vue-eslint-parser: 9.3.1(eslint@9.0.0) transitivePeerDependencies: - '@babel/core' - eslint-import-resolver-typescript @@ -2252,7 +2403,7 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-vue3@5.12.0(@babel/core@7.23.2)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-vue3@5.12.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-gQBmQicZihPcxncIdkKagQGZ2dH+97ioAlUpsaczEdgY9pLrLOU5oGTetjbaxAp6zGS2sXm1n0i2BnwRIlt4Bg==} peerDependencies: eslint: '>=7.4.0' @@ -2262,22 +2413,22 @@ packages: typescript: optional: true dependencies: - '@eslint-sets/eslint-config-basic': 5.12.0(@babel/core@7.23.2)(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5) - '@eslint-sets/eslint-config-ts': 5.12.0(@babel/core@7.23.2)(eslint@8.57.0)(prettier@3.2.5)(typescript@5.4.5) - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-plugin-jsdoc: 48.0.6(eslint@8.57.0) - eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) + '@eslint-sets/eslint-config-basic': 5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) + '@eslint-sets/eslint-config-ts': 5.12.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + eslint: 9.0.0 + eslint-config-prettier: 9.1.0(eslint@9.0.0) + eslint-plugin-jsdoc: 48.0.6(eslint@9.0.0) + eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.0.0)(prettier@3.2.5) eslint-plugin-tsdoc: 0.2.17 eslint-plugin-vitest-globals: 1.4.0 - eslint-plugin-vue: 9.21.1(eslint@8.57.0) - eslint-plugin-vue-scoped-css: 2.7.2(eslint@8.57.0)(vue-eslint-parser@9.4.2) + eslint-plugin-vue: 9.21.1(eslint@9.0.0) + eslint-plugin-vue-scoped-css: 2.7.2(eslint@9.0.0)(vue-eslint-parser@9.4.2) local-pkg: 0.5.0 prettier: 3.2.5 typescript: 5.4.5 - vue-eslint-parser: 9.4.2(eslint@8.57.0) + vue-eslint-parser: 9.4.2(eslint@9.0.0) transitivePeerDependencies: - '@babel/core' - '@types/eslint' @@ -2303,23 +2454,6 @@ packages: - supports-color dev: true - /@eslint/eslintrc@2.1.4: - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.2.4 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - /@eslint/eslintrc@3.0.2: resolution: {integrity: sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2342,11 +2476,6 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@eslint/js@8.57.0: - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@eslint/js@9.0.0: resolution: {integrity: sha512-RThY/MnKrhubF6+s1JflwUjPEsnCEmYCWwqa/aRISKWNXGZ9epUwft4bUMM35SdKF9xvBrLydAM1RDHd1Z//ZQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2363,17 +2492,6 @@ packages: - supports-color dev: true - /@humanwhocodes/config-array@0.11.14: - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4(supports-color@8.1.1) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - /@humanwhocodes/config-array@0.12.3: resolution: {integrity: sha512-jsNnTBlMWuTpDkeE3on7+dWJi0D6fdDfeANj/w7MpS8ztROCoLvIO2nG0CcFj+E4k8j4QrSTh4Oryi3i2G669g==} engines: {node: '>=10.10.0'} @@ -2576,7 +2694,7 @@ packages: cpu: [wasm32] requiresBuild: true dependencies: - '@emnapi/runtime': 1.1.0 + '@emnapi/runtime': 1.1.1 dev: false optional: true @@ -2852,14 +2970,33 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.20 + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + dev: true + /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + dev: true + /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + dev: true + /@jridgewell/source-map@0.3.5: resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} dependencies: @@ -2881,6 +3018,13 @@ packages: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: @@ -3332,7 +3476,7 @@ packages: - encoding dev: false - /@rollup/plugin-alias@5.1.0(rollup@4.14.1): + /@rollup/plugin-alias@5.1.0(rollup@4.14.2): resolution: {integrity: sha512-lpA3RZ9PdIG7qqhEfv79tBffNaoDuukFDrmhLqg9ifv99u/ehn+lOg30x2zmhf8AQqQUZaMk/B9fZraQ6/acDQ==} engines: {node: '>=14.0.0'} peerDependencies: @@ -3341,11 +3485,11 @@ packages: rollup: optional: true dependencies: - rollup: 4.14.1 + rollup: 4.14.2 slash: 4.0.0 dev: true - /@rollup/plugin-json@6.1.0(rollup@4.14.1): + /@rollup/plugin-json@6.1.0(rollup@4.14.2): resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -3354,8 +3498,8 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.14.1) - rollup: 4.14.1 + '@rollup/pluginutils': 5.1.0(rollup@4.14.2) + rollup: 4.14.2 dev: true /@rollup/pluginutils@4.2.1: @@ -3366,7 +3510,7 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/pluginutils@5.1.0(rollup@4.14.1): + /@rollup/pluginutils@5.1.0(rollup@4.14.2): resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} peerDependencies: @@ -3378,123 +3522,123 @@ packages: '@types/estree': 1.0.3 estree-walker: 2.0.2 picomatch: 2.3.1 - rollup: 4.14.1 + rollup: 4.14.2 dev: true - /@rollup/rollup-android-arm-eabi@4.14.1: - resolution: {integrity: sha512-fH8/o8nSUek8ceQnT7K4EQbSiV7jgkHq81m9lWZFIXjJ7lJzpWXbQFpT/Zh6OZYnpFykvzC3fbEvEAFZu03dPA==} + /@rollup/rollup-android-arm-eabi@4.14.2: + resolution: {integrity: sha512-ahxSgCkAEk+P/AVO0vYr7DxOD3CwAQrT0Go9BJyGQ9Ef0QxVOfjDZMiF4Y2s3mLyPrjonchIMH/tbWHucJMykQ==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.14.1: - resolution: {integrity: sha512-Y/9OHLjzkunF+KGEoJr3heiD5X9OLa8sbT1lm0NYeKyaM3oMhhQFvPB0bNZYJwlq93j8Z6wSxh9+cyKQaxS7PQ==} + /@rollup/rollup-android-arm64@4.14.2: + resolution: {integrity: sha512-lAarIdxZWbFSHFSDao9+I/F5jDaKyCqAPMq5HqnfpBw8dKDiCaaqM0lq5h1pQTLeIqueeay4PieGR5jGZMWprw==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.14.1: - resolution: {integrity: sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==} + /@rollup/rollup-darwin-arm64@4.14.2: + resolution: {integrity: sha512-SWsr8zEUk82KSqquIMgZEg2GE5mCSfr9sE/thDROkX6pb3QQWPp8Vw8zOq2GyxZ2t0XoSIUlvHDkrf5Gmf7x3Q==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.14.1: - resolution: {integrity: sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==} + /@rollup/rollup-darwin-x64@4.14.2: + resolution: {integrity: sha512-o/HAIrQq0jIxJAhgtIvV5FWviYK4WB0WwV91SLUnsliw1lSAoLsmgEEgRWzDguAFeUEUUoIWXiJrPqU7vGiVkA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.14.1: - resolution: {integrity: sha512-mS6wQ6Do6/wmrF9aTFVpIJ3/IDXhg1EZcQFYHZLHqw6AzMBjTHWnCG35HxSqUNphh0EHqSM6wRTT8HsL1C0x5g==} + /@rollup/rollup-linux-arm-gnueabihf@4.14.2: + resolution: {integrity: sha512-nwlJ65UY9eGq91cBi6VyDfArUJSKOYt5dJQBq8xyLhvS23qO+4Nr/RreibFHjP6t+5ap2ohZrUJcHv5zk5ju/g==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.14.1: - resolution: {integrity: sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==} + /@rollup/rollup-linux-arm64-gnu@4.14.2: + resolution: {integrity: sha512-Pg5TxxO2IVlMj79+c/9G0LREC9SY3HM+pfAwX7zj5/cAuwrbfj2Wv9JbMHIdPCfQpYsI4g9mE+2Bw/3aeSs2rQ==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.14.1: - resolution: {integrity: sha512-nDY6Yz5xS/Y4M2i9JLQd3Rofh5OR8Bn8qe3Mv/qCVpHFlwtZSBYSPaU4mrGazWkXrdQ98GB//H0BirGR/SKFSw==} + /@rollup/rollup-linux-arm64-musl@4.14.2: + resolution: {integrity: sha512-cAOTjGNm84gc6tS02D1EXtG7tDRsVSDTBVXOLbj31DkwfZwgTPYZ6aafSU7rD/4R2a34JOwlF9fQayuTSkoclA==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-powerpc64le-gnu@4.14.1: - resolution: {integrity: sha512-im7HE4VBL+aDswvcmfx88Mp1soqL9OBsdDBU8NqDEYtkri0qV0THhQsvZtZeNNlLeCUQ16PZyv7cqutjDF35qw==} - cpu: [ppc64le] + /@rollup/rollup-linux-powerpc64le-gnu@4.14.2: + resolution: {integrity: sha512-4RyT6v1kXb7C0fn6zV33rvaX05P0zHoNzaXI/5oFHklfKm602j+N4mn2YvoezQViRLPnxP8M1NaY4s/5kXO5cw==} + cpu: [ppc64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.14.1: - resolution: {integrity: sha512-RWdiHuAxWmzPJgaHJdpvUUlDz8sdQz4P2uv367T2JocdDa98iRw2UjIJ4QxSyt077mXZT2X6pKfT2iYtVEvOFw==} + /@rollup/rollup-linux-riscv64-gnu@4.14.2: + resolution: {integrity: sha512-KNUH6jC/vRGAKSorySTyc/yRYlCwN/5pnMjXylfBniwtJx5O7X17KG/0efj8XM3TZU7raYRXJFFReOzNmL1n1w==} cpu: [riscv64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-s390x-gnu@4.14.1: - resolution: {integrity: sha512-VMgaGQ5zRX6ZqV/fas65/sUGc9cPmsntq2FiGmayW9KMNfWVG/j0BAqImvU4KTeOOgYSf1F+k6at1UfNONuNjA==} + /@rollup/rollup-linux-s390x-gnu@4.14.2: + resolution: {integrity: sha512-xPV4y73IBEXToNPa3h5lbgXOi/v0NcvKxU0xejiFw6DtIYQqOTMhZ2DN18/HrrP0PmiL3rGtRG9gz1QE8vFKXQ==} cpu: [s390x] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.14.1: - resolution: {integrity: sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==} + /@rollup/rollup-linux-x64-gnu@4.14.2: + resolution: {integrity: sha512-QBhtr07iFGmF9egrPOWyO5wciwgtzKkYPNLVCFZTmr4TWmY0oY2Dm/bmhHjKRwZoGiaKdNcKhFtUMBKvlchH+Q==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.14.1: - resolution: {integrity: sha512-JNEG/Ti55413SsreTguSx0LOVKX902OfXIKVg+TCXO6Gjans/k9O6ww9q3oLGjNDaTLxM+IHFMeXy/0RXL5R/g==} + /@rollup/rollup-linux-x64-musl@4.14.2: + resolution: {integrity: sha512-8zfsQRQGH23O6qazZSFY5jP5gt4cFvRuKTpuBsC1ZnSWxV8ZKQpPqOZIUtdfMOugCcBvFGRa1pDC/tkf19EgBw==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.14.1: - resolution: {integrity: sha512-ryS22I9y0mumlLNwDFYZRDFLwWh3aKaC72CWjFcFvxK0U6v/mOkM5Up1bTbCRAhv3kEIwW2ajROegCIQViUCeA==} + /@rollup/rollup-win32-arm64-msvc@4.14.2: + resolution: {integrity: sha512-H4s8UjgkPnlChl6JF5empNvFHp77Jx+Wfy2EtmYPe9G22XV+PMuCinZVHurNe8ggtwoaohxARJZbaH/3xjB/FA==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.14.1: - resolution: {integrity: sha512-TdloItiGk+T0mTxKx7Hp279xy30LspMso+GzQvV2maYePMAWdmrzqSNZhUpPj3CGw12aGj57I026PgLCTu8CGg==} + /@rollup/rollup-win32-ia32-msvc@4.14.2: + resolution: {integrity: sha512-djqpAjm/i8erWYF0K6UY4kRO3X5+T4TypIqw60Q8MTqSBaQNpNXDhxdjpZ3ikgb+wn99svA7jxcXpiyg9MUsdw==} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.14.1: - resolution: {integrity: sha512-wQGI+LY/Py20zdUPq+XCem7JcPOyzIJBm3dli+56DJsQOHbnXZFEwgmnC6el1TPAfC8lBT3m+z69RmLykNUbew==} + /@rollup/rollup-win32-x64-msvc@4.14.2: + resolution: {integrity: sha512-teAqzLT0yTYZa8ZP7zhFKEx4cotS8Tkk5XiqNMJhD4CpaWB1BHARE4Qy+RzwnXvSAYv+Q3jAqCVBS+PS+Yee8Q==} cpu: [x64] os: [win32] requiresBuild: true @@ -4301,8 +4445,8 @@ packages: resolution: {integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==} dev: true - /@types/sortablejs@1.15.4: - resolution: {integrity: sha512-7oL7CcPSfoyoNx3Ba1+79ykJzpEKVhHUyfAiN5eT/FoeDXOR3eBDLXf9ndDNuxaExmjpI+zVi2dMMuaoXUOzNA==} + /@types/sortablejs@1.15.8: + resolution: {integrity: sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==} dev: true /@types/stack-utils@2.0.2: @@ -4435,7 +4579,7 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.5): + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4447,12 +4591,12 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.9.1 - '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/type-utils': 5.62.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/utils': 5.62.0(eslint@9.0.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare-lite: 1.4.0 @@ -4463,7 +4607,7 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.5): + /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -4475,13 +4619,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.9.1 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/type-utils': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/utils': 6.21.0(eslint@9.0.0)(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -4512,7 +4656,7 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5): + /@typescript-eslint/parser@5.62.0(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4526,13 +4670,13 @@ packages: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5): + /@typescript-eslint/parser@6.21.0(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -4547,7 +4691,7 @@ packages: '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -4589,7 +4733,7 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@5.4.5): + /@typescript-eslint/type-utils@5.62.0(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4600,16 +4744,16 @@ packages: optional: true dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 5.62.0(eslint@9.0.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 tsutils: 3.21.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.4.5): + /@typescript-eslint/type-utils@6.21.0(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -4620,9 +4764,9 @@ packages: optional: true dependencies: '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 6.21.0(eslint@9.0.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 ts-api-utils: 1.0.1(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: @@ -4723,19 +4867,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.4.5): + /@typescript-eslint/utils@5.62.0(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) - eslint: 8.57.0 + eslint: 9.0.0 eslint-scope: 5.1.1 semver: 7.6.0 transitivePeerDependencies: @@ -4743,19 +4887,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.4.5): + /@typescript-eslint/utils@6.21.0(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) '@types/json-schema': 7.0.14 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) - eslint: 8.57.0 + eslint: 9.0.0 semver: 7.6.0 transitivePeerDependencies: - supports-color @@ -4778,10 +4922,6 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@ungap/structured-clone@1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true - /@vercel/nft@0.26.3: resolution: {integrity: sha512-h1z/NN9ppS4YOKwSgBoopJlhm7tS2Qb/9Ld1HXjDpvvTE7mY0xVD8nllXs+RihD9uTGJISOIMzp18Eg0EApaMA==} engines: {node: '>=16'} @@ -4811,26 +4951,26 @@ packages: vite: ^5.0.0 vue: ^3.2.25 dependencies: - vite: 5.2.8(@types/node@20.12.7)(sass@1.74.1) + vite: 5.2.8(@types/node@20.12.7)(sass@1.75.0) vue: 3.4.21(typescript@5.4.5) dev: true - /@volar/language-core@2.2.0-alpha.7: - resolution: {integrity: sha512-igpp+nTkyl8faVzRJMpSCeA4XlBJ5UVSyc/WGyksmUmP10YbfufbcQCFlxEXv2uMBV+a3L4JVCj+Vju+08FOSA==} + /@volar/language-core@2.2.0-alpha.8: + resolution: {integrity: sha512-Ew1Iw7/RIRNuDLn60fWJdOLApAlfTVPxbPiSLzc434PReC9kleYtaa//Wo2WlN1oiRqneW0pWQQV0CwYqaimLQ==} dependencies: - '@volar/source-map': 2.2.0-alpha.7 + '@volar/source-map': 2.2.0-alpha.8 dev: true - /@volar/source-map@2.2.0-alpha.7: - resolution: {integrity: sha512-iIZM2EovdEnr6mMwlsnt4ciix4xz7HSGHyUSviRaY5cii5PMXGHeUU9UDeb+xzLCx8kdk3L5J4z+ts50AhkYcg==} + /@volar/source-map@2.2.0-alpha.8: + resolution: {integrity: sha512-E1ZVmXFJ5DU4fWDcWHzi8OLqqReqIDwhXvIMhVdk6+VipfMVv4SkryXu7/rs4GA/GsebcRyJdaSkKBB3OAkIcA==} dependencies: muggle-string: 0.4.1 dev: true - /@volar/typescript@2.2.0-alpha.7: - resolution: {integrity: sha512-qy04/hx4UbW1BdPlzaxlH60D4plubcyqdbYM6Y5vZiascZxFowtd6vE39Td9FYzDxwcKgzb/Crvf/ABhdHnuBA==} + /@volar/typescript@2.2.0-alpha.8: + resolution: {integrity: sha512-RLbRDI+17CiayHZs9HhSzlH0FhLl/+XK6o2qoiw2o2GGKcyD1aDoY6AcMd44acYncTOrqoTNoY6LuCiRyiJiGg==} dependencies: - '@volar/language-core': 2.2.0-alpha.7 + '@volar/language-core': 2.2.0-alpha.8 path-browserify: 1.0.1 dev: true @@ -4880,19 +5020,19 @@ packages: '@vue/shared': 3.4.21 dev: true - /@vue/language-core@2.0.12(typescript@5.4.5): - resolution: {integrity: sha512-aIStDPt69SHOpiIckGTIIjEz/sXc6ZfCMS5uWYL1AcbcRMhzFCLZscGAVte1+ad+RRFepSpKBjGttyPcgKJ7ww==} + /@vue/language-core@2.0.13(typescript@5.4.5): + resolution: {integrity: sha512-oQgM+BM66SU5GKtUMLQSQN0bxHFkFpLSSAiY87wVziPaiNQZuKVDt/3yA7GB9PiQw0y/bTNL0bOc0jM/siYjKg==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@volar/language-core': 2.2.0-alpha.7 + '@volar/language-core': 2.2.0-alpha.8 '@vue/compiler-dom': 3.4.21 '@vue/shared': 3.4.21 computeds: 0.0.1 - minimatch: 9.0.3 + minimatch: 9.0.4 path-browserify: 1.0.1 typescript: 5.4.5 vue-template-compiler: 2.7.16 @@ -5607,6 +5747,10 @@ packages: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} dev: false + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: false + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -5693,9 +5837,17 @@ packages: /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} + dev: true - /aws-sdk@2.1597.0: - resolution: {integrity: sha512-YvApP9p5a5TD870mvQRrcUyJz3nKFrtlnDLaA4yrmAaidMDGzdNJ+AZlW0+onRCB4llzKD4Hos56zea0ulR+zQ==} + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + dev: false + + /aws-sdk@2.1599.0: + resolution: {integrity: sha512-jPb1LAN+s1TLTK+VR3TTJLr//sb3AhhT60Bm9jxB5G/fVeeRczXtBtixNpQ00gksQdkstILYLc9S6MuKMsksxA==} engines: {node: '>= 10.0.0'} requiresBuild: true dependencies: @@ -6022,6 +6174,17 @@ packages: node-releases: 2.0.13 update-browserslist-db: 1.0.13(browserslist@4.22.1) + /browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001609 + electron-to-chromium: 1.4.736 + node-releases: 2.0.14 + update-browserslist-db: 1.0.13(browserslist@4.23.0) + dev: true + /bs-logger@0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} engines: {node: '>= 6'} @@ -6075,7 +6238,7 @@ packages: resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} dependencies: base64-js: 1.5.1 - ieee754: 1.2.1 + ieee754: 1.1.13 isarray: 1.0.0 dev: false @@ -6260,6 +6423,10 @@ packages: /caniuse-lite@1.0.30001551: resolution: {integrity: sha512-vtBAez47BoGMMzlbYhfXrMV1kvRF2WP/lqiMuDu1Sb4EE4LKEgjopFDSRtZfdVnslNRpOqV/woE+Xgrwj6VQlg==} + /caniuse-lite@1.0.30001609: + resolution: {integrity: sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==} + dev: true + /canonicalize@1.0.8: resolution: {integrity: sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==} dev: false @@ -6451,6 +6618,21 @@ packages: fsevents: 2.3.3 dev: true + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -6623,7 +6805,7 @@ packages: resolution: {integrity: sha512-sX/LQ7LqUhgyaxzbe7IqwPeTr2yfpfUIQ/dgpKo6ZI4y4lpQA0YxAomWIY+7I7rHWcG02PG+OuPREzMW/5tszQ==} dependencies: inflation: 2.0.0 - qs: 6.12.0 + qs: 6.12.1 raw-body: 2.5.2 type-is: 1.6.18 dev: false @@ -6632,7 +6814,7 @@ packages: resolution: {integrity: sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==} dependencies: inflation: 2.0.0 - qs: 6.12.0 + qs: 6.12.1 raw-body: 2.5.2 type-is: 1.6.18 dev: false @@ -6845,7 +7027,7 @@ packages: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} dev: true - /consolidate@0.16.0(ejs@3.1.9)(pug@3.0.2): + /consolidate@0.16.0(ejs@3.1.10)(pug@3.0.2): resolution: {integrity: sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==} engines: {node: '>= 0.10.0'} deprecated: Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog @@ -7012,7 +7194,7 @@ packages: optional: true dependencies: bluebird: 3.7.2 - ejs: 3.1.9 + ejs: 3.1.10 pug: 3.0.2 dev: false @@ -7077,8 +7259,8 @@ packages: resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==} dev: false - /core-js@3.33.0: - resolution: {integrity: sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw==} + /core-js@3.36.1: + resolution: {integrity: sha512-BTvUrwxVBezj5SZ3f10ImnX2oRByMxql3EimVqMysepbC9EeMUOpLwdy6Eoili2x6E4kf+ZUB5k/+Jv55alPfA==} requiresBuild: true dev: true @@ -7477,8 +7659,8 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /deepl-node@1.12.0: - resolution: {integrity: sha512-c/8x1R0dXPL7NSDdQ94lYPou/A+I6cbo6b7gFb/28HbjcHnKB4RtWXWLgdv7n51GEXL7OE2eoRZQcAu4ZI+vGg==} + /deepl-node@1.13.0: + resolution: {integrity: sha512-pm8Al5B+/fRHiIKoreoSmv2RlXidF18+CznhtLILiYcj3EbxZpIhxWO8cgXCCsCTrUDMAbScIl8CuH3AqLPpGg==} engines: {node: '>=12.0'} dependencies: '@types/node': 20.12.7 @@ -7763,8 +7945,8 @@ packages: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: false - /ejs@3.1.9: - resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} + /ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} hasBin: true dependencies: @@ -7778,6 +7960,10 @@ packages: /electron-to-chromium@1.4.561: resolution: {integrity: sha512-eS5t4ulWOBfVHdq9SW2dxEaFarj1lPjvJ8PaYMOjY0DecBaj/t4ARziL2IPpDr4atyWwjLFGQ2vo/VCgQFezVQ==} + /electron-to-chromium@1.4.736: + resolution: {integrity: sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==} + dev: true + /emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} @@ -8028,41 +8214,41 @@ packages: engines: {node: '>=12'} dev: true - /eslint-compat-utils@0.1.2(eslint@8.57.0): + /eslint-compat-utils@0.1.2(eslint@9.0.0): resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: - eslint: 8.57.0 + eslint: 9.0.0 dev: true - /eslint-compat-utils@0.4.1(eslint@8.57.0): + /eslint-compat-utils@0.4.1(eslint@9.0.0): resolution: {integrity: sha512-5N7ZaJG5pZxUeNNJfUchurLVrunD1xJvyg5kYOIVF8kg1f3ajTikmAu/5fZ9w100omNPOoMjngRszh/Q/uFGMg==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: - eslint: 8.57.0 + eslint: 9.0.0 semver: 7.6.0 dev: true - /eslint-config-prettier@8.9.0(eslint@8.57.0): + /eslint-config-prettier@8.9.0(eslint@9.0.0): resolution: {integrity: sha512-+sbni7NfVXnOpnRadUA8S28AUlsZt9GjgFvABIRL9Hkn8KqNzOp+7Lw4QWtrwn20KzU3wqu1QoOj2m+7rKRqkA==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.57.0 + eslint: 9.0.0 dev: true - /eslint-config-prettier@9.1.0(eslint@8.57.0): + /eslint-config-prettier@9.1.0(eslint@9.0.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.57.0 + eslint: 9.0.0 dev: true /eslint-config-standard@16.0.3(eslint-plugin-import@2.28.0)(eslint-plugin-node@11.1.0)(eslint-plugin-promise@6.1.1)(eslint@8.46.0): @@ -8132,7 +8318,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@9.0.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -8153,15 +8339,15 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) debug: 3.2.7 - eslint: 8.57.0 + eslint: 9.0.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@9.0.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -8182,24 +8368,24 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) debug: 3.2.7 - eslint: 8.57.0 + eslint: 9.0.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-es-x@7.5.0(eslint@8.57.0): + /eslint-plugin-es-x@7.5.0(eslint@9.0.0): resolution: {integrity: sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) '@eslint-community/regexpp': 4.9.1 - eslint: 8.57.0 - eslint-compat-utils: 0.1.2(eslint@8.57.0) + eslint: 9.0.0 + eslint-compat-utils: 0.1.2(eslint@9.0.0) dev: true /eslint-plugin-es@3.0.1(eslint@8.46.0): @@ -8213,35 +8399,35 @@ packages: regexpp: 3.2.0 dev: true - /eslint-plugin-es@4.1.0(eslint@8.57.0): + /eslint-plugin-es@4.1.0(eslint@9.0.0): resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} engines: {node: '>=8.10.0'} peerDependencies: eslint: '>=4.19.1' dependencies: - eslint: 8.57.0 + eslint: 9.0.0 eslint-utils: 2.1.0 regexpp: 3.2.0 dev: true - /eslint-plugin-eslint-comments@3.2.0(eslint@8.57.0): + /eslint-plugin-eslint-comments@3.2.0(eslint@9.0.0): resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} engines: {node: '>=6.5.0'} peerDependencies: eslint: '>=4.19.1' dependencies: escape-string-regexp: 1.0.5 - eslint: 8.57.0 + eslint: 9.0.0 ignore: 5.2.4 dev: true - /eslint-plugin-file-progress@1.3.0(eslint@8.57.0): + /eslint-plugin-file-progress@1.3.0(eslint@9.0.0): resolution: {integrity: sha512-LncpnGHU26KPvCrvDC2Sl9PfjdrsG8qltgiK6BR7KybWtfqrdlsu1ax3+hyPMn5OkKBTF3Wki3oqK1MSMeOtQw==} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: chalk: 4.1.2 - eslint: 8.57.0 + eslint: 9.0.0 ora: 5.4.1 dev: true @@ -8287,7 +8473,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.29.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0): + /eslint-plugin-import@2.29.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0): resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} engines: {node: '>=4'} peerDependencies: @@ -8297,16 +8483,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.0 + eslint: 9.0.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@9.0.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -8322,7 +8508,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint@9.0.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: @@ -8332,16 +8518,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.0 + eslint: 9.0.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@9.0.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -8357,7 +8543,7 @@ packages: - supports-color dev: true - /eslint-plugin-jsdoc@48.0.6(eslint@8.57.0): + /eslint-plugin-jsdoc@48.0.6(eslint@9.0.0): resolution: {integrity: sha512-LgwXOX6TWxxFYcbdVe+BJ94Kl/pgjSPYHLzqEdAMXTA1BH9WDx7iJ+9/iDajPF64LtzWX8C1mCfpbMZjJGhAOw==} engines: {node: '>=18'} peerDependencies: @@ -8368,7 +8554,7 @@ packages: comment-parser: 1.4.1 debug: 4.3.4(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint: 8.57.0 + eslint: 9.0.0 esquery: 1.5.0 is-builtin-module: 3.2.1 semver: 7.6.0 @@ -8377,28 +8563,28 @@ packages: - supports-color dev: true - /eslint-plugin-jsonc@2.10.0(eslint@8.57.0): + /eslint-plugin-jsonc@2.10.0(eslint@9.0.0): resolution: {integrity: sha512-9d//o6Jyh4s1RxC9fNSt1+MMaFN2ruFdXPG9XZcb/mR2KkfjADYiNL/hbU6W0Cyxfg3tS/XSFuhl5LgtMD8hmw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - eslint: 8.57.0 - eslint-compat-utils: 0.1.2(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + eslint: 9.0.0 + eslint-compat-utils: 0.1.2(eslint@9.0.0) jsonc-eslint-parser: 2.3.0 natural-compare: 1.4.0 dev: true - /eslint-plugin-jsonc@2.13.0(eslint@8.57.0): + /eslint-plugin-jsonc@2.13.0(eslint@9.0.0): resolution: {integrity: sha512-2wWdJfpO/UbZzPDABuUVvlUQjfMJa2p2iQfYt/oWxOMpXCcjuiMUSaA02gtY/Dbu82vpaSqc+O7Xq6ECHwtIxA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - eslint: 8.57.0 - eslint-compat-utils: 0.4.1(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + eslint: 9.0.0 + eslint-compat-utils: 0.4.1(eslint@9.0.0) espree: 9.6.1 graphemer: 1.4.0 jsonc-eslint-parser: 2.4.0 @@ -8406,28 +8592,28 @@ packages: synckit: 0.6.2 dev: true - /eslint-plugin-markdown@3.0.1(eslint@8.57.0): + /eslint-plugin-markdown@3.0.1(eslint@9.0.0): resolution: {integrity: sha512-8rqoc148DWdGdmYF6WSQFT3uQ6PO7zXYgeBpHAOAakX/zpq+NvFYbDA/H7PYzHajwtmaOzAwfxyl++x0g1/N9A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - eslint: 8.57.0 + eslint: 9.0.0 mdast-util-from-markdown: 0.8.5 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-n@15.7.0(eslint@8.57.0): + /eslint-plugin-n@15.7.0(eslint@9.0.0): resolution: {integrity: sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==} engines: {node: '>=12.22.0'} peerDependencies: eslint: '>=7.0.0' dependencies: builtins: 5.0.1 - eslint: 8.57.0 - eslint-plugin-es: 4.1.0(eslint@8.57.0) - eslint-utils: 3.0.0(eslint@8.57.0) + eslint: 9.0.0 + eslint-plugin-es: 4.1.0(eslint@9.0.0) + eslint-utils: 3.0.0(eslint@9.0.0) ignore: 5.2.4 is-core-module: 2.13.1 minimatch: 3.1.2 @@ -8435,16 +8621,16 @@ packages: semver: 7.6.0 dev: true - /eslint-plugin-n@16.6.2(eslint@8.57.0): + /eslint-plugin-n@16.6.2(eslint@9.0.0): resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==} engines: {node: '>=16.0.0'} peerDependencies: eslint: '>=7.0.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) builtins: 5.0.1 - eslint: 8.57.0 - eslint-plugin-es-x: 7.5.0(eslint@8.57.0) + eslint: 9.0.0 + eslint-plugin-es-x: 7.5.0(eslint@9.0.0) get-tsconfig: 4.7.2 globals: 13.24.0 ignore: 5.2.4 @@ -8470,7 +8656,7 @@ packages: semver: 6.3.1 dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.9.0)(eslint@8.57.0)(prettier@3.2.5): + /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.9.0)(eslint@9.0.0)(prettier@3.2.5): resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -8481,13 +8667,13 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.57.0 - eslint-config-prettier: 8.9.0(eslint@8.57.0) + eslint: 9.0.0 + eslint-config-prettier: 8.9.0(eslint@9.0.0) prettier: 3.2.5 prettier-linter-helpers: 1.0.0 dev: true - /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5): + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@9.0.0)(prettier@3.2.5): resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -8501,20 +8687,20 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.57.0 - eslint-config-prettier: 9.1.0(eslint@8.57.0) + eslint: 9.0.0 + eslint-config-prettier: 9.1.0(eslint@9.0.0) prettier: 3.2.5 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 dev: true - /eslint-plugin-promise@5.2.0(eslint@8.57.0): + /eslint-plugin-promise@5.2.0(eslint@9.0.0): resolution: {integrity: sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: eslint: ^7.0.0 dependencies: - eslint: 8.57.0 + eslint: 9.0.0 dev: true /eslint-plugin-promise@6.1.1(eslint@8.46.0): @@ -8526,13 +8712,13 @@ packages: eslint: 8.46.0 dev: true - /eslint-plugin-promise@6.1.1(eslint@8.57.0): + /eslint-plugin-promise@6.1.1(eslint@9.0.0): resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - eslint: 8.57.0 + eslint: 9.0.0 dev: true /eslint-plugin-standard@5.0.0(eslint@8.46.0): @@ -8551,7 +8737,7 @@ packages: '@microsoft/tsdoc-config': 0.16.2 dev: true - /eslint-plugin-unicorn@40.1.0(eslint@8.57.0): + /eslint-plugin-unicorn@40.1.0(eslint@9.0.0): resolution: {integrity: sha512-y5doK2DF9Sr5AqKEHbHxjFllJ167nKDRU01HDcWyv4Tnmaoe9iNxMrBnaybZvWZUaE3OC5Unu0lNIevYamloig==} engines: {node: '>=12'} peerDependencies: @@ -8560,8 +8746,8 @@ packages: '@babel/helper-validator-identifier': 7.22.20 ci-info: 3.9.0 clean-regexp: 1.0.0 - eslint: 8.57.0 - eslint-utils: 3.0.0(eslint@8.57.0) + eslint: 9.0.0 + eslint-utils: 3.0.0(eslint@9.0.0) esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 @@ -8574,17 +8760,17 @@ packages: strip-indent: 3.0.0 dev: true - /eslint-plugin-unicorn@45.0.2(eslint@8.57.0): + /eslint-plugin-unicorn@45.0.2(eslint@9.0.0): resolution: {integrity: sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==} engines: {node: '>=14.18'} peerDependencies: eslint: '>=8.28.0' dependencies: '@babel/helper-validator-identifier': 7.22.5 - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) ci-info: 3.9.0 clean-regexp: 1.0.0 - eslint: 8.57.0 + eslint: 9.0.0 esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 @@ -8603,92 +8789,92 @@ packages: resolution: {integrity: sha512-WE+YlK9X9s4vf5EaYRU0Scw7WItDZStm+PapFSYlg2ABNtaQ4zIG7wEqpoUB3SlfM+SgkhgmzR0TeJOO5k3/Nw==} dev: true - /eslint-plugin-vue-scoped-css@2.5.0(eslint@8.57.0)(vue-eslint-parser@9.3.1): + /eslint-plugin-vue-scoped-css@2.5.0(eslint@9.0.0)(vue-eslint-parser@9.3.1): resolution: {integrity: sha512-vR+raYNE1aQ69lS1lZGiKoz8rXFI3MWf2fxrfns/XCQ0XT5sIguhDtQS+9JmUQJClenLDEe2CQx7P+eeSdF4cA==} engines: {node: ^12.22 || ^14.17 || >=16} peerDependencies: eslint: '>=5.0.0' vue-eslint-parser: '>=7.1.0' dependencies: - eslint: 8.57.0 - eslint-utils: 3.0.0(eslint@8.57.0) + eslint: 9.0.0 + eslint-utils: 3.0.0(eslint@9.0.0) lodash: 4.17.21 postcss: 8.4.31 postcss-safe-parser: 6.0.0(postcss@8.4.31) postcss-scss: 4.0.6(postcss@8.4.31) postcss-selector-parser: 6.0.13 postcss-styl: 0.12.3 - vue-eslint-parser: 9.3.1(eslint@8.57.0) + vue-eslint-parser: 9.3.1(eslint@9.0.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-vue-scoped-css@2.7.2(eslint@8.57.0)(vue-eslint-parser@9.4.2): + /eslint-plugin-vue-scoped-css@2.7.2(eslint@9.0.0)(vue-eslint-parser@9.4.2): resolution: {integrity: sha512-myJ99CJuwmAx5kq1WjgIeaUkxeU6PIEUh7age79Alm30bhN4fVTapOQLSMlvVTgxr36Y3igsZ3BCJM32LbHHig==} engines: {node: ^12.22 || ^14.17 || >=16} peerDependencies: eslint: '>=5.0.0' vue-eslint-parser: '>=7.1.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - eslint: 8.57.0 - eslint-compat-utils: 0.4.1(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + eslint: 9.0.0 + eslint-compat-utils: 0.4.1(eslint@9.0.0) lodash: 4.17.21 postcss: 8.4.31 postcss-safe-parser: 6.0.0(postcss@8.4.31) postcss-scss: 4.0.6(postcss@8.4.31) postcss-selector-parser: 6.0.13 postcss-styl: 0.12.3 - vue-eslint-parser: 9.4.2(eslint@8.57.0) + vue-eslint-parser: 9.4.2(eslint@9.0.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-vue@9.16.1(eslint@8.57.0): + /eslint-plugin-vue@9.16.1(eslint@9.0.0): resolution: {integrity: sha512-2FtnTqazA6aYONfDuOZTk0QzwhAwi7Z4+uJ7+GHeGxcKapjqWlDsRWDenvyG/utyOfAS5bVRmAG3cEWiYEz2bA==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - eslint: 8.57.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + eslint: 9.0.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.13 semver: 7.6.0 - vue-eslint-parser: 9.3.2(eslint@8.57.0) + vue-eslint-parser: 9.3.2(eslint@9.0.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-vue@9.21.1(eslint@8.57.0): + /eslint-plugin-vue@9.21.1(eslint@9.0.0): resolution: {integrity: sha512-XVtI7z39yOVBFJyi8Ljbn7kY9yHzznKXL02qQYn+ta63Iy4A9JFBw6o4OSB9hyD2++tVT+su9kQqetUyCCwhjw==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - eslint: 8.57.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + eslint: 9.0.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.13 semver: 7.6.0 - vue-eslint-parser: 9.4.2(eslint@8.57.0) + vue-eslint-parser: 9.4.2(eslint@9.0.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-yml@1.10.0(eslint@8.57.0): + /eslint-plugin-yml@1.10.0(eslint@9.0.0): resolution: {integrity: sha512-53SUwuNDna97lVk38hL/5++WXDuugPM9SUQ1T645R0EHMRCdBIIxGye/oOX2qO3FQ7aImxaUZJU/ju+NMUBrLQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 - eslint-compat-utils: 0.1.2(eslint@8.57.0) + eslint: 9.0.0 + eslint-compat-utils: 0.1.2(eslint@9.0.0) lodash: 4.17.21 natural-compare: 1.4.0 yaml-eslint-parser: 1.2.2 @@ -8696,15 +8882,15 @@ packages: - supports-color dev: true - /eslint-plugin-yml@1.12.2(eslint@8.57.0): + /eslint-plugin-yml@1.12.2(eslint@9.0.0): resolution: {integrity: sha512-hvS9p08FhPT7i/ynwl7/Wt7ke7Rf4P2D6fT8lZlL43peZDTsHtH2A0SIFQ7Kt7+mJ6if6P+FX3iJhMkdnxQwpg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 - eslint-compat-utils: 0.4.1(eslint@8.57.0) + eslint: 9.0.0 + eslint-compat-utils: 0.4.1(eslint@9.0.0) lodash: 4.17.21 natural-compare: 1.4.0 yaml-eslint-parser: 1.2.2 @@ -8747,13 +8933,13 @@ packages: eslint-visitor-keys: 1.3.0 dev: true - /eslint-utils@3.0.0(eslint@8.57.0): + /eslint-utils@3.0.0(eslint@9.0.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.57.0 + eslint: 9.0.0 eslint-visitor-keys: 2.1.0 dev: true @@ -8828,53 +9014,6 @@ packages: - supports-color dev: true - /eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.9.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.2.4 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.3 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - dev: true - /eslint@9.0.0: resolution: {integrity: sha512-IMryZ5SudxzQvuod6rUdIUz29qFItWx281VhtFVc2Psy/ZhlCeD/5DT6lBIJ4H3G+iamGJoTln1v+QSuPw0p7Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -9584,7 +9723,7 @@ packages: dezalgo: 1.0.4 hexoid: 1.0.0 once: 1.4.0 - qs: 6.12.0 + qs: 6.12.1 dev: false /fragment-cache@0.2.1: @@ -9648,7 +9787,7 @@ packages: requiresBuild: true dependencies: bindings: 1.5.0 - nan: 2.18.0 + nan: 2.19.0 dev: false optional: true @@ -9727,9 +9866,9 @@ packages: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.0 + hasown: 2.0.2 /get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} @@ -10183,6 +10322,10 @@ packages: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} @@ -10193,6 +10336,12 @@ packages: dependencies: has-symbols: 1.0.3 + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + /has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} dev: true @@ -10240,6 +10389,12 @@ packages: dependencies: function-bind: 1.1.2 + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -10437,8 +10592,8 @@ packages: engines: {node: '>= 4'} dev: true - /immutable@4.3.2: - resolution: {integrity: sha512-oGXzbEDem9OOpDWZu88jGiYCvIsLHMvGw+8OXlpsvTFvIQplQbjg1B1cvKg8f7Hoch6+NGjpPsH1Fr+Mc2D1aA==} + /immutable@4.3.5: + resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} dev: true /import-fresh@3.3.0: @@ -10595,7 +10750,7 @@ packages: resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} engines: {node: '>= 0.10'} dependencies: - hasown: 2.0.0 + hasown: 2.0.2 dev: false /is-alphabetical@1.0.4: @@ -10614,7 +10769,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: false /is-array-buffer@3.0.2: @@ -10657,7 +10812,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-buffer@1.1.6: @@ -10689,14 +10844,14 @@ packages: resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} engines: {node: '>= 0.4'} dependencies: - hasown: 2.0.0 + hasown: 2.0.2 dev: false /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-decimal@1.0.4: @@ -10829,7 +10984,7 @@ packages: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-number@3.0.0: @@ -10947,6 +11102,14 @@ packages: engines: {node: '>= 0.4'} dependencies: which-typed-array: 1.1.11 + dev: true + + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.15 + dev: false /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -11102,7 +11265,7 @@ packages: engines: {node: '>=10'} hasBin: true dependencies: - async: 3.2.4 + async: 3.2.5 chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 @@ -12002,7 +12165,7 @@ packages: http-errors: 1.8.1 koa-compose: 4.1.0 methods: 1.1.2 - path-to-regexp: 6.2.1 + path-to-regexp: 6.2.2 transitivePeerDependencies: - supports-color dev: false @@ -12036,7 +12199,7 @@ packages: - supports-color dev: false - /koa-views@7.0.2(@types/koa@2.15.0)(ejs@3.1.9)(pug@3.0.2): + /koa-views@7.0.2(@types/koa@2.15.0)(ejs@3.1.10)(pug@3.0.2): resolution: {integrity: sha512-dvx3mdVeSVuIPEaKAoGbxLcenudvhl821xxyuRbcoA+bOJ2dvN8wlGjkLu0ZFMlkCscXZV6lzxy28rafeazI/w==} deprecated: This package is deprecated, please use the new fork @ladjs/koa-views. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/koa-views for updates and release changelog peerDependencies: @@ -12046,7 +12209,7 @@ packages: optional: true dependencies: '@types/koa': 2.15.0 - consolidate: 0.16.0(ejs@3.1.9)(pug@3.0.2) + consolidate: 0.16.0(ejs@3.1.10)(pug@3.0.2) debug: 4.3.4(supports-color@8.1.1) get-paths: 0.0.7 koa-send: 5.0.1 @@ -12275,8 +12438,8 @@ packages: engines: {node: '>=6.11.5'} dev: true - /loadjs@4.2.0: - resolution: {integrity: sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==} + /loadjs@4.3.0: + resolution: {integrity: sha512-vNX4ZZLJBeDEOBvdr2v/F+0aN5oMuPu7JTqrMwp+DtgK+AryOlpy6Xtm2/HpNr+azEa828oQjOtWsB6iDtSfSQ==} dev: true /local-pkg@0.5.0: @@ -12727,6 +12890,13 @@ packages: dependencies: brace-expansion: 2.0.1 + /minimatch@9.0.4: + resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} engines: {node: '>= 6'} @@ -12903,8 +13073,8 @@ packages: thenify-all: 1.6.0 dev: false - /nan@2.18.0: - resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} + /nan@2.19.0: + resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} requiresBuild: true dev: false optional: true @@ -13055,6 +13225,10 @@ packages: /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + dev: true + /nodemailer@6.9.13: resolution: {integrity: sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==} engines: {node: '>=6.0.0'} @@ -13682,6 +13856,10 @@ packages: resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} dev: false + /path-to-regexp@6.2.2: + resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} + dev: false + /path-type@1.1.0: resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} engines: {node: '>=0.10.0'} @@ -13907,8 +14085,8 @@ packages: engines: {node: '>=14.19.0'} dev: false - /pnpm@8.15.6: - resolution: {integrity: sha512-d7iem+d6Kwatj0A6Gcrl4il29hAj+YrTI9XDAZSVjrwC7gpq5dE+5FT2E05OjK8poF8LGg4dKxe8prah8RWfhg==} + /pnpm@8.15.7: + resolution: {integrity: sha512-yFzSG22hAzIVaxyiqnnAph7nrS6wRTuIqymSienoypPmCRIyslwHy/YfbfdxKNnISeXJrG5EhU29IRxJ86Z63A==} engines: {node: '>=16.14'} hasBin: true dev: true @@ -13918,6 +14096,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: false + /postcss-calc@5.3.1: resolution: {integrity: sha512-iBcptYFq+QUh9gzP7ta2btw50o40s4uLI4UDVgd5yRAZtUDWc5APdl5yQDd2h/TyiZNbJrv0HiYhT102CMgN7Q==} dependencies: @@ -14512,8 +14695,8 @@ packages: yargs: 15.4.1 dev: false - /qs@6.12.0: - resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==} + /qs@6.12.1: + resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==} engines: {node: '>=0.6'} dependencies: side-channel: 1.0.6 @@ -15009,28 +15192,28 @@ packages: seedrandom: 2.4.2 dev: false - /rollup@4.14.1: - resolution: {integrity: sha512-4LnHSdd3QK2pa1J6dFbfm1HN0D7vSK/ZuZTsdyUAlA6Rr1yTouUTL13HaDOGJVgby461AhrNGBS7sCGXXtT+SA==} + /rollup@4.14.2: + resolution: {integrity: sha512-WkeoTWvuBoFjFAhsEOHKRoZ3r9GfTyhh7Vff1zwebEFLEFjT1lG3784xEgKiTa7E+e70vsC81roVL2MP4tgEEQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.14.1 - '@rollup/rollup-android-arm64': 4.14.1 - '@rollup/rollup-darwin-arm64': 4.14.1 - '@rollup/rollup-darwin-x64': 4.14.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.14.1 - '@rollup/rollup-linux-arm64-gnu': 4.14.1 - '@rollup/rollup-linux-arm64-musl': 4.14.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.14.1 - '@rollup/rollup-linux-riscv64-gnu': 4.14.1 - '@rollup/rollup-linux-s390x-gnu': 4.14.1 - '@rollup/rollup-linux-x64-gnu': 4.14.1 - '@rollup/rollup-linux-x64-musl': 4.14.1 - '@rollup/rollup-win32-arm64-msvc': 4.14.1 - '@rollup/rollup-win32-ia32-msvc': 4.14.1 - '@rollup/rollup-win32-x64-msvc': 4.14.1 + '@rollup/rollup-android-arm-eabi': 4.14.2 + '@rollup/rollup-android-arm64': 4.14.2 + '@rollup/rollup-darwin-arm64': 4.14.2 + '@rollup/rollup-darwin-x64': 4.14.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.14.2 + '@rollup/rollup-linux-arm64-gnu': 4.14.2 + '@rollup/rollup-linux-arm64-musl': 4.14.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.14.2 + '@rollup/rollup-linux-riscv64-gnu': 4.14.2 + '@rollup/rollup-linux-s390x-gnu': 4.14.2 + '@rollup/rollup-linux-x64-gnu': 4.14.2 + '@rollup/rollup-linux-x64-musl': 4.14.2 + '@rollup/rollup-win32-arm64-msvc': 4.14.2 + '@rollup/rollup-win32-ia32-msvc': 4.14.2 + '@rollup/rollup-win32-x64-msvc': 4.14.2 fsevents: 2.3.3 dev: true @@ -15102,13 +15285,13 @@ packages: postcss: 8.4.35 dev: false - /sass@1.74.1: - resolution: {integrity: sha512-w0Z9p/rWZWelb88ISOLyvqTWGmtmu2QJICqDBGyNnfG4OUnPX9BBjjYIXUpXCMOOg5MQWNpqzt876la1fsTvUA==} + /sass@1.75.0: + resolution: {integrity: sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==} engines: {node: '>=14.0.0'} hasBin: true dependencies: - chokidar: 3.5.3 - immutable: 4.3.2 + chokidar: 3.6.0 + immutable: 4.3.5 source-map-js: 1.2.0 dev: true @@ -16257,7 +16440,7 @@ packages: typescript: 5.4.5 dev: true - /ts-jest@29.1.1(@babel/core@7.23.2)(jest@29.7.0)(typescript@4.9.4): + /ts-jest@29.1.1(@babel/core@7.24.4)(jest@29.7.0)(typescript@4.9.4): resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -16278,7 +16461,7 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.23.2 + '@babel/core': 7.24.4 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 jest: 29.7.0(@types/node@18.11.18) @@ -16806,6 +16989,17 @@ packages: escalade: 3.1.1 picocolors: 1.0.0 + /update-browserslist-db@1.0.13(browserslist@4.23.0): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.23.0 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -16849,8 +17043,8 @@ packages: inherits: 2.0.4 is-arguments: 1.1.1 is-generator-function: 1.0.10 - is-typed-array: 1.1.12 - which-typed-array: 1.1.11 + is-typed-array: 1.1.13 + which-typed-array: 1.1.15 dev: false /uuid@8.0.0: @@ -16982,12 +17176,12 @@ packages: chalk: 4.1.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 10.1.0 - vite: 5.2.8(@types/node@20.12.7)(sass@1.74.1) + vite: 5.2.8(@types/node@20.12.7)(sass@1.75.0) transitivePeerDependencies: - supports-color dev: true - /vite@5.2.8(@types/node@20.12.7)(sass@1.74.1): + /vite@5.2.8(@types/node@20.12.7)(sass@1.75.0): resolution: {integrity: sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -17018,8 +17212,8 @@ packages: '@types/node': 20.12.7 esbuild: 0.20.2 postcss: 8.4.38 - rollup: 4.14.1 - sass: 1.74.1 + rollup: 4.14.2 + sass: 1.75.0 optionalDependencies: fsevents: 2.3.3 dev: true @@ -17036,7 +17230,7 @@ packages: resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} dev: true - /vue-draggable-plus@0.4.0(@types/sortablejs@1.15.4): + /vue-draggable-plus@0.4.0(@types/sortablejs@1.15.8): resolution: {integrity: sha512-CcvSopMmSZY9McCdQ56QsAydT5cZilx9LzLU0UIz6KDYe9ll6QnmNHN80t6wnxN402ZECSXc5X1dm/myiMFi+A==} peerDependencies: '@types/sortablejs': ^1.15.0 @@ -17045,17 +17239,17 @@ packages: '@vue/composition-api': optional: true dependencies: - '@types/sortablejs': 1.15.4 + '@types/sortablejs': 1.15.8 dev: true - /vue-eslint-parser@9.3.1(eslint@8.57.0): + /vue-eslint-parser@9.3.1(eslint@9.0.0): resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -17066,14 +17260,14 @@ packages: - supports-color dev: true - /vue-eslint-parser@9.3.2(eslint@8.57.0): + /vue-eslint-parser@9.3.2(eslint@9.0.0): resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -17084,14 +17278,14 @@ packages: - supports-color dev: true - /vue-eslint-parser@9.4.2(eslint@8.57.0): + /vue-eslint-parser@9.4.2(eslint@9.0.0): resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + eslint: 9.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -17125,14 +17319,14 @@ packages: he: 1.2.0 dev: true - /vue-tsc@2.0.12(typescript@5.4.5): - resolution: {integrity: sha512-thlBBWlPYrNdba535oDdxz7PRUufZgRZRVP5Aql5wBVpGSWSeqou4EzFXeKVoZr59lp9hJROubDVzlhACmcEhg==} + /vue-tsc@2.0.13(typescript@5.4.5): + resolution: {integrity: sha512-a3nL3FvguCWVJUQW/jFrUxdeUtiEkbZoQjidqvMeBK//tuE2w6NWQAbdrEpY2+6nSa4kZoKZp8TZUMtHpjt4mQ==} hasBin: true peerDependencies: typescript: '*' dependencies: - '@volar/typescript': 2.2.0-alpha.7 - '@vue/language-core': 2.0.12(typescript@5.4.5) + '@volar/typescript': 2.2.0-alpha.8 + '@vue/language-core': 2.0.13(typescript@5.4.5) semver: 7.6.0 typescript: 5.4.5 dev: true @@ -17319,6 +17513,18 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 + dev: true + + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + dev: false /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} @@ -17459,7 +17665,7 @@ packages: resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} engines: {node: '>=4.0.0'} dependencies: - sax: 1.2.4 + sax: 1.2.1 xmlbuilder: 11.0.1 dev: false @@ -17677,9 +17883,9 @@ packages: name: plyr version: 3.7.0 dependencies: - core-js: 3.33.0 + core-js: 3.36.1 custom-event-polyfill: 1.0.7 - loadjs: 4.2.0 + loadjs: 4.3.0 rangetouch: 2.0.1 url-polyfill: 1.1.12 dev: true From eb5dccacfe1a54c7d135c4a78e0df847573ec230 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 15 Apr 2024 04:17:35 +0900 Subject: [PATCH 11/22] chore (firefish-js): remove bun lockfile Why is it there? --- packages/firefish-js/bun.lockb | Bin 205415 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 packages/firefish-js/bun.lockb diff --git a/packages/firefish-js/bun.lockb b/packages/firefish-js/bun.lockb deleted file mode 100755 index 96788d2325e16f3b57147f261f42045089d2e48e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 205415 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 Date: Mon, 15 Apr 2024 04:30:49 +0900 Subject: [PATCH 12/22] chore (backend): remove 'quiet' settings --- packages/backend/src/boot/index.ts | 4 +- packages/backend/src/boot/master.ts | 98 ++++++------ packages/backend/src/env.ts | 2 - .../remote/activitypub/kernel/delete/note.ts | 4 +- .../api/endpoints/notes/make-private.ts | 2 +- packages/backend/src/services/logger.ts | 1 - packages/backend/src/services/note/delete.ts | 142 +++++++++--------- 7 files changed, 119 insertions(+), 134 deletions(-) diff --git a/packages/backend/src/boot/index.ts b/packages/backend/src/boot/index.ts index 8caf7d062e..4ba24c280b 100644 --- a/packages/backend/src/boot/index.ts +++ b/packages/backend/src/boot/index.ts @@ -76,9 +76,7 @@ cluster.on("exit", (worker) => { }); // Display detail of unhandled promise rejection -if (!envOption.quiet) { - process.on("unhandledRejection", console.dir); -} +process.on("unhandledRejection", console.dir); // Display detail of uncaught exception process.on("uncaughtException", (err) => { diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index e54a2889e2..cd21c33021 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -28,58 +28,56 @@ const bootLogger = logger.createSubLogger("boot", "magenta", false); const themeColor = chalk.hex("#31748f"); function greet() { - if (!envOption.quiet) { - //#region Firefish logo - console.log( - themeColor( - "██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄ ", - ), - ); - console.log( - themeColor( - "██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄ ", - ), - ); - console.log( - themeColor( - "█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄ ", - ), - ); - console.log( - themeColor( - "██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄ ", - ), - ); - console.log( - themeColor( - "██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █ ", - ), - ); - console.log( - themeColor( - "╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀ ", - ), - ); - //#endregion + //#region Firefish logo + console.log( + themeColor( + "██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄ ", + ), + ); + console.log( + themeColor( + "██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄ ", + ), + ); + console.log( + themeColor( + "█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄ ", + ), + ); + console.log( + themeColor( + "██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄ ", + ), + ); + console.log( + themeColor( + "██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █ ", + ), + ); + console.log( + themeColor( + "╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀ ", + ), + ); + //#endregion - console.log( - " Firefish is an open-source decentralized microblogging platform.", - ); - console.log( - chalk.rgb( - 255, - 136, - 0, - )( - " If you like Firefish, please consider contributing to the repo. https://firefish.dev/firefish/firefish", - ), - ); + console.log( + " Firefish is an open-source decentralized microblogging platform.", + ); + console.log( + chalk.rgb( + 255, + 136, + 0, + )( + " If you like Firefish, please consider contributing to the repo. https://firefish.dev/firefish/firefish", + ), + ); - console.log(""); - console.log( - chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`, - ); - } + console.log(""); + console.log( + chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`, + ); bootLogger.info("Welcome to Firefish!"); bootLogger.info(`Firefish v${meta.version}`, null, true); diff --git a/packages/backend/src/env.ts b/packages/backend/src/env.ts index a788a0fba2..a10952133e 100644 --- a/packages/backend/src/env.ts +++ b/packages/backend/src/env.ts @@ -5,7 +5,6 @@ const envOption = { disableClustering: false, verbose: false, withLogTime: false, - quiet: false, slow: false, }; @@ -19,7 +18,6 @@ for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) { } if (process.env.NODE_ENV === "test") envOption.disableClustering = true; -if (process.env.NODE_ENV === "test") envOption.quiet = true; if (process.env.NODE_ENV === "test") envOption.noDaemons = true; export { envOption }; diff --git a/packages/backend/src/remote/activitypub/kernel/delete/note.ts b/packages/backend/src/remote/activitypub/kernel/delete/note.ts index 4656480c2f..ae3a593d05 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/note.ts @@ -1,5 +1,5 @@ import type { CacheableRemoteUser } from "@/models/entities/user.js"; -import deleteNode from "@/services/note/delete.js"; +import deleteNote from "@/services/note/delete.js"; import { apLogger } from "../../logger.js"; import DbResolver from "../../db-resolver.js"; import { getApLock } from "@/misc/app-lock.js"; @@ -36,7 +36,7 @@ export default async function ( return "The user trying to delete the post is not the post author"; } - await deleteNode(actor, note); + await deleteNote(actor, note); return "ok: note deleted"; } finally { await lock.release(); diff --git a/packages/backend/src/server/api/endpoints/notes/make-private.ts b/packages/backend/src/server/api/endpoints/notes/make-private.ts index 7b9ebc4d1a..5ddf1f3bf1 100644 --- a/packages/backend/src/server/api/endpoints/notes/make-private.ts +++ b/packages/backend/src/server/api/endpoints/notes/make-private.ts @@ -53,7 +53,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.accessDenied); } - await deleteNote(user, note, false, false); + await deleteNote(user, note, false); await Notes.update(note.id, { visibility: "specified", visibleUserIds: [], diff --git a/packages/backend/src/services/logger.ts b/packages/backend/src/services/logger.ts index 63eb3d00b9..47a1fe82f8 100644 --- a/packages/backend/src/services/logger.ts +++ b/packages/backend/src/services/logger.ts @@ -56,7 +56,6 @@ export default class Logger { subDomains: Domain[] = [], store = true, ): void { - if (envOption.quiet) return; if ( !(typeof config.logLevel === "undefined") && !config.logLevel.includes(level) diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index ac3515cfae..be3bf1e8b2 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -38,7 +38,6 @@ async function recalculateNotesCountOfLocalUser(user: { export default async function ( user: { id: User["id"]; uri: User["uri"]; host: User["host"] }, note: Note, - quiet = false, deleteFromDb = true, ) { const deletedAt = new Date(); @@ -67,87 +66,80 @@ export default async function ( } const instanceNotesCountDecreasement: Record = {}; - if (!quiet) { - // Only broadcast "deleted" to local if the note is deleted from db + // Only broadcast "deleted" to local if the note is deleted from db + if (deleteFromDb) { + publishNoteStream(note.id, "deleted", { + deletedAt: deletedAt, + }); + } + + //#region ローカルの投稿なら削除アクティビティを配送 + if (Users.isLocalUser(user) && !note.localOnly) { + let renote: Note | null = null; + + // if deletd note is renote + if ( + note.renoteId && + note.text == null && + !note.hasPoll && + (note.fileIds == null || note.fileIds.length === 0) + ) { + renote = await Notes.findOneBy({ + id: note.renoteId, + }); + } + + const content = renderActivity( + renote + ? renderUndo( + renderAnnounce( + renote.uri || `${config.url}/notes/${renote.id}`, + note, + ), + user, + ) + : renderDelete(renderTombstone(`${config.url}/notes/${note.id}`), user), + ); + + deliverToConcerned(user, note, content); + } + + // also deliever delete activity to cascaded notes + for (const cascadingNote of cascadingNotes) { if (deleteFromDb) { - publishNoteStream(note.id, "deleted", { + // For other notes, publishNoteStream is also required. + publishNoteStream(cascadingNote.id, "deleted", { deletedAt: deletedAt, }); } - //#region ローカルの投稿なら削除アクティビティを配送 - if (Users.isLocalUser(user) && !note.localOnly) { - let renote: Note | null = null; - - // if deletd note is renote - if ( - note.renoteId && - note.text == null && - !note.hasPoll && - (note.fileIds == null || note.fileIds.length === 0) - ) { - renote = await Notes.findOneBy({ - id: note.renoteId, - }); - } - - const content = renderActivity( - renote - ? renderUndo( - renderAnnounce( - renote.uri || `${config.url}/notes/${renote.id}`, - note, - ), - user, - ) - : renderDelete( - renderTombstone(`${config.url}/notes/${note.id}`), - user, - ), - ); - - deliverToConcerned(user, note, content); + if (!cascadingNote.user) continue; + if (!Users.isLocalUser(cascadingNote.user)) { + if (!Users.isRemoteUser(cascadingNote.user)) continue; + instanceNotesCountDecreasement[cascadingNote.user.host] ??= 0; + instanceNotesCountDecreasement[cascadingNote.user.host]++; + continue; // filter out remote users } + affectedLocalUsers[cascadingNote.user.id] ??= cascadingNote.user; + if (cascadingNote.localOnly) continue; // filter out local-only notes + const content = renderActivity( + renderDelete( + renderTombstone(`${config.url}/notes/${cascadingNote.id}`), + cascadingNote.user, + ), + ); + deliverToConcerned(cascadingNote.user, cascadingNote, content); + } + //#endregion - // also deliever delete activity to cascaded notes - for (const cascadingNote of cascadingNotes) { - if (deleteFromDb) { - // For other notes, publishNoteStream is also required. - publishNoteStream(cascadingNote.id, "deleted", { - deletedAt: deletedAt, - }); - } - - if (!cascadingNote.user) continue; - if (!Users.isLocalUser(cascadingNote.user)) { - if (!Users.isRemoteUser(cascadingNote.user)) continue; - instanceNotesCountDecreasement[cascadingNote.user.host] ??= 0; - instanceNotesCountDecreasement[cascadingNote.user.host]++; - continue; // filter out remote users - } - affectedLocalUsers[cascadingNote.user.id] ??= cascadingNote.user; - if (cascadingNote.localOnly) continue; // filter out local-only notes - const content = renderActivity( - renderDelete( - renderTombstone(`${config.url}/notes/${cascadingNote.id}`), - cascadingNote.user, - ), - ); - deliverToConcerned(cascadingNote.user, cascadingNote, content); - } - //#endregion - - if (Users.isRemoteUser(user)) { - instanceNotesCountDecreasement[user.host] ??= 0; - instanceNotesCountDecreasement[user.host]++; - } - for (const [host, count] of Object.entries( - instanceNotesCountDecreasement, - )) { - registerOrFetchInstanceDoc(host).then((i) => { - Instances.decrement({ id: i.id }, "notesCount", count); - }); - } + if (Users.isRemoteUser(user)) { + instanceNotesCountDecreasement[user.host] ??= 0; + instanceNotesCountDecreasement[user.host]++; + } + for (const [host, count] of Object.entries(instanceNotesCountDecreasement)) { + registerOrFetchInstanceDoc(host).then((i) => { + Instances.decrement({ id: i.id }, "notesCount", count); + }); } if (deleteFromDb) { From 884c69f3777bfe26d5c519da102af450bcb6b65f Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 15 Apr 2024 04:34:00 +0900 Subject: [PATCH 13/22] chore (minor, backend): organize imports --- packages/backend/src/misc/reaction-lib.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts index 691d9743c8..fbdfe949ff 100644 --- a/packages/backend/src/misc/reaction-lib.ts +++ b/packages/backend/src/misc/reaction-lib.ts @@ -1,7 +1,6 @@ import { emojiRegex } from "./emoji-regex.js"; -import { fetchMeta } from "backend-rs"; +import { fetchMeta, toPuny } from "backend-rs"; import { Emojis } from "@/models/index.js"; -import { toPuny } from "backend-rs"; import { IsNull } from "typeorm"; export function convertReactions(reactions: Record) { From 74875f174b1f84622ebb0375041483d2d04444e8 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 15 Apr 2024 04:34:36 +0900 Subject: [PATCH 14/22] chore (minor, backend): use a template literal --- packages/backend/src/misc/post.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/misc/post.ts b/packages/backend/src/misc/post.ts index dbe703d1a0..0b107ed009 100644 --- a/packages/backend/src/misc/post.ts +++ b/packages/backend/src/misc/post.ts @@ -12,7 +12,7 @@ export function parse(acct: any): Post { cw: acct.cw, localOnly: acct.localOnly, createdAt: new Date(acct.createdAt), - visibility: "hidden" + (acct.visibility || ""), + visibility: `hidden${acct.visibility || ""}`, }; } From 2731003bc948613e1161ea64219af6c361b75de1 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 15 Apr 2024 05:13:35 +0900 Subject: [PATCH 15/22] refactor (backend): port emoji-regex to backend-rs --- Cargo.lock | 34 ++ Cargo.toml | 1 + packages/backend-rs/Cargo.toml | 1 + packages/backend-rs/index.d.ts | 1 + packages/backend-rs/index.js | 3 +- packages/backend-rs/src/misc/emoji.rs | 31 ++ packages/backend-rs/src/misc/mod.rs | 1 + packages/backend/package.json | 1 - packages/backend/src/misc/emoji-regex.ts | 5 - packages/backend/src/misc/reaction-lib.ts | 13 +- .../server/api/mastodon/endpoints/status.ts | 5 +- pnpm-lock.yaml | 427 ++++++++---------- 12 files changed, 269 insertions(+), 254 deletions(-) create mode 100644 packages/backend-rs/src/misc/emoji.rs delete mode 100644 packages/backend/src/misc/emoji-regex.ts diff --git a/Cargo.lock b/Cargo.lock index bc584faf24..c6ba96e683 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -209,6 +209,7 @@ dependencies = [ "cfg-if", "chrono", "cuid2", + "emojis", "idna", "jsonschema", "macro_rs", @@ -702,6 +703,15 @@ dependencies = [ "serde", ] +[[package]] +name = "emojis" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee61eb945bff65ee7d19d157d39c67c33290ff0742907413fd5eefd29edc979" +dependencies = [ + "phf", +] + [[package]] name = "encoding_rs" version = "0.8.34" @@ -1662,6 +1672,24 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -2313,6 +2341,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" diff --git a/Cargo.toml b/Cargo.toml index c9efe1f69a..7ca43c960b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ cfg-if = "1.0.0" chrono = "0.4.37" convert_case = "0.6.0" cuid2 = "0.1.2" +emojis = "0.6.1" idna = "0.5.0" jsonschema = "0.17.1" once_cell = "1.19.0" diff --git a/packages/backend-rs/Cargo.toml b/packages/backend-rs/Cargo.toml index 235fcc8706..af9e10cdc1 100644 --- a/packages/backend-rs/Cargo.toml +++ b/packages/backend-rs/Cargo.toml @@ -24,6 +24,7 @@ bcrypt = { workspace = true } cfg-if = { workspace = true } chrono = { workspace = true } cuid2 = { workspace = true } +emojis = { workspace = true } idna = { workspace = true } jsonschema = { workspace = true } once_cell = { workspace = true } diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index a9398aacc1..9b8a64142f 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -132,6 +132,7 @@ export function isSelfHost(host?: string | undefined | null): boolean export function isSameOrigin(uri: string): boolean export function extractHost(uri: string): string export function toPuny(host: string): string +export function isUnicodeEmoji(s: string): boolean export function sqlLikeEscape(src: string): string export function safeForSql(src: string): boolean /** Convert milliseconds to a human readable string */ diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 7a404d6447..16de16297f 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding +const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding module.exports.readServerConfig = readServerConfig module.exports.stringToAcct = stringToAcct @@ -321,6 +321,7 @@ module.exports.isSelfHost = isSelfHost module.exports.isSameOrigin = isSameOrigin module.exports.extractHost = extractHost module.exports.toPuny = toPuny +module.exports.isUnicodeEmoji = isUnicodeEmoji module.exports.sqlLikeEscape = sqlLikeEscape module.exports.safeForSql = safeForSql module.exports.formatMilliseconds = formatMilliseconds diff --git a/packages/backend-rs/src/misc/emoji.rs b/packages/backend-rs/src/misc/emoji.rs new file mode 100644 index 0000000000..df7d33848c --- /dev/null +++ b/packages/backend-rs/src/misc/emoji.rs @@ -0,0 +1,31 @@ +#[inline] +#[crate::export] +pub fn is_unicode_emoji(s: &str) -> bool { + emojis::get(s).is_some() +} + +#[cfg(test)] +mod unit_test { + use super::is_unicode_emoji; + + #[test] + fn test_unicode_emoji_check() { + assert!(is_unicode_emoji("⭐")); + assert!(is_unicode_emoji("👍")); + assert!(is_unicode_emoji("❤")); + assert!(is_unicode_emoji("♥️")); + assert!(is_unicode_emoji("❤️")); + assert!(is_unicode_emoji("💙")); + assert!(is_unicode_emoji("🩷")); + assert!(is_unicode_emoji("🖖🏿")); + assert!(is_unicode_emoji("🏃‍➡️")); + assert!(is_unicode_emoji("👩‍❤️‍👨")); + assert!(is_unicode_emoji("👩‍👦‍👦")); + assert!(is_unicode_emoji("🏳️‍🌈")); + + assert!(!is_unicode_emoji("⭐⭐")); + assert!(!is_unicode_emoji("x")); + assert!(!is_unicode_emoji("\t")); + assert!(!is_unicode_emoji(":meow_aww:")); + } +} diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index 74a483ea51..3fd447f4d5 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -1,6 +1,7 @@ pub mod acct; pub mod check_word_mute; pub mod convert_host; +pub mod emoji; pub mod escape_sql; pub mod format_milliseconds; pub mod mastodon_id; diff --git a/packages/backend/package.json b/packages/backend/package.json index bf435ec64b..9289c2f7ea 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -33,7 +33,6 @@ "@peertube/http-signature": "1.7.0", "@redocly/openapi-core": "1.11.0", "@sinonjs/fake-timers": "11.2.2", - "@twemoji/parser": "^15.1.1", "adm-zip": "0.5.10", "ajv": "8.12.0", "archiver": "7.0.1", diff --git a/packages/backend/src/misc/emoji-regex.ts b/packages/backend/src/misc/emoji-regex.ts deleted file mode 100644 index 72d6a62d9a..0000000000 --- a/packages/backend/src/misc/emoji-regex.ts +++ /dev/null @@ -1,5 +0,0 @@ -import twemoji from "@twemoji/parser/dist/lib/regex.js"; -const twemojiRegex = twemoji.default; - -export const emojiRegex = new RegExp(`(${twemojiRegex.source})`); -export const emojiRegexAtStartToEnd = new RegExp(`^(${twemojiRegex.source})$`); diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts index fbdfe949ff..ac9ba5652d 100644 --- a/packages/backend/src/misc/reaction-lib.ts +++ b/packages/backend/src/misc/reaction-lib.ts @@ -1,5 +1,4 @@ -import { emojiRegex } from "./emoji-regex.js"; -import { fetchMeta, toPuny } from "backend-rs"; +import { fetchMeta, isUnicodeEmoji, toPuny } from "backend-rs"; import { Emojis } from "@/models/index.js"; import { IsNull } from "typeorm"; @@ -22,17 +21,15 @@ export async function toDbReaction( ): Promise { if (!reaction) return (await fetchMeta(true)).defaultReaction; - reacterHost = reacterHost == null ? null : toPuny(reacterHost); - if (reaction.includes("❤") || reaction.includes("♥️")) return "❤️"; // Allow unicode reactions - const match = emojiRegex.exec(reaction); - if (match) { - const unicode = match[0]; - return unicode; + if (isUnicodeEmoji(reaction)) { + return reaction; } + reacterHost = reacterHost == null ? null : toPuny(reacterHost); + const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/); if (custom) { const name = custom[1]; diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index 5286c90fac..6fa70717e7 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -1,10 +1,9 @@ import Router from "@koa/router"; import { getClient } from "../ApiMastodonCompatibleService.js"; -import { emojiRegexAtStartToEnd } from "@/misc/emoji-regex.js"; import querystring from "node:querystring"; import qs from "qs"; import { convertTimelinesArgsId, limitToInt } from "./timeline.js"; -import { fetchMeta, fromMastodonId } from "backend-rs"; +import { fetchMeta, fromMastodonId, isUnicodeEmoji } from "backend-rs"; import { convertAccount, convertAttachment, @@ -37,7 +36,7 @@ export function apiStatusMastodon(router: Router): void { } const text = body.status; const removed = text.replace(/@\S+/g, "").replace(/\s|​/g, ""); - const isDefaultEmoji = emojiRegexAtStartToEnd.test(removed); + const isDefaultEmoji = isUnicodeEmoji(removed); const isCustomEmoji = /^:[a-zA-Z0-9@_]+:$/.test(removed); if ((body.in_reply_to_id && isDefaultEmoji) || isCustomEmoji) { const a = await client.createEmojiReaction( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53b6089f9c..b591ffe9c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,9 +87,6 @@ importers: '@sinonjs/fake-timers': specifier: 11.2.2 version: 11.2.2 - '@twemoji/parser': - specifier: ^15.1.1 - version: 15.1.1 adm-zip: specifier: 0.5.10 version: 0.5.10 @@ -547,10 +544,10 @@ importers: devDependencies: '@eslint-sets/eslint-config-vue3': specifier: ^5.12.0 - version: 5.12.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) + version: 5.12.0(@babel/core@7.24.4)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5) '@eslint-sets/eslint-config-vue3-ts': specifier: ^3.3.0 - version: 3.3.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) + version: 3.3.0(@babel/core@7.24.4)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5) '@phosphor-icons/web': specifier: ^2.1.1 version: 2.1.1 @@ -658,7 +655,7 @@ importers: version: 3.0.12 eslint-plugin-file-progress: specifier: ^1.3.0 - version: 1.3.0(eslint@9.0.0) + version: 1.3.0(eslint@8.46.0) eventemitter3: specifier: 5.0.1 version: 5.0.1 @@ -1081,7 +1078,7 @@ packages: - supports-color dev: true - /@babel/eslint-parser@7.23.10(@babel/core@7.24.4)(eslint@9.0.0): + /@babel/eslint-parser@7.23.10(@babel/core@7.24.4)(eslint@8.46.0): resolution: {integrity: sha512-3wSYDPZVnhseRnxRJH6ZVTNknBz76AEnyC+AYYhasjP3Yy23qz0ERR7Fcd2SHmYuSFJ2kY9gaaDd3vyqU09eSw==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: @@ -1090,12 +1087,12 @@ packages: dependencies: '@babel/core': 7.24.4 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 9.0.0 + eslint: 8.46.0 eslint-visitor-keys: 2.1.0 semver: 6.3.1 dev: true - /@babel/eslint-parser@7.23.3(@babel/core@7.24.4)(eslint@9.0.0): + /@babel/eslint-parser@7.23.3(@babel/core@7.24.4)(eslint@8.46.0): resolution: {integrity: sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: @@ -1104,7 +1101,7 @@ packages: dependencies: '@babel/core': 7.24.4 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 9.0.0 + eslint: 8.46.0 eslint-visitor-keys: 2.1.0 semver: 6.3.1 dev: true @@ -2256,29 +2253,29 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint-sets/eslint-config-basic@3.3.0(@babel/core@7.24.4)(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(prettier@3.2.5): + /@eslint-sets/eslint-config-basic@3.3.0(@babel/core@7.24.4)(@typescript-eslint/parser@5.62.0)(eslint@8.46.0)(prettier@3.2.5): resolution: {integrity: sha512-x5YH0CvZJxn19/5ehu188XaoLQpxOGlFiIuPHCN6FyONgrmriakT/cmIIBOJg2Vi/y1bn2xbhsgVNb00J3HyTg==} peerDependencies: eslint: '>=8.0.0' prettier: '>=2.0.0' dependencies: - '@babel/eslint-parser': 7.23.3(@babel/core@7.24.4)(eslint@9.0.0) - eslint: 9.0.0 - eslint-config-prettier: 8.9.0(eslint@9.0.0) - eslint-plugin-eslint-comments: 3.2.0(eslint@9.0.0) + '@babel/eslint-parser': 7.23.3(@babel/core@7.24.4)(eslint@8.46.0) + eslint: 8.46.0 + eslint-config-prettier: 8.9.0(eslint@8.46.0) + eslint-plugin-eslint-comments: 3.2.0(eslint@8.46.0) eslint-plugin-html: 7.1.0 - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0) - eslint-plugin-jsonc: 2.10.0(eslint@9.0.0) - eslint-plugin-markdown: 3.0.1(eslint@9.0.0) - eslint-plugin-n: 15.7.0(eslint@9.0.0) - eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@9.0.0)(prettier@3.2.5) - eslint-plugin-promise: 5.2.0(eslint@9.0.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0) + eslint-plugin-jsonc: 2.10.0(eslint@8.46.0) + eslint-plugin-markdown: 3.0.1(eslint@8.46.0) + eslint-plugin-n: 15.7.0(eslint@8.46.0) + eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@8.46.0)(prettier@3.2.5) + eslint-plugin-promise: 5.2.0(eslint@8.46.0) eslint-plugin-tsdoc: 0.2.17 - eslint-plugin-unicorn: 45.0.2(eslint@9.0.0) - eslint-plugin-yml: 1.10.0(eslint@9.0.0) + eslint-plugin-unicorn: 45.0.2(eslint@8.46.0) + eslint-plugin-yml: 1.10.0(eslint@8.46.0) jsonc-eslint-parser: 2.3.0 prettier: 3.2.5 - vue-eslint-parser: 9.3.2(eslint@9.0.0) + vue-eslint-parser: 9.3.2(eslint@8.46.0) yaml-eslint-parser: 1.2.2 transitivePeerDependencies: - '@babel/core' @@ -2288,7 +2285,7 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-basic@5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-basic@5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-AgECfmJsiVOWKmvgjv780VuuoT9SE6PRgxGTtytHSfE9b9MAJjHxToVTKtD4UEKvocEGbg2EcwqGbff8cxDWKw==} peerDependencies: eslint: '>=7.4.0' @@ -2298,24 +2295,24 @@ packages: typescript: optional: true dependencies: - '@babel/eslint-parser': 7.23.10(@babel/core@7.24.4)(eslint@9.0.0) - eslint: 9.0.0 - eslint-config-prettier: 9.1.0(eslint@9.0.0) - eslint-plugin-eslint-comments: 3.2.0(eslint@9.0.0) + '@babel/eslint-parser': 7.23.10(@babel/core@7.24.4)(eslint@8.46.0) + eslint: 8.46.0 + eslint-config-prettier: 9.1.0(eslint@8.46.0) + eslint-plugin-eslint-comments: 3.2.0(eslint@8.46.0) eslint-plugin-html: 7.1.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@9.0.0) - eslint-plugin-jsonc: 2.13.0(eslint@9.0.0) - eslint-plugin-markdown: 3.0.1(eslint@9.0.0) - eslint-plugin-n: 16.6.2(eslint@9.0.0) - eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.0.0)(prettier@3.2.5) - eslint-plugin-promise: 6.1.1(eslint@9.0.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.46.0) + eslint-plugin-jsonc: 2.13.0(eslint@8.46.0) + eslint-plugin-markdown: 3.0.1(eslint@8.46.0) + eslint-plugin-n: 16.6.2(eslint@8.46.0) + eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.46.0)(prettier@3.2.5) + eslint-plugin-promise: 6.1.1(eslint@8.46.0) eslint-plugin-tsdoc: 0.2.17 - eslint-plugin-unicorn: 40.1.0(eslint@9.0.0) - eslint-plugin-yml: 1.12.2(eslint@9.0.0) + eslint-plugin-unicorn: 40.1.0(eslint@8.46.0) + eslint-plugin-yml: 1.12.2(eslint@8.46.0) jsonc-eslint-parser: 2.4.0 prettier: 3.2.5 typescript: 5.4.5 - vue-eslint-parser: 9.4.2(eslint@9.0.0) + vue-eslint-parser: 9.4.2(eslint@8.46.0) yaml-eslint-parser: 1.2.2 transitivePeerDependencies: - '@babel/core' @@ -2326,19 +2323,19 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-ts@3.3.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-ts@3.3.0(@babel/core@7.24.4)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-4Vj3KxYx16hmW6AyEv1mil0gVN8H3rdJt8TRWufbAj0ZN+EjwOPf3TqE7ASCYto/NpA8xWQY3NGm/og9Or/dDQ==} peerDependencies: eslint: '>=8.0.0' prettier: '>=2.0.0' typescript: '>=4.0.0' dependencies: - '@eslint-sets/eslint-config-basic': 3.3.0(@babel/core@7.24.4)(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(prettier@3.2.5) - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(typescript@5.4.5) - '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) - eslint: 9.0.0 - eslint-config-prettier: 8.9.0(eslint@9.0.0) - eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@9.0.0)(prettier@3.2.5) + '@eslint-sets/eslint-config-basic': 3.3.0(@babel/core@7.24.4)(@typescript-eslint/parser@5.62.0)(eslint@8.46.0)(prettier@3.2.5) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.46.0)(typescript@5.4.5) + eslint: 8.46.0 + eslint-config-prettier: 8.9.0(eslint@8.46.0) + eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@8.46.0)(prettier@3.2.5) eslint-plugin-tsdoc: 0.2.17 prettier: 3.2.5 typescript: 5.4.5 @@ -2349,7 +2346,7 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-ts@5.12.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-ts@5.12.0(@babel/core@7.24.4)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-7vOzV6qYv0SbA9W17m9lkG/Zv+qVeCcAbWEY1d9hUbBHx9Ip48kNMNVDrnh97zUORXGcmjxsZ81W2lC36Ox2pw==} peerDependencies: eslint: '>=7.4.0' @@ -2359,12 +2356,12 @@ packages: typescript: optional: true dependencies: - '@eslint-sets/eslint-config-basic': 5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(typescript@5.4.5) - '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) - eslint: 9.0.0 - eslint-config-prettier: 9.1.0(eslint@9.0.0) - eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.0.0)(prettier@3.2.5) + '@eslint-sets/eslint-config-basic': 5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.46.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@8.46.0)(typescript@5.4.5) + eslint: 8.46.0 + eslint-config-prettier: 9.1.0(eslint@8.46.0) + eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.46.0)(prettier@3.2.5) eslint-plugin-tsdoc: 0.2.17 prettier: 3.2.5 typescript: 5.4.5 @@ -2376,26 +2373,26 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-vue3-ts@3.3.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-vue3-ts@3.3.0(@babel/core@7.24.4)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-KX3VFuS5U4FYKfZ6PABQjl54BMpNapNjYYe103Nm2Zy8y9zphDCBAARbhU97XNSvzkurve7HhJcsi9gXrWlGFA==} peerDependencies: eslint: '>=8.0.0' prettier: '>=2.0.0' typescript: '>=4.0.0' dependencies: - '@eslint-sets/eslint-config-ts': 3.3.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(typescript@5.4.5) - '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) - eslint: 9.0.0 - eslint-config-prettier: 8.9.0(eslint@9.0.0) - eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@9.0.0)(prettier@3.2.5) + '@eslint-sets/eslint-config-ts': 3.3.0(@babel/core@7.24.4)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.46.0)(typescript@5.4.5) + eslint: 8.46.0 + eslint-config-prettier: 8.9.0(eslint@8.46.0) + eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.9.0)(eslint@8.46.0)(prettier@3.2.5) eslint-plugin-tsdoc: 0.2.17 eslint-plugin-vitest-globals: 1.4.0 - eslint-plugin-vue: 9.16.1(eslint@9.0.0) - eslint-plugin-vue-scoped-css: 2.5.0(eslint@9.0.0)(vue-eslint-parser@9.3.1) + eslint-plugin-vue: 9.16.1(eslint@8.46.0) + eslint-plugin-vue-scoped-css: 2.5.0(eslint@8.46.0)(vue-eslint-parser@9.3.1) prettier: 3.2.5 typescript: 5.4.5 - vue-eslint-parser: 9.3.1(eslint@9.0.0) + vue-eslint-parser: 9.3.1(eslint@8.46.0) transitivePeerDependencies: - '@babel/core' - eslint-import-resolver-typescript @@ -2403,7 +2400,7 @@ packages: - supports-color dev: true - /@eslint-sets/eslint-config-vue3@5.12.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5): + /@eslint-sets/eslint-config-vue3@5.12.0(@babel/core@7.24.4)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5): resolution: {integrity: sha512-gQBmQicZihPcxncIdkKagQGZ2dH+97ioAlUpsaczEdgY9pLrLOU5oGTetjbaxAp6zGS2sXm1n0i2BnwRIlt4Bg==} peerDependencies: eslint: '>=7.4.0' @@ -2413,22 +2410,22 @@ packages: typescript: optional: true dependencies: - '@eslint-sets/eslint-config-basic': 5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) - '@eslint-sets/eslint-config-ts': 5.12.0(@babel/core@7.24.4)(eslint@9.0.0)(prettier@3.2.5)(typescript@5.4.5) - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(typescript@5.4.5) - '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) - eslint: 9.0.0 - eslint-config-prettier: 9.1.0(eslint@9.0.0) - eslint-plugin-jsdoc: 48.0.6(eslint@9.0.0) - eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.0.0)(prettier@3.2.5) + '@eslint-sets/eslint-config-basic': 5.12.0(@babel/core@7.24.4)(@typescript-eslint/parser@6.21.0)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5) + '@eslint-sets/eslint-config-ts': 5.12.0(@babel/core@7.24.4)(eslint@8.46.0)(prettier@3.2.5)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.46.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@8.46.0)(typescript@5.4.5) + eslint: 8.46.0 + eslint-config-prettier: 9.1.0(eslint@8.46.0) + eslint-plugin-jsdoc: 48.0.6(eslint@8.46.0) + eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.46.0)(prettier@3.2.5) eslint-plugin-tsdoc: 0.2.17 eslint-plugin-vitest-globals: 1.4.0 - eslint-plugin-vue: 9.21.1(eslint@9.0.0) - eslint-plugin-vue-scoped-css: 2.7.2(eslint@9.0.0)(vue-eslint-parser@9.4.2) + eslint-plugin-vue: 9.21.1(eslint@8.46.0) + eslint-plugin-vue-scoped-css: 2.7.2(eslint@8.46.0)(vue-eslint-parser@9.4.2) local-pkg: 0.5.0 prettier: 3.2.5 typescript: 5.4.5 - vue-eslint-parser: 9.4.2(eslint@9.0.0) + vue-eslint-parser: 9.4.2(eslint@8.46.0) transitivePeerDependencies: - '@babel/core' - '@types/eslint' @@ -3880,10 +3877,6 @@ packages: /@twemoji/parser@15.0.0: resolution: {integrity: sha512-lh9515BNsvKSNvyUqbj5yFu83iIDQ77SwVcsN/SnEGawczhsKU6qWuogewN1GweTi5Imo5ToQ9s+nNTf97IXvg==} - /@twemoji/parser@15.1.1: - resolution: {integrity: sha512-CChRzIu6ngkCJOmURBlYEdX5DZSu+bBTtqR60XjBkFrmvplKW7OQsea+i8XwF4bLVlUXBO7ZmHhRPDzfQyLwwg==} - dev: false - /@types/accepts@1.3.5: resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==} dependencies: @@ -4579,7 +4572,7 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0)(typescript@5.4.5): + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0)(typescript@5.4.5): resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4591,12 +4584,12 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.9.1 - '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.46.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0(eslint@9.0.0)(typescript@5.4.5) - '@typescript-eslint/utils': 5.62.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/type-utils': 5.62.0(eslint@8.46.0)(typescript@5.4.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.46.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare-lite: 1.4.0 @@ -4607,7 +4600,7 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@9.0.0)(typescript@5.4.5): + /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.46.0)(typescript@5.4.5): resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -4619,13 +4612,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.9.1 - '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@8.46.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@9.0.0)(typescript@5.4.5) - '@typescript-eslint/utils': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/type-utils': 6.21.0(eslint@8.46.0)(typescript@5.4.5) + '@typescript-eslint/utils': 6.21.0(eslint@8.46.0)(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -4656,7 +4649,7 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@5.62.0(eslint@9.0.0)(typescript@5.4.5): + /@typescript-eslint/parser@5.62.0(eslint@8.46.0)(typescript@5.4.5): resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4670,13 +4663,13 @@ packages: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.21.0(eslint@9.0.0)(typescript@5.4.5): + /@typescript-eslint/parser@6.21.0(eslint@8.46.0)(typescript@5.4.5): resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -4691,7 +4684,7 @@ packages: '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -4733,7 +4726,7 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils@5.62.0(eslint@9.0.0)(typescript@5.4.5): + /@typescript-eslint/type-utils@5.62.0(eslint@8.46.0)(typescript@5.4.5): resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4744,16 +4737,16 @@ packages: optional: true dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) - '@typescript-eslint/utils': 5.62.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.46.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 tsutils: 3.21.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/type-utils@6.21.0(eslint@9.0.0)(typescript@5.4.5): + /@typescript-eslint/type-utils@6.21.0(eslint@8.46.0)(typescript@5.4.5): resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -4764,9 +4757,9 @@ packages: optional: true dependencies: '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) - '@typescript-eslint/utils': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/utils': 6.21.0(eslint@8.46.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 ts-api-utils: 1.0.1(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: @@ -4867,19 +4860,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@5.62.0(eslint@9.0.0)(typescript@5.4.5): + /@typescript-eslint/utils@5.62.0(eslint@8.46.0)(typescript@5.4.5): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) - eslint: 9.0.0 + eslint: 8.46.0 eslint-scope: 5.1.1 semver: 7.6.0 transitivePeerDependencies: @@ -4887,19 +4880,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.21.0(eslint@9.0.0)(typescript@5.4.5): + /@typescript-eslint/utils@6.21.0(eslint@8.46.0)(typescript@5.4.5): resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) '@types/json-schema': 7.0.14 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) - eslint: 9.0.0 + eslint: 8.46.0 semver: 7.6.0 transitivePeerDependencies: - supports-color @@ -8214,41 +8207,41 @@ packages: engines: {node: '>=12'} dev: true - /eslint-compat-utils@0.1.2(eslint@9.0.0): + /eslint-compat-utils@0.1.2(eslint@8.46.0): resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: - eslint: 9.0.0 + eslint: 8.46.0 dev: true - /eslint-compat-utils@0.4.1(eslint@9.0.0): + /eslint-compat-utils@0.4.1(eslint@8.46.0): resolution: {integrity: sha512-5N7ZaJG5pZxUeNNJfUchurLVrunD1xJvyg5kYOIVF8kg1f3ajTikmAu/5fZ9w100omNPOoMjngRszh/Q/uFGMg==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: - eslint: 9.0.0 + eslint: 8.46.0 semver: 7.6.0 dev: true - /eslint-config-prettier@8.9.0(eslint@9.0.0): + /eslint-config-prettier@8.9.0(eslint@8.46.0): resolution: {integrity: sha512-+sbni7NfVXnOpnRadUA8S28AUlsZt9GjgFvABIRL9Hkn8KqNzOp+7Lw4QWtrwn20KzU3wqu1QoOj2m+7rKRqkA==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 9.0.0 + eslint: 8.46.0 dev: true - /eslint-config-prettier@9.1.0(eslint@9.0.0): + /eslint-config-prettier@9.1.0(eslint@8.46.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 9.0.0 + eslint: 8.46.0 dev: true /eslint-config-standard@16.0.3(eslint-plugin-import@2.28.0)(eslint-plugin-node@11.1.0)(eslint-plugin-promise@6.1.1)(eslint@8.46.0): @@ -8318,7 +8311,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@9.0.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.46.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -8339,53 +8332,24 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@8.46.0)(typescript@5.4.5) debug: 3.2.7 - eslint: 9.0.0 + eslint: 8.46.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@9.0.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) - debug: 3.2.7 - eslint: 9.0.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-plugin-es-x@7.5.0(eslint@9.0.0): + /eslint-plugin-es-x@7.5.0(eslint@8.46.0): resolution: {integrity: sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) '@eslint-community/regexpp': 4.9.1 - eslint: 9.0.0 - eslint-compat-utils: 0.1.2(eslint@9.0.0) + eslint: 8.46.0 + eslint-compat-utils: 0.1.2(eslint@8.46.0) dev: true /eslint-plugin-es@3.0.1(eslint@8.46.0): @@ -8399,35 +8363,35 @@ packages: regexpp: 3.2.0 dev: true - /eslint-plugin-es@4.1.0(eslint@9.0.0): + /eslint-plugin-es@4.1.0(eslint@8.46.0): resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} engines: {node: '>=8.10.0'} peerDependencies: eslint: '>=4.19.1' dependencies: - eslint: 9.0.0 + eslint: 8.46.0 eslint-utils: 2.1.0 regexpp: 3.2.0 dev: true - /eslint-plugin-eslint-comments@3.2.0(eslint@9.0.0): + /eslint-plugin-eslint-comments@3.2.0(eslint@8.46.0): resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} engines: {node: '>=6.5.0'} peerDependencies: eslint: '>=4.19.1' dependencies: escape-string-regexp: 1.0.5 - eslint: 9.0.0 + eslint: 8.46.0 ignore: 5.2.4 dev: true - /eslint-plugin-file-progress@1.3.0(eslint@9.0.0): + /eslint-plugin-file-progress@1.3.0(eslint@8.46.0): resolution: {integrity: sha512-LncpnGHU26KPvCrvDC2Sl9PfjdrsG8qltgiK6BR7KybWtfqrdlsu1ax3+hyPMn5OkKBTF3Wki3oqK1MSMeOtQw==} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: chalk: 4.1.2 - eslint: 9.0.0 + eslint: 8.46.0 ora: 5.4.1 dev: true @@ -8473,7 +8437,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.29.0(@typescript-eslint/parser@5.62.0)(eslint@9.0.0): + /eslint-plugin-import@2.29.0(@typescript-eslint/parser@5.62.0)(eslint@8.46.0): resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} engines: {node: '>=4'} peerDependencies: @@ -8483,16 +8447,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.62.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.46.0)(typescript@5.4.5) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.0.0 + eslint: 8.46.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@9.0.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.46.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -8508,7 +8472,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint@9.0.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.46.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: @@ -8518,16 +8482,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + '@typescript-eslint/parser': 6.21.0(eslint@8.46.0)(typescript@5.4.5) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.0.0 + eslint: 8.46.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@9.0.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.46.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -8543,7 +8507,7 @@ packages: - supports-color dev: true - /eslint-plugin-jsdoc@48.0.6(eslint@9.0.0): + /eslint-plugin-jsdoc@48.0.6(eslint@8.46.0): resolution: {integrity: sha512-LgwXOX6TWxxFYcbdVe+BJ94Kl/pgjSPYHLzqEdAMXTA1BH9WDx7iJ+9/iDajPF64LtzWX8C1mCfpbMZjJGhAOw==} engines: {node: '>=18'} peerDependencies: @@ -8554,7 +8518,7 @@ packages: comment-parser: 1.4.1 debug: 4.3.4(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint: 9.0.0 + eslint: 8.46.0 esquery: 1.5.0 is-builtin-module: 3.2.1 semver: 7.6.0 @@ -8563,28 +8527,28 @@ packages: - supports-color dev: true - /eslint-plugin-jsonc@2.10.0(eslint@9.0.0): + /eslint-plugin-jsonc@2.10.0(eslint@8.46.0): resolution: {integrity: sha512-9d//o6Jyh4s1RxC9fNSt1+MMaFN2ruFdXPG9XZcb/mR2KkfjADYiNL/hbU6W0Cyxfg3tS/XSFuhl5LgtMD8hmw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) - eslint: 9.0.0 - eslint-compat-utils: 0.1.2(eslint@9.0.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) + eslint: 8.46.0 + eslint-compat-utils: 0.1.2(eslint@8.46.0) jsonc-eslint-parser: 2.3.0 natural-compare: 1.4.0 dev: true - /eslint-plugin-jsonc@2.13.0(eslint@9.0.0): + /eslint-plugin-jsonc@2.13.0(eslint@8.46.0): resolution: {integrity: sha512-2wWdJfpO/UbZzPDABuUVvlUQjfMJa2p2iQfYt/oWxOMpXCcjuiMUSaA02gtY/Dbu82vpaSqc+O7Xq6ECHwtIxA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) - eslint: 9.0.0 - eslint-compat-utils: 0.4.1(eslint@9.0.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) + eslint: 8.46.0 + eslint-compat-utils: 0.4.1(eslint@8.46.0) espree: 9.6.1 graphemer: 1.4.0 jsonc-eslint-parser: 2.4.0 @@ -8592,28 +8556,28 @@ packages: synckit: 0.6.2 dev: true - /eslint-plugin-markdown@3.0.1(eslint@9.0.0): + /eslint-plugin-markdown@3.0.1(eslint@8.46.0): resolution: {integrity: sha512-8rqoc148DWdGdmYF6WSQFT3uQ6PO7zXYgeBpHAOAakX/zpq+NvFYbDA/H7PYzHajwtmaOzAwfxyl++x0g1/N9A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - eslint: 9.0.0 + eslint: 8.46.0 mdast-util-from-markdown: 0.8.5 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-n@15.7.0(eslint@9.0.0): + /eslint-plugin-n@15.7.0(eslint@8.46.0): resolution: {integrity: sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==} engines: {node: '>=12.22.0'} peerDependencies: eslint: '>=7.0.0' dependencies: builtins: 5.0.1 - eslint: 9.0.0 - eslint-plugin-es: 4.1.0(eslint@9.0.0) - eslint-utils: 3.0.0(eslint@9.0.0) + eslint: 8.46.0 + eslint-plugin-es: 4.1.0(eslint@8.46.0) + eslint-utils: 3.0.0(eslint@8.46.0) ignore: 5.2.4 is-core-module: 2.13.1 minimatch: 3.1.2 @@ -8621,16 +8585,16 @@ packages: semver: 7.6.0 dev: true - /eslint-plugin-n@16.6.2(eslint@9.0.0): + /eslint-plugin-n@16.6.2(eslint@8.46.0): resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==} engines: {node: '>=16.0.0'} peerDependencies: eslint: '>=7.0.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) builtins: 5.0.1 - eslint: 9.0.0 - eslint-plugin-es-x: 7.5.0(eslint@9.0.0) + eslint: 8.46.0 + eslint-plugin-es-x: 7.5.0(eslint@8.46.0) get-tsconfig: 4.7.2 globals: 13.24.0 ignore: 5.2.4 @@ -8656,7 +8620,7 @@ packages: semver: 6.3.1 dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.9.0)(eslint@9.0.0)(prettier@3.2.5): + /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.9.0)(eslint@8.46.0)(prettier@3.2.5): resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -8667,13 +8631,13 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 9.0.0 - eslint-config-prettier: 8.9.0(eslint@9.0.0) + eslint: 8.46.0 + eslint-config-prettier: 8.9.0(eslint@8.46.0) prettier: 3.2.5 prettier-linter-helpers: 1.0.0 dev: true - /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@9.0.0)(prettier@3.2.5): + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.46.0)(prettier@3.2.5): resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -8687,20 +8651,20 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 9.0.0 - eslint-config-prettier: 9.1.0(eslint@9.0.0) + eslint: 8.46.0 + eslint-config-prettier: 9.1.0(eslint@8.46.0) prettier: 3.2.5 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 dev: true - /eslint-plugin-promise@5.2.0(eslint@9.0.0): + /eslint-plugin-promise@5.2.0(eslint@8.46.0): resolution: {integrity: sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: eslint: ^7.0.0 dependencies: - eslint: 9.0.0 + eslint: 8.46.0 dev: true /eslint-plugin-promise@6.1.1(eslint@8.46.0): @@ -8712,15 +8676,6 @@ packages: eslint: 8.46.0 dev: true - /eslint-plugin-promise@6.1.1(eslint@9.0.0): - resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - dependencies: - eslint: 9.0.0 - dev: true - /eslint-plugin-standard@5.0.0(eslint@8.46.0): resolution: {integrity: sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg==} deprecated: 'standard 16.0.0 and eslint-config-standard 16.0.0 no longer require the eslint-plugin-standard package. You can remove it from your dependencies with ''npm rm eslint-plugin-standard''. More info here: https://github.com/standard/standard/issues/1316' @@ -8737,7 +8692,7 @@ packages: '@microsoft/tsdoc-config': 0.16.2 dev: true - /eslint-plugin-unicorn@40.1.0(eslint@9.0.0): + /eslint-plugin-unicorn@40.1.0(eslint@8.46.0): resolution: {integrity: sha512-y5doK2DF9Sr5AqKEHbHxjFllJ167nKDRU01HDcWyv4Tnmaoe9iNxMrBnaybZvWZUaE3OC5Unu0lNIevYamloig==} engines: {node: '>=12'} peerDependencies: @@ -8746,8 +8701,8 @@ packages: '@babel/helper-validator-identifier': 7.22.20 ci-info: 3.9.0 clean-regexp: 1.0.0 - eslint: 9.0.0 - eslint-utils: 3.0.0(eslint@9.0.0) + eslint: 8.46.0 + eslint-utils: 3.0.0(eslint@8.46.0) esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 @@ -8760,17 +8715,17 @@ packages: strip-indent: 3.0.0 dev: true - /eslint-plugin-unicorn@45.0.2(eslint@9.0.0): + /eslint-plugin-unicorn@45.0.2(eslint@8.46.0): resolution: {integrity: sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==} engines: {node: '>=14.18'} peerDependencies: eslint: '>=8.28.0' dependencies: '@babel/helper-validator-identifier': 7.22.5 - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) ci-info: 3.9.0 clean-regexp: 1.0.0 - eslint: 9.0.0 + eslint: 8.46.0 esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 @@ -8789,92 +8744,92 @@ packages: resolution: {integrity: sha512-WE+YlK9X9s4vf5EaYRU0Scw7WItDZStm+PapFSYlg2ABNtaQ4zIG7wEqpoUB3SlfM+SgkhgmzR0TeJOO5k3/Nw==} dev: true - /eslint-plugin-vue-scoped-css@2.5.0(eslint@9.0.0)(vue-eslint-parser@9.3.1): + /eslint-plugin-vue-scoped-css@2.5.0(eslint@8.46.0)(vue-eslint-parser@9.3.1): resolution: {integrity: sha512-vR+raYNE1aQ69lS1lZGiKoz8rXFI3MWf2fxrfns/XCQ0XT5sIguhDtQS+9JmUQJClenLDEe2CQx7P+eeSdF4cA==} engines: {node: ^12.22 || ^14.17 || >=16} peerDependencies: eslint: '>=5.0.0' vue-eslint-parser: '>=7.1.0' dependencies: - eslint: 9.0.0 - eslint-utils: 3.0.0(eslint@9.0.0) + eslint: 8.46.0 + eslint-utils: 3.0.0(eslint@8.46.0) lodash: 4.17.21 postcss: 8.4.31 postcss-safe-parser: 6.0.0(postcss@8.4.31) postcss-scss: 4.0.6(postcss@8.4.31) postcss-selector-parser: 6.0.13 postcss-styl: 0.12.3 - vue-eslint-parser: 9.3.1(eslint@9.0.0) + vue-eslint-parser: 9.3.1(eslint@8.46.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-vue-scoped-css@2.7.2(eslint@9.0.0)(vue-eslint-parser@9.4.2): + /eslint-plugin-vue-scoped-css@2.7.2(eslint@8.46.0)(vue-eslint-parser@9.4.2): resolution: {integrity: sha512-myJ99CJuwmAx5kq1WjgIeaUkxeU6PIEUh7age79Alm30bhN4fVTapOQLSMlvVTgxr36Y3igsZ3BCJM32LbHHig==} engines: {node: ^12.22 || ^14.17 || >=16} peerDependencies: eslint: '>=5.0.0' vue-eslint-parser: '>=7.1.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) - eslint: 9.0.0 - eslint-compat-utils: 0.4.1(eslint@9.0.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) + eslint: 8.46.0 + eslint-compat-utils: 0.4.1(eslint@8.46.0) lodash: 4.17.21 postcss: 8.4.31 postcss-safe-parser: 6.0.0(postcss@8.4.31) postcss-scss: 4.0.6(postcss@8.4.31) postcss-selector-parser: 6.0.13 postcss-styl: 0.12.3 - vue-eslint-parser: 9.4.2(eslint@9.0.0) + vue-eslint-parser: 9.4.2(eslint@8.46.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-vue@9.16.1(eslint@9.0.0): + /eslint-plugin-vue@9.16.1(eslint@8.46.0): resolution: {integrity: sha512-2FtnTqazA6aYONfDuOZTk0QzwhAwi7Z4+uJ7+GHeGxcKapjqWlDsRWDenvyG/utyOfAS5bVRmAG3cEWiYEz2bA==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) - eslint: 9.0.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) + eslint: 8.46.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.13 semver: 7.6.0 - vue-eslint-parser: 9.3.2(eslint@9.0.0) + vue-eslint-parser: 9.3.2(eslint@8.46.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-vue@9.21.1(eslint@9.0.0): + /eslint-plugin-vue@9.21.1(eslint@8.46.0): resolution: {integrity: sha512-XVtI7z39yOVBFJyi8Ljbn7kY9yHzznKXL02qQYn+ta63Iy4A9JFBw6o4OSB9hyD2++tVT+su9kQqetUyCCwhjw==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) - eslint: 9.0.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0) + eslint: 8.46.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.13 semver: 7.6.0 - vue-eslint-parser: 9.4.2(eslint@9.0.0) + vue-eslint-parser: 9.4.2(eslint@8.46.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-yml@1.10.0(eslint@9.0.0): + /eslint-plugin-yml@1.10.0(eslint@8.46.0): resolution: {integrity: sha512-53SUwuNDna97lVk38hL/5++WXDuugPM9SUQ1T645R0EHMRCdBIIxGye/oOX2qO3FQ7aImxaUZJU/ju+NMUBrLQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 - eslint-compat-utils: 0.1.2(eslint@9.0.0) + eslint: 8.46.0 + eslint-compat-utils: 0.1.2(eslint@8.46.0) lodash: 4.17.21 natural-compare: 1.4.0 yaml-eslint-parser: 1.2.2 @@ -8882,15 +8837,15 @@ packages: - supports-color dev: true - /eslint-plugin-yml@1.12.2(eslint@9.0.0): + /eslint-plugin-yml@1.12.2(eslint@8.46.0): resolution: {integrity: sha512-hvS9p08FhPT7i/ynwl7/Wt7ke7Rf4P2D6fT8lZlL43peZDTsHtH2A0SIFQ7Kt7+mJ6if6P+FX3iJhMkdnxQwpg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 - eslint-compat-utils: 0.4.1(eslint@9.0.0) + eslint: 8.46.0 + eslint-compat-utils: 0.4.1(eslint@8.46.0) lodash: 4.17.21 natural-compare: 1.4.0 yaml-eslint-parser: 1.2.2 @@ -8933,13 +8888,13 @@ packages: eslint-visitor-keys: 1.3.0 dev: true - /eslint-utils@3.0.0(eslint@9.0.0): + /eslint-utils@3.0.0(eslint@8.46.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 9.0.0 + eslint: 8.46.0 eslint-visitor-keys: 2.1.0 dev: true @@ -17242,14 +17197,14 @@ packages: '@types/sortablejs': 1.15.8 dev: true - /vue-eslint-parser@9.3.1(eslint@9.0.0): + /vue-eslint-parser@9.3.1(eslint@8.46.0): resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -17260,14 +17215,14 @@ packages: - supports-color dev: true - /vue-eslint-parser@9.3.2(eslint@9.0.0): + /vue-eslint-parser@9.3.2(eslint@8.46.0): resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -17278,14 +17233,14 @@ packages: - supports-color dev: true - /vue-eslint-parser@9.4.2(eslint@9.0.0): + /vue-eslint-parser@9.4.2(eslint@8.46.0): resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 9.0.0 + eslint: 8.46.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 From 0f3126196f49b2eb57b08bc21929b3c115476d3a Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 15 Apr 2024 10:02:44 +0900 Subject: [PATCH 16/22] refactor (backend): port reaction-lib to backend-rs --- packages/backend-rs/index.d.ts | 8 + packages/backend-rs/index.js | 5 +- packages/backend-rs/src/misc/mod.rs | 1 + packages/backend-rs/src/misc/reaction.rs | 191 ++++++++++++++++++ packages/backend/src/misc/populate-emojis.ts | 3 +- packages/backend/src/misc/reaction-lib.ts | 83 -------- .../src/models/repositories/note-reaction.ts | 2 +- .../backend/src/models/repositories/note.ts | 5 +- .../src/services/note/reaction/create.ts | 5 +- .../src/services/note/reaction/delete.ts | 2 +- 10 files changed, 211 insertions(+), 94 deletions(-) create mode 100644 packages/backend-rs/src/misc/reaction.rs delete mode 100644 packages/backend/src/misc/reaction-lib.ts diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 9b8a64142f..a47495508e 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -156,6 +156,14 @@ export function nyaify(text: string, lang?: string | undefined | null): string export function hashPassword(password: string): string export function verifyPassword(password: string, hash: string): boolean export function isOldPasswordAlgorithm(hash: string): boolean +export interface DecodedReaction { + reaction: string + name: string | null + host: string | null +} +export function decodeReaction(reaction: string): DecodedReaction +export function countReactions(reactions: Record): Record +export function toDbReaction(reaction?: string | undefined | null, host?: string | undefined | null): Promise export interface AbuseUserReport { id: string createdAt: Date diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 16de16297f..6fca851430 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,7 +310,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding +const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding module.exports.readServerConfig = readServerConfig module.exports.stringToAcct = stringToAcct @@ -333,6 +333,9 @@ module.exports.nyaify = nyaify module.exports.hashPassword = hashPassword module.exports.verifyPassword = verifyPassword module.exports.isOldPasswordAlgorithm = isOldPasswordAlgorithm +module.exports.decodeReaction = decodeReaction +module.exports.countReactions = countReactions +module.exports.toDbReaction = toDbReaction module.exports.AntennaSrcEnum = AntennaSrcEnum module.exports.MutedNoteReasonEnum = MutedNoteReasonEnum module.exports.NoteVisibilityEnum = NoteVisibilityEnum diff --git a/packages/backend-rs/src/misc/mod.rs b/packages/backend-rs/src/misc/mod.rs index 3fd447f4d5..45fd31cdcd 100644 --- a/packages/backend-rs/src/misc/mod.rs +++ b/packages/backend-rs/src/misc/mod.rs @@ -8,3 +8,4 @@ pub mod mastodon_id; pub mod meta; pub mod nyaify; pub mod password; +pub mod reaction; diff --git a/packages/backend-rs/src/misc/reaction.rs b/packages/backend-rs/src/misc/reaction.rs new file mode 100644 index 0000000000..a29ddf95de --- /dev/null +++ b/packages/backend-rs/src/misc/reaction.rs @@ -0,0 +1,191 @@ +use crate::database::db_conn; +use crate::misc::{convert_host::to_puny, emoji::is_unicode_emoji, meta::fetch_meta}; +use crate::model::entity::emoji; +use once_cell::sync::Lazy; +use regex::Regex; +use sea_orm::prelude::*; +use std::collections::HashMap; + +#[derive(PartialEq, Debug)] +#[crate::export(object)] +pub struct DecodedReaction { + pub reaction: String, + pub name: Option, + pub host: Option, +} + +#[crate::export] +pub fn decode_reaction(reaction: &str) -> DecodedReaction { + // Misskey allows you to include "+" and "-" in emoji shortcodes + // MFM spec: https://github.com/misskey-dev/mfm.js/blob/6aaf68089023c6adebe44123eebbc4dcd75955e0/docs/syntax.md?plain=1#L583 + // Misskey's implementation: https://github.com/misskey-dev/misskey/blob/bba3097765317cbf95d09627961b5b5dce16a972/packages/backend/src/core/ReactionService.ts#L68 + static RE: Lazy = + Lazy::new(|| Regex::new(r"^:([0-9A-Za-z_+-]+)(?:@([0-9A-Za-z_.-]+))?:$").unwrap()); + + if let Some(captures) = RE.captures(reaction) { + let name = &captures[1]; + let host = captures.get(2).map(|s| s.as_str()); + + DecodedReaction { + reaction: format!(":{}@{}:", name, host.unwrap_or(".")), + name: Some(name.to_owned()), + host: host.map(|s| s.to_owned()), + } + } else { + DecodedReaction { + reaction: reaction.to_owned(), + name: None, + host: None, + } + } +} + +#[crate::export] +pub fn count_reactions(reactions: &HashMap) -> HashMap { + let mut res = HashMap::::new(); + + for (reaction, count) in reactions.iter() { + if count > &0 { + let decoded = decode_reaction(reaction).reaction; + let total = res.entry(decoded).or_insert(0); + *total += count; + } + } + + res +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Idna error: {0}")] + IdnaError(#[from] idna::Errors), + #[error("Database error: {0}")] + DbError(#[from] DbErr), +} + +#[crate::export] +pub async fn to_db_reaction(reaction: Option<&str>, host: Option<&str>) -> Result { + if let Some(reaction) = reaction { + // FIXME: Is it okay to do this only here? + // This was introduced in https://firefish.dev/firefish/firefish/-/commit/af730e75b6fc1a57ca680ce83459d7e433b130cf + if reaction.contains('❤') || reaction.contains("♥️") { + return Ok("❤️".to_owned()); + } + + if is_unicode_emoji(reaction) { + return Ok(reaction.to_owned()); + } + + static RE: Lazy = + Lazy::new(|| Regex::new(r"^:([0-9A-Za-z_+-]+)(?:@\.)?:$").unwrap()); + + if let Some(captures) = RE.captures(reaction) { + let name = &captures[1]; + let db = db_conn().await?; + + if let Some(host) = host { + // remote emoji + let ascii_host = to_puny(host)?; + + // TODO: Does SeaORM have the `exists` method? + if emoji::Entity::find() + .filter(emoji::Column::Name.eq(name)) + .filter(emoji::Column::Host.eq(&ascii_host)) + .one(db) + .await? + .is_some() + { + return Ok(format!(":{name}@{ascii_host}:")); + } + } else { + // local emoji + // TODO: Does SeaORM have the `exists` method? + if emoji::Entity::find() + .filter(emoji::Column::Name.eq(name)) + .filter(emoji::Column::Host.is_null()) + .one(db) + .await? + .is_some() + { + return Ok(format!(":{name}:")); + } + } + }; + }; + + Ok(fetch_meta(true).await?.default_reaction) +} + +#[cfg(test)] +mod unit_test { + use super::{decode_reaction, DecodedReaction}; + use pretty_assertions::{assert_eq, assert_ne}; + + #[test] + fn test_decode_reaction() { + let unicode_emoji_1 = DecodedReaction { + reaction: "⭐".to_string(), + name: None, + host: None, + }; + let unicode_emoji_2 = DecodedReaction { + reaction: "🩷".to_string(), + name: None, + host: None, + }; + + assert_eq!(decode_reaction("⭐"), unicode_emoji_1); + assert_eq!(decode_reaction("🩷"), unicode_emoji_2); + + assert_ne!(decode_reaction("⭐"), unicode_emoji_2); + assert_ne!(decode_reaction("🩷"), unicode_emoji_1); + + let unicode_emoji_3 = DecodedReaction { + reaction: "🖖🏿".to_string(), + name: None, + host: None, + }; + assert_eq!(decode_reaction("🖖🏿"), unicode_emoji_3); + + let local_emoji = DecodedReaction { + reaction: ":meow_melt_tears@.:".to_string(), + name: Some("meow_melt_tears".to_string()), + host: None, + }; + assert_eq!(decode_reaction(":meow_melt_tears:"), local_emoji); + + let remote_emoji_1 = DecodedReaction { + reaction: ":meow_uwu@some-domain.example.org:".to_string(), + name: Some("meow_uwu".to_string()), + host: Some("some-domain.example.org".to_string()), + }; + assert_eq!( + decode_reaction(":meow_uwu@some-domain.example.org:"), + remote_emoji_1 + ); + + let remote_emoji_2 = DecodedReaction { + reaction: ":C++23@xn--eckwd4c7c.example.org:".to_string(), + name: Some("C++23".to_string()), + host: Some("xn--eckwd4c7c.example.org".to_string()), + }; + assert_eq!( + decode_reaction(":C++23@xn--eckwd4c7c.example.org:"), + remote_emoji_2 + ); + + let invalid_reaction_1 = DecodedReaction { + reaction: ":foo".to_string(), + name: None, + host: None, + }; + assert_eq!(decode_reaction(":foo"), invalid_reaction_1); + + let invalid_reaction_2 = DecodedReaction { + reaction: ":foo&@example.com:".to_string(), + name: None, + host: None, + }; + assert_eq!(decode_reaction(":foo&@example.com:"), invalid_reaction_2); + } +} diff --git a/packages/backend/src/misc/populate-emojis.ts b/packages/backend/src/misc/populate-emojis.ts index f18b23c9a4..4ca60b222f 100644 --- a/packages/backend/src/misc/populate-emojis.ts +++ b/packages/backend/src/misc/populate-emojis.ts @@ -3,8 +3,7 @@ import { Emojis } from "@/models/index.js"; import type { Emoji } from "@/models/entities/emoji.js"; import type { Note } from "@/models/entities/note.js"; import { Cache } from "./cache.js"; -import { isSelfHost, toPuny } from "backend-rs"; -import { decodeReaction } from "./reaction-lib.js"; +import { decodeReaction, isSelfHost, toPuny } from "backend-rs"; import config from "@/config/index.js"; import { query } from "@/prelude/url.js"; import { redisClient } from "@/db/redis.js"; diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts deleted file mode 100644 index ac9ba5652d..0000000000 --- a/packages/backend/src/misc/reaction-lib.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { fetchMeta, isUnicodeEmoji, toPuny } from "backend-rs"; -import { Emojis } from "@/models/index.js"; -import { IsNull } from "typeorm"; - -export function convertReactions(reactions: Record) { - const result = new Map(); - - for (const reaction in reactions) { - if (reactions[reaction] <= 0) continue; - - const decoded = decodeReaction(reaction).reaction; - result.set(decoded, (result.get(decoded) || 0) + reactions[reaction]); - } - - return Object.fromEntries(result); -} - -export async function toDbReaction( - reaction?: string | null, - reacterHost?: string | null, -): Promise { - if (!reaction) return (await fetchMeta(true)).defaultReaction; - - if (reaction.includes("❤") || reaction.includes("♥️")) return "❤️"; - - // Allow unicode reactions - if (isUnicodeEmoji(reaction)) { - return reaction; - } - - reacterHost = reacterHost == null ? null : toPuny(reacterHost); - - const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/); - if (custom) { - const name = custom[1]; - const emoji = await Emojis.findOneBy({ - host: reacterHost || IsNull(), - name, - }); - - if (emoji) return reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; - } - - return (await fetchMeta(true)).defaultReaction; -} - -type DecodedReaction = { - /** - * リアクション名 (Unicode Emoji or ':name@hostname' or ':name@.') - */ - reaction: string; - - /** - * name (カスタム絵文字の場合name, Emojiクエリに使う) - */ - name?: string; - - /** - * host (カスタム絵文字の場合host, Emojiクエリに使う) - */ - host?: string | null; -}; - -export function decodeReaction(str: string): DecodedReaction { - const custom = str.match(/^:([\w+-]+)(?:@([\w.-]+))?:$/); - - if (custom) { - const name = custom[1]; - const host = custom[2] || null; - - return { - reaction: `:${name}@${host || "."}:`, // ローカル分は@以降を省略するのではなく.にする - name, - host, - }; - } - - return { - reaction: str, - name: undefined, - host: undefined, - }; -} diff --git a/packages/backend/src/models/repositories/note-reaction.ts b/packages/backend/src/models/repositories/note-reaction.ts index 20aae2876f..47e16ced0c 100644 --- a/packages/backend/src/models/repositories/note-reaction.ts +++ b/packages/backend/src/models/repositories/note-reaction.ts @@ -2,7 +2,7 @@ import { db } from "@/db/postgre.js"; import { NoteReaction } from "@/models/entities/note-reaction.js"; import { Notes, Users } from "../index.js"; import type { Packed } from "@/misc/schema.js"; -import { decodeReaction } from "@/misc/reaction-lib.js"; +import { decodeReaction } from "backend-rs"; import type { User } from "@/models/entities/user.js"; export const NoteReactionRepository = db.getRepository(NoteReaction).extend({ diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index ed6ecc4a5c..1bf4ef657f 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -12,9 +12,8 @@ import { Channels, } from "../index.js"; import type { Packed } from "@/misc/schema.js"; -import { nyaify } from "backend-rs"; +import { countReactions, decodeReaction, nyaify } from "backend-rs"; import { awaitAll } from "@/prelude/await-all.js"; -import { convertReactions, decodeReaction } from "@/misc/reaction-lib.js"; import type { NoteReaction } from "@/models/entities/note-reaction.js"; import { aggregateNoteEmojis, @@ -214,7 +213,7 @@ export const NoteRepository = db.getRepository(Note).extend({ note.visibility === "specified" ? note.visibleUserIds : undefined, renoteCount: note.renoteCount, repliesCount: note.repliesCount, - reactions: convertReactions(note.reactions), + reactions: countReactions(note.reactions), reactionEmojis: reactionEmoji, emojis: noteEmoji, tags: note.tags.length > 0 ? note.tags : undefined, diff --git a/packages/backend/src/services/note/reaction/create.ts b/packages/backend/src/services/note/reaction/create.ts index a07ffdabad..3b8b97cefd 100644 --- a/packages/backend/src/services/note/reaction/create.ts +++ b/packages/backend/src/services/note/reaction/create.ts @@ -2,7 +2,6 @@ import { publishNoteStream } from "@/services/stream.js"; import { renderLike } from "@/remote/activitypub/renderer/like.js"; import DeliverManager from "@/remote/activitypub/deliver-manager.js"; import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import { toDbReaction, decodeReaction } from "@/misc/reaction-lib.js"; import type { User, IRemoteUser } from "@/models/entities/user.js"; import type { Note } from "@/models/entities/note.js"; import { @@ -14,7 +13,7 @@ import { Blockings, } from "@/models/index.js"; import { IsNull, Not } from "typeorm"; -import { genId } from "backend-rs"; +import { decodeReaction, genId, toDbReaction } from "backend-rs"; import { createNotification } from "@/services/create-notification.js"; import deleteReaction from "./delete.js"; import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; @@ -95,7 +94,7 @@ export default async ( const emoji = await Emojis.findOne({ where: { - name: decodedReaction.name, + name: decodedReaction.name ?? undefined, host: decodedReaction.host ?? IsNull(), }, select: ["name", "host", "originalUrl", "publicUrl"], diff --git a/packages/backend/src/services/note/reaction/delete.ts b/packages/backend/src/services/note/reaction/delete.ts index 49879a0c02..e5416a78a8 100644 --- a/packages/backend/src/services/note/reaction/delete.ts +++ b/packages/backend/src/services/note/reaction/delete.ts @@ -7,7 +7,7 @@ import { IdentifiableError } from "@/misc/identifiable-error.js"; import type { User, IRemoteUser } from "@/models/entities/user.js"; import type { Note } from "@/models/entities/note.js"; import { NoteReactions, Users, Notes } from "@/models/index.js"; -import { decodeReaction } from "@/misc/reaction-lib.js"; +import { decodeReaction } from "backend-rs"; export default async ( user: { id: User["id"]; host: User["host"] }, From 71c158fbd3088ab3194e39aa8a6ce71cddde257d Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 15 Apr 2024 17:28:20 +0900 Subject: [PATCH 17/22] refactor (backend): port env.ts to backend-rs --- packages/backend-rs/index.d.ts | 10 +++++++ packages/backend-rs/index.js | 3 ++- packages/backend-rs/src/config/environment.rs | 27 +++++++++++++++++++ packages/backend-rs/src/config/mod.rs | 1 + packages/backend/src/boot/index.ts | 2 +- packages/backend/src/boot/master.ts | 2 +- packages/backend/src/config/index.ts | 2 ++ packages/backend/src/env.ts | 23 ---------------- packages/backend/src/queue/index.ts | 2 +- packages/backend/src/server/index.ts | 5 ++-- packages/backend/src/services/logger.ts | 3 +-- 11 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 packages/backend-rs/src/config/environment.rs delete mode 100644 packages/backend/src/env.ts diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index a47495508e..ae050e01d8 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -3,6 +3,16 @@ /* auto-generated by NAPI-RS */ +export interface EnvConfig { + onlyQueue: boolean + onlyServer: boolean + noDaemons: boolean + disableClustering: boolean + verbose: boolean + withLogTime: boolean + slow: boolean +} +export function readEnvironmentConfig(): EnvConfig export interface ServerConfig { url: string port: number diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js index 6fca851430..6acd3ca68d 100644 --- a/packages/backend-rs/index.js +++ b/packages/backend-rs/index.js @@ -310,8 +310,9 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding +const { readEnvironmentConfig, readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding +module.exports.readEnvironmentConfig = readEnvironmentConfig module.exports.readServerConfig = readServerConfig module.exports.stringToAcct = stringToAcct module.exports.acctToString = acctToString diff --git a/packages/backend-rs/src/config/environment.rs b/packages/backend-rs/src/config/environment.rs new file mode 100644 index 0000000000..7d66aec7ba --- /dev/null +++ b/packages/backend-rs/src/config/environment.rs @@ -0,0 +1,27 @@ +// FIXME: Are these options used? +#[crate::export(object)] +pub struct EnvConfig { + pub only_queue: bool, + pub only_server: bool, + pub no_daemons: bool, + pub disable_clustering: bool, + pub verbose: bool, + pub with_log_time: bool, + pub slow: bool, +} + +#[crate::export] +pub fn read_environment_config() -> EnvConfig { + let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase(); + let is_testing = node_env == "test"; + + EnvConfig { + only_queue: std::env::var("MK_ONLY_QUEUE").is_ok(), + only_server: std::env::var("MK_ONLY_SERVER").is_ok(), + no_daemons: is_testing || std::env::var("MK_NO_DAEMONS").is_ok(), + disable_clustering: is_testing || std::env::var("MK_DISABLE_CLUSTERING").is_ok(), + verbose: std::env::var("MK_VERBOSE").is_ok(), + with_log_time: std::env::var("MK_WITH_LOG_TIME").is_ok(), + slow: std::env::var("MK_SLOW").is_ok(), + } +} diff --git a/packages/backend-rs/src/config/mod.rs b/packages/backend-rs/src/config/mod.rs index 74f47ad347..b708f2b265 100644 --- a/packages/backend-rs/src/config/mod.rs +++ b/packages/backend-rs/src/config/mod.rs @@ -1 +1,2 @@ +pub mod environment; pub mod server; diff --git a/packages/backend/src/boot/index.ts b/packages/backend/src/boot/index.ts index 4ba24c280b..9854d2dce4 100644 --- a/packages/backend/src/boot/index.ts +++ b/packages/backend/src/boot/index.ts @@ -3,7 +3,7 @@ import chalk from "chalk"; import Xev from "xev"; import Logger from "@/services/logger.js"; -import { envOption } from "../env.js"; +import { envOption } from "@/config/index.js"; import { inspect } from "node:util"; // for typeorm diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index cd21c33021..3ba2d0cf50 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -10,7 +10,7 @@ import semver from "semver"; import Logger from "@/services/logger.js"; import loadConfig from "@/config/load.js"; import type { Config } from "@/config/types.js"; -import { envOption } from "@/env.js"; +import { envOption } from "@/config/index.js"; import { showMachineInfo } from "@/misc/show-machine-info.js"; import { db, initDb } from "@/db/postgre.js"; import { inspect } from "node:util"; diff --git a/packages/backend/src/config/index.ts b/packages/backend/src/config/index.ts index ae197b09ca..fe87e5026a 100644 --- a/packages/backend/src/config/index.ts +++ b/packages/backend/src/config/index.ts @@ -1,3 +1,5 @@ import load from "./load.js"; +import { readEnvironmentConfig } from "backend-rs"; export default load(); +export const envOption = readEnvironmentConfig(); diff --git a/packages/backend/src/env.ts b/packages/backend/src/env.ts deleted file mode 100644 index a10952133e..0000000000 --- a/packages/backend/src/env.ts +++ /dev/null @@ -1,23 +0,0 @@ -const envOption = { - onlyQueue: false, - onlyServer: false, - noDaemons: false, - disableClustering: false, - verbose: false, - withLogTime: false, - slow: false, -}; - -for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) { - if ( - process.env[ - `MK_${key.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase()}` - ] - ) - envOption[key] = true; -} - -if (process.env.NODE_ENV === "test") envOption.disableClustering = true; -if (process.env.NODE_ENV === "test") envOption.noDaemons = true; - -export { envOption }; diff --git a/packages/backend/src/queue/index.ts b/packages/backend/src/queue/index.ts index 58a0ae7486..e4e413be52 100644 --- a/packages/backend/src/queue/index.ts +++ b/packages/backend/src/queue/index.ts @@ -5,7 +5,7 @@ import config from "@/config/index.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import type { IActivity } from "@/remote/activitypub/type.js"; import type { Webhook, webhookEventTypes } from "@/models/entities/webhook.js"; -import { envOption } from "../env.js"; +import { envOption } from "@/config/index.js"; import processDeliver from "./processors/deliver.js"; import processInbox from "./processors/inbox.js"; diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 6cf837b4ed..17358a4758 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -13,15 +13,14 @@ import koaLogger from "koa-logger"; import * as slow from "koa-slow"; import { IsNull } from "typeorm"; -import config from "@/config/index.js"; +import config, { envOption } from "@/config/index.js"; import Logger from "@/services/logger.js"; import { Users } from "@/models/index.js"; import { fetchMeta } from "backend-rs"; import { genIdenticon } from "@/misc/gen-identicon.js"; import { createTemp } from "@/misc/create-temp.js"; import { stringToAcct } from "backend-rs"; -import { envOption } from "@/env.js"; -import megalodon, { MegalodonInterface } from "megalodon"; +import megalodon, { type MegalodonInterface } from "megalodon"; import activityPub from "./activitypub.js"; import nodeinfo from "./nodeinfo.js"; import wellKnown from "./well-known.js"; diff --git a/packages/backend/src/services/logger.ts b/packages/backend/src/services/logger.ts index 47a1fe82f8..e53279e31c 100644 --- a/packages/backend/src/services/logger.ts +++ b/packages/backend/src/services/logger.ts @@ -2,8 +2,7 @@ import cluster from "node:cluster"; import chalk from "chalk"; import { default as convertColor } from "color-convert"; import { format as dateFormat } from "date-fns"; -import { envOption } from "@/env.js"; -import config from "@/config/index.js"; +import config, { envOption } from "@/config/index.js"; import * as SyslogPro from "syslog-pro"; From 80b80277e2d87588ef210867140eec3b9d4cba75 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 16 Apr 2024 01:50:42 +0900 Subject: [PATCH 18/22] fix (pug): random MOTD not showing --- packages/backend/src/server/web/views/base.pug | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index bdbe153fbe..738d3ffc01 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -72,8 +72,8 @@ html div#splash img#splashIcon(src= splashIcon || `/static-assets/splash.svg?${ timestamp }`) span#splashText - block randomMOTD - = randomMOTD + block randomMotd + = randomMotd div#splashSpinner From 38192052c909c4583ca245f6102806ce787504bb Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 16 Apr 2024 05:34:43 +0900 Subject: [PATCH 19/22] meta: update issue/merge request templates --- .gitlab/issue_templates/bug.md | 32 ++++++++++++++-------- .gitlab/issue_templates/feature.md | 12 ++++---- .gitlab/merge_request_templates/default.md | 4 +-- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/.gitlab/issue_templates/bug.md b/.gitlab/issue_templates/bug.md index 3bffa21cde..a94fae0f0d 100644 --- a/.gitlab/issue_templates/bug.md +++ b/.gitlab/issue_templates/bug.md @@ -3,30 +3,38 @@ 🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md) 🤝 By submitting this issue, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) --> -**What happened?** _(Please give us a brief description of what happened.)_ +## What happened? -**What did you expect to happen?** _(Please give us a brief description of what you expected to happen.)_ +## What did you expect to happen? -**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_ +## Version -**Instance** _(What instance of firefish are you using?)_ +## What type of issue is this? -**What type of issue is this?** _(If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side.)_ +- [] server-side +- [] client-side +- [] not sure -**What browser are you using? (Client-side issues only)** +
-**What operating system are you using? (Client-side issues only)** +### Instance -**How do you deploy Firefish on your server? (Server-side issues only)** +### What browser are you using? (client-side issues only) -**What operating system are you using? (Server-side issues only)** +### What operating system are you using? (client-side issues only) -**Relevant log output** _(Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks.)_ +### How do you deploy Firefish on your server? (server-side issues only) -**Contribution Guidelines** +### What operating system are you using? (Server-side issues only) + +### Relevant log output + +
+ +## Contribution Guidelines By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) - [ ] I agree to follow this project's Contribution Guidelines - [ ] I have searched the issue tracker for similar issues, and this is not a duplicate. -**Are you willing to fix this bug?** (optional) +## Are you willing to fix this bug? (optional) - [ ] Yes. I will fix this bug and open a merge request if the change is agreed upon. diff --git a/.gitlab/issue_templates/feature.md b/.gitlab/issue_templates/feature.md index b4af4884b7..7b4917ecb3 100644 --- a/.gitlab/issue_templates/feature.md +++ b/.gitlab/issue_templates/feature.md @@ -3,18 +3,18 @@ 🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md) 🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) --> -**What feature would you like implemented?** _(Please give us a brief description of what you'd like.)_ +## What feature would you like implemented? -**Why should we add this feature?** _(Please give us a brief description of why your feature is important.)_ +## Why should we add this feature? -**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_ +## Version -**Instance** _(What instance of firefish are you using?)_ +## Instance -**Contribution Guidelines** +## Contribution Guidelines By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) - [ ] I agree to follow this project's Contribution Guidelines - [ ] I have searched the issue tracker for similar requests, and this is not a duplicate. -**Are you willing to implement this feature?** (optional) +## Are you willing to implement this feature? (optional) - [ ] Yes. I will implement this feature and open a merge request if the change is agreed upon. diff --git a/.gitlab/merge_request_templates/default.md b/.gitlab/merge_request_templates/default.md index 2a1c926223..c2382481e3 100644 --- a/.gitlab/merge_request_templates/default.md +++ b/.gitlab/merge_request_templates/default.md @@ -1,8 +1,8 @@ -**What does this PR do?** _(Please give us a brief description of what this PR does.)_ +## What does this PR do? -**Contribution Guidelines** +## Contribution Guidelines By submitting this merge request, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) - [ ] This change is reviewed in an issue / This is a minor bug fix - [ ] I agree to follow this project's Contribution Guidelines From fd333250c9801fea344216778059ad8c3b3a5978 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 16 Apr 2024 08:56:05 +0900 Subject: [PATCH 20/22] chore (backend): set proxyRemoteFiles to true by default (close #9426) --- .config/example.yml | 2 +- packages/backend/src/config/load.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.config/example.yml b/.config/example.yml index 9082dfb868..fdfb0b0965 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -178,7 +178,7 @@ logLevel: [ # Media Proxy #mediaProxy: https://example.com/proxy -# Proxy remote files (default: false) +# Proxy remote files (default: true) #proxyRemoteFiles: true #allowedPrivateNetworks: [ diff --git a/packages/backend/src/config/load.ts b/packages/backend/src/config/load.ts index 2b286b9439..682bf309d2 100644 --- a/packages/backend/src/config/load.ts +++ b/packages/backend/src/config/load.ts @@ -55,6 +55,7 @@ export default function load() { mixin.userAgent = `Firefish/${meta.version} (${config.url})`; mixin.clientEntry = clientManifest["src/init.ts"]; + if (config.proxyRemoteFiles == null) config.proxyRemoteFiles = true; if (!config.redis.prefix) config.redis.prefix = mixin.hostname; if (config.cacheServer && !config.cacheServer.prefix) config.cacheServer.prefix = mixin.hostname; From 77a2bcfc4b6ba4505242e5ffb23eeaeade32dbb2 Mon Sep 17 00:00:00 2001 From: naskya Date: Tue, 16 Apr 2024 09:01:12 +0900 Subject: [PATCH 21/22] chore: remove unused items from example config file --- .config/example.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.config/example.yml b/.config/example.yml index fdfb0b0965..17149f6c3a 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -185,12 +185,6 @@ logLevel: [ # '127.0.0.1/32' #] -# TWA -#twa: -# nameSpace: android_app -# packageName: tld.domain.twa -# sha256CertFingerprints: ['AB:CD:EF'] - # Upload or download file size limits (bytes) #maxFileSize: 262144000 From 7af2cca2d4e507e8e50ada87ea1488d407df9c17 Mon Sep 17 00:00:00 2001 From: Gary O'Regan Kelly Date: Mon, 15 Apr 2024 02:27:04 +0000 Subject: [PATCH 22/22] locale: update translations (French) Currently translated at 100.0% (1920 of 1920 strings) Translation: Firefish/locales Translate-URL: https://hosted.weblate.org/projects/firefish/locales/fr/ --- locales/fr-FR.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index da56856077..14c46b1740 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -2324,3 +2324,4 @@ markLocalFilesNsfwByDefaultDescription: Indépendamment de ce réglage, les util peuvent supprimer le drapeau « sensible » (NSFW) eux-mêmes. Les fichiers existants ne sont pas affectés. noteEditHistory: Historique des publications +media: Multimédia