Merge branch 'develop' into emoji-re

This commit is contained in:
tamaina 2023-01-25 14:22:26 +00:00
commit 605b0f27e4
55 changed files with 824 additions and 757 deletions

View file

@ -9,6 +9,30 @@
You should also include the user name that made the change. You should also include the user name that made the change.
--> -->
## 13.2.2 (2023/01/25)
### Improvements
- サーバーのパフォーマンスを改善
### Bugfixes
- サインイン時に誤ったレートリミットがかかることがある問題を修正
- MFMのposition、rotate、scaleで小数が使えない問題を修正
## 13.2.1 (2023/01/24)
### Improvements
- デザインの調整
- サーバーのパフォーマンスを改善
## 13.2.0 (2023/01/23)
### Improvements
- onlyServer / onlyQueue オプションを復活
- 他人の実績閲覧時は獲得条件を表示しないように
- アニメーション減らすオプション有効時はリアクションのアニメーションを無効に
- カスタム絵文字一覧のパフォーマンスを改善
### Bugfixes
- Aiscript: button is not defined
## 13.1.7 (2023/01/22) ## 13.1.7 (2023/01/22)
### Improvements ### Improvements

View file

@ -20,7 +20,7 @@ gulp.task('copy:frontend:fonts', () =>
); );
gulp.task('copy:frontend:tabler-icons', () => gulp.task('copy:frontend:tabler-icons', () =>
gulp.src('./packages/frontend/node_modules/@tabler/icons/iconfont/**/*').pipe(gulp.dest('./built/_frontend_dist_/tabler-icons/')) gulp.src('./packages/frontend/node_modules/@tabler/icons-webfont/**/*').pipe(gulp.dest('./built/_frontend_dist_/tabler-icons/'))
); );
gulp.task('copy:frontend:locales', cb => { gulp.task('copy:frontend:locales', cb => {

View file

@ -1104,9 +1104,12 @@ _achievements:
title: "I Love Misskey" title: "I Love Misskey"
description: "Sende \"I ❤ #Misskey\"" description: "Sende \"I ❤ #Misskey\""
flavor: "Danke, dass du Misskey verwendest! - vom Entwicklerteam" flavor: "Danke, dass du Misskey verwendest! - vom Entwicklerteam"
_foundTreasure:
title: "Schatzsuche"
description: "Du hast einen verborgenen Schatz gefunden"
_client30min: _client30min:
title: "Kleine Pause" title: "Kurze Pause"
description: "Seit dem Öffnen deines Clients sind 30 Minuten vergangen" description: "Habe Misskey für 30 Minuten geöffnet"
_noteDeletedWithin1min: _noteDeletedWithin1min:
title: "Ups" title: "Ups"
description: "Lösche eine Notiz innerhalb von 1 Minute nachdem sie gesendet wurde" description: "Lösche eine Notiz innerhalb von 1 Minute nachdem sie gesendet wurde"
@ -1124,6 +1127,9 @@ _achievements:
_htl20npm: _htl20npm:
title: "Fließende Chronik" title: "Fließende Chronik"
description: "Deine Startseitenchronik erreicht eine Geschwindigkeit von 20 npm (Notizen pro Minute)" description: "Deine Startseitenchronik erreicht eine Geschwindigkeit von 20 npm (Notizen pro Minute)"
_viewInstanceChart:
title: "Analyst"
description: "Schau dir die Messwerte der Instanz an"
_outputHelloWorldOnScratchpad: _outputHelloWorldOnScratchpad:
title: "Hallo Welt!" title: "Hallo Welt!"
description: "Gib \"hello world\" in der Testumgebung aus" description: "Gib \"hello world\" in der Testumgebung aus"

View file

@ -945,7 +945,7 @@ _achievements:
_notes1: _notes1:
title: "just setting up my msky" title: "just setting up my msky"
description: "Post your first note" description: "Post your first note"
flavor: "Have a good Misskey life!" flavor: "Have a good time with Misskey!"
_notes10: _notes10:
title: "Some notes" title: "Some notes"
description: "Post 10 notes" description: "Post 10 notes"
@ -1104,6 +1104,9 @@ _achievements:
title: "I Love Misskey" title: "I Love Misskey"
description: "Post \"I ❤ #Misskey\"" description: "Post \"I ❤ #Misskey\""
flavor: "Misskey's development team greatly appreciates your support!" flavor: "Misskey's development team greatly appreciates your support!"
_foundTreasure:
title: "Treasure Hunt"
description: "You've found the hidden treasure"
_client30min: _client30min:
title: "Short break" title: "Short break"
description: "Spend 30 minutes on Misskey" description: "Spend 30 minutes on Misskey"
@ -1124,6 +1127,9 @@ _achievements:
_htl20npm: _htl20npm:
title: "Flowing Timeline" title: "Flowing Timeline"
description: "Have the speed of your home timeline exceed 20 npm (notes per minute)" description: "Have the speed of your home timeline exceed 20 npm (notes per minute)"
_viewInstanceChart:
title: "Analyst"
description: "View your instance's charts"
_outputHelloWorldOnScratchpad: _outputHelloWorldOnScratchpad:
title: "Hello, world!" title: "Hello, world!"
description: "Output \"hello world\" in the Scratchpad" description: "Output \"hello world\" in the Scratchpad"

View file

@ -1059,8 +1059,8 @@ _achievements:
description: "Aggiungi le orecchie da gatto al tuo profilo" description: "Aggiungi le orecchie da gatto al tuo profilo"
flavor: "Ti chiamerò..." flavor: "Ti chiamerò..."
_following1: _following1:
title: "Hai seguito il tuo primo profilo" title: "Il mio primo Follow"
description: "Il tuo primo profilo Follower" description: "Hai seguito il tuo primo profilo"
_following10: _following10:
title: "Segui, segui!" title: "Segui, segui!"
description: "Hai seguito 10 profili" description: "Hai seguito 10 profili"
@ -1074,17 +1074,17 @@ _achievements:
title: "Sovraccarico di amici" title: "Sovraccarico di amici"
description: "Hai seguito 300 profili" description: "Hai seguito 300 profili"
_followers1: _followers1:
title: "Primo Follower" title: "Il primo profilo tuo Follower"
description: "Hai ottenuto un Follower" description: "Hai ottenuto il tuo primo Follower"
_followers10: _followers10:
title: "Follow me!" title: "Follow me!"
description: "Hai ottenuto 10 Follower" description: "Hai ottenuto 10 profili Follower"
_followers50: _followers50:
title: "Follower a frotte" title: "Follower a frotte"
description: "Hai ottenuto 50 Follower" description: "Hai ottenuto 50 Follower"
_followers100: _followers100:
title: "Popolare" title: "Popolare"
description: "Hai ottenuto 100 Follower" description: "Hai ottenuto 100 profili Follower"
_followers300: _followers300:
title: "Mettetevi in fila" title: "Mettetevi in fila"
description: "Hai ottenuto 300 Follower" description: "Hai ottenuto 300 Follower"
@ -1093,7 +1093,7 @@ _achievements:
description: "Hai ottenuto 500 Follower" description: "Hai ottenuto 500 Follower"
_followers1000: _followers1000:
title: "Influenzer" title: "Influenzer"
description: "Hai superato i 1.000 Follower" description: "Hai superato i 1.000 profili Follower"
_collectAchievements30: _collectAchievements30:
title: "Collezionista di successi" title: "Collezionista di successi"
description: "Hai raggiunto 30 obiettivi" description: "Hai raggiunto 30 obiettivi"
@ -1104,9 +1104,12 @@ _achievements:
title: "I LOVE Misskey" title: "I LOVE Misskey"
description: "Pubblica «I ♥ #Misskey»" description: "Pubblica «I ♥ #Misskey»"
flavor: "Grazie per aver utilizzato Misskey! Dal team di sviluppo" flavor: "Grazie per aver utilizzato Misskey! Dal team di sviluppo"
_foundTreasure:
title: "Caccia al tesoro"
description: "Hai trovato un tesoro nascosto"
_client30min: _client30min:
title: "Piccola pausa" title: "Piccola pausa"
description: "Hai passato più di 30 minuti di fila su Misskey" description: "Hai passato più di 30 minuti su Misskey"
_noteDeletedWithin1min: _noteDeletedWithin1min:
title: "Ooops!" title: "Ooops!"
description: "Hai eliminato una nota entro un minuto dalla sua pubblicazione" description: "Hai eliminato una nota entro un minuto dalla sua pubblicazione"
@ -1124,6 +1127,9 @@ _achievements:
_htl20npm: _htl20npm:
title: "Timeline scorrevole" title: "Timeline scorrevole"
description: "La tua Timeline personale ha superato la velocità di 20 Note orarie (Note al minuto)" description: "La tua Timeline personale ha superato la velocità di 20 Note orarie (Note al minuto)"
_viewInstanceChart:
title: "Analista"
description: "Visualizza i grafici dell'istanza"
_outputHelloWorldOnScratchpad: _outputHelloWorldOnScratchpad:
title: "Hello, world!" title: "Hello, world!"
description: "Hai scritto «Hello world» nel blocco appunti" description: "Hai scritto «Hello world» nel blocco appunti"
@ -1501,8 +1507,8 @@ _sfx:
channel: "Notifiche di canale" channel: "Notifiche di canale"
_ago: _ago:
future: "Futuro" future: "Futuro"
justNow: "Ora" justNow: "Adesso"
secondsAgo: "{n}s fa" secondsAgo: "{n} sec fa"
minutesAgo: "{n} min fa" minutesAgo: "{n} min fa"
hoursAgo: "{n} ore fa" hoursAgo: "{n} ore fa"
daysAgo: "{n} gg fa" daysAgo: "{n} gg fa"

View file

@ -943,8 +943,8 @@ _achievements:
earnedAt: "달성 일시" earnedAt: "달성 일시"
_types: _types:
_notes1: _notes1:
title: "미스키 설정하고 있었는데요" title: "미스키 시작했는데요"
description: "첫 노트를 포스트했습니다" description: "첫 노트를 작성했습니다"
flavor: "Misskey에 오신 것을 환영합니다!" flavor: "Misskey에 오신 것을 환영합니다!"
_notes10: _notes10:
title: "노트 조금" title: "노트 조금"
@ -962,7 +962,7 @@ _achievements:
title: "노트가 어디서 솟아?" title: "노트가 어디서 솟아?"
description: "5,000개의 노트를 작성했습니다" description: "5,000개의 노트를 작성했습니다"
_notes10000: _notes10000:
title: "슈퍼-노트" title: "슈퍼 노트"
description: "10,000개의 노트를 작성했습니다" description: "10,000개의 노트를 작성했습니다"
_notes20000: _notes20000:
title: "노트 더 없어?" title: "노트 더 없어?"
@ -989,7 +989,7 @@ _achievements:
title: "노트 우주" title: "노트 우주"
description: "90,000개의 노트를 작성했습니다" description: "90,000개의 노트를 작성했습니다"
_notes100000: _notes100000:
title: "네 모든 노트는 내 거야" title: "ALL YOUR NOTE ARE BELONG TO US"
description: "100,000개의 노트를 작성했습니다" description: "100,000개의 노트를 작성했습니다"
flavor: "이만큼 쓸 일도 없겠지만... 다른 할 일이 있진 않으신가요?" flavor: "이만큼 쓸 일도 없겠지만... 다른 할 일이 있진 않으신가요?"
_login3: _login3:
@ -1012,7 +1012,7 @@ _achievements:
_login100: _login100:
title: "미스키스트 III" title: "미스키스트 III"
description: "총 100일간 로그인했습니다" description: "총 100일간 로그인했습니다"
flavor: "그 유저, 미스키스트를 위하여" flavor: "그 유저, 미스키스트이다"
_login200: _login200:
title: "단골 I" title: "단골 I"
description: "총 200일간 로그인했습니다" description: "총 200일간 로그인했습니다"
@ -1025,7 +1025,7 @@ _achievements:
_login500: _login500:
title: "베테랑 I" title: "베테랑 I"
description: "총 500일간 로그인했습니다" description: "총 500일간 로그인했습니다"
flavor: "여러분, 저 이 노트들 좋아해요" flavor: "제군, 나는 노트가 좋다"
_login600: _login600:
title: "베테랑 II" title: "베테랑 II"
description: "총 600일간 로그인했습니다" description: "총 600일간 로그인했습니다"
@ -1041,13 +1041,16 @@ _achievements:
_login1000: _login1000:
title: "노트 마스터 III" title: "노트 마스터 III"
description: "총 1,000일간 로그인했습니다" description: "총 1,000일간 로그인했습니다"
flavor: "미스키를 사용해 주셔서 감사합니다!" flavor: "Misskey를 사용해 주셔서 감사합니다!"
_noteClipped1: _noteClipped1:
title: "클립할 수밖에 없었어" title: "클립할 수밖에 없었어"
description: "처음으로 노트를 클립했습니다" description: "처음으로 노트를 클립했습니다"
_noteFavorited1: _noteFavorited1:
title: "별을 바라보는 자" title: "별을 바라보는 자"
description: "처음으로 노트를 즐겨찾기했습니다" description: "처음으로 노트를 즐겨찾기했습니다"
_myNoteFavorited1:
title: "별을 원하는 자"
description: "다른 사람이 당신의 노트를 즐겨찾기했습니다"
_profileFilled: _profileFilled:
title: "준비 완료" title: "준비 완료"
description: "프로필 설정을 완료했습니다" description: "프로필 설정을 완료했습니다"
@ -1074,7 +1077,7 @@ _achievements:
title: "첫 팔로워" title: "첫 팔로워"
description: "사용자가 처음으로 팔로잉했습니다" description: "사용자가 처음으로 팔로잉했습니다"
_followers10: _followers10:
title: "날 따라와!" title: "팔로우 미!"
description: "10명의 사용자가 팔로우했습니다" description: "10명의 사용자가 팔로우했습니다"
_followers50: _followers50:
title: "이곳저곳" title: "이곳저곳"
@ -1096,11 +1099,14 @@ _achievements:
description: "30개의 도전과제를 획득했습니다" description: "30개의 도전과제를 획득했습니다"
_viewAchievements3min: _viewAchievements3min:
title: "저 도전과제 좋아해요" title: "저 도전과제 좋아해요"
description: "도전과제 목록을 3분 이상 보세요" description: "도전 과제 목록을 3분 이상 쳐다봤습니다"
_iLoveMisskey: _iLoveMisskey:
title: "I Love Misskey" title: "I Love Misskey"
description: "\"I ❤ #Misskey\"를 포스트했습니다" description: "\"I ❤ #Misskey\"를 포스트했습니다"
flavor: "Misskey를 이용해주셔서 감사합니다! - 개발팀 일동" flavor: "Misskey를 이용해주셔서 감사합니다! - 개발팀 일동"
_foundTreasure:
title: "보물찾기"
description: "숨겨진 보물을 발견했습니다"
_client30min: _client30min:
title: "잠깐 쉬어" title: "잠깐 쉬어"
description: "클라이언트를 시작하고 30분이 경과하였습니다" description: "클라이언트를 시작하고 30분이 경과하였습니다"
@ -1113,7 +1119,7 @@ _achievements:
flavor: "잠 좀 자세요. 걱정돼요." flavor: "잠 좀 자세요. 걱정돼요."
_postedAt0min0sec: _postedAt0min0sec:
title: "정각" title: "정각"
description: "1초도 어긋나지 않은 정각에 노트를 포스트했습니다" description: "0분 0초 정각에 노트를 작성했습니다"
flavor: "째깍 째깍 째깍 땡!" flavor: "째깍 째깍 째깍 땡!"
_selfQuote: _selfQuote:
title: "혼잣말" title: "혼잣말"
@ -1121,21 +1127,24 @@ _achievements:
_htl20npm: _htl20npm:
title: "타임라인 폭주 중" title: "타임라인 폭주 중"
description: "1분 사이에 홈 타임라인에 노트가 20개 넘게 생성되었습니다" description: "1분 사이에 홈 타임라인에 노트가 20개 넘게 생성되었습니다"
_viewInstanceChart:
title: "애널리스트"
description: "인스턴스의 차트를 열었습니다"
_outputHelloWorldOnScratchpad: _outputHelloWorldOnScratchpad:
title: "Hello, world!" title: "Hello, world!"
description: "스크래치패드에서 hello world를 출력하세요" description: "스크래치패드에서 hello world를 출력했습니다"
_open3windows: _open3windows:
title: "멀티 윈도우" title: "멀티 윈도우"
description: "3개 이상의 창을 여세요" description: "3개 이상의 창을 열었습니다"
_driveFolderCircularReference: _driveFolderCircularReference:
title: "순환 참조" title: "순환 참조"
description: "드라이브 폴더를 자신을 가리키도록 만드려 시도했습니다" description: "드라이브 폴더를 자신을 가리키도록 만드려 시도했습니다"
_reactWithoutRead: _reactWithoutRead:
title: "읽고 답하긴 하시는 건가요?" title: "읽고 답하긴 하시는 건가요?"
description: "100자가 넘는 포스트에 3초 안에 포스트했습니다" description: "100자가 넘는 노트가 작성되고 3초 안에 반응했습니다"
_clickedClickHere: _clickedClickHere:
title: "여길 눌러보세요" title: "여길 눌러보세요"
description: "이 곳을 눌러봤습니다" description: "여길을 눌러봤습니다"
_justPlainLucky: _justPlainLucky:
title: "그냥 운이 좋았어" title: "그냥 운이 좋았어"
description: "매 10초마다 0.01%의 확률로 달성됩니다" description: "매 10초마다 0.01%의 확률로 달성됩니다"
@ -1143,25 +1152,25 @@ _achievements:
title: "신 콤플렉스" title: "신 콤플렉스"
description: "이름을 syuilo로 설정했습니다" description: "이름을 syuilo로 설정했습니다"
_passedSinceAccountCreated1: _passedSinceAccountCreated1:
title: "1년" title: "1년"
description: "계정을 생성하고 1년이 지났습니다" description: "계정을 생성하고 1년이 지났습니다"
_passedSinceAccountCreated2: _passedSinceAccountCreated2:
title: "2년" title: "2년"
description: "계정을 생성하고 2년이 지났습니다" description: "계정을 생성하고 2년이 지났습니다"
_passedSinceAccountCreated3: _passedSinceAccountCreated3:
title: "3년" title: "3년"
description: "계정을 생성하고 3년이 지났습니다" description: "계정을 생성하고 3년이 지났습니다"
_loggedInOnBirthday: _loggedInOnBirthday:
title: "생일 축하합니다!" title: "생일 축하합니다!"
description: "설정한 생일에 로그인했습니다" description: "생일에 로그인했습니다"
_loggedInOnNewYearsDay: _loggedInOnNewYearsDay:
title: "새해 복 많이 받으세요" title: "새해 복 많이 받으세요"
description: "새해 첫 날에 로그인했습니다" description: "새해 첫 날에 로그인했습니다"
flavor: "올해에도 저희 인스턴스에 관심을 가져 주셔서 감사합니다" flavor: "올해에도 저희 인스턴스에 관심을 가져 주셔서 감사합니다"
_cookieClicked: _cookieClicked:
title: "쿠키 클리커 게임" title: "쿠키를 클릭하는 게임"
description: "쿠키를 클릭했습니다" description: "쿠키를 클릭했습니다"
flavor: "뭔가 문제가 있나요?" flavor: "소프트웨어 착각하지 않으셨나요?"
_brainDiver: _brainDiver:
title: "Brain Diver" title: "Brain Diver"
description: "Brain Diver로의 링크를 첨부했습니다" description: "Brain Diver로의 링크를 첨부했습니다"

View file

@ -1004,7 +1004,7 @@ _achievements:
_login100: _login100:
title: "Мискиец Ⅲ" title: "Мискиец Ⅲ"
description: "100 дней на сайте" description: "100 дней на сайте"
flavor: "Жестокий Misskist " flavor: "Жестокий мискиец"
_login200: _login200:
title: "Завсегдатай " title: "Завсегдатай "
description: "200 дней на сайте" description: "200 дней на сайте"

View file

@ -942,14 +942,51 @@ achievements: "ความสำเร็จ"
_achievements: _achievements:
earnedAt: "ได้รับเมื่อ" earnedAt: "ได้รับเมื่อ"
_types: _types:
_notes1:
title: "เพียงแค่ตั้งค่า msky ของฉัน"
_followers100: _followers100:
title: "บุคคลที่เป็นที่นิยม" title: "บุคคลที่เป็นที่นิยม"
_followers500: _followers500:
title: "เสาสัญญาณ" title: "เสาสัญญาณ"
_followers1000:
title: "ผู้ทรงอิทธิพล"
_iLoveMisskey: _iLoveMisskey:
title: "ฉันรัก Misskey" title: "ฉันรัก Misskey"
description: "โพสต์ \"I ❤ #Misskey\""
_foundTreasure:
title: "ล่าสมบัติ"
description: "คุณพบสมบัติที่ซ่อนอยู่"
_client30min:
title: "พักผ่อนสักหน่อย"
_noteDeletedWithin1min:
title: "ไม่เป็นไร"
_postedAtLateNight:
title: "กลางคืน"
_viewInstanceChart:
title: "วิเคราะห์"
description: "ดูแผนภูมิอินสแตนซ์ของคุณ"
_driveFolderCircularReference: _driveFolderCircularReference:
title: "อ้างอิงวงจร" title: "อ้างอิงวงจร"
_clickedClickHere:
title: "คลิ๊กที่นี่"
description: "คุณได้คลิกที่นี่"
_passedSinceAccountCreated1:
title: "ครบรอบหนึ่งปี"
_passedSinceAccountCreated2:
title: "ครบรอบสองปี"
_passedSinceAccountCreated3:
title: "ครบรอบสามปี"
_loggedInOnBirthday:
title: "สุขสันต์วันเกิด"
description: "เข้าสู่ระบบในวันเกิดของคุณ"
_loggedInOnNewYearsDay:
title: "สวัสดีปีใหม่!"
description: "เข้าสู่ระบบในวันแรกของปี"
_cookieClicked:
description: "คลิกคุกกี้"
_brainDiver:
title: "Brain Diver"
flavor: "Misskey-Misskey La-Tu-Ma"
_role: _role:
new: "บทบาทใหม่" new: "บทบาทใหม่"
edit: "แก้ไขบทบาท" edit: "แก้ไขบทบาท"

View file

@ -901,6 +901,7 @@ show: "Відображення"
color: "Колір" color: "Колір"
achievements: "Досягнення" achievements: "Досягнення"
_achievements: _achievements:
earnedAt: "Відкрито"
_types: _types:
_notes1: _notes1:
title: "налаштовую свій msky" title: "налаштовую свій msky"
@ -908,6 +909,124 @@ _achievements:
flavor: "Приємного часу з Misskey!" flavor: "Приємного часу з Misskey!"
_notes10: _notes10:
title: "Декілька нотаток" title: "Декілька нотаток"
description: "10 нотаток відправлено"
_notes100:
title: "Купа нотаток"
description: "100 нотаток відправлено"
_notes500:
title: "Все в нотатках"
description: "500 нотаток відправлено"
_notes1000:
title: "Гора нотаток"
description: "1 000 нотаток відправлено"
_notes5000:
title: "Переповнюючі нотатки"
description: "5 000 нотаток відправлено"
_notes10000:
title: "Супернотатка"
description: "10 000 нотаток відправлено"
_notes20000:
title: "Треба Більше Нотаток"
description: "20 000 нотаток відправлено"
_notes30000:
title: "Нотатки нотатки нотатки"
description: "30 000 нотаток відправлено"
_notes40000:
title: "Фабрика нотаток"
description: "40 000 нотаток відправлено"
_notes50000:
title: "Планета нотаток"
description: "50 000 нотаток відправлено"
_notes60000:
title: "Нотатковий квазар"
description: "60 000 нотаток відправлено"
_notes70000:
title: "Чорна нотаткова діра"
description: "70 000 нотаток відправлено"
_notes80000:
title: "Галактика нотаток"
description: "80 000 нотаток відправлено"
_notes90000:
title: "Нотатковерс"
description: "90 000 нотаток відправлено"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "100 000 нотаток відправлено"
flavor: "Так багато потрібно сказати?"
_login3:
title: "Новачок I"
description: "3 дні користування загально"
_login7:
title: "Новачок II"
description: "7 днів користування загально"
_login15:
title: "Новачок III"
description: "15 днів користування загально"
_login30:
title: "Міскієць I"
description: "30 днів користування загально"
_login60:
title: "Міскієць II"
description: "60 днів користування загально"
_login100:
title: "Міскієць III"
description: "100 днів користування загально"
_login200:
title: "Завсідник I"
description: "200 днів користування загально"
_login300:
title: "Завсідник II"
description: "300 днів користування загально"
_login400:
title: "Завсідник III"
description: "400 днів користування загально"
_login500:
title: "Ветеран I"
description: "500 днів користування загально"
_login600:
title: "Ветеран II"
description: "600 днів користування загально"
_login700:
title: "Ветеран III"
description: "700 днів користування загально"
_login800:
description: "800 днів користування загально"
_login900:
description: "900 днів користування загально"
_login1000:
description: "1000 днів користування загально"
flavor: "Дякуємо, що користуєтеся Misskey!"
_following50:
description: "Кількість підписок сягнула 50"
_following100:
title: "100 друзів"
description: "Кількість підписок сягнула 100"
_following300:
title: "Надлишок друзів"
description: "Кількість підписок сягнула 300"
_followers1:
title: "Перший підписник"
description: "З'явився перший підписник"
_followers10:
title: "Follow me!"
description: "Кількість підписників досягла 10"
_followers50:
description: "Кількість підписників досягла 50"
_followers100:
description: "Кількість підписників досягла 100"
_followers300:
description: "Кількість підписників досягла 300"
_followers500:
description: "Кількість підписників досягла 500"
_followers1000:
title: "Інфлюенсер"
description: "Кількість підписників досягла 1000"
_passedSinceAccountCreated3:
description: "Минуло 3 роки з моменту створення акаунта"
_loggedInOnBirthday:
title: "З Днем народження!"
_brainDiver:
flavor: "Misskey-Misskey La-Tu-Ma"
_role: _role:
priority: "Пріоритет" priority: "Пріоритет"
_priority: _priority:

View file

@ -1007,6 +1007,9 @@ _achievements:
flavor: "感谢您使用Misskey" flavor: "感谢您使用Misskey"
_noteFavorited1: _noteFavorited1:
title: "观星者" title: "观星者"
_profileFilled:
title: "整装待发"
description: "设置了个人资料"
_markedAsCat: _markedAsCat:
title: "我是猫" title: "我是猫"
description: "将账户设定为一只猫" description: "将账户设定为一只猫"

View file

@ -950,13 +950,13 @@ _achievements:
title: "若干貼文" title: "若干貼文"
description: "發表了10則貼文" description: "發表了10則貼文"
_notes100: _notes100:
title: "許多貼文" title: "許多貼文"
description: "發表了100則貼文" description: "發表了100則貼文"
_notes500: _notes500:
title: "滿滿的貼文" title: "滿滿的貼文"
description: "發表了500則貼文" description: "發表了500則貼文"
_notes1000: _notes1000:
title: "堆貼文" title: "積如山的貼文"
description: "發表了1000則貼文" description: "發表了1000則貼文"
_notes5000: _notes5000:
title: "滔滔不絕的貼文" title: "滔滔不絕的貼文"
@ -1104,6 +1104,9 @@ _achievements:
title: "I Love Misskey" title: "I Love Misskey"
description: "發布「I ❤ #Misskey」" description: "發布「I ❤ #Misskey」"
flavor: "感謝您使用Misskey by 開發團隊" flavor: "感謝您使用Misskey by 開發團隊"
_foundTreasure:
title: "尋寶"
description: "發現了隱藏的寶藏"
_client30min: _client30min:
title: "休息一下" title: "休息一下"
description: "用戶端啟動已超過30分鐘" description: "用戶端啟動已超過30分鐘"
@ -1124,6 +1127,9 @@ _achievements:
_htl20npm: _htl20npm:
title: "流動的TL" title: "流動的TL"
description: "在首頁時間軸的流速超過20npm" description: "在首頁時間軸的流速超過20npm"
_viewInstanceChart:
title: "分析師"
description: "顯示了實例的圖表"
_outputHelloWorldOnScratchpad: _outputHelloWorldOnScratchpad:
title: "Hello world!" title: "Hello world!"
description: "在暫存記憶體輸出了 hello world" description: "在暫存記憶體輸出了 hello world"

View file

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "13.1.7", "version": "13.2.2",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",
@ -54,12 +54,12 @@
"devDependencies": { "devDependencies": {
"@types/gulp": "4.0.10", "@types/gulp": "4.0.10",
"@types/gulp-rename": "2.0.1", "@types/gulp-rename": "2.0.1",
"@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.48.2", "@typescript-eslint/parser": "5.49.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "12.3.0", "cypress": "12.3.0",
"eslint": "^8.32.0", "eslint": "^8.32.0",
"start-server-and-test": "1.15.2" "start-server-and-test": "1.15.3"
}, },
"optionalDependencies": { "optionalDependencies": {
"@tensorflow/tfjs-core": "^4.2.0" "@tensorflow/tfjs-core": "^4.2.0"

View file

@ -19,13 +19,13 @@
"test-and-coverage": "pnpm jest-and-coverage" "test-and-coverage": "pnpm jest-and-coverage"
}, },
"optionalDependencies": { "optionalDependencies": {
"@tensorflow/tfjs": "^4.1.0", "@tensorflow/tfjs": "^4.2.0",
"@tensorflow/tfjs-node": "4.1.0" "@tensorflow/tfjs-node": "4.2.0"
}, },
"dependencies": { "dependencies": {
"@bull-board/api": "^4.10.2", "@bull-board/api": "^4.11.0",
"@bull-board/fastify": "^4.10.2", "@bull-board/fastify": "^4.11.0",
"@bull-board/ui": "^4.10.2", "@bull-board/ui": "^4.11.0",
"@discordapp/twemoji": "14.0.2", "@discordapp/twemoji": "14.0.2",
"@fastify/accepts": "4.1.0", "@fastify/accepts": "4.1.0",
"@fastify/cookie": "^8.3.0", "@fastify/cookie": "^8.3.0",
@ -63,15 +63,14 @@
"file-type": "18.2.0", "file-type": "18.2.0",
"fluent-ffmpeg": "2.1.2", "fluent-ffmpeg": "2.1.2",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"got": "12.5.3", "got": "^12.5.3",
"hpagent": "1.2.0", "hpagent": "1.2.0",
"ioredis": "4.28.5", "ioredis": "4.28.5",
"ip-cidr": "3.0.11", "ip-cidr": "3.0.11",
"is-svg": "4.3.2", "is-svg": "4.3.2",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"jsdom": "21.0.0", "jsdom": "21.1.0",
"json5": "2.2.3", "json5": "2.2.3",
"json5-loader": "4.0.1",
"jsonld": "8.1.0", "jsonld": "8.1.0",
"jsrsasign": "10.6.1", "jsrsasign": "10.6.1",
"mfm-js": "0.23.3", "mfm-js": "0.23.3",
@ -120,14 +119,14 @@
"typeorm": "0.3.11", "typeorm": "0.3.11",
"typescript": "4.9.4", "typescript": "4.9.4",
"ulid": "2.3.0", "ulid": "2.3.0",
"undici": "^5.15.1",
"unzipper": "0.10.11", "unzipper": "0.10.11",
"uuid": "9.0.0", "uuid": "9.0.0",
"vary": "1.1.2", "vary": "1.1.2",
"web-push": "3.5.0", "web-push": "3.5.0",
"websocket": "1.0.34", "websocket": "1.0.34",
"ws": "8.12.0", "ws": "8.12.0",
"xev": "3.0.2" "xev": "3.0.2",
"node-fetch": "3.3.0"
}, },
"devDependencies": { "devDependencies": {
"@redocly/openapi-core": "1.0.0-beta.120", "@redocly/openapi-core": "1.0.0-beta.120",
@ -176,14 +175,13 @@
"@types/web-push": "3.3.2", "@types/web-push": "3.3.2",
"@types/websocket": "1.0.5", "@types/websocket": "1.0.5",
"@types/ws": "8.5.4", "@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.48.2", "@typescript-eslint/parser": "5.49.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint": "8.32.0", "eslint": "8.32.0",
"eslint-plugin-import": "2.27.5", "eslint-plugin-import": "2.27.5",
"execa": "6.1.0", "execa": "6.1.0",
"jest": "29.3.1", "jest": "29.3.1",
"jest-mock": "^29.3.1", "jest-mock": "^29.3.1"
"node-fetch": "3.3.0"
} }
} }

View file

@ -0,0 +1,35 @@
import { NestFactory } from '@nestjs/core';
import { ChartManagementService } from '@/core/chart/ChartManagementService.js';
import { QueueProcessorService } from '@/queue/QueueProcessorService.js';
import { NestLogger } from '@/NestLogger.js';
import { QueueProcessorModule } from '@/queue/QueueProcessorModule.js';
import { JanitorService } from '@/daemons/JanitorService.js';
import { QueueStatsService } from '@/daemons/QueueStatsService.js';
import { ServerStatsService } from '@/daemons/ServerStatsService.js';
import { ServerService } from '@/server/ServerService.js';
import { MainModule } from '@/MainModule.js';
export async function server() {
const app = await NestFactory.createApplicationContext(MainModule, {
logger: new NestLogger(),
});
app.enableShutdownHooks();
const serverService = app.get(ServerService);
serverService.launch();
app.get(ChartManagementService).start();
app.get(JanitorService).start();
app.get(QueueStatsService).start();
app.get(ServerStatsService).start();
}
export async function jobQueue() {
const jobQueue = await NestFactory.createApplicationContext(QueueProcessorModule, {
logger: new NestLogger(),
});
jobQueue.enableShutdownHooks();
jobQueue.get(QueueProcessorService).start();
jobQueue.get(ChartManagementService).start();
}

View file

@ -6,21 +6,12 @@ import cluster from 'node:cluster';
import chalk from 'chalk'; import chalk from 'chalk';
import chalkTemplate from 'chalk-template'; import chalkTemplate from 'chalk-template';
import semver from 'semver'; import semver from 'semver';
import { NestFactory } from '@nestjs/core';
import Logger from '@/logger.js'; import Logger from '@/logger.js';
import { loadConfig } from '@/config.js'; import { loadConfig } from '@/config.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { lessThan } from '@/misc/prelude/array.js';
import { showMachineInfo } from '@/misc/show-machine-info.js'; import { showMachineInfo } from '@/misc/show-machine-info.js';
import { DaemonModule } from '@/daemons/DaemonModule.js'; import { envOption } from '@/env.js';
import { JanitorService } from '@/daemons/JanitorService.js'; import { jobQueue, server } from './common.js';
import { QueueStatsService } from '@/daemons/QueueStatsService.js';
import { ServerStatsService } from '@/daemons/ServerStatsService.js';
import { NestLogger } from '@/NestLogger.js';
import { ChartManagementService } from '@/core/chart/ChartManagementService.js';
import { ServerService } from '@/server/ServerService.js';
import { MainModule } from '@/MainModule.js';
import { envOption } from '../env.js';
const _filename = fileURLToPath(import.meta.url); const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename); const _dirname = dirname(_filename);
@ -73,14 +64,13 @@ export async function masterMain() {
process.exit(1); process.exit(1);
} }
const app = await NestFactory.createApplicationContext(MainModule, { if (envOption.onlyServer) {
logger: new NestLogger(), await server();
}); } else if (envOption.onlyQueue) {
app.enableShutdownHooks(); await jobQueue();
} else {
// start server await server();
const serverService = app.get(ServerService); }
serverService.launch();
bootLogger.succ('Misskey initialized'); bootLogger.succ('Misskey initialized');
@ -89,11 +79,6 @@ export async function masterMain() {
} }
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true); bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
app.get(ChartManagementService).start();
app.get(JanitorService).start();
app.get(QueueStatsService).start();
app.get(ServerStatsService).start();
} }
function showEnvironment(): void { function showEnvironment(): void {

View file

@ -1,23 +1,18 @@
import cluster from 'node:cluster'; import cluster from 'node:cluster';
import { NestFactory } from '@nestjs/core'; import { envOption } from '@/env.js';
import { ChartManagementService } from '@/core/chart/ChartManagementService.js'; import { jobQueue, server } from './common.js';
import { QueueProcessorService } from '@/queue/QueueProcessorService.js';
import { NestLogger } from '@/NestLogger.js';
import { QueueProcessorModule } from '@/queue/QueueProcessorModule.js';
/** /**
* Init worker process * Init worker process
*/ */
export async function workerMain() { export async function workerMain() {
const jobQueue = await NestFactory.createApplicationContext(QueueProcessorModule, { if (envOption.onlyServer) {
logger: new NestLogger(), await server();
}); } else if (envOption.onlyQueue) {
jobQueue.enableShutdownHooks(); await jobQueue();
} else {
// start job queue await jobQueue();
jobQueue.get(QueueProcessorService).start(); }
jobQueue.get(ChartManagementService).start();
if (cluster.isWorker) { if (cluster.isWorker) {
// Send a 'ready' message to parent process // Send a 'ready' message to parent process

View file

@ -77,10 +77,16 @@ export class AntennaService implements OnApplicationShutdown {
const { type, body } = obj.message as StreamMessages['internal']['payload']; const { type, body } = obj.message as StreamMessages['internal']['payload'];
switch (type) { switch (type) {
case 'antennaCreated': case 'antennaCreated':
this.antennas.push(body); this.antennas.push({
...body,
createdAt: new Date(body.createdAt),
});
break; break;
case 'antennaUpdated': case 'antennaUpdated':
this.antennas[this.antennas.findIndex(a => a.id === body.id)] = body; this.antennas[this.antennas.findIndex(a => a.id === body.id)] = {
...body,
createdAt: new Date(body.createdAt),
};
break; break;
case 'antennaDeleted': case 'antennaDeleted':
this.antennas = this.antennas.filter(a => a.id !== body.id); this.antennas = this.antennas.filter(a => a.id !== body.id);

View file

@ -21,18 +21,13 @@ export class CaptchaService {
response, response,
}); });
const res = await this.httpRequestService.fetch( const res = await this.httpRequestService.send(url, {
url,
{
method: 'POST', method: 'POST',
body: params, body: JSON.stringify(params),
headers: {
'Content-Type': 'application/json',
}, },
{ }, { throwErrorWhenResponseNotOk: false });
noOkError: true,
}
).catch(err => {
throw `${err.message ?? err}`;
});
if (!res.ok) { if (!res.ok) {
throw `${res.status}`; throw `${res.status}`;

View file

@ -4,16 +4,15 @@ import * as util from 'node:util';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import IPCIDR from 'ip-cidr'; import IPCIDR from 'ip-cidr';
import PrivateIp from 'private-ip'; import PrivateIp from 'private-ip';
import got, * as Got from 'got';
import chalk from 'chalk'; import chalk from 'chalk';
import got, * as Got from 'got';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { createTemp } from '@/misc/create-temp.js'; import { createTemp } from '@/misc/create-temp.js';
import { StatusError } from '@/misc/status-error.js'; import { StatusError } from '@/misc/status-error.js';
import { LoggerService } from '@/core/LoggerService.js'; import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { buildConnector } from 'undici';
const pipeline = util.promisify(stream.pipeline); const pipeline = util.promisify(stream.pipeline);
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -21,7 +20,6 @@ import { bindThis } from '@/decorators.js';
@Injectable() @Injectable()
export class DownloadService { export class DownloadService {
private logger: Logger; private logger: Logger;
private undiciFetcher: UndiciFetcher;
constructor( constructor(
@Inject(DI.config) @Inject(DI.config)
@ -31,24 +29,6 @@ export class DownloadService {
private loggerService: LoggerService, private loggerService: LoggerService,
) { ) {
this.logger = this.loggerService.getLogger('download'); this.logger = this.loggerService.getLogger('download');
this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption(
{
connect: process.env.NODE_ENV === 'development' ?
this.httpRequestService.clientDefaults.connect
:
this.httpRequestService.getConnectorWithIpCheck(
buildConnector({
...this.httpRequestService.clientDefaults.connect,
}),
(ip) => !this.isPrivateIp(ip)
),
bodyTimeout: 30 * 1000,
},
{
connect: this.httpRequestService.clientDefaults.connect,
}
), this.logger);
} }
@bindThis @bindThis
@ -59,13 +39,59 @@ export class DownloadService {
const operationTimeout = 60 * 1000; const operationTimeout = 60 * 1000;
const maxSize = this.config.maxFileSize ?? 262144000; const maxSize = this.config.maxFileSize ?? 262144000;
const response = await this.undiciFetcher.fetch(url); const req = got.stream(url, {
headers: {
if (response.body === null) { 'User-Agent': this.config.userAgent,
throw new StatusError('No body', 400, 'No body'); },
timeout: {
lookup: timeout,
connect: timeout,
secureConnect: timeout,
socket: timeout, // read timeout
response: timeout,
send: timeout,
request: operationTimeout, // whole operation timeout
},
agent: {
http: this.httpRequestService.httpAgent,
https: this.httpRequestService.httpsAgent,
},
http2: false, // default
retry: {
limit: 0,
},
}).on('response', (res: Got.Response) => {
if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !this.config.proxy && res.ip) {
if (this.isPrivateIp(res.ip)) {
this.logger.warn(`Blocked address: ${res.ip}`);
req.destroy();
}
} }
await pipeline(stream.Readable.fromWeb(response.body), fs.createWriteStream(path)); const contentLength = res.headers['content-length'];
if (contentLength != null) {
const size = Number(contentLength);
if (size > maxSize) {
this.logger.warn(`maxSize exceeded (${size} > ${maxSize}) on response`);
req.destroy();
}
}
}).on('downloadProgress', (progress: Got.Progress) => {
if (progress.transferred > maxSize) {
this.logger.warn(`maxSize exceeded (${progress.transferred} > ${maxSize}) on downloadProgress`);
req.destroy();
}
});
try {
await pipeline(req, fs.createWriteStream(path));
} catch (e) {
if (e instanceof Got.HTTPError) {
throw new StatusError(`${e.response.statusCode} ${e.response.statusMessage}`, e.response.statusCode, e.response.statusMessage);
} else {
throw e;
}
}
this.logger.succ(`Download finished: ${chalk.cyan(url)}`); this.logger.succ(`Download finished: ${chalk.cyan(url)}`);
} }

View file

@ -2,6 +2,7 @@ import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { JSDOM } from 'jsdom'; import { JSDOM } from 'jsdom';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import fetch from 'node-fetch';
import type { Instance } from '@/models/entities/Instance.js'; import type { Instance } from '@/models/entities/Instance.js';
import type { InstancesRepository } from '@/models/index.js'; import type { InstancesRepository } from '@/models/index.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
@ -190,7 +191,9 @@ export class FetchInstanceMetadataService {
const faviconUrl = url + '/favicon.ico'; const faviconUrl = url + '/favicon.ico';
const favicon = await this.httpRequestService.fetch(faviconUrl, {}, { noOkError: true }); const favicon = await this.httpRequestService.send(faviconUrl, {
method: 'HEAD',
}, { throwErrorWhenResponseNotOk: false });
if (favicon.ok) { if (favicon.ok) {
return faviconUrl; return faviconUrl;

View file

@ -1,257 +1,67 @@
import * as http from 'node:http'; import * as http from 'node:http';
import * as https from 'node:https'; import * as https from 'node:https';
import CacheableLookup from 'cacheable-lookup'; import CacheableLookup from 'cacheable-lookup';
import fetch from 'node-fetch';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent'; import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { StatusError } from '@/misc/status-error.js'; import { StatusError } from '@/misc/status-error.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import * as undici from 'undici'; import type { Response } from 'node-fetch';
import { LookupFunction } from 'node:net'; import type { URL } from 'node:url';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
// true to allow, false to deny
export type IpChecker = (ip: string) => boolean;
/*
* Child class to create and save Agent for fetch.
* You should construct this when you want
* to change timeout, size limit, socket connect function, etc.
*/
export class UndiciFetcher {
/**
* Get http non-proxy agent (undici)
*/
public nonProxiedAgent: undici.Agent;
/**
* Get http proxy or non-proxy agent (undici)
*/
public agent: undici.ProxyAgent | undici.Agent;
private proxyBypassHosts: string[];
private userAgent: string | undefined;
private logger: Logger | undefined;
constructor(
args: {
agentOptions: undici.Agent.Options;
proxy?: {
uri: string;
options?: undici.Agent.Options; // Override of agentOptions
},
proxyBypassHosts?: string[];
userAgent?: string;
},
logger?: Logger,
) {
this.logger = logger;
this.logger?.debug('UndiciFetcher constructor', args);
this.proxyBypassHosts = args.proxyBypassHosts ?? [];
this.userAgent = args.userAgent;
this.nonProxiedAgent = new undici.Agent({
...args.agentOptions,
connect: (process.env.NODE_ENV !== 'production' && typeof args.agentOptions.connect !== 'function')
? (options, cb) => {
// Custom connector for debug
undici.buildConnector(args.agentOptions.connect as undici.buildConnector.BuildOptions)(options, (err, socket) => {
this.logger?.debug('Socket connector called', socket);
if (err) {
this.logger?.debug(`Socket error`, err);
cb(new Error(`Error while socket connecting\n${err}`), null);
return;
}
this.logger?.debug(`Socket connected: port ${socket.localPort} => remote ${socket.remoteAddress}`);
cb(null, socket);
});
} : args.agentOptions.connect,
});
this.agent = args.proxy
? new undici.ProxyAgent({
...args.agentOptions,
...args.proxy.options,
uri: args.proxy.uri,
connect: (process.env.NODE_ENV !== 'production' && typeof (args.proxy?.options?.connect ?? args.agentOptions.connect) !== 'function')
? (options, cb) => {
// Custom connector for debug
undici.buildConnector((args.proxy?.options?.connect ?? args.agentOptions.connect) as undici.buildConnector.BuildOptions)(options, (err, socket) => {
this.logger?.debug('Socket connector called (secure)', socket);
if (err) {
this.logger?.debug(`Socket error`, err);
cb(new Error(`Error while socket connecting\n${err}`), null);
return;
}
this.logger?.debug(`Socket connected (secure): port ${socket.localPort} => remote ${socket.remoteAddress}`);
cb(null, socket);
});
} : (args.proxy?.options?.connect ?? args.agentOptions.connect),
})
: this.nonProxiedAgent;
}
/**
* Get agent by URL
* @param url URL
* @param bypassProxy Allways bypass proxy
*/
@bindThis
public getAgentByUrl(url: URL, bypassProxy = false): undici.Agent | undici.ProxyAgent {
if (bypassProxy || this.proxyBypassHosts.includes(url.hostname)) {
return this.nonProxiedAgent;
} else {
return this.agent;
}
}
@bindThis
public async fetch(
url: string | URL,
options: undici.RequestInit = {},
privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false }
): Promise<undici.Response> {
const res = await undici.fetch(url, {
dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy),
...options,
headers: {
'User-Agent': this.userAgent ?? '',
...(options.headers ?? {}),
},
}).catch((err) => {
this.logger?.error(`fetch error to ${typeof url === 'string' ? url : url.href}`, err);
throw new StatusError('Resource Unreachable', 500, 'Resource Unreachable');
});
if (!res.ok && !privateOptions.noOkError) {
throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText);
}
return res;
}
@bindThis
public async getJson<T extends unknown>(url: string, accept = 'application/json, */*', headers?: Record<string, string>): Promise<T> {
const res = await this.fetch(
url,
{
headers: Object.assign({
Accept: accept,
}, headers ?? {}),
}
);
return await res.json() as T;
}
@bindThis
public async getHtml(url: string, accept = 'text/html, */*', headers?: Record<string, string>): Promise<string> {
const res = await this.fetch(
url,
{
headers: Object.assign({
Accept: accept,
}, headers ?? {}),
}
);
return await res.text();
}
}
@Injectable() @Injectable()
export class HttpRequestService { export class HttpRequestService {
public defaultFetcher: UndiciFetcher; /**
public fetch: UndiciFetcher['fetch']; * Get http non-proxy agent
public getHtml: UndiciFetcher['getHtml']; */
public defaultJsonFetcher: UndiciFetcher;
public getJson: UndiciFetcher['getJson'];
//#region for old http/https, only used in S3Service
// http non-proxy agent
private http: http.Agent; private http: http.Agent;
// https non-proxy agent /**
* Get https non-proxy agent
*/
private https: https.Agent; private https: https.Agent;
// http proxy or non-proxy agent /**
* Get http proxy or non-proxy agent
*/
public httpAgent: http.Agent; public httpAgent: http.Agent;
// https proxy or non-proxy agent /**
* Get https proxy or non-proxy agent
*/
public httpsAgent: https.Agent; public httpsAgent: https.Agent;
//#endregion
public readonly dnsCache: CacheableLookup;
public readonly clientDefaults: undici.Agent.Options;
private maxSockets: number;
private logger: Logger;
constructor( constructor(
@Inject(DI.config) @Inject(DI.config)
private config: Config, private config: Config,
private loggerService: LoggerService,
) { ) {
this.logger = this.loggerService.getLogger('http-request'); const cache = new CacheableLookup({
this.dnsCache = new CacheableLookup({
maxTtl: 3600, // 1hours maxTtl: 3600, // 1hours
errorTtl: 30, // 30secs errorTtl: 30, // 30secs
lookup: false, // nativeのdns.lookupにfallbackしない lookup: false, // nativeのdns.lookupにfallbackしない
}); });
this.clientDefaults = {
keepAliveTimeout: 30 * 1000,
keepAliveMaxTimeout: 10 * 60 * 1000,
keepAliveTimeoutThreshold: 1 * 1000,
strictContentLength: true,
headersTimeout: 10 * 1000,
bodyTimeout: 10 * 1000,
maxHeaderSize: 16364, // default
maxResponseSize: 10 * 1024 * 1024,
maxRedirections: 3,
connect: {
timeout: 10 * 1000, // コネクションが確立するまでのタイムアウト
maxCachedSessions: 300, // TLSセッションのキャッシュ数 https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L80
lookup: this.dnsCache.lookup as LookupFunction, // https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L98
},
}
this.maxSockets = Math.max(64, this.config.deliverJobConcurrency ?? 128);
this.defaultFetcher = new UndiciFetcher(this.getStandardUndiciFetcherOption(), this.logger);
this.fetch = this.defaultFetcher.fetch;
this.getHtml = this.defaultFetcher.getHtml;
this.defaultJsonFetcher = new UndiciFetcher(this.getStandardUndiciFetcherOption({
maxResponseSize: 1024 * 256,
}), this.logger);
this.getJson = this.defaultJsonFetcher.getJson;
//#region for old http/https, only used in S3Service
this.http = new http.Agent({ this.http = new http.Agent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * 1000,
lookup: this.dnsCache.lookup, lookup: cache.lookup,
} as http.AgentOptions); } as http.AgentOptions);
this.https = new https.Agent({ this.https = new https.Agent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * 1000,
lookup: this.dnsCache.lookup, lookup: cache.lookup,
} as https.AgentOptions); } as https.AgentOptions);
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
this.httpAgent = config.proxy this.httpAgent = config.proxy
? new HttpProxyAgent({ ? new HttpProxyAgent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * 1000,
maxSockets: this.maxSockets, maxSockets,
maxFreeSockets: 256, maxFreeSockets: 256,
scheduling: 'lifo', scheduling: 'lifo',
proxy: config.proxy, proxy: config.proxy,
@ -262,42 +72,21 @@ export class HttpRequestService {
? new HttpsProxyAgent({ ? new HttpsProxyAgent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * 1000,
maxSockets: this.maxSockets, maxSockets,
maxFreeSockets: 256, maxFreeSockets: 256,
scheduling: 'lifo', scheduling: 'lifo',
proxy: config.proxy, proxy: config.proxy,
}) })
: this.https; : this.https;
//#endregion
}
@bindThis
public getStandardUndiciFetcherOption(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}) {
return {
agentOptions: {
...this.clientDefaults,
...opts,
},
...(this.config.proxy ? {
proxy: {
uri: this.config.proxy,
options: {
connections: this.maxSockets,
...proxyOpts,
}
}
} : {}),
userAgent: this.config.userAgent,
}
} }
/** /**
* Get http agent by URL * Get agent by URL
* @param url URL * @param url URL
* @param bypassProxy Allways bypass proxy * @param bypassProxy Allways bypass proxy
*/ */
@bindThis @bindThis
public getHttpAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent { public getAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent {
if (bypassProxy || (this.config.proxyBypassHosts || []).includes(url.hostname)) { if (bypassProxy || (this.config.proxyBypassHosts || []).includes(url.hostname)) {
return url.protocol === 'http:' ? this.http : this.https; return url.protocol === 'http:' ? this.http : this.https;
} else { } else {
@ -305,37 +94,67 @@ export class HttpRequestService {
} }
} }
/**
* check ip
*/
@bindThis @bindThis
public getConnectorWithIpCheck(connector: undici.buildConnector.connector, checkIp: IpChecker): undici.buildConnector.connectorAsync { public async getJson(url: string, accept = 'application/json, */*', headers?: Record<string, string>): Promise<unknown> {
return (options, cb) => { const res = await this.send(url, {
connector(options, (err, socket) => { method: 'GET',
this.logger.debug('Socket connector (with ip checker) called', socket); headers: Object.assign({
if (err) { 'User-Agent': this.config.userAgent,
this.logger.error(`Socket error`, err) Accept: accept,
cb(new Error(`Error while socket connecting\n${err}`), null); }, headers ?? {}),
return; timeout: 5000,
} size: 1024 * 256,
if (socket.remoteAddress == undefined) {
this.logger.error(`Socket error: remoteAddress is undefined`);
cb(new Error('remoteAddress is undefined (maybe socket destroyed)'), null);
return;
}
// allow
if (checkIp(socket.remoteAddress)) {
this.logger.debug(`Socket connected (ip ok): ${socket.localPort} => ${socket.remoteAddress}`);
cb(null, socket);
return;
}
this.logger.error('IP is not allowed', socket);
cb(new StatusError('IP is not allowed', 403, 'IP is not allowed'), null);
socket.destroy();
}); });
};
return await res.json();
}
@bindThis
public async getHtml(url: string, accept = 'text/html, */*', headers?: Record<string, string>): Promise<string> {
const res = await this.send(url, {
method: 'GET',
headers: Object.assign({
'User-Agent': this.config.userAgent,
Accept: accept,
}, headers ?? {}),
timeout: 5000,
});
return await res.text();
}
@bindThis
public async send(url: string, args: {
method?: string,
body?: string,
headers?: Record<string, string>,
timeout?: number,
size?: number,
} = {}, extra: {
throwErrorWhenResponseNotOk: boolean;
} = {
throwErrorWhenResponseNotOk: true,
}): Promise<Response> {
const timeout = args.timeout ?? 5000;
const controller = new AbortController();
setTimeout(() => {
controller.abort();
}, timeout);
const res = await fetch(url, {
method: args.method ?? 'GET',
headers: args.headers,
body: args.body,
size: args.size ?? 10 * 1024 * 1024,
agent: (url) => this.getAgentByUrl(url),
signal: controller.signal,
});
if (!res.ok && extra.throwErrorWhenResponseNotOk) {
throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText);
}
return res;
} }
} }

View file

@ -91,10 +91,12 @@ export class RoleService implements OnApplicationShutdown {
case 'roleCreated': { case 'roleCreated': {
const cached = this.rolesCache.get(null); const cached = this.rolesCache.get(null);
if (cached) { if (cached) {
body.createdAt = new Date(body.createdAt); cached.push({
body.updatedAt = new Date(body.updatedAt); ...body,
body.lastUsedAt = new Date(body.lastUsedAt); createdAt: new Date(body.createdAt),
cached.push(body); updatedAt: new Date(body.updatedAt),
lastUsedAt: new Date(body.lastUsedAt),
});
} }
break; break;
} }
@ -103,10 +105,12 @@ export class RoleService implements OnApplicationShutdown {
if (cached) { if (cached) {
const i = cached.findIndex(x => x.id === body.id); const i = cached.findIndex(x => x.id === body.id);
if (i > -1) { if (i > -1) {
body.createdAt = new Date(body.createdAt); cached[i] = {
body.updatedAt = new Date(body.updatedAt); ...body,
body.lastUsedAt = new Date(body.lastUsedAt); createdAt: new Date(body.createdAt),
cached[i] = body; updatedAt: new Date(body.updatedAt),
lastUsedAt: new Date(body.lastUsedAt),
};
} }
} }
break; break;
@ -121,8 +125,10 @@ export class RoleService implements OnApplicationShutdown {
case 'userRoleAssigned': { case 'userRoleAssigned': {
const cached = this.roleAssignmentByUserIdCache.get(body.userId); const cached = this.roleAssignmentByUserIdCache.get(body.userId);
if (cached) { if (cached) {
body.createdAt = new Date(body.createdAt); cached.push({
cached.push(body); ...body,
createdAt: new Date(body.createdAt),
});
} }
break; break;
} }

View file

@ -33,7 +33,7 @@ export class S3Service {
? false ? false
: meta.objectStorageS3ForcePathStyle, : meta.objectStorageS3ForcePathStyle,
httpOptions: { httpOptions: {
agent: this.httpRequestService.getHttpAgentByUrl(new URL(u), !meta.objectStorageUseProxy), agent: this.httpRequestService.getAgentByUrl(new URL(u), !meta.objectStorageUseProxy),
}, },
}); });
} }

View file

@ -21,11 +21,11 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import type { UserKeypair } from '@/models/entities/UserKeypair.js'; import type { UserKeypair } from '@/models/entities/UserKeypair.js';
import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, EmojisRepository, PollsRepository } from '@/models/index.js'; import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, EmojisRepository, PollsRepository } from '@/models/index.js';
import { bindThis } from '@/decorators.js';
import { LdSignatureService } from './LdSignatureService.js'; import { LdSignatureService } from './LdSignatureService.js';
import { ApMfmService } from './ApMfmService.js'; import { ApMfmService } from './ApMfmService.js';
import type { IActivity, IObject } from './type.js'; import type { IActivity, IObject } from './type.js';
import type { IIdentifier } from './models/identifier.js'; import type { IIdentifier } from './models/identifier.js';
import { bindThis } from '@/decorators.js';
@Injectable() @Injectable()
export class ApRendererService { export class ApRendererService {

View file

@ -5,7 +5,7 @@ import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { User } from '@/models/entities/User.js'; import type { User } from '@/models/entities/User.js';
import { UserKeypairStoreService } from '@/core/UserKeypairStoreService.js'; import { UserKeypairStoreService } from '@/core/UserKeypairStoreService.js';
import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { LoggerService } from '@/core/LoggerService.js'; import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
@ -30,7 +30,6 @@ type PrivateKey = {
@Injectable() @Injectable()
export class ApRequestService { export class ApRequestService {
private undiciFetcher: UndiciFetcher;
private logger: Logger; private logger: Logger;
constructor( constructor(
@ -41,10 +40,8 @@ export class ApRequestService {
private httpRequestService: HttpRequestService, private httpRequestService: HttpRequestService,
private loggerService: LoggerService, private loggerService: LoggerService,
) { ) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption({
maxRedirections: 0,
}), this.logger );
} }
@bindThis @bindThis
@ -163,14 +160,11 @@ export class ApRequestService {
}, },
}); });
await this.undiciFetcher.fetch( await this.httpRequestService.send(url, {
url,
{
method: req.request.method, method: req.request.method,
headers: req.request.headers, headers: req.request.headers,
body, body,
} });
);
} }
/** /**
@ -192,13 +186,10 @@ export class ApRequestService {
}, },
}); });
const res = await this.httpRequestService.fetch( const res = await this.httpRequestService.send(url, {
url,
{
method: req.request.method, method: req.request.method,
headers: req.request.headers, headers: req.request.headers,
} });
);
return await res.json(); return await res.json();
} }

View file

@ -4,22 +4,21 @@ import { InstanceActorService } from '@/core/InstanceActorService.js';
import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository } from '@/models/index.js'; import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { UtilityService } from '@/core/UtilityService.js'; import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
import { isCollectionOrOrderedCollection } from './type.js'; import { isCollectionOrOrderedCollection } from './type.js';
import { ApDbResolverService } from './ApDbResolverService.js'; import { ApDbResolverService } from './ApDbResolverService.js';
import { ApRendererService } from './ApRendererService.js'; import { ApRendererService } from './ApRendererService.js';
import { ApRequestService } from './ApRequestService.js'; import { ApRequestService } from './ApRequestService.js';
import { LoggerService } from '@/core/LoggerService.js';
import type { IObject, ICollection, IOrderedCollection } from './type.js'; import type { IObject, ICollection, IOrderedCollection } from './type.js';
import type Logger from '@/logger.js';
export class Resolver { export class Resolver {
private history: Set<string>; private history: Set<string>;
private user?: ILocalUser; private user?: ILocalUser;
private undiciFetcher: UndiciFetcher;
private logger: Logger; private logger: Logger;
constructor( constructor(
@ -39,10 +38,8 @@ export class Resolver {
private recursionLimit = 100, private recursionLimit = 100,
) { ) {
this.history = new Set(); this.history = new Set();
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption({
maxRedirections: 0,
}), this.logger);
} }
@bindThis @bindThis
@ -106,7 +103,7 @@ export class Resolver {
const object = (this.user const object = (this.user
? await this.apRequestService.signedGet(value, this.user) as IObject ? await this.apRequestService.signedGet(value, this.user) as IObject
: await this.undiciFetcher.getJson<IObject>(value, 'application/activity+json, application/ld+json')); : await this.httpRequestService.getJson(value, 'application/activity+json, application/ld+json')) as IObject;
if (object == null || ( if (object == null || (
Array.isArray(object['@context']) ? Array.isArray(object['@context']) ?

View file

@ -9,7 +9,7 @@ import { CONTEXTS } from './misc/contexts.js';
class LdSignature { class LdSignature {
public debug = false; public debug = false;
public preLoad = true; public preLoad = true;
public loderTimeout = 10 * 1000; public loderTimeout = 5000;
constructor( constructor(
private httpRequestService: HttpRequestService, private httpRequestService: HttpRequestService,
@ -115,19 +115,12 @@ class LdSignature {
@bindThis @bindThis
private async fetchDocument(url: string) { private async fetchDocument(url: string) {
const json = await this.httpRequestService.fetch( const json = await this.httpRequestService.send(url, {
url,
{
headers: { headers: {
Accept: 'application/ld+json, application/json', Accept: 'application/ld+json, application/json',
}, },
// TODO timeout: this.loderTimeout,
//timeout: this.loderTimeout, }, { throwErrorWhenResponseNotOk: false }).then(res => {
},
{
noOkError: true,
}
).then(res => {
if (!res.ok) { if (!res.ok) {
throw `${res.status} ${res.statusText}`; throw `${res.status} ${res.statusText}`;
} else { } else {

View file

@ -566,22 +566,22 @@ export class ApPersonService implements OnModuleInit {
this.logger.info(`Updating the featured: ${user.uri}`); this.logger.info(`Updating the featured: ${user.uri}`);
if (resolver == null) resolver = this.apResolverService.createResolver(); const _resolver = resolver ?? this.apResolverService.createResolver();
// Resolve to (Ordered)Collection Object // Resolve to (Ordered)Collection Object
const collection = await resolver.resolveCollection(user.featured); const collection = await _resolver.resolveCollection(user.featured);
if (!isCollectionOrOrderedCollection(collection)) throw new Error('Object is not Collection or OrderedCollection'); if (!isCollectionOrOrderedCollection(collection)) throw new Error('Object is not Collection or OrderedCollection');
// Resolve to Object(may be Note) arrays // Resolve to Object(may be Note) arrays
const unresolvedItems = isCollection(collection) ? collection.items : collection.orderedItems; const unresolvedItems = isCollection(collection) ? collection.items : collection.orderedItems;
const items = await Promise.all(toArray(unresolvedItems).map(x => resolver.resolve(x))); const items = await Promise.all(toArray(unresolvedItems).map(x => _resolver.resolve(x)));
// Resolve and regist Notes // Resolve and regist Notes
const limit = promiseLimit<Note | null>(2); const limit = promiseLimit<Note | null>(2);
const featuredNotes = await Promise.all(items const featuredNotes = await Promise.all(items
.filter(item => getApType(item) === 'Note') // TODO: Noteでなくてもいいかも .filter(item => getApType(item) === 'Note') // TODO: Noteでなくてもいいかも
.slice(0, 5) .slice(0, 5)
.map(item => limit(() => this.apNoteService.resolveNote(item, resolver)))); .map(item => limit(() => this.apNoteService.resolveNote(item, _resolver))));
await this.db.transaction(async transactionalEntityManager => { await this.db.transaction(async transactionalEntityManager => {
await transactionalEntityManager.delete(UserNotePining, { userId: user.id }); await transactionalEntityManager.delete(UserNotePining, { userId: user.id });

View file

@ -496,10 +496,10 @@ export class UserEntityService implements OnModuleInit {
showTimelineReplies: user.showTimelineReplies ?? falsy, showTimelineReplies: user.showTimelineReplies ?? falsy,
achievements: profile!.achievements, achievements: profile!.achievements,
loggedInDays: profile!.loggedInDates.length, loggedInDays: profile!.loggedInDates.length,
policies: this.roleService.getUserPolicies(user.id),
} : {}), } : {}),
...(opts.includeSecrets ? { ...(opts.includeSecrets ? {
policies: this.roleService.getUserPolicies(user.id),
email: profile!.email, email: profile!.email,
emailVerified: profile!.emailVerified, emailVerified: profile!.emailVerified,
securityKeysList: profile!.twoFactorEnabled securityKeysList: profile!.twoFactorEnabled

View file

@ -0,0 +1,11 @@
import { Writable, WritableOptions } from "node:stream";
export class DevNull extends Writable implements NodeJS.WritableStream {
constructor(opts?: WritableOptions) {
super(opts);
}
_write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) {
setImmediate(cb);
}
}

View file

@ -1,9 +1,14 @@
import IPCIDR from 'ip-cidr'; import IPCIDR from 'ip-cidr';
export function getIpHash(ip: string) { export function getIpHash(ip: string) {
try {
// because a single person may control many IPv6 addresses, // because a single person may control many IPv6 addresses,
// only a /64 subnet prefix of any IP will be taken into account. // only a /64 subnet prefix of any IP will be taken into account.
// (this means for IPv4 the entire address is used) // (this means for IPv4 the entire address is used)
const prefix = IPCIDR.createAddress(ip).mask(64); const prefix = IPCIDR.createAddress(ip).mask(64);
return 'ip-' + BigInt('0b' + prefix).toString(36); return 'ip-' + BigInt('0b' + prefix).toString(36);
} catch (e) {
const prefix = IPCIDR.createAddress(ip.replace(/:[0-9]+$/, '')).mask(64);
return 'ip-' + BigInt('0b' + prefix).toString(36);
}
} }

View file

@ -6,10 +6,10 @@ import type { Config } from '@/config.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { HttpRequestService } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { StatusError } from '@/misc/status-error.js'; import { StatusError } from '@/misc/status-error.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js'; import { QueueLoggerService } from '../QueueLoggerService.js';
import type Bull from 'bull'; import type Bull from 'bull';
import type { WebhookDeliverJobData } from '../types.js'; import type { WebhookDeliverJobData } from '../types.js';
import { bindThis } from '@/decorators.js';
@Injectable() @Injectable()
export class WebhookDeliverProcessorService { export class WebhookDeliverProcessorService {
@ -33,9 +33,7 @@ export class WebhookDeliverProcessorService {
try { try {
this.logger.debug(`delivering ${job.data.webhookId}`); this.logger.debug(`delivering ${job.data.webhookId}`);
const res = await this.httpRequestService.fetch( const res = await this.httpRequestService.send(job.data.to, {
job.data.to,
{
method: 'POST', method: 'POST',
headers: { headers: {
'User-Agent': 'Misskey-Hooks', 'User-Agent': 'Misskey-Hooks',
@ -51,8 +49,7 @@ export class WebhookDeliverProcessorService {
type: job.data.type, type: job.data.type,
body: job.data.content, body: job.data.content,
}), }),
} });
);
this.webhooksRepository.update({ id: job.data.webhookId }, { this.webhooksRepository.update({ id: job.data.webhookId }, {
latestSentAt: new Date(), latestSentAt: new Date(),

View file

@ -33,16 +33,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private httpRequestService: HttpRequestService, private httpRequestService: HttpRequestService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const res = await this.httpRequestService.fetch( const res = await this.httpRequestService.send(ps.url, {
ps.url,
{
method: 'GET', method: 'GET',
headers: { headers: {
Accept: 'application/rss+xml, */*', Accept: 'application/rss+xml, */*',
}, },
// timeout: 5000, timeout: 5000,
} });
);
const text = await res.text(); const text = await res.text();

View file

@ -7,8 +7,8 @@ import { DI } from '@/di-symbols.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { HttpRequestService } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js';
export const meta = { export const meta = {
tags: ['notes'], tags: ['notes'],
@ -83,20 +83,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate'; const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate';
const res = await this.httpRequestService.fetch( const res = await this.httpRequestService.send(endpoint, {
endpoint,
{
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json, */*', Accept: 'application/json, */*',
}, },
body: params.toString(), body: params.toString(),
}, });
{
noOkError: false,
}
);
const json = (await res.json()) as { const json = (await res.json()) as {
translations: { translations: {

View file

@ -30,7 +30,7 @@ export interface InternalStreamTypes {
remoteUserUpdated: Serialized<{ id: User['id']; }>; remoteUserUpdated: Serialized<{ id: User['id']; }>;
follow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>; follow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
unfollow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>; unfollow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
policiesUpdated: Serialized<Role['options']>; policiesUpdated: Serialized<Role['policies']>;
roleCreated: Serialized<Role>; roleCreated: Serialized<Role>;
roleDeleted: Serialized<Role>; roleDeleted: Serialized<Role>;
roleUpdated: Serialized<Role>; roleUpdated: Serialized<Role>;

View file

@ -35,7 +35,7 @@ html
link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg')
link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg')
link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg')
link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.css') link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css')
link(rel='modulepreload' href=`/vite/${clientEntry.file}`) link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
if !config.clientManifestExists if !config.clientManifestExists

View file

@ -12,7 +12,7 @@
"@rollup/plugin-json": "6.0.0", "@rollup/plugin-json": "6.0.0",
"@rollup/pluginutils": "5.0.2", "@rollup/pluginutils": "5.0.2",
"@syuilo/aiscript": "0.12.2", "@syuilo/aiscript": "0.12.2",
"@tabler/icons": "^1.118.0", "@tabler/icons-webfont": "^2.0.0",
"@vitejs/plugin-vue": "4.0.0", "@vitejs/plugin-vue": "4.0.0",
"@vue/compiler-sfc": "3.2.45", "@vue/compiler-sfc": "3.2.45",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
@ -82,15 +82,15 @@
"@types/uuid": "9.0.0", "@types/uuid": "9.0.0",
"@types/websocket": "1.0.5", "@types/websocket": "1.0.5",
"@types/ws": "8.5.4", "@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "5.48.2", "@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.48.2", "@typescript-eslint/parser": "5.49.0",
"@vue/runtime-core": "3.2.45", "@vue/runtime-core": "3.2.45",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "12.3.0", "cypress": "12.3.0",
"eslint": "8.32.0", "eslint": "8.32.0",
"eslint-plugin-import": "2.27.5", "eslint-plugin-import": "2.27.5",
"eslint-plugin-vue": "9.9.0", "eslint-plugin-vue": "9.9.0",
"start-server-and-test": "1.15.2", "start-server-and-test": "1.15.3",
"vue-eslint-parser": "^9.1.0", "vue-eslint-parser": "^9.1.0",
"vue-tsc": "^1.0.24" "vue-tsc": "^1.0.24"
} }

View file

@ -16,8 +16,8 @@
<time v-tooltip="new Date(achievement.unlockedAt).toLocaleString()">{{ new Date(achievement.unlockedAt).getFullYear() }}/{{ new Date(achievement.unlockedAt).getMonth() + 1 }}/{{ new Date(achievement.unlockedAt).getDate() }}</time> <time v-tooltip="new Date(achievement.unlockedAt).toLocaleString()">{{ new Date(achievement.unlockedAt).getFullYear() }}/{{ new Date(achievement.unlockedAt).getMonth() + 1 }}/{{ new Date(achievement.unlockedAt).getDate() }}</time>
</span> </span>
</div> </div>
<div :class="$style.description">{{ i18n.ts._achievements._types['_' + achievement.name].description }}</div> <div :class="$style.description">{{ withDescription ? i18n.ts._achievements._types['_' + achievement.name].description : '???' }}</div>
<div v-if="i18n.ts._achievements._types['_' + achievement.name].flavor" :class="$style.flavor">{{ i18n.ts._achievements._types['_' + achievement.name].flavor }}</div> <div v-if="i18n.ts._achievements._types['_' + achievement.name].flavor && withDescription" :class="$style.flavor">{{ i18n.ts._achievements._types['_' + achievement.name].flavor }}</div>
</div> </div>
</div> </div>
<template v-if="withLocked"> <template v-if="withLocked">
@ -49,8 +49,10 @@ import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/scrip
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
user: misskey.entities.User; user: misskey.entities.User;
withLocked: boolean; withLocked: boolean;
withDescription: boolean;
}>(), { }>(), {
withLocked: true, withLocked: true,
withDescription: true,
}); });
let achievements = $ref(); let achievements = $ref();

View file

@ -335,8 +335,7 @@ onBeforeUnmount(() => {
} }
.icon { .icon {
margin-right: 5px; margin-right: 8px;
width: 20px;
} }
.caret { .caret {

View file

@ -15,7 +15,7 @@
<i v-else-if="notification.type === 'mention'" class="ti ti-at"></i> <i v-else-if="notification.type === 'mention'" class="ti ti-at"></i>
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i> <i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i> <i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-military-award"></i> <i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
<!-- notification.reaction null になることはまずないがここでoptional chaining使うと一部ブラウザで刺さるので念の為 --> <!-- notification.reaction null になることはまずないがここでoptional chaining使うと一部ブラウザで刺さるので念の為 -->
<MkReactionIcon <MkReactionIcon
v-else-if="notification.type === 'reaction'" v-else-if="notification.type === 'reaction'"
@ -249,7 +249,7 @@ useTooltip(reactionRef, (showing) => {
.t_achievementEarned { .t_achievementEarned {
padding: 3px; padding: 3px;
background: #88a6b7; background: #cb9a11;
pointer-events: none; pointer-events: none;
} }

View file

@ -21,6 +21,7 @@ import { useTooltip } from '@/scripts/use-tooltip';
import { $i } from '@/account'; import { $i } from '@/account';
import MkReactionEffect from '@/components/MkReactionEffect.vue'; import MkReactionEffect from '@/components/MkReactionEffect.vue';
import { claimAchievement } from '@/scripts/achievements'; import { claimAchievement } from '@/scripts/achievements';
import { defaultStore } from '@/store';
const props = defineProps<{ const props = defineProps<{
reaction: string; reaction: string;
@ -61,6 +62,7 @@ const toggleReaction = () => {
const anime = () => { const anime = () => {
if (document.hidden) return; if (document.hidden) return;
if (!defaultStore.state.animation) return;
const rect = buttonEl.value.getBoundingClientRect(); const rect = buttonEl.value.getBoundingClientRect();
const x = rect.left + 16; const x = rect.left + 16;

View file

@ -6,15 +6,15 @@
<div class="items"> <div class="items">
<template v-for="(item, i) in group.items"> <template v-for="(item, i) in group.items">
<a v-if="item.type === 'a'" :href="item.href" :target="item.target" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }"> <a v-if="item.type === 'a'" :href="item.href" :target="item.target" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }">
<i v-if="item.icon" class="icon ti-fw" :class="item.icon"></i> <span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span>
<span class="text">{{ item.text }}</span> <span class="text">{{ item.text }}</span>
</a> </a>
<button v-else-if="item.type === 'button'" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }" :disabled="item.active" @click="ev => item.action(ev)"> <button v-else-if="item.type === 'button'" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }" :disabled="item.active" @click="ev => item.action(ev)">
<i v-if="item.icon" class="icon ti-fw" :class="item.icon"></i> <span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span>
<span class="text">{{ item.text }}</span> <span class="text">{{ item.text }}</span>
</button> </button>
<MkA v-else :to="item.to" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }"> <MkA v-else :to="item.to" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }">
<i v-if="item.icon" class="icon ti-fw" :class="item.icon"></i> <span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span>
<span class="text">{{ item.text }}</span> <span class="text">{{ item.text }}</span>
</MkA> </MkA>
</template> </template>

View file

@ -33,7 +33,7 @@ const url = computed(() => {
return char2path(char.value); return char2path(char.value);
} else if (props.host == null && !customEmojiName.value.includes('@')) { } else if (props.host == null && !customEmojiName.value.includes('@')) {
const found = customEmojis.value.find(x => x.name === customEmojiName.value); const found = customEmojis.value.find(x => x.name === customEmojiName.value);
return found ? found.url : null; return found ? defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(found.url) : found.url : null;
} else { } else {
const rawUrl = props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`; const rawUrl = props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`;
return defaultStore.state.disableShowingAnimatedImages return defaultStore.state.disableShowingAnimatedImages

View file

@ -190,19 +190,19 @@ export default defineComponent({
return h(MkSparkle, {}, genEl(token.children)); return h(MkSparkle, {}, genEl(token.children));
} }
case 'rotate': { case 'rotate': {
const degrees = parseInt(token.props.args.deg) ?? '90'; const degrees = parseFloat(token.props.args.deg) ?? '90';
style = `transform: rotate(${degrees}deg); transform-origin: center center;`; style = `transform: rotate(${degrees}deg); transform-origin: center center;`;
break; break;
} }
case 'position': { case 'position': {
const x = parseInt(token.props.args.x ?? '0'); const x = parseFloat(token.props.args.x ?? '0');
const y = parseInt(token.props.args.y ?? '0'); const y = parseFloat(token.props.args.y ?? '0');
style = `transform: translateX(${x}em) translateY(${y}em);`; style = `transform: translateX(${x}em) translateY(${y}em);`;
break; break;
} }
case 'scale': { case 'scale': {
const x = Math.min(parseInt(token.props.args.x ?? '1'), 5); const x = Math.min(parseFloat(token.props.args.x ?? '1'), 5);
const y = Math.min(parseInt(token.props.args.y ?? '1'), 5); const y = Math.min(parseFloat(token.props.args.y ?? '1'), 5);
style = `transform: scale(${x}, ${y});`; style = `transform: scale(${x}, ${y});`;
break; break;
} }

View file

@ -105,7 +105,7 @@ export const navbarItemDef = reactive({
}, },
achievements: { achievements: {
title: i18n.ts.achievements, title: i18n.ts.achievements,
icon: 'ti ti-military-award', icon: 'ti ti-medal',
show: computed(() => $i != null), show: computed(() => $i != null),
to: '/my/achievements', to: '/my/achievements',
}, },

View file

@ -40,11 +40,31 @@
</FormSection> </FormSection>
<FormSection> <FormSection>
<template #label>{{ i18n.ts._aboutMisskey.contributors }}</template> <template #label>{{ i18n.ts._aboutMisskey.contributors }}</template>
<div class="_formLinksGrid"> <div :class="$style.contributors">
<FormLink to="https://github.com/syuilo" external>@syuilo</FormLink> <a href="https://github.com/syuilo" target="_blank" :class="$style.contributor">
<FormLink to="https://github.com/tamaina" external>@tamaina</FormLink> <img src="https://avatars.githubusercontent.com/u/4439005?v=4" :class="$style.contributorAvatar">
<FormLink to="https://github.com/acid-chicken" external>@acid-chicken</FormLink> <span :class="$style.contributorUsername">@syuilo</span>
<FormLink to="https://github.com/rinsuki" external>@rinsuki</FormLink> </a>
<a href="https://github.com/tamaina" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/7973572?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@tamaina</span>
</a>
<a href="https://github.com/acid-chicken" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/20679825?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@acid-chicken</span>
</a>
<a href="https://github.com/rinsuki" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/6533808?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@rinsuki</span>
</a>
<a href="https://github.com/mei23" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/30769358?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@mei23</span>
</a>
<a href="https://github.com/robflop" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/8159402?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@robflop</span>
</a>
</div> </div>
<template #caption><MkLink url="https://github.com/misskey-dev/misskey/graphs/contributors">{{ i18n.ts._aboutMisskey.allContributors }}</MkLink></template> <template #caption><MkLink url="https://github.com/misskey-dev/misskey/graphs/contributors">{{ i18n.ts._aboutMisskey.allContributors }}</MkLink></template>
</FormSection> </FormSection>
@ -295,3 +315,38 @@ definePageMetadata({
} }
} }
</style> </style>
<style lang="scss" module>
.contributors {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-gap: 12px;
}
.contributor {
display: flex;
align-items: center;
padding: 12px;
background: var(--buttonBg);
border-radius: 6px;
&:hover {
text-decoration: none;
background: var(--buttonHoverBg);
}
&.active {
color: var(--accent);
background: var(--buttonHoverBg);
}
}
.contributorAvatar {
width: 30px;
border-radius: 100%;
}
.contributorUsername {
margin-left: 12px;
}
</style>

View file

@ -45,7 +45,7 @@ onDeactivated(() => {
definePageMetadata({ definePageMetadata({
title: i18n.ts.achievements, title: i18n.ts.achievements,
icon: 'ti ti-military-award', icon: 'ti ti-medal',
}); });
</script> </script>

View file

@ -38,7 +38,7 @@
<template #label>Access key</template> <template #label>Access key</template>
</MkInput> </MkInput>
<MkInput v-model="objectStorageSecretKey"> <MkInput v-model="objectStorageSecretKey" type="password">
<template #prefix><i class="ti ti-key"></i></template> <template #prefix><i class="ti ti-key"></i></template>
<template #label>Secret key</template> <template #label>Secret key</template>
</MkInput> </MkInput>

View file

@ -1,6 +1,6 @@
<template> <template>
<button class="zuvgdzyu _button" @click="menu"> <button class="zuvgdzyu _button" @click="menu">
<img :src="`/emoji/${emoji.name}.webp`" class="img" loading="lazy"/> <img :src="emoji.url" class="img" loading="lazy"/>
<div class="body"> <div class="body">
<div class="name _monospace">{{ emoji.name }}</div> <div class="name _monospace">{{ emoji.name }}</div>
<div class="info">{{ emoji.aliases.join(' ') }}</div> <div class="info">{{ emoji.aliases.join(' ') }}</div>
@ -15,7 +15,12 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
const props = defineProps<{ const props = defineProps<{
emoji: Record<string, unknown>; // TODO emoji: {
name: string;
aliases: string[];
category: string;
url: string;
};
}>(); }>();
function menu(ev) { function menu(ev) {

View file

@ -1,6 +1,6 @@
<template> <template>
<MkSpacer :content-max="1200"> <MkSpacer :content-max="1200">
<MkAchievements :user="user" :with-locked="false"/> <MkAchievements :user="user" :with-locked="false" :with-description="$i != null && (props.user.id === $i.id)"/>
</MkSpacer> </MkSpacer>
</template> </template>

View file

@ -81,7 +81,7 @@ const headerTabs = $computed(() => user ? [{
}, ...(user.host == null ? [{ }, ...(user.host == null ? [{
key: 'achievements', key: 'achievements',
title: i18n.ts.achievements, title: i18n.ts.achievements,
icon: 'ti ti-military-award', icon: 'ti ti-medal',
}] : []), ...($i && ($i.id === user.id)) || user.publicReactions ? [{ }] : []), ...($i && ($i.id === user.id)) || user.publicReactions ? [{
key: 'reactions', key: 'reactions',
title: i18n.ts.reaction, title: i18n.ts.reaction,

View file

@ -303,7 +303,7 @@ function getButtonOptions(def: values.Value | undefined, call: (fn: values.VFn,
if (primary) utils.assertBoolean(primary); if (primary) utils.assertBoolean(primary);
const rounded = def.value.get('rounded'); const rounded = def.value.get('rounded');
if (rounded) utils.assertBoolean(rounded); if (rounded) utils.assertBoolean(rounded);
const disabled = button.value.get('disabled'); const disabled = def.value.get('disabled');
if (disabled) utils.assertBoolean(disabled); if (disabled) utils.assertBoolean(disabled);
return { return {

View file

@ -127,11 +127,13 @@ hr {
} }
.ti { .ti {
vertical-align: -10%; vertical-align: -40%;
line-height: 0.9em; line-height: 1em;
&:before { &:before {
font-size: 130%; display: inline-block;
font-size: 165%;
width: 0.74em;
} }
} }

View file

@ -54,6 +54,8 @@ export default defineConfig(({ command, mode }) => {
'@/': __dirname + '/src/', '@/': __dirname + '/src/',
'/client-assets/': __dirname + '/assets/', '/client-assets/': __dirname + '/assets/',
'/static-assets/': __dirname + '/../backend/assets/', '/static-assets/': __dirname + '/../backend/assets/',
'/fluent-emojis/': __dirname + '/../../fluent-emojis/dist/',
'/fluent-emoji/': __dirname + '/../../fluent-emojis/dist/',
}, },
}, },

View file

@ -11,8 +11,8 @@ importers:
'@tensorflow/tfjs-core': ^4.2.0 '@tensorflow/tfjs-core': ^4.2.0
'@types/gulp': 4.0.10 '@types/gulp': 4.0.10
'@types/gulp-rename': 2.0.1 '@types/gulp-rename': 2.0.1
'@typescript-eslint/eslint-plugin': 5.48.2 '@typescript-eslint/eslint-plugin': 5.49.0
'@typescript-eslint/parser': 5.48.2 '@typescript-eslint/parser': 5.49.0
cross-env: 7.0.3 cross-env: 7.0.3
cypress: 12.3.0 cypress: 12.3.0
eslint: ^8.32.0 eslint: ^8.32.0
@ -23,7 +23,7 @@ importers:
gulp-replace: 1.1.4 gulp-replace: 1.1.4
gulp-terser: 2.1.0 gulp-terser: 2.1.0
js-yaml: 4.1.0 js-yaml: 4.1.0
start-server-and-test: 1.15.2 start-server-and-test: 1.15.3
typescript: 4.9.4 typescript: 4.9.4
dependencies: dependencies:
execa: 5.1.1 execa: 5.1.1
@ -39,18 +39,18 @@ importers:
devDependencies: devDependencies:
'@types/gulp': 4.0.10 '@types/gulp': 4.0.10
'@types/gulp-rename': 2.0.1 '@types/gulp-rename': 2.0.1
'@typescript-eslint/eslint-plugin': 5.48.2_caon6io6stgpr7lz2rtbhekxqy '@typescript-eslint/eslint-plugin': 5.49.0_iu322prlnwsygkcra5kbpy22si
'@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
cross-env: 7.0.3 cross-env: 7.0.3
cypress: 12.3.0 cypress: 12.3.0
eslint: 8.32.0 eslint: 8.32.0
start-server-and-test: 1.15.2 start-server-and-test: 1.15.3
packages/backend: packages/backend:
specifiers: specifiers:
'@bull-board/api': ^4.10.2 '@bull-board/api': ^4.11.0
'@bull-board/fastify': ^4.10.2 '@bull-board/fastify': ^4.11.0
'@bull-board/ui': ^4.10.2 '@bull-board/ui': ^4.11.0
'@discordapp/twemoji': 14.0.2 '@discordapp/twemoji': 14.0.2
'@fastify/accepts': 4.1.0 '@fastify/accepts': 4.1.0
'@fastify/cookie': ^8.3.0 '@fastify/cookie': ^8.3.0
@ -68,8 +68,8 @@ importers:
'@swc/cli': ^0.1.59 '@swc/cli': ^0.1.59
'@swc/core': 1.3.27 '@swc/core': 1.3.27
'@swc/jest': 0.2.24 '@swc/jest': 0.2.24
'@tensorflow/tfjs': ^4.1.0 '@tensorflow/tfjs': ^4.2.0
'@tensorflow/tfjs-node': 4.1.0 '@tensorflow/tfjs-node': 4.2.0
'@types/accepts': 1.3.5 '@types/accepts': 1.3.5
'@types/archiver': 5.3.1 '@types/archiver': 5.3.1
'@types/bcryptjs': 2.4.2 '@types/bcryptjs': 2.4.2
@ -112,8 +112,8 @@ importers:
'@types/web-push': 3.3.2 '@types/web-push': 3.3.2
'@types/websocket': 1.0.5 '@types/websocket': 1.0.5
'@types/ws': 8.5.4 '@types/ws': 8.5.4
'@typescript-eslint/eslint-plugin': 5.48.2 '@typescript-eslint/eslint-plugin': 5.49.0
'@typescript-eslint/parser': 5.48.2 '@typescript-eslint/parser': 5.49.0
accepts: ^1.3.8 accepts: ^1.3.8
ajv: 8.12.0 ajv: 8.12.0
archiver: 5.3.1 archiver: 5.3.1
@ -142,7 +142,7 @@ importers:
file-type: 18.2.0 file-type: 18.2.0
fluent-ffmpeg: 2.1.2 fluent-ffmpeg: 2.1.2
form-data: ^4.0.0 form-data: ^4.0.0
got: 12.5.3 got: ^12.5.3
hpagent: 1.2.0 hpagent: 1.2.0
ioredis: 4.28.5 ioredis: 4.28.5
ip-cidr: 3.0.11 ip-cidr: 3.0.11
@ -150,9 +150,8 @@ importers:
jest: 29.3.1 jest: 29.3.1
jest-mock: ^29.3.1 jest-mock: ^29.3.1
js-yaml: 4.1.0 js-yaml: 4.1.0
jsdom: 21.0.0 jsdom: 21.1.0
json5: 2.2.3 json5: 2.2.3
json5-loader: 4.0.1
jsonld: 8.1.0 jsonld: 8.1.0
jsrsasign: 10.6.1 jsrsasign: 10.6.1
mfm-js: 0.23.3 mfm-js: 0.23.3
@ -202,7 +201,6 @@ importers:
typeorm: 0.3.11 typeorm: 0.3.11
typescript: 4.9.4 typescript: 4.9.4
ulid: 2.3.0 ulid: 2.3.0
undici: ^5.15.1
unzipper: 0.10.11 unzipper: 0.10.11
uuid: 9.0.0 uuid: 9.0.0
vary: 1.1.2 vary: 1.1.2
@ -211,9 +209,9 @@ importers:
ws: 8.12.0 ws: 8.12.0
xev: 3.0.2 xev: 3.0.2
dependencies: dependencies:
'@bull-board/api': 4.10.2 '@bull-board/api': 4.11.0
'@bull-board/fastify': 4.10.2 '@bull-board/fastify': 4.11.0
'@bull-board/ui': 4.10.2 '@bull-board/ui': 4.11.0
'@discordapp/twemoji': 14.0.2 '@discordapp/twemoji': 14.0.2
'@fastify/accepts': 4.1.0 '@fastify/accepts': 4.1.0
'@fastify/cookie': 8.3.0 '@fastify/cookie': 8.3.0
@ -257,9 +255,8 @@ importers:
ip-cidr: 3.0.11 ip-cidr: 3.0.11
is-svg: 4.3.2 is-svg: 4.3.2
js-yaml: 4.1.0 js-yaml: 4.1.0
jsdom: 21.0.0 jsdom: 21.1.0
json5: 2.2.3 json5: 2.2.3
json5-loader: 4.0.1
jsonld: 8.1.0 jsonld: 8.1.0
jsrsasign: 10.6.1 jsrsasign: 10.6.1
mfm-js: 0.23.3 mfm-js: 0.23.3
@ -267,8 +264,9 @@ importers:
misskey-js: 0.0.14 misskey-js: 0.0.14
ms: 3.0.0-canary.1 ms: 3.0.0-canary.1
nested-property: 4.0.0 nested-property: 4.0.0
node-fetch: 3.3.0
nodemailer: 6.9.0 nodemailer: 6.9.0
nsfwjs: 2.4.2_@tensorflow+tfjs@4.1.0 nsfwjs: 2.4.2_@tensorflow+tfjs@4.2.0
oauth: 0.10.0 oauth: 0.10.0
os-utils: 0.0.14 os-utils: 0.0.14
parse5: 7.1.2 parse5: 7.1.2
@ -308,7 +306,6 @@ importers:
typeorm: 0.3.11_ioredis@4.28.5+pg@8.8.0 typeorm: 0.3.11_ioredis@4.28.5+pg@8.8.0
typescript: 4.9.4 typescript: 4.9.4
ulid: 2.3.0 ulid: 2.3.0
undici: 5.15.1
unzipper: 0.10.11 unzipper: 0.10.11
uuid: 9.0.0 uuid: 9.0.0
vary: 1.1.2 vary: 1.1.2
@ -317,8 +314,8 @@ importers:
ws: 8.12.0 ws: 8.12.0
xev: 3.0.2 xev: 3.0.2
optionalDependencies: optionalDependencies:
'@tensorflow/tfjs': 4.1.0_seedrandom@3.0.5 '@tensorflow/tfjs': 4.2.0_seedrandom@3.0.5
'@tensorflow/tfjs-node': 4.1.0_seedrandom@3.0.5 '@tensorflow/tfjs-node': 4.2.0_seedrandom@3.0.5
devDependencies: devDependencies:
'@redocly/openapi-core': 1.0.0-beta.120 '@redocly/openapi-core': 1.0.0-beta.120
'@swc/cli': 0.1.59_2w2rsb5d2wh3txrlxuiknf4vra '@swc/cli': 0.1.59_2w2rsb5d2wh3txrlxuiknf4vra
@ -366,15 +363,14 @@ importers:
'@types/web-push': 3.3.2 '@types/web-push': 3.3.2
'@types/websocket': 1.0.5 '@types/websocket': 1.0.5
'@types/ws': 8.5.4 '@types/ws': 8.5.4
'@typescript-eslint/eslint-plugin': 5.48.2_caon6io6stgpr7lz2rtbhekxqy '@typescript-eslint/eslint-plugin': 5.49.0_iu322prlnwsygkcra5kbpy22si
'@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
cross-env: 7.0.3 cross-env: 7.0.3
eslint: 8.32.0 eslint: 8.32.0
eslint-plugin-import: 2.27.5_2l6piu6guil2f63lj3qmhzbnn4 eslint-plugin-import: 2.27.5_6savw6y3b7jng6f64kgkyoij64
execa: 6.1.0 execa: 6.1.0
jest: 29.3.1_@types+node@18.11.18 jest: 29.3.1_@types+node@18.11.18
jest-mock: 29.3.1 jest-mock: 29.3.1
node-fetch: 3.3.0
packages/frontend: packages/frontend:
specifiers: specifiers:
@ -383,7 +379,7 @@ importers:
'@rollup/plugin-json': 6.0.0 '@rollup/plugin-json': 6.0.0
'@rollup/pluginutils': 5.0.2 '@rollup/pluginutils': 5.0.2
'@syuilo/aiscript': 0.12.2 '@syuilo/aiscript': 0.12.2
'@tabler/icons': ^1.118.0 '@tabler/icons-webfont': ^2.0.0
'@types/escape-regexp': 0.0.1 '@types/escape-regexp': 0.0.1
'@types/glob': 8.0.1 '@types/glob': 8.0.1
'@types/gulp': 4.0.10 '@types/gulp': 4.0.10
@ -398,8 +394,8 @@ importers:
'@types/uuid': 9.0.0 '@types/uuid': 9.0.0
'@types/websocket': 1.0.5 '@types/websocket': 1.0.5
'@types/ws': 8.5.4 '@types/ws': 8.5.4
'@typescript-eslint/eslint-plugin': 5.48.2 '@typescript-eslint/eslint-plugin': 5.49.0
'@typescript-eslint/parser': 5.48.2 '@typescript-eslint/parser': 5.49.0
'@vitejs/plugin-vue': 4.0.0 '@vitejs/plugin-vue': 4.0.0
'@vue/compiler-sfc': 3.2.45 '@vue/compiler-sfc': 3.2.45
'@vue/runtime-core': 3.2.45 '@vue/runtime-core': 3.2.45
@ -442,7 +438,7 @@ importers:
sanitize-html: ^2.8.1 sanitize-html: ^2.8.1
sass: 1.57.1 sass: 1.57.1
seedrandom: 3.0.5 seedrandom: 3.0.5
start-server-and-test: 1.15.2 start-server-and-test: 1.15.3
strict-event-emitter-types: 2.0.0 strict-event-emitter-types: 2.0.0
stringz: 2.1.0 stringz: 2.1.0
syuilo-password-strength: 0.0.1 syuilo-password-strength: 0.0.1
@ -468,7 +464,7 @@ importers:
'@rollup/plugin-json': 6.0.0_rollup@3.10.1 '@rollup/plugin-json': 6.0.0_rollup@3.10.1
'@rollup/pluginutils': 5.0.2_rollup@3.10.1 '@rollup/pluginutils': 5.0.2_rollup@3.10.1
'@syuilo/aiscript': 0.12.2 '@syuilo/aiscript': 0.12.2
'@tabler/icons': 1.119.0 '@tabler/icons-webfont': 2.0.0
'@vitejs/plugin-vue': 4.0.0_vite@4.0.4+vue@3.2.45 '@vitejs/plugin-vue': 4.0.0_vite@4.0.4+vue@3.2.45
'@vue/compiler-sfc': 3.2.45 '@vue/compiler-sfc': 3.2.45
autobind-decorator: 2.4.0 autobind-decorator: 2.4.0
@ -537,15 +533,15 @@ importers:
'@types/uuid': 9.0.0 '@types/uuid': 9.0.0
'@types/websocket': 1.0.5 '@types/websocket': 1.0.5
'@types/ws': 8.5.4 '@types/ws': 8.5.4
'@typescript-eslint/eslint-plugin': 5.48.2_caon6io6stgpr7lz2rtbhekxqy '@typescript-eslint/eslint-plugin': 5.49.0_iu322prlnwsygkcra5kbpy22si
'@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@vue/runtime-core': 3.2.45 '@vue/runtime-core': 3.2.45
cross-env: 7.0.3 cross-env: 7.0.3
cypress: 12.3.0 cypress: 12.3.0
eslint: 8.32.0 eslint: 8.32.0
eslint-plugin-import: 2.27.5_2l6piu6guil2f63lj3qmhzbnn4 eslint-plugin-import: 2.27.5_6savw6y3b7jng6f64kgkyoij64
eslint-plugin-vue: 9.9.0_eslint@8.32.0 eslint-plugin-vue: 9.9.0_eslint@8.32.0
start-server-and-test: 1.15.2 start-server-and-test: 1.15.3
vue-eslint-parser: 9.1.0_eslint@8.32.0 vue-eslint-parser: 9.1.0_eslint@8.32.0
vue-tsc: 1.0.24_typescript@4.9.4 vue-tsc: 1.0.24_typescript@4.9.4
@ -915,17 +911,17 @@ packages:
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
dev: true dev: true
/@bull-board/api/4.10.2: /@bull-board/api/4.11.0:
resolution: {integrity: sha512-lRHo0A7hsz71aOx1ZN0SmLLWfSuvKdL6EZ4imlgo5SuXGozybvlRc5KPIJU2/E1w5meoUGi+nFezBwp1gT/SMw==} resolution: {integrity: sha512-qFnG63s3BkaslsNnXYagEUcdeK9SijZTJ+I4vMU+OiZt9VlKh01X1KjNlqjF9guvWcjk+Rg8UOMm0fWwM6PK6g==}
dependencies: dependencies:
redis-info: 3.1.0 redis-info: 3.1.0
dev: false dev: false
/@bull-board/fastify/4.10.2: /@bull-board/fastify/4.11.0:
resolution: {integrity: sha512-yp/TlfyfMBgR6vibyCUBOTKn2BFlBSLxkJxzlvIcMDs2Vl3PMXMs4YoCr2o3m+dXxSNzpTfomxAc5XQfJdp0VQ==} resolution: {integrity: sha512-G4sAFVx5kGT5T/F2gL91RjZ2+YrMHNrLWoVo/QfHMcZe3RoOP4PpbOLgLC/O67KYn3JK6t8ysGyyP035OSJ2HA==}
dependencies: dependencies:
'@bull-board/api': 4.10.2 '@bull-board/api': 4.11.0
'@bull-board/ui': 4.10.2 '@bull-board/ui': 4.11.0
'@fastify/static': 6.6.1 '@fastify/static': 6.6.1
'@fastify/view': 7.4.0 '@fastify/view': 7.4.0
ejs: 3.1.8 ejs: 3.1.8
@ -933,10 +929,10 @@ packages:
- supports-color - supports-color
dev: false dev: false
/@bull-board/ui/4.10.2: /@bull-board/ui/4.11.0:
resolution: {integrity: sha512-vaHGojG5D3xjnaed3nwOaLy4Y06RgDJdYRaFR5E06SjZ0vOvjVYGD6s4cykK512Aw/ElFhKDPwzhf8BvpwAtDQ==} resolution: {integrity: sha512-/Yb7x/3tWxysA2jRDQ89xEPnscvfGQdf4MmDRzWH5lDkVmL8b1HvZAQxLrHcxwB6y16oorQTf/1KbRZl0rJDHg==}
dependencies: dependencies:
'@bull-board/api': 4.10.2 '@bull-board/api': 4.11.0
dev: false dev: false
/@chainsafe/is-ip/2.0.1: /@chainsafe/is-ip/2.0.1:
@ -1077,7 +1073,7 @@ packages:
dependencies: dependencies:
ky: 0.30.0 ky: 0.30.0
ky-universal: 0.10.1_ky@0.30.0 ky-universal: 0.10.1_ky@0.30.0
undici: 5.15.1 undici: 5.16.0
transitivePeerDependencies: transitivePeerDependencies:
- web-streams-polyfill - web-streams-polyfill
dev: false dev: false
@ -1402,7 +1398,7 @@ packages:
fastify-plugin: 4.5.0 fastify-plugin: 4.5.0
pump: 3.0.0 pump: 3.0.0
tiny-lru: 10.0.1 tiny-lru: 10.0.1
undici: 5.15.1 undici: 5.16.0
dev: false dev: false
/@fastify/send/1.0.0: /@fastify/send/1.0.0:
@ -2323,65 +2319,47 @@ packages:
defer-to-connect: 2.0.1 defer-to-connect: 2.0.1
dev: false dev: false
/@tabler/icons/1.119.0: /@tabler/icons-webfont/2.0.0:
resolution: {integrity: sha512-Fk3Qq4w2SXcTjc/n1cuL5bccPkylrOMo7cYpQIf/yw6zP76LQV9dtLcHQUjFiUnaYuswR645CnURIhlafyAh9g==} resolution: {integrity: sha512-ApVVupe7WKZOJzK6T2iw15/k6VrTALsL5YzAmvgvcriuX8sRCKlcWaRljcf2sZMUrqyY+Yq6xiOpL2p2NHgQBQ==}
peerDependencies: dependencies:
react: ^16.x || 17.x || 18.x '@tabler/icons': 2.0.0
react-dom: ^16.x || 17.x || 18.x
peerDependenciesMeta:
react:
optional: true
react-dom:
optional: true
dev: false dev: false
/@tensorflow/tfjs-backend-cpu/4.1.0_npjwttp6o2hhjgfcmiedqvkgoa: /@tabler/icons/2.0.0:
resolution: {integrity: sha512-NqxrwpYa/hXGaBa1RzxfHsLAsaniIZryhF5CxQM9uSp1ny8wUJMH+Mda/Y8+llS3weHug8JDAbAW2cabn8l84A==} resolution: {integrity: sha512-ye93cVD8baCwJJ7J3GKlUM3FN+qW6lsEz4uaH8bHCwC8un2R4p+ZzyRNc/ksqVgMQJ4PKQ8xbYpv4dnbbRffsA==}
dev: false
/@tensorflow/tfjs-backend-cpu/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y:
resolution: {integrity: sha512-8HWg9J69m0Ovc6w8TVhhixMOcwA3t/NPXLblOA/sgJ+/JD5gsbpLWJk4QISQyb1RnpSVzw6PX3BSMTJU7hWVOg==}
engines: {yarn: '>= 1.3.2'} engines: {yarn: '>= 1.3.2'}
peerDependencies: peerDependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
dependencies: dependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
'@types/seedrandom': 2.4.30 '@types/seedrandom': 2.4.30
seedrandom: 3.0.5 seedrandom: 3.0.5
dev: false dev: false
/@tensorflow/tfjs-backend-webgl/4.1.0_npjwttp6o2hhjgfcmiedqvkgoa: /@tensorflow/tfjs-backend-webgl/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y:
resolution: {integrity: sha512-RDjwbFCPESjh+QTrTvKC623MO58gIqxQvtX3DfJLhlsSbnsvIpA5s1CXNJYzNVmFDia35mPYKmQQWvEvhl9weA==} resolution: {integrity: sha512-Qvf+hD5pSh+xi48kChSGzcDKJemkc4EKfoVVjuxl4k25ZUPwuEd7zZUAtinkLu1dzgHNyvePZY8k+9rVm59HJA==}
engines: {yarn: '>= 1.3.2'} engines: {yarn: '>= 1.3.2'}
peerDependencies: peerDependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
dependencies: dependencies:
'@tensorflow/tfjs-backend-cpu': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa '@tensorflow/tfjs-backend-cpu': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
'@types/offscreencanvas': 2019.3.0 '@types/offscreencanvas': 2019.3.0
'@types/seedrandom': 2.4.30 '@types/seedrandom': 2.4.30
'@types/webgl-ext': 0.0.30 '@types/webgl-ext': 0.0.30
seedrandom: 3.0.5 seedrandom: 3.0.5
dev: false dev: false
/@tensorflow/tfjs-converter/4.1.0_npjwttp6o2hhjgfcmiedqvkgoa: /@tensorflow/tfjs-converter/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y:
resolution: {integrity: sha512-pR4TSUI949a/5uUWjHga8xzxD7Y9AbobHJtCmg86Bldfl2GV8aibz87cNjpoO+iUhH8WZo1TOJy8GpM+MPT2DA==} resolution: {integrity: sha512-m+E2KJM6yGQdi8ElzWpChdD/JaqhWMCi9yK70v/ndkOaCL2q2UN48nYP2T5S15vkDvMIgzAQyZfh7hxQsMuvRQ==}
peerDependencies: peerDependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
dependencies: dependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
dev: false
/@tensorflow/tfjs-core/4.1.0:
resolution: {integrity: sha512-zERD4xtxNq3dV3+wPEMi2HWSV68FA8WucSAogzErp38/q98Byv9G1x8DhxQ+jowTcqN4srGWcBfK59jYwjlAvA==}
engines: {yarn: '>= 1.3.2'}
dependencies:
'@types/long': 4.0.2
'@types/offscreencanvas': 2019.7.0
'@types/seedrandom': 2.4.30
'@types/webgl-ext': 0.0.30
'@webgpu/types': 0.1.21
long: 4.0.0
node-fetch: 2.6.7
seedrandom: 3.0.5
transitivePeerDependencies:
- encoding
dev: false dev: false
/@tensorflow/tfjs-core/4.2.0: /@tensorflow/tfjs-core/4.2.0:
@ -2400,15 +2378,14 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
dev: false dev: false
optional: true
/@tensorflow/tfjs-data/4.1.0_x6uqorr55fevqojbxncmwlp444: /@tensorflow/tfjs-data/4.2.0_qsavyspjcgrxymzlcpasp6rzxe:
resolution: {integrity: sha512-H6ef6NXPwi2xKYB6tVNZi5RqniMFpfUSlxG3q0BNxnyuyeCUSjJvHJFpah9hT/ysYjVdwspzh/I6B67h+lBchg==} resolution: {integrity: sha512-11t7Q+ikseduJgkd9iSeRrtor1aA3o5PVCFhC5yYvR3JLO55ic1+4Ryo0EJfhRoismS6zBUJrpzX4K0zlLbIfw==}
peerDependencies: peerDependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
seedrandom: ^3.0.5 seedrandom: ^3.0.5
dependencies: dependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
'@types/node-fetch': 2.6.2 '@types/node-fetch': 2.6.2
node-fetch: 2.6.7 node-fetch: 2.6.7
seedrandom: 3.0.5 seedrandom: 3.0.5
@ -2417,21 +2394,21 @@ packages:
- encoding - encoding
dev: false dev: false
/@tensorflow/tfjs-layers/4.1.0_npjwttp6o2hhjgfcmiedqvkgoa: /@tensorflow/tfjs-layers/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y:
resolution: {integrity: sha512-lzHNTZu1GwKl7hW5tt2COSpflE0m7xrsOf8AzRzpTDVJYYRx/x5ScMt/y//5jbRuaDOnb3EjT1FxWxwkD44/sg==} resolution: {integrity: sha512-SO0KTmCFOjrW+PlP9nKYXz07XGFq6uE7am9yH2bRaRPWpEeaKT/+k0C9vFMxI/GzRwY8AK4sLe4U+jE1mhYxGw==}
peerDependencies: peerDependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
dependencies: dependencies:
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
dev: false dev: false
/@tensorflow/tfjs-node/4.1.0_seedrandom@3.0.5: /@tensorflow/tfjs-node/4.2.0_seedrandom@3.0.5:
resolution: {integrity: sha512-2H7UJqVafuM9fbsMdzUkcfWLpH/owgvVHWES+gQsiueIqyOjpq6ZGSQLDxyuKtHP2D/8/kWeVIbnzAjnIRniuA==} resolution: {integrity: sha512-dkyExfqTjMVDpKLBzHH2b7JWzGK+QORtYswvoNHbeHwx7kvYYRAQeiHxp+xrgry6LdbWfZs88IWCwNGoOiZ21w==}
engines: {node: '>=8.11.0'} engines: {node: '>=8.11.0'}
requiresBuild: true requiresBuild: true
dependencies: dependencies:
'@mapbox/node-pre-gyp': 1.0.9 '@mapbox/node-pre-gyp': 1.0.9
'@tensorflow/tfjs': 4.1.0_seedrandom@3.0.5 '@tensorflow/tfjs': 4.2.0_seedrandom@3.0.5
adm-zip: 0.5.10 adm-zip: 0.5.10
google-protobuf: 3.21.2 google-protobuf: 3.21.2
https-proxy-agent: 2.2.4 https-proxy-agent: 2.2.4
@ -2445,17 +2422,16 @@ packages:
dev: false dev: false
optional: true optional: true
/@tensorflow/tfjs/4.1.0_seedrandom@3.0.5: /@tensorflow/tfjs/4.2.0_seedrandom@3.0.5:
resolution: {integrity: sha512-jlrJ6MIBos8NkmF+NHIWBnKVBGYJTG06QmW/A0vgyXwkp+3PgzX8TJ4MWIv/7oZr7g27zfY6dXA1OFzrrgvklA==} resolution: {integrity: sha512-iZmtyGC9IJkx+TpFnkgDol8BHv2BU3zJ01HyNcuvnm1w1EqoNe+1n8bwvLzI/sxHMcHTqzuu7VugMaphryxE+A==}
hasBin: true hasBin: true
requiresBuild: true
dependencies: dependencies:
'@tensorflow/tfjs-backend-cpu': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa '@tensorflow/tfjs-backend-cpu': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y
'@tensorflow/tfjs-backend-webgl': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa '@tensorflow/tfjs-backend-webgl': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y
'@tensorflow/tfjs-converter': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa '@tensorflow/tfjs-converter': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y
'@tensorflow/tfjs-core': 4.1.0 '@tensorflow/tfjs-core': 4.2.0
'@tensorflow/tfjs-data': 4.1.0_x6uqorr55fevqojbxncmwlp444 '@tensorflow/tfjs-data': 4.2.0_qsavyspjcgrxymzlcpasp6rzxe
'@tensorflow/tfjs-layers': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa '@tensorflow/tfjs-layers': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y
argparse: 1.0.10 argparse: 1.0.10
chalk: 4.1.2 chalk: 4.1.2
core-js: 3.27.1 core-js: 3.27.1
@ -2669,6 +2645,7 @@ packages:
/@types/json-schema/7.0.11: /@types/json-schema/7.0.11:
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
dev: true
/@types/json5/0.0.29: /@types/json5/0.0.29:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
@ -2956,8 +2933,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@typescript-eslint/eslint-plugin/5.48.2_caon6io6stgpr7lz2rtbhekxqy: /@typescript-eslint/eslint-plugin/5.49.0_iu322prlnwsygkcra5kbpy22si:
resolution: {integrity: sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==} resolution: {integrity: sha512-IhxabIpcf++TBaBa1h7jtOWyon80SXPRLDq0dVz5SLFC/eW6tofkw/O7Ar3lkx5z5U6wzbKDrl2larprp5kk5Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': ^5.0.0 '@typescript-eslint/parser': ^5.0.0
@ -2967,10 +2944,10 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/scope-manager': 5.48.2 '@typescript-eslint/scope-manager': 5.49.0
'@typescript-eslint/type-utils': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/type-utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/utils': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje
debug: 4.3.4 debug: 4.3.4
eslint: 8.32.0 eslint: 8.32.0
ignore: 5.2.4 ignore: 5.2.4
@ -3003,8 +2980,8 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/parser/5.48.2_7uibuqfxkfaozanbtbziikiqje: /@typescript-eslint/parser/5.49.0_7uibuqfxkfaozanbtbziikiqje:
resolution: {integrity: sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==} resolution: {integrity: sha512-veDlZN9mUhGqU31Qiv2qEp+XrJj5fgZpJ8PW30sHU+j/8/e5ruAhLaVDAeznS7A7i4ucb/s8IozpDtt9NqCkZg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
@ -3013,9 +2990,9 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/scope-manager': 5.48.2 '@typescript-eslint/scope-manager': 5.49.0
'@typescript-eslint/types': 5.48.2 '@typescript-eslint/types': 5.49.0
'@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.4 '@typescript-eslint/typescript-estree': 5.49.0_typescript@4.9.4
debug: 4.3.4 debug: 4.3.4
eslint: 8.32.0 eslint: 8.32.0
typescript: 4.9.4 typescript: 4.9.4
@ -3031,16 +3008,16 @@ packages:
'@typescript-eslint/visitor-keys': 5.48.1 '@typescript-eslint/visitor-keys': 5.48.1
dev: true dev: true
/@typescript-eslint/scope-manager/5.48.2: /@typescript-eslint/scope-manager/5.49.0:
resolution: {integrity: sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==} resolution: {integrity: sha512-clpROBOiMIzpbWNxCe1xDK14uPZh35u4QaZO1GddilEzoCLAEz4szb51rBpdgurs5k2YzPtJeTEN3qVbG+LRUQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies: dependencies:
'@typescript-eslint/types': 5.48.2 '@typescript-eslint/types': 5.49.0
'@typescript-eslint/visitor-keys': 5.48.2 '@typescript-eslint/visitor-keys': 5.49.0
dev: true dev: true
/@typescript-eslint/type-utils/5.48.2_7uibuqfxkfaozanbtbziikiqje: /@typescript-eslint/type-utils/5.49.0_7uibuqfxkfaozanbtbziikiqje:
resolution: {integrity: sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==} resolution: {integrity: sha512-eUgLTYq0tR0FGU5g1YHm4rt5H/+V2IPVkP0cBmbhRyEmyGe4XvJ2YJ6sYTmONfjmdMqyMLad7SB8GvblbeESZA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
eslint: '*' eslint: '*'
@ -3049,8 +3026,8 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.4 '@typescript-eslint/typescript-estree': 5.49.0_typescript@4.9.4
'@typescript-eslint/utils': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje
debug: 4.3.4 debug: 4.3.4
eslint: 8.32.0 eslint: 8.32.0
tsutils: 3.21.0_typescript@4.9.4 tsutils: 3.21.0_typescript@4.9.4
@ -3064,8 +3041,8 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
/@typescript-eslint/types/5.48.2: /@typescript-eslint/types/5.49.0:
resolution: {integrity: sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==} resolution: {integrity: sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
@ -3090,8 +3067,8 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/typescript-estree/5.48.2_typescript@4.9.4: /@typescript-eslint/typescript-estree/5.49.0_typescript@4.9.4:
resolution: {integrity: sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==} resolution: {integrity: sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
@ -3099,8 +3076,8 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/types': 5.48.2 '@typescript-eslint/types': 5.49.0
'@typescript-eslint/visitor-keys': 5.48.2 '@typescript-eslint/visitor-keys': 5.49.0
debug: 4.3.4 debug: 4.3.4
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
@ -3111,17 +3088,17 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/utils/5.48.2_7uibuqfxkfaozanbtbziikiqje: /@typescript-eslint/utils/5.49.0_7uibuqfxkfaozanbtbziikiqje:
resolution: {integrity: sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==} resolution: {integrity: sha512-cPJue/4Si25FViIb74sHCLtM4nTSBXtLx1d3/QT6mirQ/c65bV8arBEebBJJizfq8W2YyMoPI/WWPFWitmNqnQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies: dependencies:
'@types/json-schema': 7.0.11 '@types/json-schema': 7.0.11
'@types/semver': 7.3.13 '@types/semver': 7.3.13
'@typescript-eslint/scope-manager': 5.48.2 '@typescript-eslint/scope-manager': 5.49.0
'@typescript-eslint/types': 5.48.2 '@typescript-eslint/types': 5.49.0
'@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.4 '@typescript-eslint/typescript-estree': 5.49.0_typescript@4.9.4
eslint: 8.32.0 eslint: 8.32.0
eslint-scope: 5.1.1 eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@8.32.0 eslint-utils: 3.0.0_eslint@8.32.0
@ -3139,11 +3116,11 @@ packages:
eslint-visitor-keys: 3.3.0 eslint-visitor-keys: 3.3.0
dev: true dev: true
/@typescript-eslint/visitor-keys/5.48.2: /@typescript-eslint/visitor-keys/5.49.0:
resolution: {integrity: sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==} resolution: {integrity: sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies: dependencies:
'@typescript-eslint/types': 5.48.2 '@typescript-eslint/types': 5.49.0
eslint-visitor-keys: 3.3.0 eslint-visitor-keys: 3.3.0
dev: true dev: true
@ -3386,14 +3363,6 @@ packages:
ajv: 8.12.0 ajv: 8.12.0
dev: false dev: false
/ajv-keywords/3.5.2_ajv@6.12.6:
resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
peerDependencies:
ajv: ^6.9.1
dependencies:
ajv: 6.12.6
dev: false
/ajv/6.12.6: /ajv/6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
dependencies: dependencies:
@ -3835,10 +3804,11 @@ packages:
- debug - debug
dev: false dev: false
/axios/0.25.0_debug@4.3.4: /axios/0.27.2_debug@4.3.4:
resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
dependencies: dependencies:
follow-redirects: 1.15.2 follow-redirects: 1.15.2
form-data: 4.0.0
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug
dev: true dev: true
@ -3978,10 +3948,6 @@ packages:
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
dev: false dev: false
/big.js/5.2.2:
resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
dev: false
/bin-check/4.1.0: /bin-check/4.1.0:
resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==} resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -5671,11 +5637,6 @@ packages:
/emoji-regex/8.0.0: /emoji-regex/8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
/emojis-list/3.0.0:
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
engines: {node: '>= 4'}
dev: false
/encode-utf8/1.0.3: /encode-utf8/1.0.3:
resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
dev: false dev: false
@ -6109,7 +6070,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/eslint-module-utils/2.7.4_kvyj4idustix6trhy5lyssy2sq: /eslint-module-utils/2.7.4_cnxxylyx37asr43xy64ejg3pwe:
resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==}
engines: {node: '>=4'} engines: {node: '>=4'}
peerDependencies: peerDependencies:
@ -6130,7 +6091,7 @@ packages:
eslint-import-resolver-webpack: eslint-import-resolver-webpack:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
debug: 3.2.7 debug: 3.2.7
eslint: 8.32.0 eslint: 8.32.0
eslint-import-resolver-node: 0.3.7 eslint-import-resolver-node: 0.3.7
@ -6200,7 +6161,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/eslint-plugin-import/2.27.5_2l6piu6guil2f63lj3qmhzbnn4: /eslint-plugin-import/2.27.5_6savw6y3b7jng6f64kgkyoij64:
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
engines: {node: '>=4'} engines: {node: '>=4'}
peerDependencies: peerDependencies:
@ -6210,7 +6171,7 @@ packages:
'@typescript-eslint/parser': '@typescript-eslint/parser':
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
array-includes: 3.1.6 array-includes: 3.1.6
array.prototype.flat: 1.3.1 array.prototype.flat: 1.3.1
array.prototype.flatmap: 1.3.1 array.prototype.flatmap: 1.3.1
@ -6218,7 +6179,7 @@ packages:
doctrine: 2.1.0 doctrine: 2.1.0
eslint: 8.32.0 eslint: 8.32.0
eslint-import-resolver-node: 0.3.7 eslint-import-resolver-node: 0.3.7
eslint-module-utils: 2.7.4_kvyj4idustix6trhy5lyssy2sq eslint-module-utils: 2.7.4_cnxxylyx37asr43xy64ejg3pwe
has: 1.0.3 has: 1.0.3
is-core-module: 2.11.0 is-core-module: 2.11.0
is-glob: 4.0.3 is-glob: 4.0.3
@ -7069,7 +7030,6 @@ packages:
asynckit: 0.4.0 asynckit: 0.4.0
combined-stream: 1.0.8 combined-stream: 1.0.8
mime-types: 2.1.35 mime-types: 2.1.35
dev: false
/formdata-polyfill/4.0.10: /formdata-polyfill/4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
@ -9125,8 +9085,8 @@ packages:
engines: {node: '>=0.1.90'} engines: {node: '>=0.1.90'}
dev: false dev: false
/jsdom/21.0.0: /jsdom/21.1.0:
resolution: {integrity: sha512-AIw+3ZakSUtDYvhwPwWHiZsUi3zHugpMEKlNPaurviseYoBqo0zBd3zqoUi3LPCNtPFlEP8FiW9MqCZdjb2IYA==} resolution: {integrity: sha512-m0lzlP7qOtthD918nenK3hdItSd2I+V3W9IrBcB36sqDwG+KnUs66IF5GY7laGWUnlM9vTsD0W1QwSEBYWWcJg==}
engines: {node: '>=14'} engines: {node: '>=14'}
peerDependencies: peerDependencies:
canvas: ^2.5.0 canvas: ^2.5.0
@ -9199,17 +9159,6 @@ packages:
/json-stringify-safe/5.0.1: /json-stringify-safe/5.0.1:
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
/json5-loader/4.0.1:
resolution: {integrity: sha512-c9viNZlZTz0MTIcf/4qvek5Dz1/PU3DNCB4PwUhlEZIV3qb1bSD6vQQymlV17/Wm6ncra1aCvmIPsuRj+KfEEg==}
engines: {node: '>= 10.13.0'}
peerDependencies:
webpack: ^4.0.0 || ^5.0.0
dependencies:
json5: 2.2.3
loader-utils: 2.0.4
schema-utils: 3.1.1
dev: false
/json5/1.0.1: /json5/1.0.1:
resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==}
hasBin: true hasBin: true
@ -9539,15 +9488,6 @@ packages:
strip-bom: 2.0.0 strip-bom: 2.0.0
dev: false dev: false
/loader-utils/2.0.4:
resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==}
engines: {node: '>=8.9.0'}
dependencies:
big.js: 5.2.2
emojis-list: 3.0.0
json5: 2.2.3
dev: false
/locate-path/5.0.0: /locate-path/5.0.0:
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -10403,13 +10343,13 @@ packages:
set-blocking: 2.0.0 set-blocking: 2.0.0
dev: false dev: false
/nsfwjs/2.4.2_@tensorflow+tfjs@4.1.0: /nsfwjs/2.4.2_@tensorflow+tfjs@4.2.0:
resolution: {integrity: sha512-i4Pp2yt59qPQgeZFyg3wXFBX52uSeu/hkDoqdZfe+sILRxNBUu0VDogj7Lmqak0GlrXviS/wLiVeIx40IDUu7A==} resolution: {integrity: sha512-i4Pp2yt59qPQgeZFyg3wXFBX52uSeu/hkDoqdZfe+sILRxNBUu0VDogj7Lmqak0GlrXviS/wLiVeIx40IDUu7A==}
peerDependencies: peerDependencies:
'@tensorflow/tfjs': ^3.18.0 '@tensorflow/tfjs': ^3.18.0
dependencies: dependencies:
'@nsfw-filter/gif-frames': 1.0.2 '@nsfw-filter/gif-frames': 1.0.2
'@tensorflow/tfjs': 4.1.0_seedrandom@3.0.5 '@tensorflow/tfjs': 4.2.0_seedrandom@3.0.5
dev: false dev: false
/nth-check/1.0.2: /nth-check/1.0.2:
@ -12262,15 +12202,6 @@ packages:
xmlchars: 2.2.0 xmlchars: 2.2.0
dev: false dev: false
/schema-utils/3.1.1:
resolution: {integrity: sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==}
engines: {node: '>= 10.13.0'}
dependencies:
'@types/json-schema': 7.0.11
ajv: 6.12.6
ajv-keywords: 3.5.2_ajv@6.12.6
dev: false
/secure-json-parse/2.7.0: /secure-json-parse/2.7.0:
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
dev: false dev: false
@ -12688,8 +12619,8 @@ packages:
/standard-as-callback/2.1.0: /standard-as-callback/2.1.0:
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
/start-server-and-test/1.15.2: /start-server-and-test/1.15.3:
resolution: {integrity: sha512-t5xJX04Hg7hqxiKHMJBz/n4zIMsE6G7hpAcerFAH+4Vh9le/LeyFcJERJM7WLiPygWF9TOg33oroJF1XOzJtYQ==} resolution: {integrity: sha512-4GqkqghvUR9cJ8buvtgkyT0AHgVwCJ5EN8eDEhe9grTChGwWUxGm2nqfSeE9+0PZkLRdFqcwTwxVHe1y3ViutQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
hasBin: true hasBin: true
dependencies: dependencies:
@ -12700,7 +12631,7 @@ packages:
execa: 5.1.1 execa: 5.1.1
lazy-ass: 1.6.0 lazy-ass: 1.6.0
ps-tree: 1.2.0 ps-tree: 1.2.0
wait-on: 6.0.1_debug@4.3.4 wait-on: 7.0.1_debug@4.3.4
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@ -13541,8 +13472,8 @@ packages:
undertaker-registry: 1.0.1 undertaker-registry: 1.0.1
dev: false dev: false
/undici/5.15.1: /undici/5.16.0:
resolution: {integrity: sha512-XLk8g0WAngdvFqTI+VKfBtM4YWXgdxkf1WezC771Es0Dd+Pm1KmNx8t93WTC+Hh9tnghmVxkclU1HN+j+CvIUA==} resolution: {integrity: sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ==}
engines: {node: '>=12.18'} engines: {node: '>=12.18'}
dependencies: dependencies:
busboy: 1.6.0 busboy: 1.6.0
@ -13945,12 +13876,12 @@ packages:
xml-name-validator: 4.0.0 xml-name-validator: 4.0.0
dev: false dev: false
/wait-on/6.0.1_debug@4.3.4: /wait-on/7.0.1_debug@4.3.4:
resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==}
engines: {node: '>=10.0.0'} engines: {node: '>=12.0.0'}
hasBin: true hasBin: true
dependencies: dependencies:
axios: 0.25.0_debug@4.3.4 axios: 0.27.2_debug@4.3.4
joi: 17.7.0 joi: 17.7.0
lodash: 4.17.21 lodash: 4.17.21
minimist: 1.2.7 minimist: 1.2.7