refactor: move misc/check-word-mute.ts to backend-rs
Co-authored-by: sup39 <dev@sup39.dev>
This commit is contained in:
parent
45a65d156e
commit
1f37c0c5a3
29 changed files with 416 additions and 415 deletions
|
@ -1413,6 +1413,7 @@ _menuDisplay:
|
|||
hide: "Hide"
|
||||
_wordMute:
|
||||
muteWords: "Muted words"
|
||||
mutePatterns: "Muted patterns"
|
||||
muteLangs: "Muted Languages"
|
||||
muteWordsDescription: "Separate with spaces for an AND condition or with line breaks
|
||||
for an OR condition."
|
||||
|
|
|
@ -1221,6 +1221,7 @@ _menuDisplay:
|
|||
hide: "隠す"
|
||||
_wordMute:
|
||||
muteWords: "ミュートするワード"
|
||||
mutePatterns: "ミュートするパターン"
|
||||
muteLangs: "ミュートされた言語"
|
||||
muteWordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります。"
|
||||
muteWordsDescription2: "キーワードをスラッシュで囲むと正規表現になります。"
|
||||
|
|
|
@ -295,7 +295,7 @@ if (!nativeBinding) {
|
|||
throw new Error(`Failed to load native binding`)
|
||||
}
|
||||
|
||||
const { EnvConfig, readEnvironmentConfig, readServerConfig, JsDbConn, connectToDatabase, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, stringToAcct, acctToString, getFullApAccount, isSelfHost, extractHost, toPuny, toPunyOptional, convertToHiddenPost, sqlLikeEscape, safeForSql, formatMilliseconds, nativeInitIdGenerator, nativeCreateId, nativeGetTimestamp, fetchMeta, metaToPugArgs, hasOtherRenoteOfThisNote, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, genString, IdConvertType, convertId } = nativeBinding
|
||||
const { EnvConfig, readEnvironmentConfig, readServerConfig, JsDbConn, connectToDatabase, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, extractHost, toPuny, toPunyOptional, convertToHiddenPost, sqlLikeEscape, safeForSql, formatMilliseconds, nativeInitIdGenerator, nativeCreateId, nativeGetTimestamp, fetchMeta, metaToPugArgs, hasOtherRenoteOfThisNote, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, genString, IdConvertType, convertId } = nativeBinding
|
||||
|
||||
module.exports.EnvConfig = EnvConfig
|
||||
module.exports.readEnvironmentConfig = readEnvironmentConfig
|
||||
|
@ -314,6 +314,7 @@ module.exports.UserProfileFfvisibilityEnum = UserProfileFfvisibilityEnum
|
|||
module.exports.UserProfileMutingnotificationtypesEnum = UserProfileMutingnotificationtypesEnum
|
||||
module.exports.stringToAcct = stringToAcct
|
||||
module.exports.acctToString = acctToString
|
||||
module.exports.checkWordMute = checkWordMute
|
||||
module.exports.getFullApAccount = getFullApAccount
|
||||
module.exports.isSelfHost = isSelfHost
|
||||
module.exports.extractHost = extractHost
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
BEGIN;
|
||||
|
||||
DELETE FROM "migrations" WHERE name IN (
|
||||
'SeparateHardMuteWordsAndPatterns1706413792769',
|
||||
'RenameMetaColumns1705944717480',
|
||||
'RemoveNativeUtilsMigration1705877093218',
|
||||
'DropTimeZone1705691683091',
|
||||
|
@ -12,6 +13,10 @@ DELETE FROM "migrations" WHERE name IN (
|
|||
'EmojiModerator1692825433698'
|
||||
);
|
||||
|
||||
-- separate-hard-mute-words-and-patterns
|
||||
UPDATE "user_profile" SET "mutedWords" = "mutedWords" || array_to_json("mutedPatterns")::jsonb;
|
||||
ALTER TABLE "user_profile" DROP "mutedPatterns";
|
||||
|
||||
-- rename-meta-columns
|
||||
ALTER TABLE "meta" RENAME COLUMN "tosUrl" TO "ToSUrl";
|
||||
ALTER TABLE "meta" RENAME COLUMN "objectStorageUseSsl" TO "objectStorageUseSSL";
|
||||
|
|
20
packages/backend-rs/Cargo.lock
generated
20
packages/backend-rs/Cargo.lock
generated
|
@ -94,9 +94,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||
checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
|
@ -1118,9 +1118,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.1.0"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.3",
|
||||
|
@ -1163,9 +1163,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
@ -2221,9 +2221,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.112"
|
||||
version = "1.0.113"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed"
|
||||
checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -2244,9 +2244,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.30"
|
||||
version = "0.9.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38"
|
||||
checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
|
|
|
@ -73,6 +73,8 @@ pub struct Model {
|
|||
pub prevent_ai_learning: bool,
|
||||
#[sea_orm(column_name = "isIndexable")]
|
||||
pub is_indexable: bool,
|
||||
#[sea_orm(column_name = "mutedPatterns")]
|
||||
pub muted_patterns: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
|
|
114
packages/backend-rs/src/util/check_word_mute.rs
Normal file
114
packages/backend-rs/src/util/check_word_mute.rs
Normal file
|
@ -0,0 +1,114 @@
|
|||
use crate::database::JsDbConn;
|
||||
use crate::model::entity::{drive_file, note};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use sea_orm::prelude::*;
|
||||
|
||||
// FIXME: remove this type
|
||||
#[napi_derive::napi(object)]
|
||||
pub struct NoteLike {
|
||||
pub file_ids: Vec<String>,
|
||||
pub user_id: Option<String>,
|
||||
pub text: Option<String>,
|
||||
pub cw: Option<String>,
|
||||
pub renote_id: Option<String>,
|
||||
pub reply_id: Option<String>,
|
||||
}
|
||||
|
||||
async fn full_text(conn: &JsDbConn, note: NoteLike) -> String {
|
||||
let mut to_return = format!(
|
||||
"{}\n{}\n",
|
||||
note.text.unwrap_or_default(),
|
||||
note.cw.unwrap_or_default(),
|
||||
);
|
||||
|
||||
for file_id in note.file_ids {
|
||||
if let Some(alt_text) = drive_file::Entity::find_by_id(file_id)
|
||||
.one(conn.inner())
|
||||
.await
|
||||
.expect("Failed to connect to the database")
|
||||
.expect("file_id is invalid")
|
||||
.comment
|
||||
{
|
||||
to_return.push_str(alt_text.as_str());
|
||||
to_return.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
if note.renote_id.is_some() {
|
||||
to_return.push_str(
|
||||
note::Entity::find_by_id(note.renote_id.unwrap())
|
||||
.one(conn.inner())
|
||||
.await
|
||||
.expect("Failed to connect to the database")
|
||||
.expect("renote_id is invalid")
|
||||
.text
|
||||
.unwrap_or_default()
|
||||
.as_str(),
|
||||
);
|
||||
to_return.push('\n');
|
||||
}
|
||||
|
||||
if note.reply_id.is_some() {
|
||||
to_return.push_str(
|
||||
note::Entity::find_by_id(note.reply_id.unwrap())
|
||||
.one(conn.inner())
|
||||
.await
|
||||
.expect("Failed to connect to the database")
|
||||
.expect("reply_id is invalid")
|
||||
.text
|
||||
.unwrap_or_default()
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
to_return.trim().to_owned()
|
||||
}
|
||||
|
||||
// FIXME: remove this funtion
|
||||
fn convert_regex(js_regex: String) -> String {
|
||||
static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^/(.+)/(.*)$").unwrap());
|
||||
RE.replace(&js_regex, "(?$2)$1").to_string()
|
||||
}
|
||||
|
||||
async fn check_word_mute_impl(
|
||||
text: String,
|
||||
muted_word_lists: Vec<Vec<String>>,
|
||||
muted_patterns: Vec<String>,
|
||||
) -> bool {
|
||||
if text.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let text_lowercase = text.to_lowercase();
|
||||
|
||||
muted_word_lists.into_iter().any(|muted_word_list| {
|
||||
muted_word_list
|
||||
.into_iter()
|
||||
.all(|muted_word| text_lowercase.contains(&muted_word.to_lowercase()))
|
||||
}) || muted_patterns.into_iter().any(|muted_patten| {
|
||||
match Regex::new(convert_regex(muted_patten).as_str()) {
|
||||
Ok(re) => re.is_match(&text),
|
||||
Err(_) => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[napi_derive::napi]
|
||||
pub async fn check_word_mute(
|
||||
conn: &JsDbConn,
|
||||
note: NoteLike,
|
||||
muted_word_lists: Vec<Vec<String>>,
|
||||
muted_patterns: Vec<String>,
|
||||
) -> bool {
|
||||
if muted_word_lists.is_empty() && muted_patterns.is_empty() {
|
||||
false
|
||||
} else {
|
||||
check_word_mute_impl(
|
||||
full_text(conn, note).await,
|
||||
muted_word_lists,
|
||||
muted_patterns,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod acct;
|
||||
pub mod check_word_mute;
|
||||
pub mod convert_host;
|
||||
pub mod convert_to_hidden_post;
|
||||
pub mod escape_sql;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
export class SeparateHardMuteWordsAndPatterns1706413792769 {
|
||||
name = "SeparateHardMuteWordsAndPatterns1706413792769";
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user_profile" ADD "mutedPatterns" text[] DEFAULT '{}'`,
|
||||
);
|
||||
await queryRunner.query(`
|
||||
UPDATE "user_profile" SET
|
||||
"mutedPatterns" = ARRAY(
|
||||
SELECT jsonb_array_elements_text(jsonb_path_query_array(
|
||||
"mutedWords",
|
||||
'$ ? (@.type() == "string")'
|
||||
))
|
||||
),
|
||||
"mutedWords" = jsonb_path_query_array(
|
||||
"mutedWords",
|
||||
'$ ? (@.type() == "array")'
|
||||
)
|
||||
`);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user_profile" ALTER "mutedPatterns" SET NOT NULL`,
|
||||
);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(
|
||||
`UPDATE "user_profile" SET "mutedWords" = "mutedWords" || array_to_json("mutedPatterns")::jsonb`,
|
||||
);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" DROP "mutedPatterns"`);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
import RE2 from "re2";
|
||||
|
||||
export class convertHardMutes1644010796173 {
|
||||
name = "convertHardMutes1644010796173";
|
||||
|
||||
|
@ -15,7 +13,7 @@ export class convertHardMutes1644010796173 {
|
|||
if (regexp) {
|
||||
// convert regexp's
|
||||
try {
|
||||
new RE2(regexp[1], regexp[2]);
|
||||
new RegExp(regexp[1], regexp[2]);
|
||||
return `/${regexp[1]}/${regexp[2]}`;
|
||||
} catch (err) {
|
||||
// invalid regex, ignore it
|
||||
|
|
|
@ -98,7 +98,6 @@
|
|||
"qs": "6.11.2",
|
||||
"random-seed": "0.3.0",
|
||||
"ratelimiter": "3.4.1",
|
||||
"re2": "1.20.9",
|
||||
"redis-semaphore": "5.5.0",
|
||||
"reflect-metadata": "0.2.1",
|
||||
"rename": "1.0.4",
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
readServerConfig,
|
||||
readEnvironmentConfig,
|
||||
connectToDatabase,
|
||||
checkWordMute as checkWordMuteImpl,
|
||||
fetchMeta as fetchMetaImpl,
|
||||
hasOtherRenoteOfThisNote as hasOtherRenoteOfThisNoteImpl,
|
||||
JsDbConn,
|
||||
|
@ -20,3 +21,4 @@ const curryDb =
|
|||
|
||||
export const fetchMeta = curryDb(fetchMetaImpl);
|
||||
export const hasOtherRenoteOfThisNote = curryDb(hasOtherRenoteOfThisNoteImpl);
|
||||
export const checkWordMute = curryDb(checkWordMuteImpl);
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
import type { Antenna } from "@/models/entities/antenna.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import type { UserProfile } from "@/models/entities/user-profile.js";
|
||||
import { Blockings, Followings, UserProfiles } from "@/models/index.js";
|
||||
import { getFullApAccount, stringToAcct } from "backend-rs";
|
||||
import { checkWordMute } from "@/misc/backend-rs.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { Cache } from "@/misc/cache.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
|
||||
const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5);
|
||||
const mutedWordsCache = new Cache<string[][] | undefined>("mutedWords", 60 * 5);
|
||||
const hardMutesCache = new Cache<{
|
||||
userId: UserProfile["userId"];
|
||||
mutedWords: UserProfile["mutedWords"];
|
||||
mutedPatterns: UserProfile["mutedPatterns"];
|
||||
}>("hardMutes", 60 * 5);
|
||||
const followingCache = new Cache<User["id"][]>("following", 60 * 5);
|
||||
|
||||
export async function checkHitAntenna(
|
||||
|
@ -103,12 +108,24 @@ export async function checkHitAntenna(
|
|||
if (!following.includes(note.userId)) return false;
|
||||
}
|
||||
|
||||
const mutedWords = await mutedWordsCache.fetch(antenna.userId, () =>
|
||||
UserProfiles.findOneBy({ userId: antenna.userId }).then(
|
||||
(profile) => profile?.mutedWords,
|
||||
),
|
||||
const mutes = await hardMutesCache.fetch(antenna.userId, () =>
|
||||
UserProfiles.findOneByOrFail({
|
||||
userId: antenna.userId,
|
||||
}).then((profile) => {
|
||||
return {
|
||||
userId: antenna.userId,
|
||||
mutedWords: profile.mutedWords,
|
||||
mutedPatterns: profile.mutedPatterns,
|
||||
};
|
||||
}),
|
||||
);
|
||||
if (await getWordHardMute(note, antenna.userId, mutedWords)) return false;
|
||||
if (
|
||||
mutes.mutedWords != null &&
|
||||
mutes.mutedPatterns != null &&
|
||||
antenna.userId !== note.userId &&
|
||||
(await checkWordMute(note, mutes.mutedWords, mutes.mutedPatterns))
|
||||
)
|
||||
return false;
|
||||
|
||||
// TODO: eval expression
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
import RE2 from "re2";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
|
||||
type NoteLike = {
|
||||
userId: Note["userId"];
|
||||
text: Note["text"];
|
||||
files?: Note["files"];
|
||||
cw?: Note["cw"];
|
||||
};
|
||||
|
||||
function checkWordMute(
|
||||
note: NoteLike,
|
||||
mutedWords: Array<string | string[]>,
|
||||
): boolean {
|
||||
if (note == null) return false;
|
||||
|
||||
let text = `${note.cw ?? ""} ${note.text ?? ""}`;
|
||||
if (note.files != null)
|
||||
text += ` ${note.files.map((f) => f.comment ?? "").join(" ")}`;
|
||||
text = text.trim();
|
||||
|
||||
if (text === "") return false;
|
||||
|
||||
for (const mutePattern of mutedWords) {
|
||||
if (Array.isArray(mutePattern)) {
|
||||
// Clean up
|
||||
const keywords = mutePattern.filter((keyword) => keyword !== "");
|
||||
|
||||
if (
|
||||
keywords.length > 0 &&
|
||||
keywords.every((keyword) =>
|
||||
text.toLowerCase().includes(keyword.toLowerCase()),
|
||||
)
|
||||
)
|
||||
return true;
|
||||
} else {
|
||||
// represents RegExp
|
||||
const regexp = mutePattern.match(/^\/(.+)\/(.*)$/);
|
||||
|
||||
// This should never happen due to input sanitisation.
|
||||
if (!regexp) {
|
||||
console.warn(`Found invalid regex in word mutes: ${mutePattern}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
if (new RE2(regexp[1], regexp[2]).test(text)) return true;
|
||||
} catch (err) {
|
||||
// This should never happen due to input sanitisation.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function getWordHardMute(
|
||||
note: NoteLike,
|
||||
meId: string | null | undefined,
|
||||
mutedWords?: Array<string | string[]>,
|
||||
): Promise<boolean> {
|
||||
if (note.userId === meId || mutedWords == null) return false;
|
||||
|
||||
if (mutedWords.length > 0) {
|
||||
return (
|
||||
checkWordMute(note, mutedWords) ||
|
||||
checkWordMute(note.reply, mutedWords) ||
|
||||
checkWordMute(note.renote, mutedWords)
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -223,6 +223,12 @@ export class UserProfile {
|
|||
})
|
||||
public mutedWords: string[][];
|
||||
|
||||
@Column("text", {
|
||||
array: true,
|
||||
nullable: false,
|
||||
})
|
||||
public mutedPatterns: string[];
|
||||
|
||||
@Column("jsonb", {
|
||||
default: [],
|
||||
comment: "List of instances muted by the user.",
|
||||
|
|
|
@ -573,6 +573,7 @@ export const UserRepository = db.getRepository(User).extend({
|
|||
hasPendingReceivedFollowRequest:
|
||||
this.getHasPendingReceivedFollowRequest(user.id),
|
||||
mutedWords: profile?.mutedWords,
|
||||
mutedPatterns: profile?.mutedPatterns,
|
||||
mutedInstances: profile?.mutedInstances,
|
||||
mutingNotificationTypes: profile?.mutingNotificationTypes,
|
||||
emailNotificationTypes: profile?.emailNotificationTypes,
|
||||
|
|
|
@ -474,6 +474,16 @@ export const packedMeDetailedOnlySchema = {
|
|||
},
|
||||
},
|
||||
},
|
||||
mutedPatterns: {
|
||||
type: "array",
|
||||
nullable: false,
|
||||
optional: false,
|
||||
items: {
|
||||
type: "string",
|
||||
nullable: false,
|
||||
optional: false,
|
||||
},
|
||||
},
|
||||
mutedInstances: {
|
||||
type: "array",
|
||||
nullable: true,
|
||||
|
|
|
@ -61,6 +61,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
injectFeaturedNote: profile.injectFeaturedNote,
|
||||
receiveAnnouncementEmail: profile.receiveAnnouncementEmail,
|
||||
mutedWords: profile.mutedWords,
|
||||
mutedPatterns: profile.mutedPatterns,
|
||||
mutedInstances: profile.mutedInstances,
|
||||
mutingNotificationTypes: profile.mutingNotificationTypes,
|
||||
isModerator: user.isModerator,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import RE2 from "re2";
|
||||
import * as mfm from "mfm-js";
|
||||
import { publishMainStream, publishUserEvent } from "@/services/stream.js";
|
||||
import acceptAllFollowRequests from "@/services/following/requests/accept-all.js";
|
||||
|
@ -126,6 +125,7 @@ export const paramDef = {
|
|||
ffVisibility: { type: "string", enum: ["public", "followers", "private"] },
|
||||
pinnedPageId: { type: "string", format: "misskey:id", nullable: true },
|
||||
mutedWords: { type: "array" },
|
||||
mutedPatterns: { type: "array", items: { type: "string" } },
|
||||
mutedInstances: {
|
||||
type: "array",
|
||||
items: {
|
||||
|
@ -166,23 +166,52 @@ export default define(meta, paramDef, async (ps, _user, token) => {
|
|||
profileUpdates.ffVisibility = ps.ffVisibility;
|
||||
if (ps.avatarId !== undefined) updates.avatarId = ps.avatarId;
|
||||
if (ps.bannerId !== undefined) updates.bannerId = ps.bannerId;
|
||||
if (ps.mutedWords !== undefined) {
|
||||
// validate regular expression syntax
|
||||
ps.mutedWords
|
||||
.filter((x) => !Array.isArray(x))
|
||||
.forEach((x) => {
|
||||
const regexp = x.match(/^\/(.+)\/(.*)$/);
|
||||
if (ps.mutedPatterns !== undefined) {
|
||||
for (const item of ps.mutedPatterns) {
|
||||
const regexp = item.match(/^\/(.+)\/(.*)$/);
|
||||
if (!regexp) throw new ApiError(meta.errors.invalidRegexp);
|
||||
|
||||
try {
|
||||
new RE2(regexp[1], regexp[2]);
|
||||
new RegExp(regexp[1], regexp[2]);
|
||||
} catch (err) {
|
||||
throw new ApiError(meta.errors.invalidRegexp);
|
||||
}
|
||||
});
|
||||
|
||||
profileUpdates.mutedWords = ps.mutedWords;
|
||||
profileUpdates.enableWordMute = ps.mutedWords.length > 0;
|
||||
profileUpdates.mutedPatterns = profileUpdates.mutedPatterns ?? [];
|
||||
profileUpdates.mutedPatterns.push(item);
|
||||
}
|
||||
}
|
||||
if (ps.mutedWords !== undefined) {
|
||||
// for compatibility with the upstream Firefish API
|
||||
for (const item of ps.mutedWords) {
|
||||
if (Array.isArray(item)) continue;
|
||||
|
||||
const regexp = item.match(/^\/(.+)\/(.*)$/);
|
||||
if (!regexp) throw new ApiError(meta.errors.invalidRegexp);
|
||||
|
||||
try {
|
||||
new RegExp(regexp[1], regexp[2]);
|
||||
} catch (err) {
|
||||
throw new ApiError(meta.errors.invalidRegexp);
|
||||
}
|
||||
|
||||
profileUpdates.mutedPatterns = profileUpdates.mutedPatterns ?? [];
|
||||
profileUpdates.mutedPatterns.push(item);
|
||||
}
|
||||
|
||||
profileUpdates.mutedWords = ps.mutedWords.filter((item) =>
|
||||
Array.isArray(item),
|
||||
);
|
||||
}
|
||||
if (
|
||||
profileUpdates.mutedWords !== undefined ||
|
||||
profileUpdates.mutedPatterns !== undefined
|
||||
) {
|
||||
profileUpdates.enableWordMute =
|
||||
(profileUpdates.mutedWords != null &&
|
||||
profileUpdates.mutedWords.length > 0) ||
|
||||
(profileUpdates.mutedPatterns != null &&
|
||||
profileUpdates.mutedPatterns.length > 0);
|
||||
}
|
||||
if (ps.mutedInstances !== undefined)
|
||||
profileUpdates.mutedInstances = ps.mutedInstances;
|
||||
|
|
|
@ -4,7 +4,6 @@ import { fileURLToPath } from "node:url";
|
|||
import define from "@/server/api/define.js";
|
||||
import translate from "@/misc/translate.js";
|
||||
import type { Language } from "@/misc/langmap.js";
|
||||
import RE2 from "re2";
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
|
@ -37,8 +36,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
async function translateCommitMsg(msg: string, targetLang: Language) {
|
||||
const regex = new RE2(/^(.*) (\(by .*\))$/);
|
||||
const matches = regex.match(msg);
|
||||
const matches = msg.match(/^(.*) (\(by .*\))$/);
|
||||
|
||||
if (matches == null) return msg;
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import Channel from "../channel.js";
|
||||
import { fetchMeta } from "@/misc/backend-rs.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import { isInstanceMuted } from "@/misc/is-instance-muted.js";
|
||||
import { isUserRelated } from "@/misc/is-user-related.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { checkWordMute } from "@/misc/backend-rs.js";
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = "globalTimeline";
|
||||
|
@ -68,10 +68,15 @@ export default class extends Channel {
|
|||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (
|
||||
this.userProfile &&
|
||||
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||
this.user?.id !== note.userId &&
|
||||
(await checkWordMute(
|
||||
note,
|
||||
this.userProfile.mutedWords,
|
||||
this.userProfile.mutedPatterns,
|
||||
))
|
||||
)
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import Channel from "../channel.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import { isUserRelated } from "@/misc/is-user-related.js";
|
||||
import { isInstanceMuted } from "@/misc/is-instance-muted.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { checkWordMute } from "@/misc/backend-rs.js";
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = "homeTimeline";
|
||||
|
@ -65,10 +65,15 @@ export default class extends Channel {
|
|||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (
|
||||
this.userProfile &&
|
||||
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||
this.user?.id !== note.userId &&
|
||||
(await checkWordMute(
|
||||
note,
|
||||
this.userProfile.mutedWords,
|
||||
this.userProfile.mutedPatterns,
|
||||
))
|
||||
)
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import Channel from "../channel.js";
|
||||
import { fetchMeta } from "@/misc/backend-rs.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import { isUserRelated } from "@/misc/is-user-related.js";
|
||||
import { isInstanceMuted } from "@/misc/is-instance-muted.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { checkWordMute } from "@/misc/backend-rs.js";
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = "hybridTimeline";
|
||||
|
@ -82,10 +82,15 @@ export default class extends Channel {
|
|||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (
|
||||
this.userProfile &&
|
||||
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||
this.user?.id !== note.userId &&
|
||||
(await checkWordMute(
|
||||
note,
|
||||
this.userProfile.mutedWords,
|
||||
this.userProfile.mutedPatterns,
|
||||
))
|
||||
)
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import Channel from "../channel.js";
|
||||
import { fetchMeta } from "@/misc/backend-rs.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import { isUserRelated } from "@/misc/is-user-related.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { checkWordMute } from "@/misc/backend-rs.js";
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = "localTimeline";
|
||||
|
@ -60,10 +60,15 @@ export default class extends Channel {
|
|||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (
|
||||
this.userProfile &&
|
||||
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||
this.user?.id !== note.userId &&
|
||||
(await checkWordMute(
|
||||
note,
|
||||
this.userProfile.mutedWords,
|
||||
this.userProfile.mutedPatterns,
|
||||
))
|
||||
)
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import Channel from "../channel.js";
|
||||
import { fetchMeta } from "@/misc/backend-rs.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import { isUserRelated } from "@/misc/is-user-related.js";
|
||||
import { isInstanceMuted } from "@/misc/is-instance-muted.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { checkWordMute } from "@/misc/backend-rs.js";
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = "recommendedTimeline";
|
||||
|
@ -80,10 +80,15 @@ export default class extends Channel {
|
|||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (
|
||||
this.userProfile &&
|
||||
(await getWordHardMute(note, this.user?.id, this.userProfile.mutedWords))
|
||||
this.user?.id !== note.userId &&
|
||||
(await checkWordMute(
|
||||
note,
|
||||
this.userProfile.mutedWords,
|
||||
this.userProfile.mutedPatterns,
|
||||
))
|
||||
)
|
||||
return;
|
||||
|
||||
|
|
|
@ -45,9 +45,8 @@ import { Poll } from "@/models/entities/poll.js";
|
|||
import { createNotification } from "@/services/create-notification.js";
|
||||
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
|
||||
import { checkHitAntenna } from "@/misc/check-hit-antenna.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import { addNoteToAntenna } from "@/services/add-note-to-antenna.js";
|
||||
import { hasOtherRenoteOfThisNote } from "@/misc/backend-rs.js";
|
||||
import { checkWordMute, hasOtherRenoteOfThisNote } from "@/misc/backend-rs.js";
|
||||
import { deliverToRelays, getCachedRelays } from "../relay.js";
|
||||
import type { Channel } from "@/models/entities/channel.js";
|
||||
import { normalizeForSearch } from "@/misc/normalize-for-search.js";
|
||||
|
@ -64,9 +63,13 @@ import { redisClient } from "@/db/redis.js";
|
|||
import { Mutex } from "redis-semaphore";
|
||||
import { langmap } from "@/misc/langmap.js";
|
||||
|
||||
const mutedWordsCache = new Cache<
|
||||
{ userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[]
|
||||
>("mutedWords", 60 * 5);
|
||||
const hardMutesCache = new Cache<
|
||||
{
|
||||
userId: UserProfile["userId"];
|
||||
mutedWords: UserProfile["mutedWords"];
|
||||
mutedPatterns: UserProfile["mutedPatterns"];
|
||||
}[]
|
||||
>("hardMutes", 60 * 5);
|
||||
|
||||
type NotificationType = "reply" | "renote" | "quote" | "mention";
|
||||
|
||||
|
@ -357,18 +360,20 @@ export default async (
|
|||
incNotesCountOfUser(user);
|
||||
|
||||
// Word mute
|
||||
mutedWordsCache
|
||||
hardMutesCache
|
||||
.fetch(null, () =>
|
||||
UserProfiles.find({
|
||||
where: {
|
||||
enableWordMute: true,
|
||||
},
|
||||
select: ["userId", "mutedWords"],
|
||||
select: ["userId", "mutedWords", "mutedPatterns"],
|
||||
}),
|
||||
)
|
||||
.then((us) => {
|
||||
for (const u of us) {
|
||||
getWordHardMute(data, u.userId, u.mutedWords).then((shouldMute) => {
|
||||
if (u.userId === user.id) return;
|
||||
checkWordMute(note, u.mutedWords, u.mutedPatterns).then(
|
||||
(shouldMute: boolean) => {
|
||||
if (shouldMute) {
|
||||
MutedNotes.insert({
|
||||
id: genId(),
|
||||
|
@ -377,7 +382,8 @@ export default async (
|
|||
reason: "word",
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -36,11 +36,15 @@
|
|||
>
|
||||
<FormTextarea v-model="hardMutedWords" class="_formBlock">
|
||||
<span>{{ i18n.ts._wordMute.muteWords }}</span>
|
||||
<template #caption
|
||||
>{{ i18n.ts._wordMute.muteWordsDescription }}<br />{{
|
||||
<template #caption>{{
|
||||
i18n.ts._wordMute.muteWordsDescription
|
||||
}}</template>
|
||||
</FormTextarea>
|
||||
<FormTextarea v-model="hardMutedPatterns" class="_formBlock">
|
||||
<span>{{ i18n.ts._wordMute.mutePatterns }}</span>
|
||||
<template #caption>{{
|
||||
i18n.ts._wordMute.muteWordsDescription2
|
||||
}}</template
|
||||
>
|
||||
}}</template>
|
||||
</FormTextarea>
|
||||
<MkKeyValue
|
||||
v-if="hardWordMutedNotesCount != null"
|
||||
|
@ -90,6 +94,7 @@ const tab = ref("soft");
|
|||
const softMutedWords = ref(render(defaultStore.state.mutedWords));
|
||||
const softMutedLangs = ref(render(defaultStore.state.mutedLangs));
|
||||
const hardMutedWords = ref(render($i!.mutedWords));
|
||||
const hardMutedPatterns = ref($i!.mutedPatterns.join("\n"));
|
||||
const hardWordMutedNotesCount = ref(null);
|
||||
const changed = ref(false);
|
||||
|
||||
|
@ -109,8 +114,12 @@ watch(hardMutedWords, () => {
|
|||
changed.value = true;
|
||||
});
|
||||
|
||||
watch(hardMutedPatterns, () => {
|
||||
changed.value = true;
|
||||
});
|
||||
|
||||
async function save() {
|
||||
const parseMutes = (mutes, tab) => {
|
||||
const parseSoftMutes = (mutes, tab) => {
|
||||
// split into lines, remove empty lines and unnecessary whitespace
|
||||
const lines = mutes
|
||||
.trim()
|
||||
|
@ -151,11 +160,80 @@ async function save() {
|
|||
return lines;
|
||||
};
|
||||
|
||||
let softMutes, softMLangs, hardMutes;
|
||||
const parseMutedWords = (mutes) => {
|
||||
// split into lines, remove empty lines and unnecessary whitespace
|
||||
return mutes
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line !== "")
|
||||
.map((line) => line.split(" "))
|
||||
.filter((line) => line.length > 0);
|
||||
};
|
||||
|
||||
const parseMutedPatterns = (mutes, tab) => {
|
||||
// split into lines, remove empty lines and unnecessary whitespace
|
||||
const lines = mutes
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line !== "");
|
||||
|
||||
// check each line if it is a RegExp or not
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
const regexp = line.match(/^\/(.+)\/(.*)$/);
|
||||
if (regexp) {
|
||||
// check that the RegExp is valid
|
||||
try {
|
||||
softMutes = parseMutes(softMutedWords.value, i18n.ts._wordMute.soft);
|
||||
softMLangs = parseMutes(softMutedLangs.value, i18n.ts._wordMute.lang);
|
||||
hardMutes = parseMutes(hardMutedWords.value, i18n.ts._wordMute.hard);
|
||||
new RegExp(regexp[1], regexp[2]);
|
||||
// note that regex lines will not be split by spaces!
|
||||
} catch (err: any) {
|
||||
// invalid syntax: do not save, do not reset changed flag
|
||||
os.alert({
|
||||
type: "error",
|
||||
title: i18n.ts.regexpError,
|
||||
text:
|
||||
i18n.t("regexpErrorDescription", {
|
||||
tab,
|
||||
line: i + 1,
|
||||
}) +
|
||||
"\n" +
|
||||
err.toString(),
|
||||
});
|
||||
// re-throw error so these invalid settings are not saved
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
// invalid syntax: do not save, do not reset changed flag
|
||||
os.alert({
|
||||
type: "error",
|
||||
title: i18n.ts.regexpError,
|
||||
text: i18n.t("regexpErrorDescription", {
|
||||
tab,
|
||||
line: i + 1,
|
||||
}),
|
||||
});
|
||||
// re-throw error so these invalid settings are not saved
|
||||
throw new Error("Invalid regular expression");
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
};
|
||||
|
||||
let softMutes, softMLangs, hardMWords, hardMPatterns;
|
||||
try {
|
||||
softMutes = parseSoftMutes(
|
||||
softMutedWords.value,
|
||||
i18n.ts._wordMute.soft,
|
||||
);
|
||||
softMLangs = parseMutedWords(softMutedLangs.value);
|
||||
hardMWords = parseMutedWords(hardMutedWords.value);
|
||||
hardMPatterns = parseMutedPatterns(
|
||||
hardMutedPatterns.value,
|
||||
i18n.ts._wordMute.hard,
|
||||
);
|
||||
} catch (err) {
|
||||
// already displayed error message in parseMutes
|
||||
return;
|
||||
|
@ -164,7 +242,8 @@ async function save() {
|
|||
defaultStore.set("mutedWords", softMutes);
|
||||
defaultStore.set("mutedLangs", softMLangs);
|
||||
await os.api("i/update", {
|
||||
mutedWords: hardMutes,
|
||||
mutedWords: hardMWords,
|
||||
mutedPatterns: hardMPatterns,
|
||||
});
|
||||
|
||||
changed.value = false;
|
||||
|
|
|
@ -107,6 +107,7 @@ export type MeDetailed = UserDetailed & {
|
|||
isDeleted: boolean;
|
||||
isExplorable: boolean;
|
||||
mutedWords: string[][];
|
||||
mutedPatterns: string[];
|
||||
mutingNotificationTypes: string[];
|
||||
noCrawle: boolean;
|
||||
preventAiLearning: boolean;
|
||||
|
|
263
pnpm-lock.yaml
263
pnpm-lock.yaml
|
@ -300,9 +300,6 @@ importers:
|
|||
ratelimiter:
|
||||
specifier: 3.4.1
|
||||
version: 3.4.1
|
||||
re2:
|
||||
specifier: 1.20.9
|
||||
version: 1.20.9
|
||||
redis-semaphore:
|
||||
specifier: 5.5.0
|
||||
version: 5.5.0(ioredis@5.3.2)
|
||||
|
@ -3017,26 +3014,6 @@ packages:
|
|||
fastq: 1.15.0
|
||||
dev: true
|
||||
|
||||
/@npmcli/agent@2.2.0:
|
||||
resolution: {integrity: sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==}
|
||||
engines: {node: ^16.14.0 || >=18.0.0}
|
||||
dependencies:
|
||||
agent-base: 7.1.0
|
||||
http-proxy-agent: 7.0.0
|
||||
https-proxy-agent: 7.0.2
|
||||
lru-cache: 10.0.2
|
||||
socks-proxy-agent: 8.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@npmcli/fs@3.1.0:
|
||||
resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
dependencies:
|
||||
semver: 7.5.4
|
||||
dev: false
|
||||
|
||||
/@one-ini/wasm@0.1.1:
|
||||
resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
|
||||
dev: false
|
||||
|
@ -4757,14 +4734,6 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/aggregate-error@3.1.0:
|
||||
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
clean-stack: 2.2.0
|
||||
indent-string: 4.0.0
|
||||
dev: false
|
||||
|
||||
/ajv-keywords@3.5.2(ajv@6.12.6):
|
||||
resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
|
||||
peerDependencies:
|
||||
|
@ -5708,24 +5677,6 @@ packages:
|
|||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/cacache@18.0.0:
|
||||
resolution: {integrity: sha512-I7mVOPl3PUCeRub1U8YoGz2Lqv9WOBpobZ8RyWFXmReuILz+3OAyTa5oH3QPdtKZD7N0Yk00aLfzn0qvp8dZ1w==}
|
||||
engines: {node: ^16.14.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@npmcli/fs': 3.1.0
|
||||
fs-minipass: 3.0.3
|
||||
glob: 10.3.10
|
||||
lru-cache: 10.0.2
|
||||
minipass: 7.0.4
|
||||
minipass-collect: 1.0.2
|
||||
minipass-flush: 1.0.5
|
||||
minipass-pipeline: 1.2.4
|
||||
p-map: 4.0.0
|
||||
ssri: 10.0.5
|
||||
tar: 6.2.0
|
||||
unique-filename: 3.0.0
|
||||
dev: false
|
||||
|
||||
/cache-base@1.0.1:
|
||||
resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -6092,11 +6043,6 @@ packages:
|
|||
escape-string-regexp: 1.0.5
|
||||
dev: true
|
||||
|
||||
/clean-stack@2.2.0:
|
||||
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/cli-cursor@3.1.0:
|
||||
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -7338,14 +7284,6 @@ packages:
|
|||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/encoding@0.1.13:
|
||||
resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
iconv-lite: 0.6.3
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/end-of-stream@1.4.4:
|
||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||
dependencies:
|
||||
|
@ -7371,15 +7309,6 @@ packages:
|
|||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
/env-paths@2.2.1:
|
||||
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/err-code@2.0.3:
|
||||
resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
|
||||
dev: false
|
||||
|
||||
/error-ex@1.3.2:
|
||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||
dependencies:
|
||||
|
@ -8560,10 +8489,6 @@ packages:
|
|||
jest-util: 29.7.0
|
||||
dev: true
|
||||
|
||||
/exponential-backoff@3.1.1:
|
||||
resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
|
||||
dev: false
|
||||
|
||||
/ext-list@2.2.2:
|
||||
resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -9059,13 +8984,6 @@ packages:
|
|||
dependencies:
|
||||
minipass: 3.3.6
|
||||
|
||||
/fs-minipass@3.0.3:
|
||||
resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
dependencies:
|
||||
minipass: 7.0.4
|
||||
dev: false
|
||||
|
||||
/fs-mkdirp-stream@1.0.0:
|
||||
resolution: {integrity: sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
@ -9769,16 +9687,6 @@ packages:
|
|||
toidentifier: 1.0.1
|
||||
dev: false
|
||||
|
||||
/http-proxy-agent@7.0.0:
|
||||
resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==}
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
agent-base: 7.1.0
|
||||
debug: 4.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/http2-wrapper@1.0.3:
|
||||
resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
|
||||
engines: {node: '>=10.19.0'}
|
||||
|
@ -9890,10 +9798,12 @@ packages:
|
|||
/imurmurhash@0.1.4:
|
||||
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
||||
engines: {node: '>=0.8.19'}
|
||||
dev: true
|
||||
|
||||
/indent-string@4.0.0:
|
||||
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/indent-string@5.0.0:
|
||||
resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==}
|
||||
|
@ -9930,11 +9840,6 @@ packages:
|
|||
resolution: {integrity: sha512-/nPtyeX9xPUvxZf+r0518B7uqNKlP+LqNJqSiXFEaa2T71rWIwTVXGH7hB9xO/EVdwa5/pWlFCPwShOW81XIxQ==}
|
||||
dev: true
|
||||
|
||||
/install-artifact-from-github@1.3.5:
|
||||
resolution: {integrity: sha512-gZHC7f/cJgXz7MXlHFBxPVMsvIbev1OQN1uKQYKVJDydGNm9oYf9JstbU4Atnh/eSvk41WtEovoRm+8IF686xg==}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/internal-slot@1.0.6:
|
||||
resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -10238,10 +10143,6 @@ packages:
|
|||
ip-regex: 4.3.0
|
||||
dev: false
|
||||
|
||||
/is-lambda@1.0.1:
|
||||
resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
|
||||
dev: false
|
||||
|
||||
/is-natural-number@4.0.1:
|
||||
resolution: {integrity: sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==}
|
||||
dev: false
|
||||
|
@ -10436,11 +10337,6 @@ packages:
|
|||
/isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
|
||||
/isexe@3.1.1:
|
||||
resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
|
||||
engines: {node: '>=16'}
|
||||
dev: false
|
||||
|
||||
/isobject@2.1.0:
|
||||
resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -11815,25 +11711,6 @@ packages:
|
|||
/make-error@1.3.6:
|
||||
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
||||
|
||||
/make-fetch-happen@13.0.0:
|
||||
resolution: {integrity: sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==}
|
||||
engines: {node: ^16.14.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@npmcli/agent': 2.2.0
|
||||
cacache: 18.0.0
|
||||
http-cache-semantics: 4.1.1
|
||||
is-lambda: 1.0.1
|
||||
minipass: 7.0.4
|
||||
minipass-fetch: 3.0.4
|
||||
minipass-flush: 1.0.5
|
||||
minipass-pipeline: 1.2.4
|
||||
negotiator: 0.6.3
|
||||
promise-retry: 2.0.1
|
||||
ssri: 10.0.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/make-iterator@1.0.1:
|
||||
resolution: {integrity: sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -12103,45 +11980,6 @@ packages:
|
|||
/minimist@1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
|
||||
/minipass-collect@1.0.2:
|
||||
resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
|
||||
engines: {node: '>= 8'}
|
||||
dependencies:
|
||||
minipass: 3.3.6
|
||||
dev: false
|
||||
|
||||
/minipass-fetch@3.0.4:
|
||||
resolution: {integrity: sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
dependencies:
|
||||
minipass: 7.0.4
|
||||
minipass-sized: 1.0.3
|
||||
minizlib: 2.1.2
|
||||
optionalDependencies:
|
||||
encoding: 0.1.13
|
||||
dev: false
|
||||
|
||||
/minipass-flush@1.0.5:
|
||||
resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
|
||||
engines: {node: '>= 8'}
|
||||
dependencies:
|
||||
minipass: 3.3.6
|
||||
dev: false
|
||||
|
||||
/minipass-pipeline@1.2.4:
|
||||
resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
minipass: 3.3.6
|
||||
dev: false
|
||||
|
||||
/minipass-sized@1.0.3:
|
||||
resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
minipass: 3.3.6
|
||||
dev: false
|
||||
|
||||
/minipass@3.3.6:
|
||||
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -12264,7 +12102,9 @@ packages:
|
|||
|
||||
/nan@2.18.0:
|
||||
resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==}
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/nanoid@3.3.7:
|
||||
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
|
||||
|
@ -12377,25 +12217,6 @@ packages:
|
|||
resolution: {integrity: sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==}
|
||||
hasBin: true
|
||||
|
||||
/node-gyp@10.0.1:
|
||||
resolution: {integrity: sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==}
|
||||
engines: {node: ^16.14.0 || >=18.0.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
env-paths: 2.2.1
|
||||
exponential-backoff: 3.1.1
|
||||
glob: 10.3.10
|
||||
graceful-fs: 4.2.11
|
||||
make-fetch-happen: 13.0.0
|
||||
nopt: 7.2.0
|
||||
proc-log: 3.0.0
|
||||
semver: 7.5.4
|
||||
tar: 6.2.0
|
||||
which: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/node-int64@0.4.0:
|
||||
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
|
||||
dev: true
|
||||
|
@ -12795,13 +12616,6 @@ packages:
|
|||
p-limit: 3.1.0
|
||||
dev: true
|
||||
|
||||
/p-map@4.0.0:
|
||||
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
aggregate-error: 3.1.0
|
||||
dev: false
|
||||
|
||||
/p-map@6.0.0:
|
||||
resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==}
|
||||
engines: {node: '>=16'}
|
||||
|
@ -13655,11 +13469,6 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/proc-log@3.0.0:
|
||||
resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
dev: false
|
||||
|
||||
/process-nextick-args@2.0.1:
|
||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||
|
||||
|
@ -13667,14 +13476,6 @@ packages:
|
|||
resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==}
|
||||
dev: false
|
||||
|
||||
/promise-retry@2.0.1:
|
||||
resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
err-code: 2.0.3
|
||||
retry: 0.12.0
|
||||
dev: false
|
||||
|
||||
/promise@7.3.1:
|
||||
resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==}
|
||||
dependencies:
|
||||
|
@ -13922,17 +13723,6 @@ packages:
|
|||
setimmediate: 1.0.5
|
||||
dev: false
|
||||
|
||||
/re2@1.20.9:
|
||||
resolution: {integrity: sha512-ZYcPTFr5ha2xq3WQjBDTF9CWPSDK1z28MLh5UFRxc//7X8BNQ3A7yR7ITnP0jO346661ertdKVFqw1qoL3FMEQ==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
install-artifact-from-github: 1.3.5
|
||||
nan: 2.18.0
|
||||
node-gyp: 10.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/react-is@18.2.0:
|
||||
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||
dev: true
|
||||
|
@ -14316,11 +14106,6 @@ packages:
|
|||
engines: {node: '>=0.12'}
|
||||
dev: false
|
||||
|
||||
/retry@0.12.0:
|
||||
resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
|
||||
engines: {node: '>= 4'}
|
||||
dev: false
|
||||
|
||||
/reusify@1.0.4:
|
||||
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
|
@ -14730,17 +14515,6 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/socks-proxy-agent@8.0.2:
|
||||
resolution: {integrity: sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==}
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
agent-base: 7.1.0
|
||||
debug: 4.3.4
|
||||
socks: 2.7.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/socks@2.7.1:
|
||||
resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==}
|
||||
engines: {node: '>= 10.13.0', npm: '>= 3.0.0'}
|
||||
|
@ -14882,13 +14656,6 @@ packages:
|
|||
tweetnacl: 0.14.5
|
||||
dev: false
|
||||
|
||||
/ssri@10.0.5:
|
||||
resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
dependencies:
|
||||
minipass: 7.0.4
|
||||
dev: false
|
||||
|
||||
/stack-trace@0.0.10:
|
||||
resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==}
|
||||
dev: false
|
||||
|
@ -16042,20 +15809,6 @@ packages:
|
|||
resolution: {integrity: sha512-mZdDpf3vBV5Efh29kMw5tXoup/buMgxLzOt/XKFKcVmi+15ManNQWr6HfZ2aiZTYlYixbdNJ0KFmIZIv52tHSQ==}
|
||||
dev: false
|
||||
|
||||
/unique-filename@3.0.0:
|
||||
resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
dependencies:
|
||||
unique-slug: 4.0.0
|
||||
dev: false
|
||||
|
||||
/unique-slug@4.0.0:
|
||||
resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
dependencies:
|
||||
imurmurhash: 0.1.4
|
||||
dev: false
|
||||
|
||||
/unique-stream@2.3.1:
|
||||
resolution: {integrity: sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==}
|
||||
dependencies:
|
||||
|
@ -16578,14 +16331,6 @@ packages:
|
|||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
/which@4.0.0:
|
||||
resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
|
||||
engines: {node: ^16.13.0 || >=18.0.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
isexe: 3.1.1
|
||||
dev: false
|
||||
|
||||
/wide-align@1.1.5:
|
||||
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
|
||||
requiresBuild: true
|
||||
|
|
Loading…
Reference in a new issue