Merge branch 'develop' into qr
This commit is contained in:
commit
d6a0e6f388
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,15 +1,18 @@
|
|||
## Unreleased
|
||||
|
||||
### General
|
||||
-
|
||||
## 2025.9.0
|
||||
|
||||
### Client
|
||||
- Enhance: AiScriptAppウィジェットで構文エラーを検知してもダイアログではなくウィジェット内にエラーを表示するように
|
||||
- Enhance: /flushページでサイトキャッシュをクリアできるようになりました
|
||||
- Enhance: クリップ/リスト/アンテナ/ロール追加系メニュー項目において、表示件数を拡張
|
||||
- Enhance: 「キャッシュを削除」ボタンでブラウザの内部キャッシュの削除も行えるように
|
||||
- Enhance: Ctrlキー(Commandキー)を押下しながらリンクをクリックすると新しいタブで開くように
|
||||
- Fix: プッシュ通知を有効にできない問題を修正
|
||||
- Fix: RSSティッカーウィジェットが正しく動作しない問題を修正
|
||||
- Fix: プロファイルを復元後アカウントの切り替えができない問題を修正
|
||||
- Fix: エラー画像が横に引き伸ばされてしまう問題に対応
|
||||
|
||||
### Server
|
||||
-
|
||||
|
||||
- Fix: webpなどの画像に対してセンシティブなメディアの検出が適用されていなかった問題を修正
|
||||
|
||||
## 2025.8.0
|
||||
|
||||
|
|
|
@ -1644,7 +1644,7 @@ _serverSettings:
|
|||
reactionsBufferingDescription: "Quan s'activa aquesta opció millora bastant el rendiment en recuperar les línies de temps reduint la càrrega de la base. Com a contrapunt, augmentarà l'ús de memòria de Redís. Desactiva aquesta opció en cas de tenir un servidor amb poca memòria o si tens problemes d'inestabilitat."
|
||||
remoteNotesCleaning: "Neteja automàtica de notes remotes"
|
||||
remoteNotesCleaning_description: "Quan activis aquesta opció, periòdicament es netejaran les notes remotes que no es consultin, això evitarà que la base de dades se"
|
||||
remoteNotesCleaningMaxProcessingDuration: "D'oració màxima del temps de funcionament del procés de neteja"
|
||||
remoteNotesCleaningMaxProcessingDuration: "Duració màxima del temps de funcionament del procés de neteja"
|
||||
remoteNotesCleaningExpiryDaysForEachNotes: "Duració mínima de conservació de les notes"
|
||||
inquiryUrl: "URL de consulta "
|
||||
inquiryUrlDescription: "Escriu adreça URL per al formulari de consulta per al mantenidor del servidor o una pàgina web amb el contacte d'informació."
|
||||
|
|
|
@ -1215,6 +1215,7 @@ privacyPolicyUrl: "Ссылка на Политику Конфиденциаль
|
|||
tosAndPrivacyPolicy: "Условия использования и политика конфиденциальности"
|
||||
avatarDecorations: "Украшения для аватара"
|
||||
attach: "Прикрепить"
|
||||
detachAll: "Убрать всё"
|
||||
angle: "Угол"
|
||||
flip: "Переворот"
|
||||
showAvatarDecorations: "Показать украшения для аватара"
|
||||
|
@ -1268,8 +1269,11 @@ availableRoles: "Доступные роли"
|
|||
federationDisabled: "Федерация отключена для этого сервера. Вы не можете взаимодействовать с пользователями на других серверах."
|
||||
draft: "Черновик"
|
||||
markAsSensitiveConfirm: "Отметить контент как чувствительный?"
|
||||
preferences: "Основное"
|
||||
resetToDefaultValue: "Сбросить настройки до стандартных"
|
||||
syncBetweenDevices: "Синхронизировать между устройствами"
|
||||
postForm: "Форма отправки"
|
||||
textCount: "Количество символов"
|
||||
information: "Описание"
|
||||
inMinutes: "мин"
|
||||
inDays: "сут"
|
||||
|
@ -1281,6 +1285,11 @@ _chat:
|
|||
send: "Отправить"
|
||||
_settings:
|
||||
webhook: "Вебхук"
|
||||
preferencesBanner: "Вы можете настроить общее поведение клиента по вашим предпочтениям"
|
||||
timelineAndNote: "Лента и заметки"
|
||||
_chat:
|
||||
showSenderName: "Показывать имя отправителя"
|
||||
sendOnEnter: "Использовать Enter для отправки"
|
||||
_delivery:
|
||||
stop: "Заморожено"
|
||||
_type:
|
||||
|
@ -1529,7 +1538,7 @@ _achievements:
|
|||
description: "Нажато здесь"
|
||||
_justPlainLucky:
|
||||
title: "Чистая удача"
|
||||
description: "Может достаться с вероятностью 0,01% каждые 10 секунд."
|
||||
description: "Может достаться с вероятностью 0,005% каждые 10 секунд."
|
||||
_setNameToSyuilo:
|
||||
title: "Комплекс бога"
|
||||
description: "Установлено «syuilo» в качестве имени"
|
||||
|
@ -1557,6 +1566,12 @@ _achievements:
|
|||
title: "Brain Diver"
|
||||
description: "Опубликована ссылка на песню «Brain Diver»"
|
||||
flavor: "Мисски-Мисски Ла-Ту-Ма"
|
||||
_bubbleGameExplodingHead:
|
||||
title: "🤯"
|
||||
description: "Самый большой объект в Bubble game"
|
||||
_bubbleGameDoubleExplodingHead:
|
||||
title: "Двойной🤯"
|
||||
description: "Два самых больших объекта в Bubble game одновременно!"
|
||||
_role:
|
||||
new: "Новая роль"
|
||||
edit: "Изменить роль"
|
||||
|
|
|
@ -360,7 +360,7 @@ whenServerDisconnected: "Sunucu ile bağlantı kesildiğinde"
|
|||
disconnectedFromServer: "Sunucu bağlantısı kesildi"
|
||||
reload: "Yenile"
|
||||
doNothing: "Yoksay"
|
||||
reloadConfirm: "Zaman çizelgesini yenilemek ister misin?"
|
||||
reloadConfirm: "Panoyu yenilemek ister misin?"
|
||||
watch: "İzle"
|
||||
unwatch: "İzlemeyi bırak"
|
||||
accept: "Kabul et"
|
||||
|
@ -573,9 +573,9 @@ objectStorageSetPublicRead: "Yükleme sırasında \"genel-okuma\" ayarını yap
|
|||
s3ForcePathStyleDesc: "s3ForcePathStyle etkinleştirilirse, kova adı URL'nin ana bilgisayar adı yerine URL yoluna eklenmelidir. Kendi kendine barındırılan bir Minio örneği gibi hizmetleri kullanırken bu ayarı etkinleştirmen gerekebilir."
|
||||
serverLogs: "Sunucu log kayıtları"
|
||||
deleteAll: "Tümünü sil"
|
||||
showFixedPostForm: "Gönderi formunu zaman çizelgesinin en üstünde görüntüle"
|
||||
showFixedPostFormInChannel: "Gönderi formunu zaman çizelgesinin en üstünde görüntüle (Kanallar)"
|
||||
withRepliesByDefaultForNewlyFollowed: "Yeni takip edilen kullanıcıların yanıtlarını varsayılan olarak zaman çizelgesine dahil et"
|
||||
showFixedPostForm: "Gönderi formunu pano üstünde görüntüle"
|
||||
showFixedPostFormInChannel: "Gönderi formunu pano üstünde görüntüle (Kanallar)"
|
||||
withRepliesByDefaultForNewlyFollowed: "Yeni takip edilen kullanıcıların yanıtlarını varsayılan olarak panoya dahil et"
|
||||
newNoteRecived: "Yeni Not'lar var"
|
||||
newNote: "Yeni Not"
|
||||
sounds: "Sesler"
|
||||
|
@ -1059,7 +1059,7 @@ achievements: "Başarılar"
|
|||
gotInvalidResponseError: "Geçersiz sunucu yanıtı"
|
||||
gotInvalidResponseErrorDescription: "Sunucu erişilemez durumda olabilir veya bakım çalışması yapılmaktadır. Lütfen daha sonra tekrar dene."
|
||||
thisPostMayBeAnnoying: "Bu not başkalarını rahatsız edebilir."
|
||||
thisPostMayBeAnnoyingHome: "Ana zaman çizelgesine gönder"
|
||||
thisPostMayBeAnnoyingHome: "Ana panoya gönder"
|
||||
thisPostMayBeAnnoyingCancel: "İptal"
|
||||
thisPostMayBeAnnoyingIgnore: "Yine de gönder"
|
||||
collapseRenotes: "Daha önce görüntülenen Renote'lari kısaltılmış olarak göster"
|
||||
|
@ -1218,8 +1218,8 @@ showRepliesToOthersInTimeline: "Pano'da diğer kişilere verilen yanıtları gö
|
|||
hideRepliesToOthersInTimeline: "Pano'dan diğer kişilerin yanıtlarını gizle"
|
||||
showRepliesToOthersInTimelineAll: "Pano'da takip ettiğin herkesin diğerlerine verdiği yanıtları göster"
|
||||
hideRepliesToOthersInTimelineAll: "Pano'da takip ettiğin herkesten diğer kişilere verilen yanıtları gizle"
|
||||
confirmShowRepliesAll: "Bu işlem geri alınamaz. Takip ettiğin herkesin yanıtlarını zaman çizelgende diğer kullanıcılara göstermek istiyor musun?"
|
||||
confirmHideRepliesAll: "Bu işlem geri alınamaz. Şu anda takip ettiğin tüm kullanıcıların yanıtlarını zaman tünelinde cidden göstermeyecek misin?"
|
||||
confirmShowRepliesAll: "Bu işlem geri alınamaz. Takip ettiğin herkesin yanıtlarını panoda diğer kullanıcılara göstermek istiyor musun?"
|
||||
confirmHideRepliesAll: "Bu işlem geri alınamaz. Şu anda takip ettiğin tüm kullanıcıların yanıtlarını panoda cidden göstermeyecek misin?"
|
||||
externalServices: "Dış Hizmetler"
|
||||
sourceCode: "Kaynak kodu"
|
||||
sourceCodeIsNotYetProvided: "Kaynak kodu henüz mevcut değildir. Bu sorunu gidermek için yöneticiyle iletişime geçin."
|
||||
|
@ -1570,9 +1570,9 @@ _initialTutorial:
|
|||
description: "Burada, Misskey'i kullanmanın temellerini ve özelliklerini öğrenebilirsin."
|
||||
_note:
|
||||
title: "Not nedir?"
|
||||
description: "Misskey'deki gönderiler “Notlar” olarak adlandırılır. Notlar zaman çizelgesinde kronolojik olarak düzenlenir ve gerçek zamanlı olarak güncellenir."
|
||||
description: "Misskey'deki gönderiler “Notlar” olarak adlandırılır. Notlar panoda kronolojik olarak düzenlenir ve gerçek zamanlı olarak güncellenir."
|
||||
reply: "Bir mesaja yanıt vermek için bu düğmeye tıklayın. Yanıtlara yanıt vermek de mümkündür, böylece konuşma bir konu başlığı gibi devam eder."
|
||||
renote: "Bu notu kendi zaman çizelgende paylaşabilirsiniz. Ayrıca yorumlarınızla birlikte alıntı da yapabilirsin."
|
||||
renote: "Bu notu kendi panonda paylaşabilirsin. Ayrıca yorumlarınla birlikte alıntı da yapabilirsin."
|
||||
reaction: "Not'a tepkiler ekleyebilirsin. Daha fazla ayrıntı bir sonraki sayfada açıklanacak."
|
||||
menu: "Not ayrıntılarını görüntüleyebilir, bağlantıları kopyalayabilir ve çeşitli diğer işlemleri gerçekleştirebilirsin."
|
||||
_reaction:
|
||||
|
@ -1640,7 +1640,7 @@ _serverSettings:
|
|||
shortNameDescription: "Resmi adın uzun olması durumunda görüntülenebilen, örneğin adının kısaltması."
|
||||
fanoutTimelineDescription: "Etkinleştirildiğinde Pano alma performansını büyük ölçüde artırır ve veritabanı yükünü azaltır. Bunun karşılığında Redis'in bellek kullanımı artacaktır. Sunucu belleği düşükse veya sunucu kararsızsa bunu devre dışı bırakmayı düşün."
|
||||
fanoutTimelineDbFallback: "Veritabanına geri dön"
|
||||
fanoutTimelineDbFallbackDescription: "Etkinleştirildiğinde, Pano önbelleğe alınmamışsa ek sorgular için veritabanına geri döner. Bu özelliği devre dışı bırakmak, geri dönüş sürecini ortadan kaldırarak sunucu yükünü daha da azaltır, ancak alınabilecek zaman çizelgelerinin aralığını sınırlar."
|
||||
fanoutTimelineDbFallbackDescription: "Etkinleştirildiğinde, Pano önbelleğe alınmamışsa ek sorgular için veritabanına geri döner. Bu özelliği devre dışı bırakmak, geri dönüş sürecini ortadan kaldırarak sunucu yükünü daha da azaltır, ancak alınabilecek panoların aralığını sınırlar."
|
||||
reactionsBufferingDescription: "Etkinleştirildiğinde, reaksiyon oluşturma sırasında performans büyük ölçüde artacak ve veritabanı üzerindeki yük azalacaktır. Ancak, Redis bellek kullanımı artacakt."
|
||||
remoteNotesCleaning: "Uzak notların otomatik olarak temizlenmesi"
|
||||
remoteNotesCleaning_description: "Etkinleştirildiğinde, kullanılmayan ve güncelliğini yitirmiş uzak notlar, veritabanının şişmesini önlemek için periyodik olarak temizlenecek."
|
||||
|
@ -1668,6 +1668,7 @@ _serverSettings:
|
|||
restartServerSetupWizardConfirm_text: "Bazı mevcut ayarlar sıfırlanacaktır."
|
||||
entrancePageStyle: "Giriş sayfası stili"
|
||||
showTimelineForVisitor: "Panoyu göster"
|
||||
showActivitiesForVisitor: "Aktiviteleri göster"
|
||||
_userGeneratedContentsVisibilityForVisitor:
|
||||
all: "Her şey halka açıktır."
|
||||
localOnly: "Yalnızca yerel içerik yayınlanır, uzak içerik gizli tutulur."
|
||||
|
@ -1876,7 +1877,7 @@ _achievements:
|
|||
title: "Öz Referans"
|
||||
description: "Kendi notunuzu alıntı yapın"
|
||||
_htl20npm:
|
||||
title: "Akış Zaman Çizelgesi"
|
||||
title: "Akış Panosu"
|
||||
description: "Ev zaman çizelgenizin hızı 20 npm'yi (dakika başına not sayısı) aşıyor mu?"
|
||||
_viewInstanceChart:
|
||||
title: "Analist"
|
||||
|
@ -1965,7 +1966,7 @@ _role:
|
|||
asBadge: "Rozet olarak göster"
|
||||
descriptionOfAsBadge: "This role's icon will be displayed next to the username of users with this role if turned on."
|
||||
isExplorable: "Rolü keşfedilebilir hale getir"
|
||||
descriptionOfIsExplorable: "Bu rolün zaman çizelgesi ve bu role sahip kullanıcıların listesi, etkinleştirilirse kamuya açık hale getirilecek."
|
||||
descriptionOfIsExplorable: "Bu rolün panosu ve bu role sahip kullanıcıların listesi, etkinleştirilirse kamuya açık hale getirilecek."
|
||||
displayOrder: "Pozisyon"
|
||||
descriptionOfDisplayOrder: "Sayı ne kadar yüksekse, UI pozisyonu da o kadar yüksek olur."
|
||||
preserveAssignmentOnMoveAccount: "Geçiş sırasında rol atamalarını koruyun"
|
||||
|
@ -1979,7 +1980,7 @@ _role:
|
|||
high: "Yüksek"
|
||||
_options:
|
||||
gtlAvailable: "Global Pano'yu görüntüleyebilir"
|
||||
ltlAvailable: "Yerel zaman çizelgesini görüntüleyebilir"
|
||||
ltlAvailable: "Yerel panoyu görüntüleyebilir"
|
||||
canPublicNote: "Halka açık notlar gönderebilir"
|
||||
mentionMax: "Bir notta maksimum bahsetme sayısı"
|
||||
canInvite: "Sunucu davet kodları oluşturabilir"
|
||||
|
@ -2484,7 +2485,7 @@ _visibility:
|
|||
public: "Halka açık"
|
||||
publicDescription: "Notunuz tüm kullanıcılar tarafından görülebilir olacaktır."
|
||||
home: "Pano"
|
||||
homeDescription: "Yalnızca ana zaman çizelgesine gönder"
|
||||
homeDescription: "Yalnızca ana panoya gönder"
|
||||
followers: "Takipçiler"
|
||||
followersDescription: "Sadece takipçilerine görünür hale getir"
|
||||
specified: "Doğrudan"
|
||||
|
@ -2531,7 +2532,7 @@ _exportOrImport:
|
|||
userLists: "Kullanıcı listeleri"
|
||||
excludeMutingUsers: "Sessize alınan kullanıcıları hariç tut"
|
||||
excludeInactiveUsers: "Etkin olmayan kullanıcıları hariç tut"
|
||||
withReplies: "İçe aktarılan kullanıcıların yanıtlarını zaman çizelgesine dahil edin"
|
||||
withReplies: "İçe aktarılan kullanıcıların yanıtlarını panoya dahil edin"
|
||||
_charts:
|
||||
federation: "Federasyon"
|
||||
apRequest: "Talepler"
|
||||
|
@ -2925,7 +2926,7 @@ _reversi:
|
|||
freeMatch: "Ücretsiz Eşleştirme"
|
||||
lookingForPlayer: "Rakip aranıyor..."
|
||||
gameCanceled: "Oyun iptal edildi."
|
||||
shareToTlTheGameWhenStart: "Oyun başlatıldığında zaman çizelgesinde paylaş"
|
||||
shareToTlTheGameWhenStart: "Oyun başlatıldığında panoda paylaş"
|
||||
iStartedAGame: "Oyun başladı! #MisskeyReversi"
|
||||
opponentHasSettingsChanged: "Rakip ayarlarını değiştirmiş."
|
||||
allowIrregularRules: "Düzensiz kurallar (tamamen ücretsiz)"
|
||||
|
@ -3153,7 +3154,7 @@ _clientPerformanceIssueTip:
|
|||
_clip:
|
||||
tip: "Klip, notları gruplandırmanıza olanak tanıyan bir özelliktir."
|
||||
_userLists:
|
||||
tip: "Listeler, oluşturulurken belirttiğin herhangi bir kullanıcıyı içerebilir. Oluşturulan liste, yalnızca belirtilen kullanıcıları gösteren bir zaman çizelgesi olarak görüntülenebilir."
|
||||
tip: "Listeler, oluşturulurken belirttiğin herhangi bir kullanıcıyı içerebilir. Oluşturulan liste, yalnızca belirtilen kullanıcıları gösteren bir pano olarak görüntülenebilir."
|
||||
watermark: "Filigran"
|
||||
defaultPreset: "Varsayılan Ön Ayar"
|
||||
_watermarkEditor:
|
||||
|
|
18
package.json
18
package.json
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "misskey",
|
||||
"version": "2025.8.0",
|
||||
"version": "2025.9.0-beta.0",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/misskey-dev/misskey.git"
|
||||
},
|
||||
"packageManager": "pnpm@10.15.0",
|
||||
"packageManager": "pnpm@10.15.1",
|
||||
"workspaces": [
|
||||
"packages/frontend-shared",
|
||||
"packages/frontend",
|
||||
|
@ -62,22 +62,22 @@
|
|||
"js-yaml": "4.1.0",
|
||||
"postcss": "8.5.6",
|
||||
"tar": "7.4.3",
|
||||
"terser": "5.43.1",
|
||||
"terser": "5.44.0",
|
||||
"typescript": "5.9.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@misskey-dev/eslint-plugin": "2.1.0",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/node": "22.17.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@types/node": "22.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "14.5.4",
|
||||
"eslint": "9.34.0",
|
||||
"eslint": "9.35.0",
|
||||
"globals": "16.3.0",
|
||||
"ncp": "2.0.0",
|
||||
"pnpm": "10.15.0",
|
||||
"start-server-and-test": "2.0.13"
|
||||
"pnpm": "10.15.1",
|
||||
"start-server-and-test": "2.1.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.22.0"
|
||||
|
|
|
@ -39,17 +39,17 @@
|
|||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-android-arm64": "1.3.11",
|
||||
"@swc/core-darwin-arm64": "1.13.4",
|
||||
"@swc/core-darwin-x64": "1.13.4",
|
||||
"@swc/core-darwin-arm64": "1.13.5",
|
||||
"@swc/core-darwin-x64": "1.13.5",
|
||||
"@swc/core-freebsd-x64": "1.3.11",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.13.4",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.4",
|
||||
"@swc/core-linux-arm64-musl": "1.13.4",
|
||||
"@swc/core-linux-x64-gnu": "1.13.4",
|
||||
"@swc/core-linux-x64-musl": "1.13.4",
|
||||
"@swc/core-win32-arm64-msvc": "1.13.4",
|
||||
"@swc/core-win32-ia32-msvc": "1.13.4",
|
||||
"@swc/core-win32-x64-msvc": "1.13.4",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.13.5",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.5",
|
||||
"@swc/core-linux-arm64-musl": "1.13.5",
|
||||
"@swc/core-linux-x64-gnu": "1.13.5",
|
||||
"@swc/core-linux-x64-musl": "1.13.5",
|
||||
"@swc/core-win32-arm64-msvc": "1.13.5",
|
||||
"@swc/core-win32-ia32-msvc": "1.13.5",
|
||||
"@swc/core-win32-x64-msvc": "1.13.5",
|
||||
"@tensorflow/tfjs": "4.22.0",
|
||||
"@tensorflow/tfjs-node": "4.22.0",
|
||||
"bufferutil": "4.0.9",
|
||||
|
@ -69,20 +69,20 @@
|
|||
"utf-8-validate": "6.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.873.0",
|
||||
"@aws-sdk/lib-storage": "3.873.0",
|
||||
"@aws-sdk/client-s3": "3.883.0",
|
||||
"@aws-sdk/lib-storage": "3.883.0",
|
||||
"@discordapp/twemoji": "16.0.1",
|
||||
"@fastify/accepts": "5.0.2",
|
||||
"@fastify/cookie": "11.0.2",
|
||||
"@fastify/cors": "10.1.0",
|
||||
"@fastify/express": "4.0.2",
|
||||
"@fastify/http-proxy": "10.0.2",
|
||||
"@fastify/multipart": "9.0.3",
|
||||
"@fastify/multipart": "9.2.1",
|
||||
"@fastify/static": "8.2.0",
|
||||
"@fastify/view": "10.0.2",
|
||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||
"@misskey-dev/summaly": "5.2.3",
|
||||
"@napi-rs/canvas": "0.1.77",
|
||||
"@napi-rs/canvas": "0.1.79",
|
||||
"@nestjs/common": "11.1.6",
|
||||
"@nestjs/core": "11.1.6",
|
||||
"@nestjs/testing": "11.1.6",
|
||||
|
@ -93,7 +93,7 @@
|
|||
"@sinonjs/fake-timers": "11.3.1",
|
||||
"@smithy/node-http-handler": "2.5.0",
|
||||
"@swc/cli": "0.7.8",
|
||||
"@swc/core": "1.13.4",
|
||||
"@swc/core": "1.13.5",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
"@types/redis-info": "3.0.3",
|
||||
"accepts": "1.3.8",
|
||||
|
@ -103,7 +103,7 @@
|
|||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "2.0.5",
|
||||
"body-parser": "1.20.3",
|
||||
"bullmq": "5.58.1",
|
||||
"bullmq": "5.58.5",
|
||||
"cacheable-lookup": "7.0.0",
|
||||
"cbor": "9.0.2",
|
||||
"chalk": "5.6.0",
|
||||
|
@ -114,13 +114,13 @@
|
|||
"content-disposition": "0.5.4",
|
||||
"date-fns": "2.30.0",
|
||||
"deep-email-validator": "0.1.21",
|
||||
"fastify": "5.5.0",
|
||||
"fastify": "5.6.0",
|
||||
"fastify-raw-body": "5.0.0",
|
||||
"feed": "4.2.2",
|
||||
"file-type": "19.6.0",
|
||||
"fluent-ffmpeg": "2.1.3",
|
||||
"form-data": "4.0.4",
|
||||
"got": "14.4.7",
|
||||
"got": "14.4.8",
|
||||
"happy-dom": "16.8.1",
|
||||
"hpagent": "1.2.0",
|
||||
"htmlescape": "1.1.1",
|
||||
|
@ -141,7 +141,7 @@
|
|||
"mime-types": "2.1.35",
|
||||
"misskey-js": "workspace:*",
|
||||
"misskey-reversi": "workspace:*",
|
||||
"ms": "3.0.0-canary.1",
|
||||
"ms": "3.0.0-canary.202508261828",
|
||||
"nanoid": "5.1.5",
|
||||
"nested-property": "4.0.0",
|
||||
"node-fetch": "3.3.2",
|
||||
|
@ -175,7 +175,7 @@
|
|||
"slacc": "0.0.10",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"systeminformation": "5.27.7",
|
||||
"systeminformation": "5.27.8",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tmp": "0.2.5",
|
||||
"tsc-alias": "1.8.16",
|
||||
|
@ -210,7 +210,7 @@
|
|||
"@types/jsrsasign": "10.5.15",
|
||||
"@types/mime-types": "2.1.4",
|
||||
"@types/ms": "0.7.34",
|
||||
"@types/node": "22.17.2",
|
||||
"@types/node": "22.18.1",
|
||||
"@types/nodemailer": "6.4.19",
|
||||
"@types/oauth": "0.9.6",
|
||||
"@types/oauth2orize": "1.11.5",
|
||||
|
@ -222,7 +222,7 @@
|
|||
"@types/ratelimiter": "3.4.6",
|
||||
"@types/rename": "1.0.7",
|
||||
"@types/sanitize-html": "2.16.0",
|
||||
"@types/semver": "7.7.0",
|
||||
"@types/semver": "7.7.1",
|
||||
"@types/simple-oauth2": "5.0.7",
|
||||
"@types/sinonjs__fake-timers": "8.1.5",
|
||||
"@types/supertest": "6.0.3",
|
||||
|
@ -231,8 +231,8 @@
|
|||
"@types/vary": "1.1.3",
|
||||
"@types/web-push": "3.6.4",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"aws-sdk-client-mock": "4.1.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
|
|
|
@ -29,7 +29,7 @@ export class AiService {
|
|||
}
|
||||
|
||||
@bindThis
|
||||
public async detectSensitive(path: string): Promise<nsfw.PredictionType[] | null> {
|
||||
public async detectSensitive(source: string | Buffer): Promise<nsfw.PredictionType[] | null> {
|
||||
try {
|
||||
if (isSupportedCpu === undefined) {
|
||||
isSupportedCpu = await this.computeIsSupportedCpu();
|
||||
|
@ -51,7 +51,7 @@ export class AiService {
|
|||
});
|
||||
}
|
||||
|
||||
const buffer = await fs.promises.readFile(path);
|
||||
const buffer = source instanceof Buffer ? source : await fs.promises.readFile(source);
|
||||
const image = await tf.node.decodeImage(buffer, 3) as any;
|
||||
try {
|
||||
const predictions = await this.model.classify(image);
|
||||
|
|
|
@ -21,6 +21,7 @@ import { LoggerService } from '@/core/LoggerService.js';
|
|||
import type Logger from '@/logger.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import type { PredictionType } from 'nsfwjs';
|
||||
import { isMimeImage } from '@/misc/is-mime-image.js';
|
||||
|
||||
export type FileInfo = {
|
||||
size: number;
|
||||
|
@ -204,16 +205,7 @@ export class FileInfoService {
|
|||
return [sensitive, porn];
|
||||
}
|
||||
|
||||
if ([
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/webp',
|
||||
].includes(mime)) {
|
||||
const result = await this.aiService.detectSensitive(source);
|
||||
if (result) {
|
||||
[sensitive, porn] = judgePrediction(result);
|
||||
}
|
||||
} else if (analyzeVideo && (mime === 'image/apng' || mime.startsWith('video/'))) {
|
||||
if (analyzeVideo && (mime === 'image/apng' || mime.startsWith('video/'))) {
|
||||
const [outDir, disposeOutDir] = await createTempDir();
|
||||
try {
|
||||
const command = FFmpeg()
|
||||
|
@ -281,6 +273,23 @@ export class FileInfoService {
|
|||
} finally {
|
||||
disposeOutDir();
|
||||
}
|
||||
} else if (isMimeImage(mime, 'sharp-convertible-image-with-bmp')) {
|
||||
/*
|
||||
* tfjs-node は限られた画像形式しか受け付けないため、sharp で PNG に変換する
|
||||
* せっかくなので内部処理で使われる最大サイズの299x299に事前にリサイズする
|
||||
*/
|
||||
const png = await (await sharpBmp(source, mime))
|
||||
.resize(299, 299, {
|
||||
withoutEnlargement: false,
|
||||
})
|
||||
.rotate()
|
||||
.flatten({ background: { r: 119, g: 119, b: 119 } }) // 透過部分を18%グレーで塗りつぶす
|
||||
.png()
|
||||
.toBuffer();
|
||||
const result = await this.aiService.detectSensitive(png);
|
||||
if (result) {
|
||||
[sensitive, porn] = judgePrediction(result);
|
||||
}
|
||||
}
|
||||
|
||||
return [sensitive, porn];
|
||||
|
|
|
@ -756,8 +756,8 @@ export class QueueService {
|
|||
@bindThis
|
||||
public async queueRetryJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
|
||||
const queue = this.getQueue(queueType);
|
||||
const job: Bull.Job | null = await queue.getJob(jobId);
|
||||
if (job) {
|
||||
const job = await queue.getJob(jobId);
|
||||
if (job != null) {
|
||||
if (job.finishedOn != null) {
|
||||
await job.retry();
|
||||
} else {
|
||||
|
@ -769,8 +769,8 @@ export class QueueService {
|
|||
@bindThis
|
||||
public async queueRemoveJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
|
||||
const queue = this.getQueue(queueType);
|
||||
const job: Bull.Job | null = await queue.getJob(jobId);
|
||||
if (job) {
|
||||
const job = await queue.getJob(jobId);
|
||||
if (job != null) {
|
||||
await job.remove();
|
||||
}
|
||||
}
|
||||
|
@ -803,8 +803,8 @@ export class QueueService {
|
|||
@bindThis
|
||||
public async queueGetJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
|
||||
const queue = this.getQueue(queueType);
|
||||
const job: Bull.Job | null = await queue.getJob(jobId);
|
||||
if (job) {
|
||||
const job = await queue.getJob(jobId);
|
||||
if (job != null) {
|
||||
return this.packJobData(job);
|
||||
} else {
|
||||
throw new Error(`Job not found: ${jobId}`);
|
||||
|
|
|
@ -176,6 +176,17 @@ export class ApiServerService {
|
|||
}
|
||||
});
|
||||
|
||||
fastify.all('/clear-browser-cache', (request, reply) => {
|
||||
if (['GET', 'POST'].includes(request.method)) {
|
||||
reply.header('Clear-Site-Data', '"cache", "prefetchCache", "prerenderCache", "executionContexts"');
|
||||
reply.code(204);
|
||||
reply.send();
|
||||
} else {
|
||||
reply.code(405);
|
||||
reply.send();
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure any unknown path under /api returns HTTP 404 Not Found,
|
||||
// because otherwise ClientServerService will return the base client HTML
|
||||
// page with HTTP 200.
|
||||
|
|
|
@ -201,6 +201,8 @@ export class ClientServerService {
|
|||
|
||||
@bindThis
|
||||
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
|
||||
const configUrl = new URL(this.config.url);
|
||||
|
||||
fastify.register(fastifyView, {
|
||||
root: _dirname + '/views',
|
||||
engine: {
|
||||
|
@ -239,7 +241,6 @@ export class ClientServerService {
|
|||
done();
|
||||
});
|
||||
} else {
|
||||
const configUrl = new URL(this.config.url);
|
||||
const urlOriginWithoutPort = configUrl.origin.replace(/:\d+$/, '');
|
||||
|
||||
const port = (process.env.VITE_PORT ?? '5173');
|
||||
|
@ -887,6 +888,22 @@ export class ClientServerService {
|
|||
[, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/');
|
||||
|
||||
fastify.get('/flush', async (request, reply) => {
|
||||
let sendHeader = true;
|
||||
|
||||
if (request.headers['origin']) {
|
||||
const originURL = new URL(request.headers['origin']);
|
||||
if (originURL.protocol !== 'https:') { // Clear-Site-Data only supports https
|
||||
sendHeader = false;
|
||||
}
|
||||
if (originURL.host !== configUrl.host) {
|
||||
sendHeader = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (sendHeader) {
|
||||
reply.header('Clear-Site-Data', '"*"');
|
||||
}
|
||||
reply.header('Set-Cookie', 'http-flush-failed=1; Path=/flush; Max-Age=60');
|
||||
return await reply.view('flush');
|
||||
});
|
||||
|
||||
|
|
|
@ -6,8 +6,11 @@ html
|
|||
const msg = document.getElementById('msg');
|
||||
const successText = `\nSuccess Flush! <a href="/">Back to Misskey</a>\n成功しました。<a href="/">Misskeyを開き直してください。</a>`;
|
||||
|
||||
message('Start flushing.');
|
||||
|
||||
if (!document.cookie) {
|
||||
message('Your site data is fully cleared by your browser.');
|
||||
message(successText);
|
||||
} else {
|
||||
message('Your browser does not support Clear-Site-Data header. Start opportunistic flushing.');
|
||||
(async function() {
|
||||
try {
|
||||
localStorage.clear();
|
||||
|
@ -33,7 +36,7 @@ html
|
|||
message(successText);
|
||||
} catch (e) {
|
||||
message(`\n${e}\n\nFlush Failed. <a href="/flush">Please retry.</a>\n失敗しました。<a href="/flush">もう一度試してみてください。</a>`);
|
||||
message(`\nIf you retry more than 3 times, clear the browser cache or contact to instance admin.\n3回以上試しても失敗する場合、ブラウザのキャッシュを消去し、それでもだめならインスタンス管理者に連絡してみてください。\n`)
|
||||
message(`\nIf you retry more than 3 times, try manually clearing the browser cache or contact to instance admin.\n3回以上試しても失敗する場合、ブラウザのキャッシュを手動で消去し、それでもだめならインスタンス管理者に連絡してみてください。\n`)
|
||||
|
||||
console.error(e);
|
||||
setTimeout(() => {
|
||||
|
@ -41,6 +44,7 @@ html
|
|||
}, 10000)
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
function message(text) {
|
||||
msg.insertAdjacentHTML('beforeend', `<p>[${(new Date()).toString()}] ${text.replace(/\n/g,'<br>')}</p>`)
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
"@discordapp/twemoji": "16.0.1",
|
||||
"@rollup/plugin-json": "6.1.0",
|
||||
"@rollup/plugin-replace": "6.0.2",
|
||||
"@rollup/pluginutils": "5.2.0",
|
||||
"@rollup/pluginutils": "5.3.0",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
"@vitejs/plugin-vue": "6.0.1",
|
||||
"@vue/compiler-sfc": "3.5.19",
|
||||
"@vue/compiler-sfc": "3.5.21",
|
||||
"astring": "1.9.0",
|
||||
"buraha": "0.0.1",
|
||||
"estree-walker": "3.0.3",
|
||||
|
@ -26,16 +26,16 @@
|
|||
"mfm-js": "0.25.0",
|
||||
"misskey-js": "workspace:*",
|
||||
"punycode.js": "2.3.1",
|
||||
"rollup": "4.48.0",
|
||||
"sass": "1.90.0",
|
||||
"shiki": "3.11.0",
|
||||
"rollup": "4.50.1",
|
||||
"sass": "1.92.1",
|
||||
"shiki": "3.12.2",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.2",
|
||||
"uuid": "11.1.0",
|
||||
"vite": "7.1.3",
|
||||
"vue": "3.5.19"
|
||||
"vite": "7.1.4",
|
||||
"vue": "3.5.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@misskey-dev/summaly": "5.2.3",
|
||||
|
@ -43,14 +43,14 @@
|
|||
"@testing-library/vue": "8.1.0",
|
||||
"@types/estree": "1.0.8",
|
||||
"@types/micromatch": "4.0.9",
|
||||
"@types/node": "22.17.2",
|
||||
"@types/node": "22.18.1",
|
||||
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
||||
"@types/tinycolor2": "1.4.6",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@vue/runtime-core": "3.5.19",
|
||||
"@vue/runtime-core": "3.5.21",
|
||||
"acorn": "8.15.0",
|
||||
"cross-env": "10.0.0",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
|
@ -59,11 +59,11 @@
|
|||
"happy-dom": "18.0.1",
|
||||
"intersection-observer": "0.12.2",
|
||||
"micromatch": "4.0.8",
|
||||
"msw": "2.10.5",
|
||||
"msw": "2.11.1",
|
||||
"nodemon": "3.1.10",
|
||||
"prettier": "3.6.2",
|
||||
"start-server-and-test": "2.0.13",
|
||||
"tsx": "4.20.4",
|
||||
"start-server-and-test": "2.1.0",
|
||||
"tsx": "4.20.5",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vue-component-type-helpers": "3.0.6",
|
||||
"vue-eslint-parser": "10.2.0",
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
"lint": "pnpm typecheck && pnpm eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.17.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@types/node": "22.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"esbuild": "0.25.9",
|
||||
"eslint-plugin-vue": "10.4.0",
|
||||
"nodemon": "3.1.10",
|
||||
|
@ -35,6 +35,6 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"misskey-js": "workspace:*",
|
||||
"vue": "3.5.19"
|
||||
"vue": "3.5.21"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
"@misskey-dev/browser-image-resizer": "2024.1.0",
|
||||
"@rollup/plugin-json": "6.1.0",
|
||||
"@rollup/plugin-replace": "6.0.2",
|
||||
"@rollup/pluginutils": "5.2.0",
|
||||
"@sentry/vue": "10.5.0",
|
||||
"@rollup/pluginutils": "5.3.0",
|
||||
"@sentry/vue": "10.10.0",
|
||||
"@syuilo/aiscript": "1.1.0",
|
||||
"@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
"@vitejs/plugin-vue": "6.0.1",
|
||||
"@vue/compiler-sfc": "3.5.19",
|
||||
"@vue/compiler-sfc": "3.5.21",
|
||||
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15",
|
||||
"analytics": "0.8.19",
|
||||
"astring": "1.9.0",
|
||||
|
@ -41,7 +41,7 @@
|
|||
"chartjs-chart-matrix": "3.0.0",
|
||||
"chartjs-plugin-gradient": "0.6.1",
|
||||
"chartjs-plugin-zoom": "2.2.0",
|
||||
"chromatic": "13.1.3",
|
||||
"chromatic": "13.1.4",
|
||||
"compare-versions": "6.1.1",
|
||||
"cropperjs": "2.0.1",
|
||||
"date-fns": "4.1.0",
|
||||
|
@ -65,21 +65,21 @@
|
|||
"punycode.js": "2.3.1",
|
||||
"qr-code-styling": "1.9.2",
|
||||
"qr-scanner": "1.4.2",
|
||||
"rollup": "4.48.0",
|
||||
"rollup": "4.50.1",
|
||||
"sanitize-html": "2.17.0",
|
||||
"sass": "1.90.0",
|
||||
"shiki": "3.11.0",
|
||||
"sass": "1.92.1",
|
||||
"shiki": "3.12.2",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.179.1",
|
||||
"three": "0.180.0",
|
||||
"throttle-debounce": "5.0.2",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.2",
|
||||
"v-code-diff": "1.13.1",
|
||||
"vite": "7.1.3",
|
||||
"vue": "3.5.19",
|
||||
"vite": "7.1.4",
|
||||
"vue": "3.5.21",
|
||||
"vuedraggable": "next",
|
||||
"wanakana": "5.3.1"
|
||||
},
|
||||
|
@ -87,7 +87,7 @@
|
|||
"@misskey-dev/summaly": "5.2.3",
|
||||
"@storybook/addon-essentials": "8.6.14",
|
||||
"@storybook/addon-interactions": "8.6.14",
|
||||
"@storybook/addon-links": "9.1.3",
|
||||
"@storybook/addon-links": "9.1.5",
|
||||
"@storybook/addon-mdx-gfm": "8.6.14",
|
||||
"@storybook/addon-storysource": "8.6.14",
|
||||
"@storybook/blocks": "8.6.14",
|
||||
|
@ -95,31 +95,31 @@
|
|||
"@storybook/core-events": "8.6.14",
|
||||
"@storybook/manager-api": "8.6.14",
|
||||
"@storybook/preview-api": "8.6.14",
|
||||
"@storybook/react": "9.1.3",
|
||||
"@storybook/react-vite": "9.1.3",
|
||||
"@storybook/react": "9.1.5",
|
||||
"@storybook/react-vite": "9.1.5",
|
||||
"@storybook/test": "8.6.14",
|
||||
"@storybook/theming": "8.6.14",
|
||||
"@storybook/types": "8.6.14",
|
||||
"@storybook/vue3": "9.1.3",
|
||||
"@storybook/vue3-vite": "9.1.3",
|
||||
"@storybook/vue3": "9.1.5",
|
||||
"@storybook/vue3-vite": "9.1.5",
|
||||
"@tabler/icons-webfont": "3.34.1",
|
||||
"@testing-library/vue": "8.1.0",
|
||||
"@types/canvas-confetti": "1.9.0",
|
||||
"@types/estree": "1.0.8",
|
||||
"@types/matter-js": "0.20.0",
|
||||
"@types/micromatch": "4.0.9",
|
||||
"@types/node": "22.17.2",
|
||||
"@types/node": "22.18.1",
|
||||
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
||||
"@types/sanitize-html": "2.16.0",
|
||||
"@types/seedrandom": "3.0.8",
|
||||
"@types/throttle-debounce": "5.0.2",
|
||||
"@types/tinycolor2": "1.4.6",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@vue/compiler-core": "3.5.19",
|
||||
"@vue/runtime-core": "3.5.19",
|
||||
"@vue/compiler-core": "3.5.21",
|
||||
"@vue/runtime-core": "3.5.21",
|
||||
"acorn": "8.15.0",
|
||||
"cross-env": "10.0.0",
|
||||
"cypress": "14.5.4",
|
||||
|
@ -130,17 +130,17 @@
|
|||
"intersection-observer": "0.12.2",
|
||||
"micromatch": "4.0.8",
|
||||
"minimatch": "10.0.3",
|
||||
"msw": "2.10.5",
|
||||
"msw": "2.11.1",
|
||||
"msw-storybook-addon": "2.0.5",
|
||||
"nodemon": "3.1.10",
|
||||
"prettier": "3.6.2",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"seedrandom": "3.0.5",
|
||||
"start-server-and-test": "2.0.13",
|
||||
"storybook": "9.1.3",
|
||||
"start-server-and-test": "2.1.0",
|
||||
"storybook": "9.1.5",
|
||||
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
|
||||
"tsx": "4.20.4",
|
||||
"tsx": "4.20.5",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vitest": "3.2.4",
|
||||
"vitest-fetch-mock": "0.4.5",
|
||||
|
|
|
@ -251,13 +251,30 @@ export async function openAccountMenu(opts: {
|
|||
}
|
||||
},
|
||||
};
|
||||
} else {
|
||||
} else { // プロファイルを復元した場合などはアカウントのトークンや詳細情報はstoreにキャッシュされていない
|
||||
return {
|
||||
type: 'button' as const,
|
||||
text: username,
|
||||
active: opts.active != null ? opts.active === id : false,
|
||||
action: async () => {
|
||||
// TODO
|
||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {
|
||||
initialUsername: username,
|
||||
}, {
|
||||
done: async (res: Misskey.entities.SigninFlowResponse & { finished: true }) => {
|
||||
store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + res.id]: res.i });
|
||||
|
||||
if (callback) {
|
||||
fetchAccount(res.i, id).then(account => {
|
||||
callback(account);
|
||||
});
|
||||
} else {
|
||||
switchAccount(host, id);
|
||||
}
|
||||
},
|
||||
closed: () => {
|
||||
dispose();
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import * as Misskey from 'misskey-js';
|
|||
import { Cache } from '@/utility/cache.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
|
||||
export const clipsCache = new Cache<Misskey.entities.Clip[]>(1000 * 60 * 30, () => misskeyApi('clips/list'));
|
||||
export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list'));
|
||||
export const clipsCache = new Cache<Misskey.entities.Clip[]>(1000 * 60 * 30, () => misskeyApi('clips/list', { limit: 30 }));
|
||||
export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list', { limit: 30 }));
|
||||
export const userListsCache = new Cache<Misskey.entities.UserList[]>(1000 * 60 * 30, () => misskeyApi('users/lists/list'));
|
||||
export const antennasCache = new Cache<Misskey.entities.Antenna[]>(1000 * 60 * 30, () => misskeyApi('antennas/list'));
|
||||
export const antennasCache = new Cache<Misskey.entities.Antenna[]>(1000 * 60 * 30, () => misskeyApi('antennas/list', { limit: 30 }));
|
||||
export const favoritedChannelsCache = new Cache<Misskey.entities.Channel[]>(1000 * 60 * 30, () => misskeyApi('channels/my-favorites', { limit: 100 }));
|
||||
|
|
|
@ -78,7 +78,7 @@ function subscribe() {
|
|||
// SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters
|
||||
return promiseDialog(registration.value.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: urlBase64ToBase64(instance.swPublickey),
|
||||
applicationServerKey: urlBase64ToUint8Array(instance.swPublickey),
|
||||
})
|
||||
.then(async subscription => {
|
||||
pushSubscription.value = subscription;
|
||||
|
@ -131,16 +131,22 @@ function encode(buffer: ArrayBuffer | null) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convert the URL safe base64 string to a base64 string
|
||||
* Convert the URL safe base64 string to a Uint8Array
|
||||
* @param base64String base64 string
|
||||
*/
|
||||
function urlBase64ToBase64(base64String: string): string {
|
||||
function urlBase64ToUint8Array(base64String: string): Uint8Array {
|
||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||
const base64 = (base64String + padding)
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
return base64;
|
||||
const rawData = window.atob(base64);
|
||||
const outputArray = new Uint8Array(rawData.length);
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i);
|
||||
}
|
||||
return outputArray;
|
||||
}
|
||||
|
||||
if (navigator.serviceWorker == null) {
|
||||
|
|
|
@ -69,9 +69,11 @@ import MkInfo from '@/components/MkInfo.vue';
|
|||
const props = withDefaults(defineProps<{
|
||||
message?: string,
|
||||
openOnRemote?: OpenOnRemoteOptions,
|
||||
initialUsername?: string;
|
||||
}>(), {
|
||||
message: '',
|
||||
openOnRemote: undefined,
|
||||
initialUsername: undefined,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
@ -81,7 +83,7 @@ const emit = defineEmits<{
|
|||
|
||||
const host = toUnicode(configHost);
|
||||
|
||||
const username = ref('');
|
||||
const username = ref(props.initialUsername ?? '');
|
||||
|
||||
//#region Open on remote
|
||||
function openRemote(options: OpenOnRemoteOptions, targetHost?: string): void {
|
||||
|
|
|
@ -20,6 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
key="input"
|
||||
:message="message"
|
||||
:openOnRemote="openOnRemote"
|
||||
:initialUsername="initialUsername"
|
||||
|
||||
@usernameSubmitted="onUsernameSubmitted"
|
||||
@passkeyClick="onPasskeyLogin"
|
||||
|
@ -89,10 +90,12 @@ const props = withDefaults(defineProps<{
|
|||
autoSet?: boolean;
|
||||
message?: string,
|
||||
openOnRemote?: OpenOnRemoteOptions,
|
||||
initialUsername?: string;
|
||||
}>(), {
|
||||
autoSet: false,
|
||||
message: '',
|
||||
openOnRemote: undefined,
|
||||
initialUsername: undefined,
|
||||
});
|
||||
|
||||
const page = ref<'input' | 'password' | 'totp' | 'passkey'>('input');
|
||||
|
|
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<button :class="$style.closeButton" class="_button" @click="onClose"><i class="ti ti-x"></i></button>
|
||||
</div>
|
||||
<div :class="$style.content">
|
||||
<MkSignin :autoSet="autoSet" :message="message" :openOnRemote="openOnRemote" @login="onLogin"/>
|
||||
<MkSignin :autoSet="autoSet" :message="message" :openOnRemote="openOnRemote" :initialUsername="initialUsername" @login="onLogin"/>
|
||||
</div>
|
||||
</div>
|
||||
</MkModal>
|
||||
|
@ -34,10 +34,12 @@ withDefaults(defineProps<{
|
|||
autoSet?: boolean;
|
||||
message?: string,
|
||||
openOnRemote?: OpenOnRemoteOptions,
|
||||
initialUsername?: string;
|
||||
}>(), {
|
||||
autoSet: false,
|
||||
message: '',
|
||||
openOnRemote: undefined,
|
||||
initialUsername: undefined,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<a ref="el" :href="to" :class="active ? activeClass : null" @click.prevent="nav" @contextmenu.prevent.stop="onContextmenu">
|
||||
<a ref="el" :href="to" :class="active ? activeClass : null" @click="nav" @contextmenu.prevent.stop="onContextmenu">
|
||||
<slot></slot>
|
||||
</a>
|
||||
</template>
|
||||
|
@ -86,6 +86,11 @@ function openWindow() {
|
|||
}
|
||||
|
||||
function nav(ev: MouseEvent) {
|
||||
// 制御キーとの組み合わせは無視(shiftを除く)
|
||||
if (ev.metaKey || ev.altKey || ev.ctrlKey) return;
|
||||
|
||||
ev.preventDefault();
|
||||
|
||||
if (behavior === 'browser') {
|
||||
window.location.href = props.to;
|
||||
return;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@ -1,70 +0,0 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
|
|
@ -131,6 +131,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<hr>
|
||||
|
||||
<MkButton @click="forceCloudBackup">Force cloud backup</MkButton>
|
||||
|
||||
<hr>
|
||||
|
||||
<template v-if="$i.policies.chatAvailability !== 'unavailable'">
|
||||
<MkButton @click="readAllChatMessages">Read all chat messages</MkButton>
|
||||
|
||||
|
@ -167,6 +171,7 @@ import { signout } from '@/signout.js';
|
|||
import { migrateOldSettings } from '@/pref-migrate.js';
|
||||
import { hideAllTips as _hideAllTips, resetAllTips as _resetAllTips } from '@/tips.js';
|
||||
import { suggestReload } from '@/utility/reload-suggest.js';
|
||||
import { cloudBackup } from '@/preferences/utility.js';
|
||||
|
||||
const $i = ensureSignin();
|
||||
|
||||
|
@ -224,6 +229,11 @@ function readAllChatMessages() {
|
|||
os.apiWithDialog('chat/read-all', {});
|
||||
}
|
||||
|
||||
async function forceCloudBackup() {
|
||||
await cloudBackup();
|
||||
os.success();
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = computed(() => []);
|
||||
|
|
|
@ -34,7 +34,7 @@ import { instance as meta } from '@/instance.js';
|
|||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 80vw; // 100%からshapeの幅を引いている
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ type HandlerDef = {
|
|||
handler: (note: Misskey.entities.Note) => void;
|
||||
};
|
||||
note_view_interruptor: {
|
||||
handler: (note: Misskey.entities.Note) => Misskey.entities.Note;
|
||||
handler: (note: Misskey.entities.Note) => Misskey.entities.Note | null;
|
||||
};
|
||||
note_post_interruptor: {
|
||||
handler: (note: FIXME) => unknown;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import { unisonReload } from '@/utility/unison-reload.js';
|
||||
import { misskeyApiGet } from '@/utility/misskey-api.js';
|
||||
import * as os from '@/os.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
||||
|
@ -16,6 +17,9 @@ export async function clearCache() {
|
|||
miLocalStorage.removeItem('theme');
|
||||
miLocalStorage.removeItem('emojis');
|
||||
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
||||
await misskeyApiGet('clear-browser-cache', {}).catch(() => {
|
||||
// ignore
|
||||
});
|
||||
await fetchInstance(true);
|
||||
await fetchCustomEmojis(true);
|
||||
unisonReload();
|
||||
|
|
|
@ -7,25 +7,26 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkContainer :showHeader="widgetProps.showHeader" class="mkw-aiscriptApp">
|
||||
<template #header>App</template>
|
||||
<div :class="$style.root">
|
||||
<MkAsUi v-if="root" :component="root" :components="components" size="small"/>
|
||||
<div v-if="isSyntaxError">Syntax error :(</div>
|
||||
<MkAsUi v-else-if="root" :component="root" :components="components" size="small"/>
|
||||
</div>
|
||||
</MkContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import type { Ref } from 'vue';
|
||||
import { Interpreter, Parser } from '@syuilo/aiscript';
|
||||
import { useWidgetPropsManager } from './widget.js';
|
||||
import type { Ref } from 'vue';
|
||||
import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
|
||||
import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
|
||||
import type { AsUiComponent, AsUiRoot } from '@/aiscript/ui.js';
|
||||
import * as os from '@/os.js';
|
||||
import { aiScriptReadline, createAiScriptEnv } from '@/aiscript/api.js';
|
||||
import { $i } from '@/i.js';
|
||||
import MkAsUi from '@/components/MkAsUi.vue';
|
||||
import MkContainer from '@/components/MkContainer.vue';
|
||||
import { registerAsUiLib } from '@/aiscript/ui.js';
|
||||
import type { AsUiComponent, AsUiRoot } from '@/aiscript/ui.js';
|
||||
|
||||
const name = 'aiscriptApp';
|
||||
|
||||
|
@ -56,8 +57,11 @@ const parser = new Parser();
|
|||
|
||||
const root = ref<AsUiRoot>();
|
||||
const components = ref<Ref<AsUiComponent>[]>([]);
|
||||
const isSyntaxError = ref(false);
|
||||
|
||||
async function run() {
|
||||
isSyntaxError.value = false;
|
||||
|
||||
const aiscript = new Interpreter({
|
||||
...createAiScriptEnv({
|
||||
storageKey: 'widget',
|
||||
|
@ -80,10 +84,7 @@ async function run() {
|
|||
try {
|
||||
ast = parser.parse(widgetProps.script);
|
||||
} catch (err) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: 'Syntax error :(',
|
||||
});
|
||||
isSyntaxError.value = true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
|
|
@ -52,7 +52,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name,
|
|||
|
||||
const parser = new Parser();
|
||||
|
||||
const run = async () => {
|
||||
async function run() {
|
||||
const aiscript = new Interpreter(createAiScriptEnv({
|
||||
storageKey: 'widget',
|
||||
token: $i?.token,
|
||||
|
@ -84,7 +84,7 @@ const run = async () => {
|
|||
text: err instanceof Error ? err.message : String(err),
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
defineExpose<WidgetComponentExpose>({
|
||||
name,
|
||||
|
|
|
@ -11,16 +11,16 @@
|
|||
"lint": "pnpm typecheck && pnpm eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.17.2",
|
||||
"@types/node": "22.18.1",
|
||||
"@types/wawoff2": "1.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tabler/icons-webfont": "3.34.1",
|
||||
"harfbuzzjs": "0.4.9",
|
||||
"harfbuzzjs": "0.4.11",
|
||||
"tiny-glob": "0.2.9",
|
||||
"tsx": "4.20.4",
|
||||
"tsx": "4.20.5",
|
||||
"typescript": "5.9.2",
|
||||
"wawoff2": "2.0.1"
|
||||
},
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
"devDependencies": {
|
||||
"@types/matter-js": "0.20.0",
|
||||
"@types/seedrandom": "3.0.8",
|
||||
"@types/node": "22.17.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@types/node": "22.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"nodemon": "3.1.10",
|
||||
"execa": "9.6.0",
|
||||
"typescript": "5.9.2",
|
||||
|
|
|
@ -1449,6 +1449,10 @@ export type Endpoints = Overwrite<Endpoints_2, {
|
|||
}>;
|
||||
res: AdminRolesCreateResponse;
|
||||
};
|
||||
'clear-browser-cache': {
|
||||
req: EmptyRequest;
|
||||
res: EmptyResponse;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@readme/openapi-parser": "5.0.1",
|
||||
"@types/node": "22.17.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@types/node": "22.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"openapi-types": "12.1.3",
|
||||
"openapi-typescript": "7.9.1",
|
||||
"ts-case-convert": "2.1.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"type": "module",
|
||||
"name": "misskey-js",
|
||||
"version": "2025.8.0",
|
||||
"version": "2025.9.0-beta.0",
|
||||
"description": "Misskey SDK for JavaScript",
|
||||
"license": "MIT",
|
||||
"main": "./built/index.js",
|
||||
|
@ -36,9 +36,9 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/api-extractor": "7.52.11",
|
||||
"@types/node": "22.17.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@types/node": "22.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"esbuild": "0.25.9",
|
||||
"execa": "9.6.0",
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { Endpoints as Gen } from './autogen/endpoint.js';
|
||||
import { UserDetailed } from './autogen/models.js';
|
||||
import { AdminRolesCreateRequest, AdminRolesCreateResponse, UsersShowRequest } from './autogen/entities.js';
|
||||
import {
|
||||
AdminRolesCreateRequest,
|
||||
AdminRolesCreateResponse,
|
||||
EmptyRequest,
|
||||
EmptyResponse,
|
||||
UsersShowRequest,
|
||||
} from './autogen/entities.js';
|
||||
import {
|
||||
PartialRolePolicyOverride,
|
||||
SigninFlowRequest,
|
||||
|
@ -106,6 +112,10 @@ export type Endpoints = Overwrite<
|
|||
'admin/roles/create': {
|
||||
req: Overwrite<AdminRolesCreateRequest, { policies: PartialRolePolicyOverride }>;
|
||||
res: AdminRolesCreateResponse;
|
||||
}
|
||||
},
|
||||
'clear-browser-cache': {
|
||||
req: EmptyRequest;
|
||||
res: EmptyResponse;
|
||||
},
|
||||
}
|
||||
>;
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
"lint": "pnpm typecheck && pnpm eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.17.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@types/node": "22.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.42.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"execa": "9.6.0",
|
||||
"nodemon": "3.1.10",
|
||||
"typescript": "5.9.2",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"misskey-js": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.42.0",
|
||||
"@typescript/lib-webworker": "npm:@types/serviceworker@0.0.74",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"nodemon": "3.1.10",
|
||||
|
|
3324
pnpm-lock.yaml
3324
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue