diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a78d91900..0583a6696 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,7 @@ "workspaceFolder": "/workspace", "features": { "ghcr.io/devcontainers-contrib/features/pnpm:2": { - "version": "8.8.0" + "version": "8.9.2" }, "ghcr.io/devcontainers/features/node:1": { "version": "20.5.1" diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml index 39f29bf77..d2df95334 100644 --- a/.github/workflows/api-misskey-js.yml +++ b/.github/workflows/api-misskey-js.yml @@ -9,7 +9,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - run: corepack enable diff --git a/.github/workflows/check_copyright_year.yml b/.github/workflows/check_copyright_year.yml index fb04cf1b0..03dfcd0a0 100644 --- a/.github/workflows/check_copyright_year.yml +++ b/.github/workflows/check_copyright_year.yml @@ -10,7 +10,7 @@ jobs: check_copyright_year: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - run: | if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then echo "Please change copyright year!" diff --git a/.github/workflows/docker-develop.yml b/.github/workflows/docker-develop.yml index 79b5cc1c6..57d6d1958 100644 --- a/.github/workflows/docker-develop.yml +++ b/.github/workflows/docker-develop.yml @@ -26,7 +26,7 @@ jobs: sudo rm -rf /usr/share/dotnet sudo rm -rf "$AGENT_TOOLSDIRECTORY" - name: Check out the repo - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v3.0.0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7312eb452..8eabaa288 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Check out the repo - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v3.0.0 diff --git a/.github/workflows/dockle.yml b/.github/workflows/dockle.yml index 2a1ac3a16..edb18b04d 100644 --- a/.github/workflows/dockle.yml +++ b/.github/workflows/dockle.yml @@ -14,7 +14,7 @@ jobs: env: DOCKER_CONTENT_TRUST: 1 steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - run: | curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb" sudo dpkg -i dockle.deb diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 95d51dc96..0c42b45c2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,7 @@ jobs: pnpm_install: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 with: fetch-depth: 0 submodules: true @@ -42,7 +42,7 @@ jobs: - sw - misskey-js steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 with: fetch-depth: 0 submodules: true @@ -68,7 +68,7 @@ jobs: - backend - misskey-js steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 with: fetch-depth: 0 submodules: true diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index dc57e293e..dccbcd855 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Check out the repo - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 with: lfs: true submodules: 'recursive' diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml index 5b0e5e726..f987d8fb0 100644 --- a/.github/workflows/pr-preview-deploy.yml +++ b/.github/workflows/pr-preview-deploy.yml @@ -53,7 +53,7 @@ jobs: # Check out merge commit - name: Fork based /deploy checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 with: ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge' diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index ac7d1afda..752e29ff7 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -29,7 +29,7 @@ jobs: - 56312:6379 steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 with: submodules: true - name: Install pnpm diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 1b69229f1..a736924e3 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -16,7 +16,7 @@ jobs: node-version: [20.5.1] steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 with: submodules: true - name: Install pnpm @@ -68,7 +68,7 @@ jobs: - 56312:6379 steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 with: submodules: true # https://github.com/cypress-io/cypress-docker-images/issues/150 diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index 1846b628d..b5c6bff64 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - run: corepack enable diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index c57001896..bcb89bb45 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -19,7 +19,7 @@ jobs: node-version: [20.5.1] steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 with: submodules: true - name: Install pnpm diff --git a/CHANGELOG.md b/CHANGELOG.md index af68dabcd..ee2d39cde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ ### General - Feat: アンテナでローカルの投稿のみ収集できるようになりました - Feat: サーバーサイレンス機能が追加されました +- Enhance: 新規にフォローした人の返信をデフォルトでTLに追加できるオプションを追加 +- Enhance: HTLとLTLを2023.10.0アップデート以前まで遡れるように +- Enhance: フォロー/フォロー解除したときに過去分のHTLにも含まれる投稿が反映されるように +- Enhance: ローカリゼーションの更新 - Enhance: 依存関係の更新 ### Client @@ -24,6 +28,9 @@ ### Server - Enhance: ストリーミングAPIのパフォーマンスを向上 +- Fix: users/notesでDBから参照した際にチャンネル投稿のみ取得される問題を修正 +- Fix: コントロールパネルの設定項目が正しく保存できない問題を修正 +- Change: nyaizeはAPIレスポンス時ではなく投稿時に一度だけ非可逆的に行われるようになりました ## 2023.10.1 ### General diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 962d23589..56e19c574 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -195,6 +195,7 @@ perHour: "Pro Stunde" perDay: "Pro Tag" stopActivityDelivery: "Senden von Aktivitäten einstellen" blockThisInstance: "Diese Instanz blockieren" +silenceThisInstance: "Instanz stummschalten" operations: "Aktionen" software: "Software" version: "Version" @@ -214,6 +215,8 @@ clearCachedFiles: "Cache leeren" clearCachedFilesConfirm: "Sollen alle im Cache gespeicherten Dateien von anderen Instanzen wirklich gelöscht werden?" blockedInstances: "Blockierte Instanzen" blockedInstancesDescription: "Gib die Hostnamen der Instanzen, welche blockiert werden sollen, durch Zeilenumbrüche getrennt an. Blockierte Instanzen können mit dieser instanz nicht mehr kommunizieren." +silencedInstances: "Stummgeschaltete Instanzen" +silencedInstancesDescription: "Gib die Hostnamen der Instanzen, welche stummgeschaltet werden sollen, durch Zeilenumbrüche getrennt an. Alle Konten dieser Instanzen werden als stummgeschaltet behandelt, können nur noch Follow-Anfragen stellen und wenn nicht gefolgt keine lokalen Konten erwähnen. Blockierte Instanzen sind davon nicht betroffen." muteAndBlock: "Stummschaltungen und Blockierungen" mutedUsers: "Stummgeschaltete Benutzer" blockedUsers: "Blockierte Benutzer" @@ -531,6 +534,7 @@ serverLogs: "Serverprotokolle" deleteAll: "Alle löschen" showFixedPostForm: "Bereich zum Schreiben neuer Notizen am Anfang der Chronik anzeigen" showFixedPostFormInChannel: "Bereich zum Schreiben neuer Notizen am Anfang der Chronik anzeigen (Kanäle)" +withRepliesByDefaultForNewlyFollowed: "Standardmäßig Antworten von neu gefolgten Benutzern in der Chronik anzeigen" newNoteRecived: "Es gibt neue Notizen" sounds: "Töne" sound: "Töne" @@ -794,7 +798,7 @@ active: "Aktiv" offline: "Offline" notRecommended: "Nicht empfohlen" botProtection: "Schutz vor Bots" -instanceBlocking: "Blockierte Instanzen" +instanceBlocking: "Blockierte/Stummgeschaltete Instanzen" selectAccount: "Benutzerkonto auswählen" switchAccount: "Konto wechseln" enabled: "Aktiviert" @@ -1921,6 +1925,7 @@ _exportOrImport: userLists: "Listen" excludeMutingUsers: "Stummgeschaltete Benutzer aussortieren" excludeInactiveUsers: "Inaktive Benutzer aussortieren" + withReplies: "Antworten von importierten Benutzern in der Chronik beinhalten" _charts: federation: "Föderation" apRequest: "Anfragen" diff --git a/locales/en-US.yml b/locales/en-US.yml index 3db8b74a1..5df9ece18 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -223,14 +223,9 @@ clearQueueConfirmText: "Any undelivered notes remaining in the queue will not be clearCachedFiles: "Clear cache" clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote files?" blockedInstances: "Blocked Instances" -silencedInstances: "Silenced Instances" -silencedInstancesDescription: "List the hostnames of the instances that you want to\ - \ silence. Accounts in the listed instances are treated as \"Silenced\", can only make follow requests, and cannot mention local accounts if not followed. This will not affect the blocked instances." -hiddenTags: "Hidden Hashtags" -hiddenTagsDescription: "List the hashtags (without the #) of the hashtags you wish\ - \ to hide from trending and explore. Hidden hashtags are still discoverable via\ - \ other means. Blocked instances are not affected even if listed here." -blockedInstancesDescription: "List the hostnames of the instances that you want to block separated by linebreaks. Listed instances will no longer be able to communicate with this instance." +blockedInstancesDescription: "List the hostnames of the instances you want to block separated by linebreaks. Listed instances will no longer be able to communicate with this instance." +silencedInstances: "Silenced instances" +silencedInstancesDescription: "List the hostnames of the instances that you want to silence. All accounts of the listed instances will be treated as silenced, can only make follow requests, and cannot mention local accounts if not followed. This will not affect blocked instances." muteAndBlock: "Mutes and Blocks" mutedUsers: "Muted users" blockedUsers: "Blocked users" @@ -551,6 +546,7 @@ serverLogs: "Server logs" deleteAll: "Delete all" showFixedPostForm: "Display the posting form at the top of the timeline" showFixedPostFormInChannel: "Display the posting form at the top of the timeline (Channels)" +withRepliesByDefaultForNewlyFollowed: "Include replies by newly followed users in the timeline by default" newNoteRecived: "There are new notes" sounds: "Sounds" sound: "Sounds" @@ -1109,6 +1105,10 @@ additionalEmojiDictionary: "Additional emoji dictionaries" installed: "Installed" branding: "Branding" enableServerMachineStats: "Publish server hardware stats" +enableAchievements: "Enable Achievements" +turnOffAchievements: "Turning this off will disable the achievement system" +enableBotTrending: "Populate Hashtags with Bots" +turnOffBotTrending: "Turning this off will stop Bots from populating Hashtags" enableIdenticonGeneration: "Enable user identicon generation" turnOffToImprovePerformance: "Turning this off can increase performance." createInviteCode: "Generate invite" @@ -1145,6 +1145,7 @@ loadConversation: "Show conversation" pinnedList: "Pinned list" keepScreenOn: "Keep screen on" clickToOpen: "Click to open notes" +showBots: "Show bots in timeline" verifiedLink: "Link ownership has been verified" notifyNotes: "Notify about new notes" unnotifyNotes: "Stop notifying about new notes" @@ -1156,8 +1157,8 @@ edited: "Edited" notificationRecieveConfig: "Notification Settings" mutualFollow: "Mutual follow" fileAttachedOnly: "Only notes with files" -showRepliesToOthersInTimeline: "Show replies to others in TL" -hideRepliesToOthersInTimeline: "Hide replies to others from TL" +showRepliesToOthersInTimeline: "Show replies to others in timeline" +hideRepliesToOthersInTimeline: "Hide replies to others from timeline" externalServices: "External Services" impressum: "Impressum" impressumUrl: "Impressum URL" @@ -1770,7 +1771,7 @@ _2fa: step2Click: "Clicking on this QR code will allow you to register 2FA to your security key or phone authenticator app." step2Uri: "Enter the following URI if you are using a desktop program" step3Title: "Enter an authentication code" - step3: "Enter the token provided by your app to finish setup." + step3: "Enter the authentication code (token) provided by your app to finish setup." setupCompleted: "Setup complete" step4: "From now on, any future login attempts will ask for such a login token." securityKeyNotSupported: "Your browser does not support security keys." @@ -1954,6 +1955,7 @@ _exportOrImport: userLists: "User lists" excludeMutingUsers: "Exclude muted users" excludeInactiveUsers: "Exclude inactive users" + withReplies: "Include replies from imported users in the timeline" _charts: federation: "Federation" apRequest: "Requests" @@ -2106,7 +2108,7 @@ _deck: introduction: "Create the perfect interface for you by arranging columns freely!" introduction2: "Click on the + on the right of the screen to add new colums whenever you want." widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget." - useSimpleUiForNonRootPages: "Use simplified UI to navigated pages" + useSimpleUiForNonRootPages: "Use simple UI for navigated pages" usedAsMinWidthWhenFlexible: "Minimum width will be used for this when the \"Auto-adjust width\" option is enabled" flexible: "Auto-adjust width" _columns: diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 9e83998df..82a996efb 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -195,6 +195,7 @@ perHour: "por hora" perDay: "por día" stopActivityDelivery: "Dejar de enviar actividades" blockThisInstance: "Bloquear instancia" +silenceThisInstance: "Silenciar esta instancia" operations: "Operaciones" software: "Software" version: "Versión" @@ -214,6 +215,8 @@ clearCachedFiles: "Limpiar caché" clearCachedFilesConfirm: "¿Desea borrar todos los archivos remotos cacheados?" blockedInstances: "Instancias bloqueadas" blockedInstancesDescription: "Seleccione los hosts de las instancias que desea bloquear, separadas por una linea nueva. Las instancias bloqueadas no podrán comunicarse con esta instancia." +silencedInstances: "Instancias silenciadas" +silencedInstancesDescription: "Listar los hostname de las instancias que quieres silenciar. Todas las cuentas de las instancias listadas serán tratadas como silenciadas, solo podrán hacer peticiones de seguimiento, y no podrán mencionar cuentas locales si no las siguen. Esto no afecta a las instancias bloqueadas." muteAndBlock: "Silenciar y bloquear" mutedUsers: "Usuarios silenciados" blockedUsers: "Usuarios bloqueados" @@ -531,6 +534,7 @@ serverLogs: "Registros del servidor" deleteAll: "Eliminar todos" showFixedPostForm: "Mostrar el formulario de las entradas encima de la línea de tiempo" showFixedPostFormInChannel: "Mostrar el formulario de publicación por encima de la cronología (Canales)" +withRepliesByDefaultForNewlyFollowed: "Incluir por defecto respuestas de usuarios recién seguidos en la línea de tiempo" newNoteRecived: "Tienes una nota nueva" sounds: "Sonidos" sound: "Sonidos" @@ -1121,6 +1125,20 @@ unnotifyNotes: "Dejar de notificar nuevas notas" authentication: "Autenticación" authenticationRequiredToContinue: "Por favor, autentifícate para continuar" dateAndTime: "Fecha y hora" +showRenotes: "Mostrar renotas" +edited: "Editado" +notificationRecieveConfig: "Ajustes de Notificaciones" +mutualFollow: "Os seguís mutuamente" +fileAttachedOnly: "Solo notas con archivos" +showRepliesToOthersInTimeline: "Mostrar respuestas a otros en la línea de tiempo" +hideRepliesToOthersInTimeline: "Ocultar respuestas a otros en la línea de tiempo" +externalServices: "Servicios Externos" +impressum: "Impressum" +impressumUrl: "Impressum URL" +impressumDescription: "En algunos países, como Alemania, la inclusión del operador de datos (el Impressum) es requerido legalmente para sitios web comerciales." +privacyPolicy: "Política de Privacidad" +privacyPolicyUrl: "URL de la Política de Privacidad" +tosAndPrivacyPolicy: "Condiciones de Uso y Política de Privacidad" _announcement: forExistingUsers: "Solo para usuarios registrados" forExistingUsersDescription: "Este anuncio solo se mostrará a aquellos usuarios registrados en el momento de su publicación. Si se deshabilita esta opción, aquellos usuarios que se registren tras su publicación también lo verán." @@ -1470,6 +1488,7 @@ _role: descriptionOfRateLimitFactor: "Límites más bajos son menos restrictivos, más altos menos restrictivos" canHideAds: "Puede ocultar anuncios" canSearchNotes: "Uso de la búsqueda de notas" + canUseTranslator: "Uso de traductor" _condition: isLocal: "Usuario local" isRemote: "Usuario remoto" @@ -1518,6 +1537,10 @@ _ad: reduceFrequencyOfThisAd: "Mostrar menos este anuncio." hide: "No mostrar" timezoneinfo: "El día de la semana está determidado por la zona horaria del servidor." + adsSettings: "Ajustes de anuncios" + notesPerOneAd: "Intervalo de actualización de anuncios en tiempo real (Notas por cada anuncio)" + setZeroToDisable: "Establece este valor a 0 para deshabilitar la actualización de anuncios en tiempo real" + adsTooClose: "El intervalo de anuncios actual puede empeorar la experiencia del usuario por ser demasiado bajo." _forgotPassword: enterEmail: "Ingrese el correo usado para registrar la cuenta. Se enviará un link para resetear la contraseña." ifNoEmail: "Si no utilizó un correo para crear la cuenta, contáctese con el administrador." @@ -1902,6 +1925,7 @@ _exportOrImport: userLists: "Listas" excludeMutingUsers: "Excluir usuarios silenciados" excludeInactiveUsers: "Excluir usuarios inactivos" + withReplies: "Incluir respuestas de los usuarios importados en la línea de tiempo" _charts: federation: "Federación" apRequest: "Pedidos" @@ -2119,3 +2143,14 @@ _moderationLogTypes: unmarkSensitiveDriveFile: "Archivo marcado como no sensible" resolveAbuseReport: "Reporte resuelto" createInvitation: "Generar invitación" + createAd: "Anuncio creado" + deleteAd: "Anuncio eliminado" + updateAd: "Anuncio actualizado" +_fileViewer: + title: "Detalles del archivo" + type: "Tipo de archivo" + size: "Tamaño del archivo" + url: "URL" + uploadedAt: "Subido el" + attachedNotes: "Notas adjuntas" + thisPageCanBeSeenFromTheAuthor: "Esta página solo puede ser vista por el autor." diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index edbcc6eff..ccaaef231 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -184,7 +184,7 @@ selectUser: "Sélectionner un·e utilisateur·rice" recipient: "Destinataire" annotation: "Commentaires" federation: "Fédération" -instances: "Instance" +instances: "Instances" registeredAt: "Premier contact le" latestRequestReceivedAt: "Dernière requête reçue" latestStatus: "Dernier statut" @@ -194,6 +194,7 @@ perHour: "par heure" perDay: "par jour" stopActivityDelivery: "Arrêter l’envoi de l’activité" blockThisInstance: "Bloquer cette instance" +silenceThisInstance: "Mettre cette instance en sourdine" operations: "Opérations" software: "Logiciel" version: "Version" @@ -213,6 +214,8 @@ clearCachedFiles: "Vider le cache" clearCachedFilesConfirm: "Êtes-vous sûr·e de vouloir vider tout le cache de fichiers distants ?" blockedInstances: "Instances bloquées" blockedInstancesDescription: "Listez les instances que vous désirez bloquer, une par ligne. Ces instances ne seront plus en capacité d'interagir avec votre instance." +silencedInstances: "Instances mises en sourdine" +silencedInstancesDescription: "Énumérer les noms d'hôte des instances à mettre en sourdine. Tous les comptes des instances énumérées seront traités comme mis en sourdine, ne peuvent faire que des demandes de suivi et ne peuvent pas mentionner les comptes locaux s'ils ne sont pas suivis. Cela n'affectera pas les instances bloquées." muteAndBlock: "Masqué·e·s / Bloqué·e·s" mutedUsers: "Utilisateur·rice·s en sourdine" blockedUsers: "Utilisateur·rice·s bloqué·e·s" @@ -927,6 +930,7 @@ remoteOnly: "Distant uniquement" failedToUpload: "Échec du transfert" cannotUploadBecauseInappropriate: "Impossible de télécharger le document car il a été déterminé qu'il pouvait contenir un contenu inapproprié." cannotUploadBecauseNoFreeSpace: "Impossible de télécharger en raison d'un manque d'espace libre sur le disque.\n" +cannotUploadBecauseExceedsFileSizeLimit: "Ce fichier ne peut pas être téléchargé parce qu'il dépasse la taille maximale." beta: "Bêta" enableAutoSensitive: "Détermination automatique de NSFW" enableAutoSensitiveDescription: "S'il est disponible, le drapeau NSFW est automatiquement défini sur le média en utilisant l'apprentissage automatique. Même si cette fonction est désactivée, elle peut être réglée automatiquement dans certains cas." @@ -948,12 +952,14 @@ caption: "Libellé" loggedInAsBot: "Connecté actuellement en tant que bot" tools: "Outils" cannotLoad: "Chargement impossible" +numberOfProfileView: "Nombre de vues du profil" like: "J'aime" unlike: "Ne plus aimer" numberOfLikes: "Favoris" show: "Affichage" neverShow: "Ne plus afficher" remindMeLater: "Peut-être plus tard" +didYouLikeMisskey: "Avez-vous aimé Misskey ?" roles: "Rôles" role: "Rôles" noRole: "Aucun rôle" @@ -963,9 +969,13 @@ assign: "Attribuer" unassign: "Retirer" color: "Couleur" manageCustomEmojis: "Gestion des émojis personnalisés" +youCannotCreateAnymore: "Vous avez atteint la limite de création." +cannotPerformTemporary: "Temporairement indisponible" +invalidParamError: "Paramètres invalides" preset: "Préréglage" selectFromPresets: "Sélectionner à partir des préréglages" achievements: "Accomplissements" +gotInvalidResponseError: "Réponse du serveur invalide" thisPostMayBeAnnoying: "Cette note peut gêner d'autres personnes." thisPostMayBeAnnoyingHome: "Publier vers le fil principal" thisPostMayBeAnnoyingCancel: "Annuler" @@ -980,6 +990,8 @@ sensitiveWords: "Mots sensibles" notesSearchNotAvailable: "La recherche de notes n'est pas disponible." license: "Licence" myClips: "Mes clips" +showClipButtonInNoteFooter: "Ajouter « Clip » au menu d'action de la note" +noteIdOrUrl: "Identifiant de la note ou URL" video: "Vidéo" videos: "Vidéos" dataSaver: "Économiseur de données" @@ -987,6 +999,7 @@ accountMigration: "Migration de compte" accountMoved: "Cet·te utilisateur·rice a migré son compte vers :" accountMovedShort: "Ce compte a migré" operationForbidden: "Opération non autorisée" +forceShowAds: "Toujours afficher les publicités" addMemo: "Ajouter un mémo" reactionsList: "Réactions" renotesList: "Liste de renotes" @@ -995,9 +1008,12 @@ leftTop: "En haut à gauche" rightTop: "En haut à droite" leftBottom: "En bas à gauche" rightBottom: "En bas à droite" +stackAxis: "Direction d'empilement" vertical: "Vertical" horizontal: "Latéral" +position: "Position" serverRules: "Règles du serveur" +preservedUsernames: "Nom d'utilisateur·rice réservé" archive: "Archive" displayOfNote: "Affichage de la note" youFollowing: "Abonné·e" @@ -1531,7 +1547,7 @@ _visibility: _postForm: replyPlaceholder: "Répondre à cette note ..." quotePlaceholder: "Citez cette note ..." - channelPlaceholder: "Publier vers le canal" + channelPlaceholder: "Publier au canal…" _placeholders: a: "Quoi de neuf ?" b: "Il s'est passé quelque chose ?" diff --git a/locales/index.d.ts b/locales/index.d.ts index f904d72e6..e7ab2048b 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -549,6 +549,7 @@ export interface Locale { "deleteAll": string; "showFixedPostForm": string; "showFixedPostFormInChannel": string; + "withRepliesByDefaultForNewlyFollowed": string; "newNoteRecived": string; "sounds": string; "sound": string; @@ -1107,6 +1108,10 @@ export interface Locale { "installed": string; "branding": string; "enableServerMachineStats": string; + "enableAchievements": string; + "turnOffAchievements": string; + "enableBotTrending": string; + "turnOffBotTrending": string; "enableIdenticonGeneration": string; "turnOffToImprovePerformance": string; "createInviteCode": string; @@ -1143,6 +1148,7 @@ export interface Locale { "pinnedList": string; "keepScreenOn": string; "clickToOpen": string; + "showBots": string; "verifiedLink": string; "notifyNotes": string; "unnotifyNotes": string; @@ -2079,6 +2085,7 @@ export interface Locale { "userLists": string; "excludeMutingUsers": string; "excludeInactiveUsers": string; + "withReplies": string; }; "_charts": { "federation": string; diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 6d8e369f4..f0b808767 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -116,8 +116,8 @@ inChannelQuote: "Cita nel canale" pinnedNote: "Nota in primo piano" pinned: "Fissa sul profilo" you: "Tu" -clickToShow: "Clicca per visualizzare" -sensitive: "Esplicito" +clickToShow: "Contenuto occultato, cliccare solo se si intende vedere" +sensitive: "Allegato esplicito" add: "Aggiungi" reaction: "Reazioni" reactions: "Reazioni" @@ -195,6 +195,7 @@ perHour: "orario" perDay: "giornaliero" stopActivityDelivery: "Interrompi la distribuzione di attività" blockThisInstance: "Blocca questa istanza" +silenceThisInstance: "Silenzia l'istanza" operations: "Operazioni" software: "Software" version: "Versione" @@ -214,6 +215,8 @@ clearCachedFiles: "Svuota cache" clearCachedFilesConfirm: "Vuoi davvero svuotare la cache da tutti i file remoti?" blockedInstances: "Istanze bloccate" blockedInstancesDescription: "Elenca le istanze che vuoi bloccare, una per riga. Esse non potranno più interagire con la tua istanza." +silencedInstances: "Istanze silenziate" +silencedInstancesDescription: "Elenca i nomi host delle istanze che vuoi silenziare. Tutti i profili nelle istanze silenziate vengono trattati come tali. Possono solo inviare richieste di follow e menzionare soltanto i profili locali che seguono. Le istanze bloccate non sono interessate." muteAndBlock: "Silenziati / Bloccati" mutedUsers: "Profili silenziati" blockedUsers: "Profili bloccati" @@ -278,7 +281,7 @@ agreeTo: "Sono d'accordo con {0}" agree: "Accetto" agreeBelow: "Accetto quanto riportato sotto" basicNotesBeforeCreateAccount: "Note importanti" -termsOfService: "Informativa ai sensi degli artt. 13 e 14 del Regolamento UE 2016/679 per la protezione dei dati personali (GDPR)" +termsOfService: "Condizioni d'uso del servizio" start: "Inizia!" home: "Home" remoteUserCaution: "Le informazioni potrebbero essere incomplete poiché questo profilo remoto potrebbe non essere completamente federato." @@ -1132,9 +1135,9 @@ externalServices: "Servizi esterni" impressum: "Dichiarazione di proprietà" impressumUrl: "URL della dichiarazione di proprietà" impressumDescription: "La dichiarazione di proprietà, è obbligatoria in alcuni paesi come la Germania (Impressum)." -privacyPolicy: "Informativa sulla privacy" +privacyPolicy: "Informativa ai sensi degli artt. 13 e 14 del Regolamento UE 2016/679 per la protezione dei dati personali (GDPR)" privacyPolicyUrl: "URL della informativa privacy" -tosAndPrivacyPolicy: "Condizioni d'uso e informativa sulla privacy" +tosAndPrivacyPolicy: "Condizioni d'uso e informativa privacy" _announcement: forExistingUsers: "Solo ai profili attuali" forExistingUsersDescription: "L'annuncio sarà visibile solo ai profili esistenti in questo momento. Se disabilitato, sarà visibile anche ai profili che verranno creati dopo la pubblicazione di questo annuncio." @@ -1879,9 +1882,9 @@ _poll: remainingSeconds: "Rimangono {s} secondi" _visibility: public: "Pubblica" - publicDescription: "Visibile per tutti sul Fediverso" + publicDescription: "Visibilità pubblica" home: "Home" - homeDescription: "Visibile solo sulla timeline locale" + homeDescription: "Visibile solo nella Home" followers: "Follower" followersDescription: "Visibile solo ai tuoi follower" specified: "Nota diretta" @@ -2141,3 +2144,11 @@ _moderationLogTypes: createAd: "Banner creato" deleteAd: "Banner eliminato" updateAd: "Banner aggiornato" +_fileViewer: + title: "Dettagli del file" + type: "Tipo di file" + size: "Dimensioni file" + url: "URL" + uploadedAt: "Caricato il" + attachedNotes: "Note a cui è allegato" + thisPageCanBeSeenFromTheAuthor: "Questa pagina può essere vista solo da chi ha caricato il file." diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 0e46d1f2b..ae25ec5d7 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -546,6 +546,7 @@ serverLogs: "サーバーログ" deleteAll: "全て削除" showFixedPostForm: "タイムライン上部に投稿フォームを表示する" showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)" +withRepliesByDefaultForNewlyFollowed: "フォローする際、デフォルトで返信をTLに含むようにする" newNoteRecived: "新しいノートがあります" sounds: "サウンド" sound: "サウンド" @@ -604,7 +605,7 @@ poll: "アンケート" useCw: "内容を隠す" enablePlayer: "プレイヤーを開く" disablePlayer: "プレイヤーを閉じる" -expandTweet: "ツイートを展開する" +expandTweet: "ポストを展開する" themeEditor: "テーマエディター" description: "説明" describeFile: "キャプションを付ける" @@ -1104,6 +1105,10 @@ additionalEmojiDictionary: "絵文字の追加辞書" installed: "インストール済み" branding: "ブランディング" enableServerMachineStats: "サーバーのマシン情報を公開する" +enableAchievements: "実績を有効にする" +turnOffAchievements: "これをオフにすると、達成システムは無効になります。" +enableBotTrending: "ハッシュタグにボットを追加する" +turnOffBotTrending: "これをオフにすると、ボットがハッシュタグを入力しなくなります。" enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする" turnOffToImprovePerformance: "オフにするとパフォーマンスが向上します。" createInviteCode: "招待コードを作成" @@ -1140,6 +1145,7 @@ loadConversation: "会話を見る" pinnedList: "ピン留めされたリスト" keepScreenOn: "デバイスの画面を常にオンにする" clickToOpen: "クリックしてノートを開く" +showBots: "ボットをタイムラインに表示" verifiedLink: "このリンク先の所有者であることが確認されました" notifyNotes: "投稿を通知" unnotifyNotes: "投稿の通知を解除" @@ -1994,6 +2000,7 @@ _exportOrImport: userLists: "リスト" excludeMutingUsers: "ミュートしているユーザーを除外" excludeInactiveUsers: "使われていないアカウントを除外" + withReplies: "インポートした人による返信をTLに含むようにする" _charts: federation: "連合" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 1c655f588..a706d3990 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -1117,15 +1117,25 @@ keepScreenOn: "เปิดหน้าจอไว้" notifyNotes: "แจ้งเตือนเกี่ยวกับโพสต์ใหม่" unnotifyNotes: "หยุดการแจ้งเตือนเกี่ยวกับโน้ตใหม่" authentication: "การตรวจสอบสิทธิ์" +authenticationRequiredToContinue: "กรุณาตรวจสอบการรับรองความถูกต้องเพื่อดำเนินการต่อ" dateAndTime: "เวลาประทับ" showRenotes: "แสดงรีโน้ต" edited: "แก้ไขแล้ว" notificationRecieveConfig: "การตั้งค่าการแจ้งเตือน" mutualFollow: "ติดตามซึ่งกันและกัน" fileAttachedOnly: "เฉพาะโน้ตที่มีไฟล์เท่านั้น" +showRepliesToOthersInTimeline: "แสดงการตอบกลับไปยังอื่นๆในไทม์ไลน์" +hideRepliesToOthersInTimeline: "ซ่อนการตอบกลับไปยังอื่นๆจากไทม์ไลน์" +externalServices: "บริการภายนอก" +impressum: "อิมเพรสชั่น" +impressumUrl: "URL อิมเพรสชั่น" +privacyPolicy: "นโยบายความเป็นส่วนตัว" +privacyPolicyUrl: "URL นโยบายความเป็นส่วนตัว" +tosAndPrivacyPolicy: "เงื่อนไขในการให้บริการและนโยบายความเป็นส่วนตัว" _announcement: forExistingUsers: "ผู้ใช้งานที่มีอยู่เท่านั้น" forExistingUsersDescription: "การประกาศนี้จะแสดงต่อผู้ใช้ที่มีอยู่ ณ จุดที่เผยแพร่นั้นๆถ้าหากเปิดใช้งาน ถ้าหากปิดใช้งานผู้ที่กำลังสมัครใหม่หลังจากโพสต์แล้วนั้นก็จะเห็นเช่นกัน" + needConfirmationToRead: "จำเป็นต้องยืนยันเพื่อทำเครื่องหมายบอกว่าอ่านแล้ว" needConfirmationToReadDescription: "ข้อความแจ้งแยก ถ้าหากต้องการเพื่อยืนยันว่ากำลังทำเครื่องหมายประกาศนี้ว่าอ่านแล้วจะแสดงขึ้นถ้าหากเปิดใช้งาน การประกาศนั้นจะไม่รวมอยู่ในฟังก์ชั่นว่า \"ทำเครื่องหมายทั้งหมดว่าอ่านแล้ว\"" end: "ประกาศเก็บถาวร" tooManyActiveAnnouncementDescription: "การมีประกาศที่ใช้งานมากเกินไปนั้นอาจจะทำให้ประสบการณ์ของผู้ใช้งานนั้นดูแย่ลง โปรดกรุณาพิจารณาการเก็บประกาศที่ล้าสมัยด้วยนะค่ะ" @@ -1150,6 +1160,8 @@ _serverRules: description: "ชุดของกฎที่จะแสดงก่อนการลงทะเบียนเราขอแนะนำให้ตั้งค่าสรุปข้อกำหนดในการให้บริการ" _serverSettings: iconUrl: "ไอคอน URL" + appIconUsageExample: "E.g. เป็น PWA หรือเมื่อแสดงผลเป็นบุ๊กมาร์กหน้าจอหลักบนโทรศัพท์" + appIconResolutionMustBe: "ความละเอียดขั้นต่ำไว้คือ {resolution}." manifestJsonOverride: "manifest.json โอเวอร์ลาย" shortName: "ชื่อย่อ" _accountMigration: @@ -1515,6 +1527,8 @@ _ad: reduceFrequencyOfThisAd: "แสดงโฆษณานี้ให้น้อยลง" hide: "ไม่ต้องแสดง" timezoneinfo: "วันในสัปดาห์นี้จะถูกกำหนดจากโซนเวลาของเซิร์ฟเวอร์" + adsSettings: "ตั้งค่าการโฆษณา" + setZeroToDisable: "ตั้งค่านี้ให้เป็น 0 เพื่อปิดใช้งานโฆษณาอัปเดตแบบเรียลไทม์" _forgotPassword: enterEmail: "ป้อนที่อยู่อีเมลที่คุณเคยใช้ในการลงทะเบียนไว้ ลิงก์ที่คุณสามารถรีเซ็ตรหัสผ่านได้นั้นจะถูกส่งไปนะ" ifNoEmail: "ถ้าหากคุณไม่ได้ใช้อีเมลระหว่างการลงทะเบียน กรุณาติดต่อผู้ดูแลระบบอินสแตนซ์แทนนะ" @@ -1714,6 +1728,7 @@ _2fa: step1: "ขั้นตอนแรก ติดตั้งแอปยืนยันตัวตน (เช่น {a} หรือ {b}) บนอุปกรณ์ของคุณ" step2: "จากนั้นสแกนรหัส QR ที่แสดงบนหน้าจอนี้" step2Click: "การคลิกที่รหัส QR นี้จะช่วยให้คุณนั้นสามารถลงทะเบียน 2FA กับคีย์ความปลอดภัยหรือแอปตรวจสอบความถูกต้องของโทรศัพท์ได้" + step2Uri: "ป้อนใส่ URL ดังต่อไปนี้ถ้าหากคุณใช้โปรแกรมเดสก์ท็อป" step3Title: "ป้อนรหัสยืนยัน" step3: "ป้อนโทเค็นที่แอปของคุณให้มาเพื่อเสร็จสิ้นการตั้งค่า" setupCompleted: "ตั้งค่าสำเร็จแล้ว" @@ -1732,6 +1747,8 @@ _2fa: renewTOTPOk: "ตั้งค่าคอนฟิกใหม่" renewTOTPCancel: "ไม่เป็นไร" backupCodes: "รหัสสำรองข้อมูล" + backupCodeUsedWarning: "มีการใช้รหัสสำรองแล้ว โปรดกรุณากำหนดค่าการตรวจสอบสิทธิ์แบบสองปัจจัยโดยเร็วที่สุดถ้าหากคุณยังไม่สามารถใช้งานได้อีกต่อไป" + backupCodesExhaustedWarning: "รหัสสำรองทั้งหมดถูกใช้แล้วถ้าหากคุณยังสูญเสียการเข้าถึงแอปการตรวจสอบสิทธิ์แบบสองปัจจัยคุณจะไม่สามารถเข้าถึงบัญชีนี้ได้ กรุณากำหนดค่าการรับรองความถูกต้องด้วยการยืนยันสองชั้น" _permissions: "read:account": "ดูข้อมูลบัญชีของคุณ" "write:account": "แก้ไขข้อมูลบัญชีของคุณ" @@ -1894,6 +1911,7 @@ _exportOrImport: userLists: "รายการ" excludeMutingUsers: "ยกเว้นผู้ใช้ที่ปิดเสียง" excludeInactiveUsers: "ยกเว้นผู้ใช้ที่ไม่ได้ใช้งาน" + withReplies: "รวมการตอบกลับจากผู้ใช้ที่นำเข้าไว้ในไทม์ไลน์" _charts: federation: "สหพันธ์" apRequest: "คำขอ" @@ -2114,3 +2132,11 @@ _moderationLogTypes: createAd: "สร้างโฆษณาแล้ว" deleteAd: "ลบโฆษณาออกแล้ว" updateAd: "อัปเดตโฆษณาแล้ว" +_fileViewer: + title: "รายละเอียดไฟล์" + type: "ประเภทไฟล์" + size: "ขนาดไฟล์" + url: "URL" + uploadedAt: "วันที่เข้าร่วม" + attachedNotes: "โน้ตที่แนบมาด้วย" + thisPageCanBeSeenFromTheAuthor: "หน้าเพจนี้จะสามารถปรากฏได้โดยผู้ใช้ที่อัปโหลดไฟล์นี้เท่านั้น" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index ccdb87379..acb4dfa5e 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1125,8 +1125,8 @@ showRenotes: "顯示轉發貼文" edited: "已編輯" notificationRecieveConfig: "接受通知的設定" mutualFollow: "互相追隨" -fileAttachedOnly: "包含附件" -showRepliesToOthersInTimeline: "在時間軸上顯示給其他人的回覆" +fileAttachedOnly: "顯示包含附件的貼文" +showRepliesToOthersInTimeline: "顯示給其他人的回覆" hideRepliesToOthersInTimeline: "在時間軸上隱藏給其他人的回覆" externalServices: "外部服務" impressum: "營運者資訊" diff --git a/package.json b/package.json index 61d12901c..b04c4f444 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://github.com/transfem-org/sharkey.git" }, - "packageManager": "pnpm@8.8.0", + "packageManager": "pnpm@8.9.2", "workspaces": [ "packages/frontend", "packages/backend", @@ -51,8 +51,8 @@ "typescript": "5.2.2" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "6.7.5", - "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/eslint-plugin": "6.8.0", + "@typescript-eslint/parser": "6.8.0", "cross-env": "7.0.3", "cypress": "13.3.1", "eslint": "8.51.0", diff --git a/packages/backend/migration/1697441463087-FollowRequestWithReplies.js b/packages/backend/migration/1697441463087-FollowRequestWithReplies.js new file mode 100644 index 000000000..214c6f668 --- /dev/null +++ b/packages/backend/migration/1697441463087-FollowRequestWithReplies.js @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + + +export class FollowRequestWithReplies1697441463087 { + name = 'FollowRequestWithReplies1697441463087' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "follow_request" ADD "withReplies" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "follow_request" DROP COLUMN "withReplies"`); + } +} diff --git a/packages/backend/migration/1697603945000-BotTrending.js b/packages/backend/migration/1697603945000-BotTrending.js new file mode 100644 index 000000000..73f1f598e --- /dev/null +++ b/packages/backend/migration/1697603945000-BotTrending.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class BotTrending1697603945000 { + name = 'BotTrending1697603945000' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "enableBotTrending" boolean NOT NULL DEFAULT true`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableBotTrending"`); + } +} diff --git a/packages/backend/migration/1697624010000-isSilenced.js b/packages/backend/migration/1697624010000-isSilenced.js new file mode 100644 index 000000000..98b5e8c55 --- /dev/null +++ b/packages/backend/migration/1697624010000-isSilenced.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class IsSilenced1697624010000 { + name = 'IsSilenced1697624010000' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "isSilenced" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isSilenced"`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index 49aedbddb..4826740ba 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -58,9 +58,10 @@ "dependencies": { "@aws-sdk/client-s3": "3.412.0", "@aws-sdk/lib-storage": "3.412.0", - "@bull-board/api": "5.8.4", - "@bull-board/fastify": "5.8.4", - "@bull-board/ui": "5.8.4", + "@smithy/node-http-handler": "2.1.5", + "@bull-board/api": "5.9.1", + "@bull-board/fastify": "5.9.1", + "@bull-board/ui": "5.9.1", "@discordapp/twemoji": "14.1.2", "@fastify/accepts": "4.2.0", "@fastify/cookie": "9.1.0", @@ -76,7 +77,6 @@ "@peertube/http-signature": "1.7.0", "@simplewebauthn/server": "8.3.2", "@sinonjs/fake-timers": "11.1.0", - "@smithy/node-http-handler": "2.1.5", "@swc/cli": "0.1.62", "@swc/core": "1.3.93", "accepts": "1.3.8", @@ -158,7 +158,7 @@ "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", "summaly": "github:misskey-dev/summaly", - "systeminformation": "5.21.11", + "systeminformation": "5.21.12", "tinycolor2": "1.6.0", "tmp": "0.2.1", "tsc-alias": "1.8.8", @@ -177,13 +177,13 @@ "@jest/globals": "29.7.0", "@simplewebauthn/typescript-types": "8.0.0", "@swc/jest": "0.2.29", - "@types/accepts": "1.3.5", - "@types/archiver": "5.3.3", - "@types/bcryptjs": "2.4.4", - "@types/body-parser": "1.19.3", + "@types/accepts": "1.3.6", + "@types/archiver": "5.3.4", + "@types/bcryptjs": "2.4.5", + "@types/body-parser": "1.19.4", "@types/cbor": "6.0.0", - "@types/color-convert": "2.0.1", - "@types/content-disposition": "0.5.6", + "@types/color-convert": "2.0.2", + "@types/content-disposition": "0.5.7", "@types/fluent-ffmpeg": "2.1.22", "@types/http-link-header": "1.0.3", "@types/jest": "29.5.5", @@ -217,8 +217,8 @@ "@types/vary": "1.1.1", "@types/web-push": "3.6.1", "@types/ws": "8.5.7", - "@typescript-eslint/eslint-plugin": "6.7.5", - "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/eslint-plugin": "6.8.0", + "@typescript-eslint/parser": "6.8.0", "aws-sdk-client-mock": "3.0.0", "cross-env": "7.0.3", "eslint": "8.51.0", diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 94c8ad0cf..65be27554 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -16,7 +16,7 @@ import type { AntennasRepository, UserListMembershipsRepository } from '@/models import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; @Injectable() @@ -39,7 +39,7 @@ export class AntennaService implements OnApplicationShutdown { private utilityService: UtilityService, private globalEventService: GlobalEventService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, ) { this.antennasFetched = false; this.antennas = []; @@ -84,7 +84,7 @@ export class AntennaService implements OnApplicationShutdown { const redisPipeline = this.redisForTimelines.pipeline(); for (const antenna of matchedAntennas) { - this.redisTimelineService.push(`antennaTimeline:${antenna.id}`, note.id, 200, redisPipeline); + this.funoutTimelineService.push(`antennaTimeline:${antenna.id}`, note.id, 200, redisPipeline); this.globalEventService.publishAntennaStream(antenna.id, 'note', note); } diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index 131c09f27..ad4f58e1d 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -62,7 +62,7 @@ import { FileInfoService } from './FileInfoService.js'; import { SearchService } from './SearchService.js'; import { ClipService } from './ClipService.js'; import { FeaturedService } from './FeaturedService.js'; -import { RedisTimelineService } from './RedisTimelineService.js'; +import { FunoutTimelineService } from './FunoutTimelineService.js'; import { ChartLoggerService } from './chart/ChartLoggerService.js'; import FederationChart from './chart/charts/federation.js'; import NotesChart from './chart/charts/notes.js'; @@ -192,7 +192,7 @@ const $FileInfoService: Provider = { provide: 'FileInfoService', useExisting: Fi const $SearchService: Provider = { provide: 'SearchService', useExisting: SearchService }; const $ClipService: Provider = { provide: 'ClipService', useExisting: ClipService }; const $FeaturedService: Provider = { provide: 'FeaturedService', useExisting: FeaturedService }; -const $RedisTimelineService: Provider = { provide: 'RedisTimelineService', useExisting: RedisTimelineService }; +const $FunoutTimelineService: Provider = { provide: 'FunoutTimelineService', useExisting: FunoutTimelineService }; const $ChartLoggerService: Provider = { provide: 'ChartLoggerService', useExisting: ChartLoggerService }; const $FederationChart: Provider = { provide: 'FederationChart', useExisting: FederationChart }; @@ -326,7 +326,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting SearchService, ClipService, FeaturedService, - RedisTimelineService, + FunoutTimelineService, ChartLoggerService, FederationChart, NotesChart, @@ -453,7 +453,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $SearchService, $ClipService, $FeaturedService, - $RedisTimelineService, + $FunoutTimelineService, $ChartLoggerService, $FederationChart, $NotesChart, @@ -581,7 +581,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting SearchService, ClipService, FeaturedService, - RedisTimelineService, + FunoutTimelineService, FederationChart, NotesChart, UsersChart, @@ -707,7 +707,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $SearchService, $ClipService, $FeaturedService, - $RedisTimelineService, + $FunoutTimelineService, $FederationChart, $NotesChart, $UsersChart, diff --git a/packages/backend/src/core/RedisTimelineService.ts b/packages/backend/src/core/FunoutTimelineService.ts similarity index 95% rename from packages/backend/src/core/RedisTimelineService.ts rename to packages/backend/src/core/FunoutTimelineService.ts index 94541759c..c633c329e 100644 --- a/packages/backend/src/core/RedisTimelineService.ts +++ b/packages/backend/src/core/FunoutTimelineService.ts @@ -10,7 +10,7 @@ import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; @Injectable() -export class RedisTimelineService { +export class FunoutTimelineService { constructor( @Inject(DI.redisForTimelines) private redisForTimelines: Redis.Redis, @@ -77,4 +77,9 @@ export class RedisTimelineService { ); }); } + + @bindThis + public purge(name: string) { + return this.redisForTimelines.del('list:' + name); + } } diff --git a/packages/backend/src/core/HashtagService.ts b/packages/backend/src/core/HashtagService.ts index 1a2f37be3..d37899990 100644 --- a/packages/backend/src/core/HashtagService.ts +++ b/packages/backend/src/core/HashtagService.ts @@ -45,7 +45,7 @@ export class HashtagService { await this.updateHashtag(user, tag, true, true); } - for (const tag of (user.tags ?? []).filter(x => !tags.includes(x))) { + for (const tag of user.tags.filter(x => !tags.includes(x))) { await this.updateHashtag(user, tag, true, false); } } diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index da7e6b133..ee2dbc385 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -54,7 +54,7 @@ import { RoleService } from '@/core/RoleService.js'; import { MetaService } from '@/core/MetaService.js'; import { SearchService } from '@/core/SearchService.js'; import { FeaturedService } from '@/core/FeaturedService.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import { nyaize } from '@/misc/nyaize.js'; import { UtilityService } from '@/core/UtilityService.js'; @@ -197,7 +197,7 @@ export class NoteCreateService implements OnApplicationShutdown { private idService: IdService, private globalEventService: GlobalEventService, private queueService: QueueService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, private noteReadService: NoteReadService, private notificationService: NotificationService, private relayService: RelayService, @@ -253,8 +253,10 @@ export class NoteCreateService implements OnApplicationShutdown { if (data.channel != null) data.visibleUsers = []; if (data.channel != null) data.localOnly = true; + const meta = await this.metaService.fetch(); + if (data.visibility === 'public' && data.channel == null) { - const sensitiveWords = (await this.metaService.fetch()).sensitiveWords; + const sensitiveWords = meta.sensitiveWords; if (this.isSensitive(data, sensitiveWords)) { data.visibility = 'home'; } else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) { @@ -262,7 +264,7 @@ export class NoteCreateService implements OnApplicationShutdown { } } - const inSilencedInstance = this.utilityService.isSilencedHost((await this.metaService.fetch()).silencedHosts, user.host); + const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host); if (data.visibility === 'public' && inSilencedInstance && user.host !== null) { data.visibility = 'home'; @@ -316,7 +318,7 @@ export class NoteCreateService implements OnApplicationShutdown { data.text = data.text.trim(); if (user.isCat && user.speakAsCat) { - patsedText = patsedText ?? mfm.parse(data.text); + patsedText = mfm.parse(data.text); function nyaizeNode(node: mfm.MfmNode) { if (node.type === 'quote') return; if (node.type === 'text') { @@ -358,7 +360,7 @@ export class NoteCreateService implements OnApplicationShutdown { mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens); } - tags = tags.filter(tag => Array.from(tag ?? '').length <= 128).splice(0, 32); + tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32); if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) { mentionedUsers.push(await this.usersRepository.findOneByOrFail({ id: data.reply!.userId })); @@ -511,7 +513,11 @@ export class NoteCreateService implements OnApplicationShutdown { // ハッシュタグ更新 if (data.visibility === 'public' || data.visibility === 'home') { - this.hashtagService.updateHashtags(user, tags); + if (user.isBot && meta.enableBotTrending) { + this.hashtagService.updateHashtags(user, tags); + } else if (!user.isBot) { + this.hashtagService.updateHashtags(user, tags); + } } // Increment notes count (user) @@ -850,9 +856,9 @@ export class NoteCreateService implements OnApplicationShutdown { const r = this.redisForTimelines.pipeline(); if (note.channelId) { - this.redisTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r); + this.funoutTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r); - this.redisTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.funoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); const channelFollowings = await this.channelFollowingsRepository.find({ where: { @@ -862,9 +868,9 @@ export class NoteCreateService implements OnApplicationShutdown { }); for (const channelFollowing of channelFollowings) { - this.redisTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.funoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } } else { @@ -902,9 +908,9 @@ export class NoteCreateService implements OnApplicationShutdown { if (!following.withReplies) continue; } - this.redisTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.funoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } @@ -920,36 +926,36 @@ export class NoteCreateService implements OnApplicationShutdown { if (!userListMembership.withReplies) continue; } - this.redisTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r); + this.funoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r); } } if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { // 自分自身のHTL - this.redisTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.funoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } // 自分自身以外への返信 if (note.replyId && note.replyUserId !== note.userId) { - this.redisTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.funoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); if (note.visibility === 'public' && note.userHost == null) { - this.redisTimelineService.push('localTimelineWithReplies', note.id, 300, r); + this.funoutTimelineService.push('localTimelineWithReplies', note.id, 300, r); } } else { - this.redisTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.funoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r); } if (note.visibility === 'public' && note.userHost == null) { - this.redisTimelineService.push('localTimeline', note.id, 1000, r); + this.funoutTimelineService.push('localTimeline', note.id, 1000, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push('localTimelineWithFiles', note.id, 500, r); + this.funoutTimelineService.push('localTimelineWithFiles', note.id, 500, r); } } } diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 69c66d100..1cbf0ee7f 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -49,7 +49,7 @@ import { RoleService } from '@/core/RoleService.js'; import { MetaService } from '@/core/MetaService.js'; import { SearchService } from '@/core/SearchService.js'; import { FeaturedService } from '@/core/FeaturedService.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import { AntennaService } from './AntennaService.js'; import NotesChart from './chart/charts/notes.js'; import PerUserNotesChart from './chart/charts/per-user-notes.js'; @@ -199,7 +199,7 @@ export class NoteEditService implements OnApplicationShutdown { private idService: IdService, private globalEventService: GlobalEventService, private queueService: QueueService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, private noteReadService: NoteReadService, private notificationService: NotificationService, private relayService: RelayService, @@ -785,9 +785,9 @@ export class NoteEditService implements OnApplicationShutdown { const r = this.redisForTimelines.pipeline(); if (note.channelId) { - this.redisTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r); + this.funoutTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r); - this.redisTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.funoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); const channelFollowings = await this.channelFollowingsRepository.find({ where: { @@ -797,9 +797,9 @@ export class NoteEditService implements OnApplicationShutdown { }); for (const channelFollowing of channelFollowings) { - this.redisTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.funoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } } else { @@ -837,9 +837,9 @@ export class NoteEditService implements OnApplicationShutdown { if (!following.withReplies) continue; } - this.redisTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.funoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } @@ -855,36 +855,36 @@ export class NoteEditService implements OnApplicationShutdown { if (!userListMembership.withReplies) continue; } - this.redisTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r); + this.funoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r); } } if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { // 自分自身のHTL - this.redisTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r); + this.funoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r); } } // 自分自身以外への返信 if (note.replyId && note.replyUserId !== note.userId) { - this.redisTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.funoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); if (note.visibility === 'public' && note.userHost == null) { - this.redisTimelineService.push('localTimelineWithReplies', note.id, 300, r); + this.funoutTimelineService.push('localTimelineWithReplies', note.id, 300, r); } } else { - this.redisTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); + this.funoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r); + this.funoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r); } if (note.visibility === 'public' && note.userHost == null) { - this.redisTimelineService.push('localTimeline', note.id, 1000, r); + this.funoutTimelineService.push('localTimeline', note.id, 1000, r); if (note.fileIds.length > 0) { - this.redisTimelineService.push('localTimelineWithFiles', note.id, 500, r); + this.funoutTimelineService.push('localTimelineWithFiles', note.id, 500, r); } } } diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index d8c725003..be378a899 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -237,10 +237,11 @@ export class QueueService { } @bindThis - public createImportFollowingJob(user: ThinUser, fileId: MiDriveFile['id']) { + public createImportFollowingJob(user: ThinUser, fileId: MiDriveFile['id'], withReplies?: boolean) { return this.dbQueue.add('importFollowing', { user: { id: user.id }, fileId: fileId, + withReplies, }, { removeOnComplete: true, removeOnFail: true, @@ -248,8 +249,8 @@ export class QueueService { } @bindThis - public createImportFollowingToDbJob(user: ThinUser, targets: string[]) { - const jobs = targets.map(rel => this.generateToDbJobData('importFollowingToDb', { user, target: rel })); + public createImportFollowingToDbJob(user: ThinUser, targets: string[], withReplies?: boolean) { + const jobs = targets.map(rel => this.generateToDbJobData('importFollowingToDb', { user, target: rel, withReplies })); return this.dbQueue.addBulk(jobs); } @@ -342,7 +343,7 @@ export class QueueService { } @bindThis - public createFollowJob(followings: { from: ThinUser, to: ThinUser, requestId?: string, silent?: boolean }[]) { + public createFollowJob(followings: { from: ThinUser, to: ThinUser, requestId?: string, silent?: boolean, withReplies?: boolean }[]) { const jobs = followings.map(rel => this.generateRelationshipJobData('follow', rel)); return this.relationshipQueue.addBulk(jobs); } @@ -384,6 +385,7 @@ export class QueueService { to: { id: data.to.id }, silent: data.silent, requestId: data.requestId, + withReplies: data.withReplies, }, opts: { removeOnComplete: true, diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 49b465a0f..1458e2b17 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -148,7 +148,7 @@ export class ReactionService { reaction = FALLBACK; } } else { - reaction = this.normalize(reaction ?? null); + reaction = this.normalize(reaction); } } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index d18fb240f..2c2ff7af1 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -20,7 +20,7 @@ import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; import type { Packed } from '@/misc/json-schema.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; export type RolePolicies = { @@ -103,7 +103,7 @@ export class RoleService implements OnApplicationShutdown { private globalEventService: GlobalEventService, private idService: IdService, private moderationLogService: ModerationLogService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, ) { //this.onMessage = this.onMessage.bind(this); @@ -470,7 +470,7 @@ export class RoleService implements OnApplicationShutdown { const redisPipeline = this.redisClient.pipeline(); for (const role of roles) { - this.redisTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline); + this.funoutTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline); this.globalEventService.publishRoleTimelineStream(role.id, 'note', note); } diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 87484f038..4d7e14f68 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -29,6 +29,7 @@ import { CacheService } from '@/core/CacheService.js'; import type { Config } from '@/config.js'; import { AccountMoveService } from '@/core/AccountMoveService.js'; import { UtilityService } from '@/core/UtilityService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import Logger from '../logger.js'; const logger = new Logger('following/create'); @@ -83,6 +84,7 @@ export class UserFollowingService implements OnModuleInit { private webhookService: WebhookService, private apRendererService: ApRendererService, private accountMoveService: AccountMoveService, + private funoutTimelineService: FunoutTimelineService, private perUserFollowingChart: PerUserFollowingChart, private instanceChart: InstanceChart, ) { @@ -93,7 +95,15 @@ export class UserFollowingService implements OnModuleInit { } @bindThis - public async follow(_follower: { id: MiUser['id'] }, _followee: { id: MiUser['id'] }, requestId?: string, silent = false): Promise { + public async follow( + _follower: { id: MiUser['id'] }, + _followee: { id: MiUser['id'] }, + { requestId, silent = false, withReplies }: { + requestId?: string, + silent?: boolean, + withReplies?: boolean, + } = {}, + ): Promise { const [follower, followee] = await Promise.all([ this.usersRepository.findOneByOrFail({ id: _follower.id }), this.usersRepository.findOneByOrFail({ id: _followee.id }), @@ -171,12 +181,12 @@ export class UserFollowingService implements OnModuleInit { } if (!autoAccept) { - await this.createFollowRequest(follower, followee, requestId); + await this.createFollowRequest(follower, followee, requestId, withReplies); return; } } - await this.insertFollowingDoc(followee, follower, silent); + await this.insertFollowingDoc(followee, follower, silent, withReplies); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee)); @@ -193,6 +203,7 @@ export class UserFollowingService implements OnModuleInit { id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'] }, silent = false, + withReplies?: boolean, ): Promise { if (follower.id === followee.id) return; @@ -202,6 +213,7 @@ export class UserFollowingService implements OnModuleInit { id: this.idService.gen(), followerId: follower.id, followeeId: followee.id, + withReplies: withReplies, // 非正規化 followerHost: follower.host, @@ -278,8 +290,8 @@ export class UserFollowingService implements OnModuleInit { this.perUserFollowingChart.update(follower, followee, true); } - // Publish follow event if (this.userEntityService.isLocalUser(follower) && !silent) { + // Publish follow event this.userEntityService.pack(followee.id, follower, { detail: true, }).then(async packed => { @@ -292,6 +304,8 @@ export class UserFollowingService implements OnModuleInit { }); } }); + + this.funoutTimelineService.purge(`homeTimeline:${follower.id}`); } // Publish followed event @@ -345,8 +359,8 @@ export class UserFollowingService implements OnModuleInit { this.decrementFollowing(following.follower, following.followee); - // Publish unfollow event if (!silent && this.userEntityService.isLocalUser(follower)) { + // Publish unfollow event this.userEntityService.pack(followee.id, follower, { detail: true, }).then(async packed => { @@ -359,6 +373,8 @@ export class UserFollowingService implements OnModuleInit { }); } }); + + this.funoutTimelineService.purge(`homeTimeline:${follower.id}`); } if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { @@ -454,6 +470,7 @@ export class UserFollowingService implements OnModuleInit { id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']; }, requestId?: string, + withReplies?: boolean, ): Promise { if (follower.id === followee.id) return; @@ -471,6 +488,7 @@ export class UserFollowingService implements OnModuleInit { followerId: follower.id, followeeId: followee.id, requestId, + withReplies, // 非正規化 followerHost: follower.host, @@ -555,7 +573,7 @@ export class UserFollowingService implements OnModuleInit { throw new IdentifiableError('8884c2dd-5795-4ac9-b27e-6a01d38190f9', 'No follow request.'); } - await this.insertFollowingDoc(followee, follower); + await this.insertFollowingDoc(followee, follower, false, request.withReplies); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee as MiPartialLocalUser, request.requestId!), followee)); @@ -695,4 +713,12 @@ export class UserFollowingService implements OnModuleInit { }); } } + + @bindThis + public getFollowees(userId: MiUser['id']) { + return this.followingsRepository.createQueryBuilder('following') + .select('following.followeeId') + .where('following.followerId = :followerId', { followerId: userId }) + .getMany(); + } } diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 048d52776..5a7b07e66 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -164,7 +164,7 @@ export class ApInboxService { } // don't queue because the sender may attempt again when timeout - await this.userFollowingService.follow(actor, followee, activity.id); + await this.userFollowingService.follow(actor, followee, { requestId: activity.id }); return 'ok'; } diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts index 5148b2ca9..14be00036 100644 --- a/packages/backend/src/core/entities/DriveFileEntityService.ts +++ b/packages/backend/src/core/entities/DriveFileEntityService.ts @@ -90,7 +90,7 @@ export class DriveFileEntityService { if (file.type.startsWith('video')) { if (file.thumbnailUrl) return file.thumbnailUrl; - return this.videoProcessingService.getExternalVideoThumbnailUrl(file.webpublicUrl ?? file.url ?? file.uri); + return this.videoProcessingService.getExternalVideoThumbnailUrl(file.webpublicUrl ?? file.url); } else if (file.uri != null && file.userHost != null && this.config.externalMediaProxyEnabled) { // 動画ではなくリモートかつメディアプロキシ return this.getProxiedUrl(file.uri, 'static'); @@ -145,7 +145,7 @@ export class DriveFileEntityService { .select('SUM(file.size)', 'sum') .getRawOne(); - return parseInt(sum, 10) ?? 0; + return parseInt(sum, 10) || 0; } @bindThis @@ -157,7 +157,7 @@ export class DriveFileEntityService { .select('SUM(file.size)', 'sum') .getRawOne(); - return parseInt(sum, 10) ?? 0; + return parseInt(sum, 10) || 0; } @bindThis @@ -169,7 +169,7 @@ export class DriveFileEntityService { .select('SUM(file.size)', 'sum') .getRawOne(); - return parseInt(sum, 10) ?? 0; + return parseInt(sum, 10) || 0; } @bindThis @@ -181,7 +181,7 @@ export class DriveFileEntityService { .select('SUM(file.size)', 'sum') .getRawOne(); - return parseInt(sum, 10) ?? 0; + return parseInt(sum, 10) || 0; } @bindThis diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index d593f6625..bb9d73580 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -323,7 +323,7 @@ export class NoteEntityService implements OnModuleInit { text: text, cw: note.cw, visibility: note.visibility, - localOnly: note.localOnly ?? undefined, + localOnly: note.localOnly, reactionAcceptance: note.reactionAcceptance, visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined, renoteCount: note.renoteCount, diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index a24319c45..b02b0af23 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -366,8 +366,9 @@ export class UserEntityService implements OnModuleInit { avatarBlurhash: user.avatarBlurhash, description: mastoapi ? mastoapi.description : profile ? profile.description : '', createdAt: this.idService.parse(user.id).date.toISOString(), - isBot: user.isBot ?? falsy, - isCat: user.isCat ?? falsy, + isBot: user.isBot, + isCat: user.isCat, + isSilenced: user.isSilenced || this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote), speakAsCat: user.speakAsCat ?? falsy, instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? { name: instance.name, @@ -404,8 +405,7 @@ export class UserEntityService implements OnModuleInit { backgroundUrl: user.backgroundUrl, backgroundBlurhash: user.backgroundBlurhash, isLocked: user.isLocked, - isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote), - isSuspended: user.isSuspended ?? falsy, + isSuspended: user.isSuspended, location: profile!.location, birthday: profile!.birthday, listenbrainz: profile!.listenbrainz, diff --git a/packages/backend/src/daemons/ServerStatsService.ts b/packages/backend/src/daemons/ServerStatsService.ts index d29462874..c5ef9b2fa 100644 --- a/packages/backend/src/daemons/ServerStatsService.ts +++ b/packages/backend/src/daemons/ServerStatsService.ts @@ -108,6 +108,5 @@ async function net() { // FS STAT async function fs() { - const data = await si.disksIO().catch(() => ({ rIO_sec: 0, wIO_sec: 0 })); - return data ?? { rIO_sec: 0, wIO_sec: 0 }; + return await si.disksIO().catch(() => ({ rIO_sec: 0, wIO_sec: 0 })); } diff --git a/packages/backend/src/models/FollowRequest.ts b/packages/backend/src/models/FollowRequest.ts index 1e907f3d6..9899694dd 100644 --- a/packages/backend/src/models/FollowRequest.ts +++ b/packages/backend/src/models/FollowRequest.ts @@ -45,6 +45,11 @@ export class MiFollowRequest { }) public requestId: string | null; + @Column('boolean', { + default: false, + }) + public withReplies: boolean; + //#region Denormalized fields @Column('varchar', { length: 128, nullable: true, diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index e34c51a69..fca214a37 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -252,6 +252,11 @@ export class MiMeta { }) public enableSensitiveMediaDetectionForVideos: boolean; + @Column('boolean', { + default: true, + }) + public enableBotTrending: boolean; + @Column('varchar', { length: 1024, nullable: true, diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 81b46d543..646caf6f6 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -173,6 +173,12 @@ export class MiUser { }) public isSuspended: boolean; + @Column('boolean', { + default: false, + comment: 'Whether the User is silenced.', + }) + public isSilenced: boolean; + @Column('boolean', { default: false, comment: 'Whether the User is locked.', diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index f1e933498..ca2436b73 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -47,6 +47,10 @@ export const packedUserLiteSchema = { nullable: false, optional: true, default: false, }, + isSilenced: { + type: 'boolean', + nullable: false, optional: false, + }, isBot: { type: 'boolean', nullable: false, optional: true, @@ -135,10 +139,6 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: false, }, - isSilenced: { - type: 'boolean', - nullable: false, optional: false, - }, isSuspended: { type: 'boolean', nullable: false, optional: false, diff --git a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts index 2b5e41a12..e75499a56 100644 --- a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts @@ -56,7 +56,7 @@ export class ImportFollowingProcessorService { const csv = await this.downloadService.downloadTextFile(file.url); const targets = csv.trim().split('\n'); - this.queueService.createImportFollowingToDbJob({ id: user.id }, targets); + this.queueService.createImportFollowingToDbJob({ id: user.id }, targets, job.data.withReplies); this.logger.succ('Import jobs created'); } @@ -93,9 +93,9 @@ export class ImportFollowingProcessorService { // skip myself if (target.id === job.data.user.id) return; - this.logger.info(`Follow ${target.id} ...`); + this.logger.info(`Follow ${target.id} ${job.data.withReplies ? 'with replies' : 'without replies'} ...`); - this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true }]); + this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true, withReplies: job.data.withReplies }]); } catch (e) { this.logger.warn(`Error: ${e}`); } diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index 99e823f9f..89d4ea503 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -88,7 +88,7 @@ export class InboxProcessorService { if (err.isClientError) { throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`); } - throw new Error(`Error in actor ${activity.actor} - ${err.statusCode ?? err}`); + throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`); } } } diff --git a/packages/backend/src/queue/processors/RelationshipProcessorService.ts b/packages/backend/src/queue/processors/RelationshipProcessorService.ts index 5b2d2ef31..b2d8e3631 100644 --- a/packages/backend/src/queue/processors/RelationshipProcessorService.ts +++ b/packages/backend/src/queue/processors/RelationshipProcessorService.ts @@ -34,8 +34,12 @@ export class RelationshipProcessorService { @bindThis public async processFollow(job: Bull.Job): Promise { - this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id}`); - await this.userFollowingService.follow(job.data.from, job.data.to, job.data.requestId, job.data.silent); + this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id} ${job.data.withReplies ? "with replies" : "without replies"}`); + await this.userFollowingService.follow(job.data.from, job.data.to, { + requestId: job.data.requestId, + silent: job.data.silent, + withReplies: job.data.withReplies, + }); return 'ok'; } diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index c9122f5ca..9330c0152 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -32,6 +32,7 @@ export type RelationshipJobData = { to: ThinUser; silent?: boolean; requestId?: string; + withReplies?: boolean; } export type DbJobData = DbJobMap[T]; @@ -79,6 +80,7 @@ export type DbUserDeleteJobData = { export type DbUserImportJobData = { user: ThinUser; fileId: MiDriveFile['id']; + withReplies?: boolean; }; export type DBAntennaImportJobData = { @@ -89,6 +91,7 @@ export type DBAntennaImportJobData = { export type DbUserImportToDbJobData = { user: ThinUser; target: string; + withReplies?: boolean; }; export type ObjectStorageJobData = ObjectStorageFileJobData | Record; diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 59c60e89c..fcd67f39f 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -63,6 +63,8 @@ import * as ep___admin_showUser from './endpoints/admin/show-user.js'; import * as ep___admin_showUsers from './endpoints/admin/show-users.js'; import * as ep___admin_nsfwUser from './endpoints/admin/nsfw-user.js'; import * as ep___admin_unnsfwUser from './endpoints/admin/unnsfw-user.js'; +import * as ep___admin_silenceUser from './endpoints/admin/silence-user.js'; +import * as ep___admin_unsilenceUser from './endpoints/admin/unsilence-user.js'; import * as ep___admin_suspendUser from './endpoints/admin/suspend-user.js'; import * as ep___admin_approveUser from './endpoints/admin/approve-user.js'; import * as ep___admin_unsuspendUser from './endpoints/admin/unsuspend-user.js'; @@ -419,6 +421,8 @@ const $admin_showUser: Provider = { provide: 'ep:admin/show-user', useClass: ep_ const $admin_showUsers: Provider = { provide: 'ep:admin/show-users', useClass: ep___admin_showUsers.default }; const $admin_nsfwUser: Provider = { provide: 'ep:admin/nsfw-user', useClass: ep___admin_nsfwUser.default }; const $admin_unnsfwUser: Provider = { provide: 'ep:admin/unnsfw-user', useClass: ep___admin_unnsfwUser.default }; +const $admin_silenceUser: Provider = { provide: 'ep:admin/silence-user', useClass: ep___admin_silenceUser.default }; +const $admin_unsilenceUser: Provider = { provide: 'ep:admin/unsilence-user', useClass: ep___admin_unsilenceUser.default }; const $admin_suspendUser: Provider = { provide: 'ep:admin/suspend-user', useClass: ep___admin_suspendUser.default }; const $admin_approveUser: Provider = { provide: 'ep:admin/approve-user', useClass: ep___admin_approveUser.default }; const $admin_unsuspendUser: Provider = { provide: 'ep:admin/unsuspend-user', useClass: ep___admin_unsuspendUser.default }; @@ -779,6 +783,8 @@ const $sponsors: Provider = { provide: 'ep:sponsors', useClass: ep___sponsors.de $admin_showUsers, $admin_nsfwUser, $admin_unnsfwUser, + $admin_silenceUser, + $admin_unsilenceUser, $admin_suspendUser, $admin_approveUser, $admin_unsuspendUser, @@ -1133,6 +1139,8 @@ const $sponsors: Provider = { provide: 'ep:sponsors', useClass: ep___sponsors.de $admin_showUsers, $admin_nsfwUser, $admin_unnsfwUser, + $admin_silenceUser, + $admin_unsilenceUser, $admin_suspendUser, $admin_approveUser, $admin_unsuspendUser, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 148d51951..be5e66cab 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -63,6 +63,8 @@ import * as ep___admin_showUser from './endpoints/admin/show-user.js'; import * as ep___admin_showUsers from './endpoints/admin/show-users.js'; import * as ep___admin_nsfwUser from './endpoints/admin/nsfw-user.js'; import * as ep___admin_unnsfwUser from './endpoints/admin/unnsfw-user.js'; +import * as ep___admin_silenceUser from './endpoints/admin/silence-user.js'; +import * as ep___admin_unsilenceUser from './endpoints/admin/unsilence-user.js'; import * as ep___admin_suspendUser from './endpoints/admin/suspend-user.js'; import * as ep___admin_approveUser from './endpoints/admin/approve-user.js'; import * as ep___admin_unsuspendUser from './endpoints/admin/unsuspend-user.js'; @@ -417,6 +419,8 @@ const eps = [ ['admin/show-users', ep___admin_showUsers], ['admin/nsfw-user', ep___admin_nsfwUser], ['admin/unnsfw-user', ep___admin_unnsfwUser], + ['admin/silence-user', ep___admin_silenceUser], + ['admin/unsilence-user', ep___admin_unsilenceUser], ['admin/suspend-user', ep___admin_suspendUser], ['admin/approve-user', ep___admin_approveUser], ['admin/unsuspend-user', ep___admin_unsuspendUser], diff --git a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts index 7b807e848..6afa82470 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts @@ -41,7 +41,7 @@ export default class extends Endpoint { // eslint- return ips.map(x => ({ ip: x.ip, - createdAt: this.idService.parse(x.id).date.toISOString(), + createdAt: x.createdAt.toISOString(), })); }); } diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 763c4ea80..a6e483254 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -182,6 +182,10 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, + enableBotTrending: { + type: 'boolean', + optional: false, nullable: false, + }, proxyAccountId: { type: 'string', optional: false, nullable: true, @@ -396,6 +400,7 @@ export default class extends Endpoint { // eslint- sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity, setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically, enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos, + enableBotTrending: instance.enableBotTrending, proxyAccountId: instance.proxyAccountId, summalyProxy: instance.summalyProxy, email: instance.email, diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 5ad90f48b..b1cf24b6a 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -58,7 +58,7 @@ export default class extends Endpoint { // eslint- } const isModerator = await this.roleService.isModerator(user); - const isSilenced = !(await this.roleService.getUserPolicies(user.id)).canPublicNote; + const isSilenced = user.isSilenced || !(await this.roleService.getUserPolicies(user.id)).canPublicNote; const _me = await this.usersRepository.findOneByOrFail({ id: me.id }); if (!await this.roleService.isAdministrator(_me) && await this.roleService.isAdministrator(user)) { diff --git a/packages/backend/src/server/api/endpoints/admin/silence-user.ts b/packages/backend/src/server/api/endpoints/admin/silence-user.ts new file mode 100644 index 000000000..ed1141da4 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/silence-user.ts @@ -0,0 +1,46 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { UsersRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { RoleService } from '@/core/RoleService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, +} as const; + +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + + private roleService: RoleService, + ) { + super(meta, paramDef, async (ps, me) => { + const user = await this.usersRepository.findOneBy({ id: ps.userId }); + + if (user == null) { + throw new Error('user not found'); + } + + if (await this.roleService.isModerator(user)) { + throw new Error('cannot silence moderator account'); + } + + await this.usersRepository.update(user.id, { + isSilenced: true, + }); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts b/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts new file mode 100644 index 000000000..7cfedca7d --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts @@ -0,0 +1,39 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { UsersRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, +} as const; + +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + ) { + super(meta, paramDef, async (ps, me) => { + const user = await this.usersRepository.findOneBy({ id: ps.userId }); + + if (user == null) { + throw new Error('user not found'); + } + + await this.usersRepository.update(user.id, { + isSilenced: false, + }); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index be14037a7..2276eb0b1 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -73,6 +73,7 @@ export const paramDef = { sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] }, setSensitiveFlagAutomatically: { type: 'boolean' }, enableSensitiveMediaDetectionForVideos: { type: 'boolean' }, + enableBotTrending: { type: 'boolean' }, proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true }, maintainerName: { type: 'string', nullable: true }, maintainerEmail: { type: 'string', nullable: true }, @@ -306,6 +307,10 @@ export default class extends Endpoint { // eslint- set.enableSensitiveMediaDetectionForVideos = ps.enableSensitiveMediaDetectionForVideos; } + if (ps.enableBotTrending !== undefined) { + set.enableBotTrending = ps.enableBotTrending; + } + if (ps.proxyAccountId !== undefined) { set.proxyAccountId = ps.proxyAccountId; } diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index ff96411f3..9b5911800 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -12,7 +12,7 @@ import { NoteReadService } from '@/core/NoteReadService.js'; import { DI } from '@/di-symbols.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { IdService } from '@/core/IdService.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -70,7 +70,7 @@ export default class extends Endpoint { // eslint- private noteEntityService: NoteEntityService, private queryService: QueryService, private noteReadService: NoteReadService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -90,7 +90,7 @@ export default class extends Endpoint { // eslint- lastUsedAt: new Date(), }); - let noteIds = await this.redisTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId); + let noteIds = await this.funoutTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); if (noteIds.length === 0) { return []; diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index 9c39d0ed8..fae4249c8 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -12,7 +12,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import ActiveUsersChart from '@/core/chart/charts/active-users.js'; import { DI } from '@/di-symbols.js'; import { IdService } from '@/core/IdService.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { CacheService } from '@/core/CacheService.js'; import { ApiError } from '../../error.js'; @@ -69,7 +69,7 @@ export default class extends Endpoint { // eslint- private idService: IdService, private noteEntityService: NoteEntityService, private queryService: QueryService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, private cacheService: CacheService, private activeUsersChart: ActiveUsersChart, ) { @@ -95,7 +95,7 @@ export default class extends Endpoint { // eslint- this.cacheService.userMutingsCache.fetch(me.id), ]) : [new Set()]; - let noteIds = await this.redisTimelineService.get(`channelTimeline:${channel.id}`, untilId, sinceId); + let noteIds = await this.funoutTimelineService.get(`channelTimeline:${channel.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); if (noteIds.length > 0) { diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index e0e7fed87..9037944ef 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -71,6 +71,7 @@ export const paramDef = { type: 'object', properties: { userId: { type: 'string', format: 'misskey:id' }, + withReplies: { type: 'boolean' } }, required: ['userId'], } as const; @@ -112,7 +113,7 @@ export default class extends Endpoint { // eslint- } try { - await this.userFollowingService.follow(follower, followee); + await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies }); } catch (e) { if (e instanceof IdentifiableError) { if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking); diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts index 38c928304..e5fa2ac96 100644 --- a/packages/backend/src/server/api/endpoints/i/import-following.ts +++ b/packages/backend/src/server/api/endpoints/i/import-following.ts @@ -52,6 +52,7 @@ export const paramDef = { type: 'object', properties: { fileId: { type: 'string', format: 'misskey:id' }, + withReplies: { type: 'boolean' }, }, required: ['fileId'], } as const; @@ -79,7 +80,7 @@ export default class extends Endpoint { // eslint- ); if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile); - this.queueService.createImportFollowingJob(me, file.id); + this.queueService.createImportFollowingJob(me, file.id, ps.withReplies); }); } } diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index be7557c21..582757754 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -13,6 +13,7 @@ import ActiveUsersChart from '@/core/chart/charts/active-users.js'; import { DI } from '@/di-symbols.js'; import { RoleService } from '@/core/RoleService.js'; import { ApiError } from '../../error.js'; +import { CacheService } from '@/core/CacheService.js'; export const meta = { tags: ['notes'], @@ -40,6 +41,7 @@ export const paramDef = { type: 'object', properties: { withFiles: { type: 'boolean', default: false }, + withBots: { type: 'boolean', default: true }, withRenotes: { type: 'boolean', default: true }, limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, @@ -60,6 +62,7 @@ export default class extends Endpoint { // eslint- private queryService: QueryService, private roleService: RoleService, private activeUsersChart: ActiveUsersChart, + private cacheService: CacheService, ) { super(meta, paramDef, async (ps, me) => { const policies = await this.roleService.getUserPolicies(me ? me.id : null); @@ -67,6 +70,12 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.gtlDisabled); } + const [ + followings, + ] = me ? await Promise.all([ + this.cacheService.userFollowingsCache.fetch(me.id), + ]) : [undefined]; + //#region Construct query const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) @@ -87,9 +96,16 @@ export default class extends Endpoint { // eslint- if (ps.withFiles) { query.andWhere('note.fileIds != \'{}\''); } + + if (!ps.withBots) query.andWhere('user.isBot = FALSE'); //#endregion - const timeline = await query.limit(ps.limit).getMany(); + let timeline = await query.limit(ps.limit).getMany(); + + timeline = timeline.filter(note => { + if (note.user?.isSilenced && me && followings && note.userId !== me.id && !followings[note.userId]) return false; + return true; + }); process.nextTick(() => { if (me) { diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 378529e30..ada88ea4f 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -5,7 +5,6 @@ import { Brackets } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; -import * as Redis from 'ioredis'; import type { NotesRepository, FollowingsRepository, MiNote } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import ActiveUsersChart from '@/core/chart/charts/active-users.js'; @@ -15,7 +14,9 @@ import { RoleService } from '@/core/RoleService.js'; import { IdService } from '@/core/IdService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { CacheService } from '@/core/CacheService.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { QueryService } from '@/core/QueryService.js'; +import { UserFollowingService } from '@/core/UserFollowingService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -56,6 +57,7 @@ export const paramDef = { withFiles: { type: 'boolean', default: false }, withRenotes: { type: 'boolean', default: true }, withReplies: { type: 'boolean', default: false }, + withBots: { type: 'boolean', default: true }, }, required: [], } as const; @@ -63,9 +65,6 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.redisForTimelines) - private redisForTimelines: Redis.Redis, - @Inject(DI.notesRepository) private notesRepository: NotesRepository, @@ -74,7 +73,9 @@ export default class extends Endpoint { // eslint- private activeUsersChart: ActiveUsersChart, private idService: IdService, private cacheService: CacheService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, + private queryService: QueryService, + private userFollowingService: UserFollowingService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -86,81 +87,170 @@ export default class extends Endpoint { // eslint- } const [ + followings, userIdsWhoMeMuting, userIdsWhoMeMutingRenotes, userIdsWhoBlockingMe, ] = await Promise.all([ + this.cacheService.userFollowingsCache.fetch(me.id), this.cacheService.userMutingsCache.fetch(me.id), this.cacheService.renoteMutingsCache.fetch(me.id), this.cacheService.userBlockedCache.fetch(me.id), ]); let noteIds: string[]; + let shouldFallbackToDb = false; if (ps.withFiles) { - const [htlNoteIds, ltlNoteIds] = await this.redisTimelineService.getMulti([ + const [htlNoteIds, ltlNoteIds] = await this.funoutTimelineService.getMulti([ `homeTimelineWithFiles:${me.id}`, 'localTimelineWithFiles', ], untilId, sinceId); noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds])); } else if (ps.withReplies) { - const [htlNoteIds, ltlNoteIds, ltlReplyNoteIds] = await this.redisTimelineService.getMulti([ + const [htlNoteIds, ltlNoteIds, ltlReplyNoteIds] = await this.funoutTimelineService.getMulti([ `homeTimeline:${me.id}`, 'localTimeline', 'localTimelineWithReplies', ], untilId, sinceId); noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds, ...ltlReplyNoteIds])); } else { - const [htlNoteIds, ltlNoteIds] = await this.redisTimelineService.getMulti([ + const [htlNoteIds, ltlNoteIds] = await this.funoutTimelineService.getMulti([ `homeTimeline:${me.id}`, 'localTimeline', ], untilId, sinceId); noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds])); + shouldFallbackToDb = htlNoteIds.length === 0; } noteIds.sort((a, b) => a > b ? -1 : 1); noteIds = noteIds.slice(0, ps.limit); - if (noteIds.length === 0) { - return []; - } + if (!shouldFallbackToDb) { + const query = this.notesRepository.createQueryBuilder('note') + .where('note.id IN (:...noteIds)', { noteIds: noteIds }) + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.channel', 'channel'); - const query = this.notesRepository.createQueryBuilder('note') - .where('note.id IN (:...noteIds)', { noteIds: noteIds }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('note.channel', 'channel'); + if (!ps.withBots) query.andWhere('user.isBot = FALSE'); - let timeline = await query.getMany(); + let timeline = await query.getMany(); - timeline = timeline.filter(note => { - if (note.userId === me.id) { - return true; - } - if (isUserRelated(note, userIdsWhoBlockingMe)) return false; - if (isUserRelated(note, userIdsWhoMeMuting)) return false; - if (note.renoteId) { - if (note.text == null && note.fileIds.length === 0 && !note.hasPoll) { - if (isUserRelated(note, userIdsWhoMeMutingRenotes)) return false; - if (ps.withRenotes === false) return false; + timeline = timeline.filter(note => { + if (note.userId === me.id) { + return true; } + if (isUserRelated(note, userIdsWhoBlockingMe)) return false; + if (isUserRelated(note, userIdsWhoMeMuting)) return false; + if (note.renoteId) { + if (note.text == null && note.fileIds.length === 0 && !note.hasPoll) { + if (isUserRelated(note, userIdsWhoMeMutingRenotes)) return false; + if (ps.withRenotes === false) return false; + } + } + if (note.user?.isSilenced && note.userId !== me.id && !followings[note.userId]) return false; + + return true; + }); + + // TODO: フィルタした結果件数が足りなかった場合の対応 + + timeline.sort((a, b) => a.id > b.id ? -1 : 1); + + process.nextTick(() => { + this.activeUsersChart.read(me); + }); + + return await this.noteEntityService.packMany(timeline, me); + } else { // fallback to db + const followees = await this.userFollowingService.getFollowees(me.id); + + const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere(new Brackets(qb => { + if (followees.length > 0) { + const meOrFolloweeIds = [me.id, ...followees.map(f => f.followeeId)]; + qb.where('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds }); + qb.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); + } else { + qb.where('note.userId = :meId', { meId: me.id }); + qb.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); + } + })) + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); + + if (!ps.withBots) query.andWhere('user.isBot = FALSE'); + + query.andWhere(new Brackets(qb => { + qb + .where('note.replyId IS NULL') // 返信ではない + .orWhere(new Brackets(qb => { + qb // 返信だけど投稿者自身への返信 + .where('note.replyId IS NOT NULL') + .andWhere('note.replyUserId = note.userId'); + })); + })); + + this.queryService.generateVisibilityQuery(query, me); + this.queryService.generateMutedUserQuery(query, me); + this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserRenotesQueryForNotes(query, me); + + if (ps.includeMyRenotes === false) { + query.andWhere(new Brackets(qb => { + qb.orWhere('note.userId != :meId', { meId: me.id }); + qb.orWhere('note.renoteId IS NULL'); + qb.orWhere('note.text IS NOT NULL'); + qb.orWhere('note.fileIds != \'{}\''); + qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); + })); } - return true; - }); + if (ps.includeRenotedMyNotes === false) { + query.andWhere(new Brackets(qb => { + qb.orWhere('note.renoteUserId != :meId', { meId: me.id }); + qb.orWhere('note.renoteId IS NULL'); + qb.orWhere('note.text IS NOT NULL'); + qb.orWhere('note.fileIds != \'{}\''); + qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); + })); + } - // TODO: フィルタした結果件数が足りなかった場合の対応 + if (ps.includeLocalRenotes === false) { + query.andWhere(new Brackets(qb => { + qb.orWhere('note.renoteUserHost IS NOT NULL'); + qb.orWhere('note.renoteId IS NULL'); + qb.orWhere('note.text IS NOT NULL'); + qb.orWhere('note.fileIds != \'{}\''); + qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); + })); + } - timeline.sort((a, b) => a.id > b.id ? -1 : 1); + if (ps.withFiles) { + query.andWhere('note.fileIds != \'{}\''); + } + //#endregion - process.nextTick(() => { - this.activeUsersChart.read(me); - }); + let timeline = await query.limit(ps.limit).getMany(); - return await this.noteEntityService.packMany(timeline, me); + timeline = timeline.filter(note => { + if (note.user?.isSilenced && note.userId !== me.id && !followings[note.userId]) return false; + return true; + }); + + process.nextTick(() => { + this.activeUsersChart.read(me); + }); + + return await this.noteEntityService.packMany(timeline, me); + } }); } } diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index f69e60ab5..85560f12c 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -5,7 +5,6 @@ import { Brackets } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; -import * as Redis from 'ioredis'; import type { MiNote, NotesRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; @@ -15,7 +14,8 @@ import { RoleService } from '@/core/RoleService.js'; import { IdService } from '@/core/IdService.js'; import { CacheService } from '@/core/CacheService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { QueryService } from '@/core/QueryService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -46,6 +46,7 @@ export const paramDef = { withFiles: { type: 'boolean', default: false }, withRenotes: { type: 'boolean', default: true }, withReplies: { type: 'boolean', default: false }, + withBots: { type: 'boolean', default: true }, excludeNsfw: { type: 'boolean', default: false }, limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, @@ -59,9 +60,6 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.redisForTimelines) - private redisForTimelines: Redis.Redis, - @Inject(DI.notesRepository) private notesRepository: NotesRepository, @@ -70,7 +68,8 @@ export default class extends Endpoint { // eslint- private activeUsersChart: ActiveUsersChart, private idService: IdService, private cacheService: CacheService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, + private queryService: QueryService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -82,21 +81,23 @@ export default class extends Endpoint { // eslint- } const [ + followings, userIdsWhoMeMuting, userIdsWhoMeMutingRenotes, userIdsWhoBlockingMe, ] = me ? await Promise.all([ + this.cacheService.userFollowingsCache.fetch(me.id), this.cacheService.userMutingsCache.fetch(me.id), this.cacheService.renoteMutingsCache.fetch(me.id), this.cacheService.userBlockedCache.fetch(me.id), - ]) : [new Set(), new Set(), new Set()]; + ]) : [undefined, new Set(), new Set(), new Set()]; let noteIds: string[]; if (ps.withFiles) { - noteIds = await this.redisTimelineService.get('localTimelineWithFiles', untilId, sinceId); + noteIds = await this.funoutTimelineService.get('localTimelineWithFiles', untilId, sinceId); } else { - const [nonReplyNoteIds, replyNoteIds] = await this.redisTimelineService.getMulti([ + const [nonReplyNoteIds, replyNoteIds] = await this.funoutTimelineService.getMulti([ 'localTimeline', 'localTimelineWithReplies', ], untilId, sinceId); @@ -106,49 +107,85 @@ export default class extends Endpoint { // eslint- noteIds = noteIds.slice(0, ps.limit); - if (noteIds.length === 0) { - return []; - } + if (noteIds.length > 0) { + const query = this.notesRepository.createQueryBuilder('note') + .where('note.id IN (:...noteIds)', { noteIds: noteIds }) + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.channel', 'channel'); - const query = this.notesRepository.createQueryBuilder('note') - .where('note.id IN (:...noteIds)', { noteIds: noteIds }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('note.channel', 'channel'); + if (!ps.withBots) query.andWhere('user.isBot = FALSE'); - let timeline = await query.getMany(); + let timeline = await query.getMany(); - timeline = timeline.filter(note => { - if (me && (note.userId === me.id)) { - return true; - } - if (!ps.withReplies && note.replyId && (me == null || note.replyUserId !== me.id)) return false; - if (me && isUserRelated(note, userIdsWhoBlockingMe)) return false; - if (me && isUserRelated(note, userIdsWhoMeMuting)) return false; - if (note.renoteId) { - if (note.text == null && note.fileIds.length === 0 && !note.hasPoll) { - if (me && isUserRelated(note, userIdsWhoMeMutingRenotes)) return false; - if (ps.withRenotes === false) return false; + timeline = timeline.filter(note => { + if (me && (note.userId === me.id)) { + return true; } + if (!ps.withReplies && note.replyId && (me == null || note.replyUserId !== me.id)) return false; + if (me && isUserRelated(note, userIdsWhoBlockingMe)) return false; + if (me && isUserRelated(note, userIdsWhoMeMuting)) return false; + if (note.renoteId) { + if (note.text == null && note.fileIds.length === 0 && !note.hasPoll) { + if (me && isUserRelated(note, userIdsWhoMeMutingRenotes)) return false; + if (ps.withRenotes === false) return false; + } + } + if (note.user?.isSilenced && me && followings && note.userId !== me.id && !followings[note.userId]) return false; + + return true; + }); + + // TODO: フィルタした結果件数が足りなかった場合の対応 + + timeline.sort((a, b) => a.id > b.id ? -1 : 1); + + process.nextTick(() => { + if (me) { + this.activeUsersChart.read(me); + } + }); + + return await this.noteEntityService.packMany(timeline, me); + } else { // fallback to db + const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), + ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); + + if (!ps.withBots) query.andWhere('user.isBot = FALSE'); + + this.queryService.generateVisibilityQuery(query, me); + if (me) this.queryService.generateMutedUserQuery(query, me); + if (me) this.queryService.generateBlockedUserQuery(query, me); + if (me) this.queryService.generateMutedUserRenotesQueryForNotes(query, me); + + if (ps.withFiles) { + query.andWhere('note.fileIds != \'{}\''); } - return true; - }); + let timeline = await query.limit(ps.limit).getMany(); - // TODO: フィルタした結果件数が足りなかった場合の対応 + timeline = timeline.filter(note => { + if (note.user?.isSilenced && me && followings && note.userId !== me.id && !followings[note.userId]) return false; + return true; + }); - timeline.sort((a, b) => a.id > b.id ? -1 : 1); + process.nextTick(() => { + if (me) { + this.activeUsersChart.read(me); + } + }); - process.nextTick(() => { - if (me) { - this.activeUsersChart.read(me); - } - }); - - return await this.noteEntityService.packMany(timeline, me); + return await this.noteEntityService.packMany(timeline, me); + } }); } } diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index b00f5207d..bc33d6948 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -12,6 +12,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { QueryService } from '@/core/QueryService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { DI } from '@/di-symbols.js'; +import { MetaService } from '@/core/MetaService.js'; export const meta = { tags: ['notes', 'hashtags'], @@ -71,6 +72,7 @@ export default class extends Endpoint { // eslint- private noteEntityService: NoteEntityService, private queryService: QueryService, + private metaService: MetaService, ) { super(meta, paramDef, async (ps, me) => { const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId) @@ -80,6 +82,10 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('reply.user', 'replyUser') .leftJoinAndSelect('renote.user', 'renoteUser'); + const meta = await this.metaService.fetch(true); + + if (!meta.enableBotTrending) query.andWhere('user.isBot = FALSE'); + this.queryService.generateVisibilityQuery(query, me); if (me) this.queryService.generateMutedUserQuery(query, me); if (me) this.queryService.generateBlockedUserQuery(query, me); diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index 8f13b3a4b..b98d1d9f9 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -5,8 +5,7 @@ import { Brackets } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; -import * as Redis from 'ioredis'; -import type { NotesRepository, FollowingsRepository, MiNote } from '@/models/_.js'; +import type { NotesRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { QueryService } from '@/core/QueryService.js'; import ActiveUsersChart from '@/core/chart/charts/active-users.js'; @@ -15,7 +14,8 @@ import { DI } from '@/di-symbols.js'; import { IdService } from '@/core/IdService.js'; import { CacheService } from '@/core/CacheService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; +import { UserFollowingService } from '@/core/UserFollowingService.js'; export const meta = { tags: ['notes'], @@ -46,6 +46,7 @@ export const paramDef = { includeLocalRenotes: { type: 'boolean', default: true }, withFiles: { type: 'boolean', default: false }, withRenotes: { type: 'boolean', default: true }, + withBots: { type: 'boolean', default: true }, }, required: [], } as const; @@ -53,9 +54,6 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.redisForTimelines) - private redisForTimelines: Redis.Redis, - @Inject(DI.notesRepository) private notesRepository: NotesRepository, @@ -63,7 +61,9 @@ export default class extends Endpoint { // eslint- private activeUsersChart: ActiveUsersChart, private idService: IdService, private cacheService: CacheService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, + private userFollowingService: UserFollowingService, + private queryService: QueryService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -81,52 +81,137 @@ export default class extends Endpoint { // eslint- this.cacheService.userBlockedCache.fetch(me.id), ]); - let noteIds = await this.redisTimelineService.get(ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, untilId, sinceId); + let noteIds = await this.funoutTimelineService.get(ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); - if (noteIds.length === 0) { - return []; - } + if (noteIds.length > 0) { + const query = this.notesRepository.createQueryBuilder('note') + .where('note.id IN (:...noteIds)', { noteIds: noteIds }) + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('note.channel', 'channel'); - const query = this.notesRepository.createQueryBuilder('note') - .where('note.id IN (:...noteIds)', { noteIds: noteIds }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('note.channel', 'channel'); + if (!ps.withBots) query.andWhere('user.isBot = FALSE'); - let timeline = await query.getMany(); + let timeline = await query.getMany(); - timeline = timeline.filter(note => { - if (note.userId === me.id) { - return true; - } - if (isUserRelated(note, userIdsWhoBlockingMe)) return false; - if (isUserRelated(note, userIdsWhoMeMuting)) return false; - if (note.renoteId) { - if (note.text == null && note.fileIds.length === 0 && !note.hasPoll) { - if (isUserRelated(note, userIdsWhoMeMutingRenotes)) return false; - if (ps.withRenotes === false) return false; + timeline = timeline.filter(note => { + if (note.userId === me.id) { + return true; } - } - if (note.reply && note.reply.visibility === 'followers') { - if (!Object.hasOwn(followings, note.reply.userId)) return false; + if (isUserRelated(note, userIdsWhoBlockingMe)) return false; + if (isUserRelated(note, userIdsWhoMeMuting)) return false; + if (note.renoteId) { + if (note.text == null && note.fileIds.length === 0 && !note.hasPoll) { + if (isUserRelated(note, userIdsWhoMeMutingRenotes)) return false; + if (ps.withRenotes === false) return false; + } + } + if (note.reply && note.reply.visibility === 'followers') { + if (!Object.hasOwn(followings, note.reply.userId)) return false; + } + if (note.user?.isSilenced && note.userId !== me.id && !followings[note.userId]) return false; + + return true; + }); + + // TODO: フィルタした結果件数が足りなかった場合の対応 + + timeline.sort((a, b) => a.id > b.id ? -1 : 1); + + process.nextTick(() => { + this.activeUsersChart.read(me); + }); + + return await this.noteEntityService.packMany(timeline, me); + } else { // fallback to db + const followees = await this.userFollowingService.getFollowees(me.id); + + //#region Construct query + const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere('note.channelId IS NULL') + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); + + if (!ps.withBots) query.andWhere('user.isBot = FALSE'); + + if (followees.length > 0) { + const meOrFolloweeIds = [me.id, ...followees.map(f => f.followeeId)]; + + query.andWhere('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds }); + } else { + query.andWhere('note.userId = :meId', { meId: me.id }); } - return true; - }); + query.andWhere(new Brackets(qb => { + qb + .where('note.replyId IS NULL') // 返信ではない + .orWhere(new Brackets(qb => { + qb // 返信だけど投稿者自身への返信 + .where('note.replyId IS NOT NULL') + .andWhere('note.replyUserId = note.userId'); + })); + })); - // TODO: フィルタした結果件数が足りなかった場合の対応 + this.queryService.generateVisibilityQuery(query, me); + this.queryService.generateMutedUserQuery(query, me); + this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserRenotesQueryForNotes(query, me); - timeline.sort((a, b) => a.id > b.id ? -1 : 1); + if (ps.includeMyRenotes === false) { + query.andWhere(new Brackets(qb => { + qb.orWhere('note.userId != :meId', { meId: me.id }); + qb.orWhere('note.renoteId IS NULL'); + qb.orWhere('note.text IS NOT NULL'); + qb.orWhere('note.fileIds != \'{}\''); + qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); + })); + } - process.nextTick(() => { - this.activeUsersChart.read(me); - }); + if (ps.includeRenotedMyNotes === false) { + query.andWhere(new Brackets(qb => { + qb.orWhere('note.renoteUserId != :meId', { meId: me.id }); + qb.orWhere('note.renoteId IS NULL'); + qb.orWhere('note.text IS NOT NULL'); + qb.orWhere('note.fileIds != \'{}\''); + qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); + })); + } - return await this.noteEntityService.packMany(timeline, me); + if (ps.includeLocalRenotes === false) { + query.andWhere(new Brackets(qb => { + qb.orWhere('note.renoteUserHost IS NOT NULL'); + qb.orWhere('note.renoteId IS NULL'); + qb.orWhere('note.text IS NOT NULL'); + qb.orWhere('note.fileIds != \'{}\''); + qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); + })); + } + + if (ps.withFiles) { + query.andWhere('note.fileIds != \'{}\''); + } + //#endregion + + let timeline = await query.limit(ps.limit).getMany(); + + timeline = timeline.filter(note => { + if (note.user?.isSilenced && note.userId !== me.id && !followings[note.userId]) return false; + return true; + }); + + process.nextTick(() => { + this.activeUsersChart.read(me); + }); + + return await this.noteEntityService.packMany(timeline, me); + } }); } } diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index b8007e78f..2b31e6169 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -15,7 +15,7 @@ import { DI } from '@/di-symbols.js'; import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -80,7 +80,7 @@ export default class extends Endpoint { // eslint- private activeUsersChart: ActiveUsersChart, private cacheService: CacheService, private idService: IdService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -105,7 +105,7 @@ export default class extends Endpoint { // eslint- this.cacheService.userBlockedCache.fetch(me.id), ]); - let noteIds = await this.redisTimelineService.get(ps.withFiles ? `userListTimelineWithFiles:${list.id}` : `userListTimeline:${list.id}`, untilId, sinceId); + let noteIds = await this.funoutTimelineService.get(ps.withFiles ? `userListTimelineWithFiles:${list.id}` : `userListTimeline:${list.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); if (noteIds.length === 0) { diff --git a/packages/backend/src/server/api/endpoints/roles/notes.ts b/packages/backend/src/server/api/endpoints/roles/notes.ts index e6e1daaa5..daa9affc2 100644 --- a/packages/backend/src/server/api/endpoints/roles/notes.ts +++ b/packages/backend/src/server/api/endpoints/roles/notes.ts @@ -11,7 +11,7 @@ import { QueryService } from '@/core/QueryService.js'; import { DI } from '@/di-symbols.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { IdService } from '@/core/IdService.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -66,7 +66,7 @@ export default class extends Endpoint { // eslint- private idService: IdService, private noteEntityService: NoteEntityService, private queryService: QueryService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -84,7 +84,7 @@ export default class extends Endpoint { // eslint- return []; } - let noteIds = await this.redisTimelineService.get(`roleTimeline:${role.id}`, untilId, sinceId); + let noteIds = await this.funoutTimelineService.get(`roleTimeline:${role.id}`, untilId, sinceId); noteIds = noteIds.slice(0, ps.limit); if (noteIds.length === 0) { diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 4f3d61ce0..343d320f6 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -14,7 +14,7 @@ import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { QueryService } from '@/core/QueryService.js'; -import { RedisTimelineService } from '@/core/RedisTimelineService.js'; +import { FunoutTimelineService } from '@/core/FunoutTimelineService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -71,7 +71,7 @@ export default class extends Endpoint { // eslint- private queryService: QueryService, private cacheService: CacheService, private idService: IdService, - private redisTimelineService: RedisTimelineService, + private funoutTimelineService: FunoutTimelineService, ) { super(meta, paramDef, async (ps, me) => { const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null); @@ -87,9 +87,9 @@ export default class extends Endpoint { // eslint- ]) : [new Set()]; const [noteIdsRes, repliesNoteIdsRes, channelNoteIdsRes] = await Promise.all([ - this.redisTimelineService.get(ps.withFiles ? `userTimelineWithFiles:${ps.userId}` : `userTimeline:${ps.userId}`, untilId, sinceId), - ps.withReplies ? this.redisTimelineService.get(`userTimelineWithReplies:${ps.userId}`, untilId, sinceId) : Promise.resolve([]), - ps.withChannelNotes ? this.redisTimelineService.get(`userTimelineWithChannel:${ps.userId}`, untilId, sinceId) : Promise.resolve([]), + this.funoutTimelineService.get(ps.withFiles ? `userTimelineWithFiles:${ps.userId}` : `userTimeline:${ps.userId}`, untilId, sinceId), + ps.withReplies ? this.funoutTimelineService.get(`userTimelineWithReplies:${ps.userId}`, untilId, sinceId) : Promise.resolve([]), + ps.withChannelNotes ? this.funoutTimelineService.get(`userTimelineWithChannel:${ps.userId}`, untilId, sinceId) : Promise.resolve([]), ]); let noteIds = Array.from(new Set([ @@ -151,7 +151,10 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); if (ps.withChannelNotes) { - if (!isSelf) query.andWhere('channel.isSensitive = false'); + if (!isSelf) query.andWhere(new Brackets(qb => { + qb.orWhere('note.channelId IS NULL'); + qb.orWhere('channel.isSensitive = false'); + })); } else { query.andWhere('note.channelId IS NULL'); } diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index 3bcf44cc4..649802744 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -5,7 +5,7 @@ import sanitizeHtml from 'sanitize-html'; import { Inject, Injectable } from '@nestjs/common'; -import type { AbuseUserReportsRepository } from '@/models/_.js'; +import type { AbuseUserReportsRepository, UserProfilesRepository } from '@/models/_.js'; import { IdService } from '@/core/IdService.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; @@ -59,6 +59,9 @@ export default class extends Endpoint { // eslint- @Inject(DI.abuseUserReportsRepository) private abuseUserReportsRepository: AbuseUserReportsRepository, + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + private idService: IdService, private metaService: MetaService, private emailService: EmailService, @@ -101,11 +104,19 @@ export default class extends Endpoint { // eslint- reporterId: report.reporterId, comment: report.comment, }); + + const profile = await this.userProfilesRepository.findOneBy({ userId: moderator.id }); + + if (profile?.email) { + this.emailService.sendEmail(profile.email, 'New abuse report', + sanitizeHtml(ps.comment), + sanitizeHtml(ps.comment)); + } } const meta = await this.metaService.fetch(); - if (meta.email) { - this.emailService.sendEmail(meta.email, 'New abuse report', + if (meta.maintainerEmail) { + this.emailService.sendEmail(meta.maintainerEmail, 'New abuse report', sanitizeHtml(ps.comment), sanitizeHtml(ps.comment)); } diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index c499d1787..b39afbe36 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -20,6 +20,7 @@ class GlobalTimelineChannel extends Channel { public static requireCredential = false; private withRenotes: boolean; private withFiles: boolean; + private withBots: boolean; constructor( private metaService: MetaService, @@ -40,6 +41,7 @@ class GlobalTimelineChannel extends Channel { this.withRenotes = params.withRenotes ?? true; this.withFiles = params.withFiles ?? false; + this.withBots = params.withBots ?? true; // Subscribe events this.subscriber.on('notesStream', this.onNote); @@ -48,6 +50,7 @@ class GlobalTimelineChannel extends Channel { @bindThis private async onNote(note: Packed<'Note'>) { if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return; + if (!this.withBots && note.user.isBot) return; if (note.visibility !== 'public') return; if (note.channelId != null) return; @@ -59,6 +62,8 @@ class GlobalTimelineChannel extends Channel { if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; } + if (note.user.isSilenced && !this.following[note.userId] && note.userId !== this.user!.id) return; + if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return; // Ignore notes from instances the user has muted diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index de755cccb..f5216bb4f 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -49,7 +49,7 @@ class HomeTimelineChannel extends Channel { } // Ignore notes from instances the user has muted - if (isInstanceMuted(note, new Set(this.userProfile!.mutedInstances ?? []))) return; + if (isInstanceMuted(note, new Set(this.userProfile!.mutedInstances))) return; if (note.visibility === 'followers') { if (!Object.hasOwn(this.following, note.userId)) return; @@ -64,6 +64,8 @@ class HomeTimelineChannel extends Channel { if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; } + if (note.user.isSilenced && !this.following[note.userId] && note.userId !== this.user!.id) return; + if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return; // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 83f0bccd9..1a062f393 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -20,6 +20,7 @@ class HybridTimelineChannel extends Channel { public static requireCredential = true; private withRenotes: boolean; private withReplies: boolean; + private withBots: boolean; private withFiles: boolean; constructor( @@ -41,6 +42,7 @@ class HybridTimelineChannel extends Channel { this.withRenotes = params.withRenotes ?? true; this.withReplies = params.withReplies ?? false; + this.withBots = params.withBots ?? true; this.withFiles = params.withFiles ?? false; // Subscribe events @@ -50,6 +52,7 @@ class HybridTimelineChannel extends Channel { @bindThis private async onNote(note: Packed<'Note'>) { if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return; + if (!this.withBots && note.user.isBot) return; // チャンネルの投稿ではなく、自分自身の投稿 または // チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または @@ -69,7 +72,7 @@ class HybridTimelineChannel extends Channel { } // Ignore notes from instances the user has muted - if (isInstanceMuted(note, new Set(this.userProfile!.mutedInstances ?? []))) return; + if (isInstanceMuted(note, new Set(this.userProfile!.mutedInstances))) return; // 関係ない返信は除外 if (note.reply && !this.following[note.userId]?.withReplies && !this.withReplies) { @@ -78,6 +81,8 @@ class HybridTimelineChannel extends Channel { if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; } + if (note.user.isSilenced && !this.following[note.userId] && note.userId !== this.user!.id) return; + if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return; // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index a21104113..738dbd80f 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -19,6 +19,7 @@ class LocalTimelineChannel extends Channel { public static requireCredential = false; private withRenotes: boolean; private withReplies: boolean; + private withBots: boolean; private withFiles: boolean; constructor( @@ -40,6 +41,7 @@ class LocalTimelineChannel extends Channel { this.withRenotes = params.withRenotes ?? true; this.withReplies = params.withReplies ?? false; + this.withBots = params.withBots ?? true; this.withFiles = params.withFiles ?? false; // Subscribe events @@ -49,6 +51,7 @@ class LocalTimelineChannel extends Channel { @bindThis private async onNote(note: Packed<'Note'>) { if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return; + if (!this.withBots && note.user.isBot) return; if (note.user.host !== null) return; if (note.visibility !== 'public') return; @@ -61,6 +64,8 @@ class LocalTimelineChannel extends Channel { if (reply.userId !== this.user.id && note.userId !== this.user.id && reply.userId !== note.userId) return; } + if (note.user.isSilenced && !this.following[note.userId] && note.userId !== this.user!.id) return; + if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return; // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts index 7a799cb8d..94d004031 100644 --- a/packages/backend/src/server/web/FeedService.ts +++ b/packages/backend/src/server/web/FeedService.ts @@ -83,7 +83,7 @@ export class FeedService { date: this.idService.parse(note.id).date, description: note.cw ?? undefined, content: note.text ?? undefined, - image: file ? this.driveFileEntityService.getPublicUrl(file) ?? undefined : undefined, + image: file ? this.driveFileEntityService.getPublicUrl(file) : undefined, }); } diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index f753b54c6..28f07bf3f 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -727,7 +727,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { }, alice); + const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); diff --git a/packages/frontend/package.json b/packages/frontend/package.json index c5ec2976f..0cc84753a 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -78,24 +78,24 @@ "vuedraggable": "next" }, "devDependencies": { - "@storybook/addon-actions": "7.4.6", - "@storybook/addon-essentials": "7.4.6", - "@storybook/addon-interactions": "7.4.6", - "@storybook/addon-links": "7.4.6", - "@storybook/addon-storysource": "7.4.6", - "@storybook/addons": "7.4.6", - "@storybook/blocks": "7.4.6", - "@storybook/core-events": "7.4.6", + "@storybook/addon-actions": "7.5.0", + "@storybook/addon-essentials": "7.5.0", + "@storybook/addon-interactions": "7.5.0", + "@storybook/addon-links": "7.5.0", + "@storybook/addon-storysource": "7.5.0", + "@storybook/addons": "7.5.0", + "@storybook/blocks": "7.5.0", + "@storybook/core-events": "7.5.0", "@storybook/jest": "0.2.3", - "@storybook/manager-api": "7.4.6", - "@storybook/preview-api": "7.4.6", - "@storybook/react": "7.4.6", - "@storybook/react-vite": "7.4.6", + "@storybook/manager-api": "7.5.0", + "@storybook/preview-api": "7.5.0", + "@storybook/react": "7.5.0", + "@storybook/react-vite": "7.5.0", "@storybook/testing-library": "0.2.2", - "@storybook/theming": "7.4.6", - "@storybook/types": "7.4.6", - "@storybook/vue3": "7.4.6", - "@storybook/vue3-vite": "7.4.6", + "@storybook/theming": "7.5.0", + "@storybook/types": "7.5.0", + "@storybook/vue3": "7.5.0", + "@storybook/vue3-vite": "7.5.0", "@testing-library/vue": "7.0.0", "@types/escape-regexp": "0.0.1", "@types/estree": "1.0.2", @@ -109,8 +109,8 @@ "@types/uuid": "9.0.5", "@types/websocket": "1.0.7", "@types/ws": "8.5.7", - "@typescript-eslint/eslint-plugin": "6.7.5", - "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/eslint-plugin": "6.8.0", + "@typescript-eslint/parser": "6.8.0", "@vitest/coverage-v8": "0.34.6", "@vue/runtime-core": "3.3.4", "acorn": "8.10.0", @@ -129,7 +129,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "start-server-and-test": "2.0.1", - "storybook": "7.4.6", + "storybook": "7.5.0", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "summaly": "github:misskey-dev/summaly", "vite-plugin-turbosnap": "1.0.3", diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index 1a7bba8a7..17714558f 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -42,6 +42,7 @@ import { useStream } from '@/stream.js'; import { i18n } from '@/i18n.js'; import { claimAchievement } from '@/scripts/achievements.js'; import { $i } from '@/account.js'; +import { defaultStore } from "@/store.js"; const props = withDefaults(defineProps<{ user: Misskey.entities.UserDetailed, @@ -52,6 +53,10 @@ const props = withDefaults(defineProps<{ large: false, }); +const emit = defineEmits<{ + (_: 'update:user', value: Misskey.entities.UserDetailed): void +}>(); + let isFollowing = $ref(props.user.isFollowing); let hasPendingFollowRequestFromYou = $ref(props.user.hasPendingFollowRequestFromYou); let wait = $ref(false); @@ -95,6 +100,11 @@ async function onClick() { } else { await os.api('following/create', { userId: props.user.id, + withReplies: defaultStore.state.defaultWithReplies, + }); + emit('update:user', { + ...props.user, + withReplies: defaultStore.state.defaultWithReplies }); hasPendingFollowRequestFromYou = true; diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index cdd72febd..fa0438419 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -25,11 +25,13 @@ const props = withDefaults(defineProps<{ sound?: boolean; withRenotes?: boolean; withReplies?: boolean; + withBots?: boolean; onlyFiles?: boolean; }>(), { withRenotes: true, withReplies: false, onlyFiles: false, + withBots: true, }); const emit = defineEmits<{ @@ -93,11 +95,13 @@ if (props.src === 'antenna') { query = { withRenotes: props.withRenotes, withReplies: props.withReplies, + withBots: props.withBots, withFiles: props.onlyFiles ? true : undefined, }; connection = stream.useChannel('localTimeline', { withRenotes: props.withRenotes, withReplies: props.withReplies, + withBots: props.withBots, withFiles: props.onlyFiles ? true : undefined, }); connection.on('note', prepend); @@ -106,11 +110,13 @@ if (props.src === 'antenna') { query = { withRenotes: props.withRenotes, withReplies: props.withReplies, + withBots: props.withBots, withFiles: props.onlyFiles ? true : undefined, }; connection = stream.useChannel('hybridTimeline', { withRenotes: props.withRenotes, withReplies: props.withReplies, + withBots: props.withBots, withFiles: props.onlyFiles ? true : undefined, }); connection.on('note', prepend); @@ -118,10 +124,12 @@ if (props.src === 'antenna') { endpoint = 'notes/global-timeline'; query = { withRenotes: props.withRenotes, + withBots: props.withBots, withFiles: props.onlyFiles ? true : undefined, }; connection = stream.useChannel('globalTimeline', { withRenotes: props.withRenotes, + withBots: props.withBots, withFiles: props.onlyFiles ? true : undefined, }); connection.on('note', prepend); diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index aa4d57533..85954d419 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only - +
diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 7d8376db0..2f6178d2b 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -78,6 +78,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+ {{ i18n.ts.silence }} {{ i18n.ts.suspend }} {{ i18n.ts.markAsNSFW }} @@ -327,6 +328,19 @@ async function toggleNSFW(v) { } } +async function toggleSilence(v) { + const confirm = await os.confirm({ + type: 'warning', + text: v ? i18n.ts.silenceConfirm : i18n.ts.unsilenceConfirm, + }); + if (confirm.canceled) { + silenced = !v; + } else { + await os.api(v ? 'admin/silence-user' : 'admin/unsilence-user', { userId: user.id }); + await refreshUser(); + } +} + async function toggleSuspend(v) { const confirm = await os.confirm({ type: 'warning', diff --git a/packages/frontend/src/pages/admin/other-settings.vue b/packages/frontend/src/pages/admin/other-settings.vue index ee24bf0fd..d1bc420db 100644 --- a/packages/frontend/src/pages/admin/other-settings.vue +++ b/packages/frontend/src/pages/admin/other-settings.vue @@ -18,8 +18,15 @@ SPDX-License-Identifier: AGPL-3.0-only
- - + + + +
+ +
+ + +
@@ -61,6 +68,7 @@ import MkSwitch from '@/components/MkSwitch.vue'; let enableServerMachineStats: boolean = $ref(false); let enableAchievements: boolean = $ref(false); +let enableBotTrending: boolean = $ref(false); let enableIdenticonGeneration: boolean = $ref(false); let enableChartsForRemoteUser: boolean = $ref(false); let enableChartsForFederatedInstances: boolean = $ref(false); @@ -69,6 +77,7 @@ async function init() { const meta = await os.api('admin/meta'); enableServerMachineStats = meta.enableServerMachineStats; enableAchievements = meta.enableAchievements; + enableBotTrending = meta.enableBotTrending; enableIdenticonGeneration = meta.enableIdenticonGeneration; enableChartsForRemoteUser = meta.enableChartsForRemoteUser; enableChartsForFederatedInstances = meta.enableChartsForFederatedInstances; @@ -78,6 +87,7 @@ function save() { os.apiWithDialog('admin/update-meta', { enableServerMachineStats, enableAchievements, + enableBotTrending, enableIdenticonGeneration, enableChartsForRemoteUser, enableChartsForFederatedInstances, diff --git a/packages/frontend/src/pages/follow.vue b/packages/frontend/src/pages/follow.vue index e382cabd7..a0a4a480b 100644 --- a/packages/frontend/src/pages/follow.vue +++ b/packages/frontend/src/pages/follow.vue @@ -14,6 +14,7 @@ import * as Misskey from 'misskey-js'; import * as os from '@/os.js'; import { mainRouter } from '@/router.js'; import { i18n } from '@/i18n.js'; +import { defaultStore } from "@/store.js"; async function follow(user): Promise { const { canceled } = await os.confirm({ @@ -28,7 +29,9 @@ async function follow(user): Promise { os.apiWithDialog('following/create', { userId: user.id, + withReplies: defaultStore.state.defaultWithReplies, }); + user.withReplies = defaultStore.state.defaultWithReplies; } const acct = new URL(location.href).searchParams.get('acct'); diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue index 4de05644b..4046e78d6 100644 --- a/packages/frontend/src/pages/gallery/post.vue +++ b/packages/frontend/src/pages/gallery/post.vue @@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- +
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 981216daa..cb0a841ac 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -29,6 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.showFixedPostForm }} {{ i18n.ts.showFixedPostFormInChannel }} + {{ i18n.ts.withRepliesByDefaultForNewlyFollowed }} @@ -152,6 +153,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.enableInfiniteScroll }} {{ i18n.ts.keepScreenOn }} {{ i18n.ts.clickToOpen }} + {{ i18n.ts.showBots }}
@@ -227,6 +229,7 @@ const showClipButtonInNoteFooter = computed(defaultStore.makeGetterSetter('showC const reactionsDisplaySize = computed(defaultStore.makeGetterSetter('reactionsDisplaySize')); const collapseRenotes = computed(defaultStore.makeGetterSetter('collapseRenotes')); const clickToOpen = computed(defaultStore.makeGetterSetter('clickToOpen')); +const showBots = computed(defaultStore.makeGetterSetter('tlWithBots')); const collapseFiles = computed(defaultStore.makeGetterSetter('collapseFiles')); const autoloadConversation = computed(defaultStore.makeGetterSetter('autoloadConversation')); const reduceAnimation = computed(defaultStore.makeGetterSetter('animation', v => !v, v => !v)); @@ -255,6 +258,7 @@ const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter(' const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition')); const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis')); const keepScreenOn = computed(defaultStore.makeGetterSetter('keepScreenOn')); +const defaultWithReplies = computed(defaultStore.makeGetterSetter('defaultWithReplies')); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); diff --git a/packages/frontend/src/pages/settings/import-export.vue b/packages/frontend/src/pages/settings/import-export.vue index 24dcdeacc..0c3e95a3d 100644 --- a/packages/frontend/src/pages/settings/import-export.vue +++ b/packages/frontend/src/pages/settings/import-export.vue @@ -40,6 +40,9 @@ SPDX-License-Identifier: AGPL-3.0-only + + {{ i18n.ts._exportOrImport.withReplies }} + {{ i18n.ts.import }} @@ -118,9 +121,11 @@ import { selectFile } from '@/scripts/select-file.js'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import { $i } from '@/account.js'; +import { defaultStore } from "@/store.js"; const excludeMutingUsers = ref(false); const excludeInactiveUsers = ref(false); +const withReplies = ref(defaultStore.state.defaultWithReplies); const onExportSuccess = () => { os.alert({ @@ -177,7 +182,10 @@ const exportAntennas = () => { const importFollowing = async (ev) => { const file = await selectFile(ev.currentTarget ?? ev.target); - os.api('i/import-following', { fileId: file.id }).then(onImportSuccess).catch(onError); + os.api('i/import-following', { + fileId: file.id, + withReplies: withReplies.value, + }).then(onImportSuccess).catch(onError); }; const importUserLists = async (ev) => { diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index c375b3839..6d1e2dbd5 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -21,6 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only :withRenotes="withRenotes" :withReplies="withReplies" :onlyFiles="onlyFiles" + :withBots="withBots" :sound="true" @queue="queueUpdated" /> @@ -63,6 +64,7 @@ let srcWhenNotSignin = $ref(isLocalTimelineAvailable ? 'local' : 'global'); const src = $computed({ get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin), set: (x) => saveSrc(x) }); const withRenotes = $ref(true); const withReplies = $ref($i ? defaultStore.state.tlWithReplies : false); +const withBots = $ref($i ? defaultStore.state.tlWithBots : true); const onlyFiles = $ref(false); watch($$(src), () => queue = 0); diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index d34221b39..d1e57db0e 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -7,9 +7,8 @@ SPDX-License-Identifier: AGPL-3.0-only
- - - + {{ i18n.ts.userSuspended }} + {{ i18n.ts.userSilenced }}
@@ -34,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.followsYou }}
- +
@@ -213,6 +212,7 @@ const props = withDefaults(defineProps<{ const router = useRouter(); +let user = $ref(props.user); let parallaxAnimationId = $ref(null); let narrow = $ref(null); let rootEl = $ref(null); @@ -285,7 +285,7 @@ const age = $computed(() => { }); function menu(ev) { - const { menu, cleanup } = getUserMenu(props.user, router); + const { menu, cleanup } = getUserMenu(user, router); os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup); } diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index ceb5b9ca5..27bc6ca74 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -373,6 +373,14 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, + tlWithBots: { + where: 'device', + default: true, + }, + defaultWithReplies: { + where: 'account', + default: false, + }, })); // TODO: 他のタブと永続化されたstateを同期 diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 6842c677e..76c6d86b4 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1185,6 +1185,7 @@ export type Endpoints = { 'following/create': { req: { userId: User['id']; + withReplies?: boolean; }; res: User; }; @@ -2987,7 +2988,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:630:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:633:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:603:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index f124c678c..2f65c3b95 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -24,8 +24,8 @@ "@swc/jest": "0.2.29", "@types/jest": "29.5.5", "@types/node": "20.8.6", - "@typescript-eslint/eslint-plugin": "6.7.5", - "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/eslint-plugin": "6.8.0", + "@typescript-eslint/parser": "6.8.0", "eslint": "8.51.0", "jest": "29.7.0", "jest-fetch-mock": "3.0.3", diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index a93bda020..09a7c6c65 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -31,6 +31,8 @@ export type Endpoints = { 'admin/show-users': { req: TODO; res: TODO; }; 'admin/silence-user': { req: TODO; res: TODO; }; 'admin/suspend-user': { req: TODO; res: TODO; }; + 'admin/nsfw-user': { req: TODO; res: TODO; }; + 'admin/unnsfw-user': { req: TODO; res: TODO; }; 'admin/unsilence-user': { req: TODO; res: TODO; }; 'admin/unsuspend-user': { req: TODO; res: TODO; }; 'admin/update-meta': { req: TODO; res: TODO; }; @@ -321,7 +323,10 @@ export type Endpoints = { 'federation/users': { req: { host: string; limit?: number; sinceId?: User['id']; untilId?: User['id']; }; res: UserDetailed[]; }; // following - 'following/create': { req: { userId: User['id'] }; res: User; }; + 'following/create': { req: { + userId: User['id'], + withReplies?: boolean, + }; res: User; }; 'following/delete': { req: { userId: User['id'] }; res: User; }; 'following/requests/accept': { req: { userId: User['id'] }; res: null; }; 'following/requests/cancel': { req: { userId: User['id'] }; res: User; }; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 2011bec95..ac79dd7a5 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -406,6 +406,7 @@ export type AdminInstanceMetadata = DetailedInstanceMetadata & { app192IconUrl: string | null; app512IconUrl: string | null; manifestJsonOverride: string; + enableBotTrending: boolean; }; export type ServerInfo = { diff --git a/packages/sw/package.json b/packages/sw/package.json index 24878a6e2..c045b3216 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -14,7 +14,7 @@ "misskey-js": "workspace:*" }, "devDependencies": { - "@typescript-eslint/parser": "6.7.5", + "@typescript-eslint/parser": "6.8.0", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67", "eslint": "8.51.0", "eslint-plugin-import": "2.28.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 095a6f5aa..ac9b31ca2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,11 +36,11 @@ importers: version: 4.4.0 devDependencies: '@typescript-eslint/eslint-plugin': - specifier: 6.7.5 - version: 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/parser': - specifier: 6.7.5 - version: 6.7.5(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(eslint@8.51.0)(typescript@5.2.2) cross-env: specifier: 7.0.3 version: 7.0.3 @@ -63,14 +63,14 @@ importers: specifier: 3.412.0 version: 3.412.0(@aws-sdk/client-s3@3.412.0) '@bull-board/api': - specifier: 5.8.4 - version: 5.8.4(@bull-board/ui@5.8.4) + specifier: 5.9.1 + version: 5.9.1(@bull-board/ui@5.9.1) '@bull-board/fastify': - specifier: 5.8.4 - version: 5.8.4 + specifier: 5.9.1 + version: 5.9.1 '@bull-board/ui': - specifier: 5.8.4 - version: 5.8.4 + specifier: 5.9.1 + version: 5.9.1 '@discordapp/twemoji': specifier: 14.1.2 version: 14.1.2 @@ -363,8 +363,8 @@ importers: specifier: github:misskey-dev/summaly version: github.com/misskey-dev/summaly/d2d8db49943ccb201c1b1b283e9d0a630519fac7 systeminformation: - specifier: 5.21.11 - version: 5.21.11 + specifier: 5.21.12 + version: 5.21.12 tinycolor2: specifier: 1.6.0 version: 1.6.0 @@ -503,26 +503,26 @@ importers: specifier: 0.2.29 version: 0.2.29(@swc/core@1.3.93) '@types/accepts': - specifier: 1.3.5 - version: 1.3.5 + specifier: 1.3.6 + version: 1.3.6 '@types/archiver': - specifier: 5.3.3 - version: 5.3.3 + specifier: 5.3.4 + version: 5.3.4 '@types/bcryptjs': - specifier: 2.4.4 - version: 2.4.4 + specifier: 2.4.5 + version: 2.4.5 '@types/body-parser': - specifier: 1.19.3 - version: 1.19.3 + specifier: 1.19.4 + version: 1.19.4 '@types/cbor': specifier: 6.0.0 version: 6.0.0 '@types/color-convert': - specifier: 2.0.1 - version: 2.0.1 + specifier: 2.0.2 + version: 2.0.2 '@types/content-disposition': - specifier: 0.5.6 - version: 0.5.6 + specifier: 0.5.7 + version: 0.5.7 '@types/fluent-ffmpeg': specifier: 2.1.22 version: 2.1.22 @@ -623,11 +623,11 @@ importers: specifier: 8.5.7 version: 8.5.7 '@typescript-eslint/eslint-plugin': - specifier: 6.7.5 - version: 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/parser': - specifier: 6.7.5 - version: 6.7.5(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(eslint@8.51.0)(typescript@5.2.2) aws-sdk-client-mock: specifier: 3.0.0 version: 3.0.0 @@ -639,7 +639,7 @@ importers: version: 8.51.0 eslint-plugin-import: specifier: 2.28.1 - version: 2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.51.0) + version: 2.28.1(@typescript-eslint/parser@6.8.0)(eslint@8.51.0) execa: specifier: 8.0.1 version: 8.0.1 @@ -837,59 +837,59 @@ importers: version: 4.1.0(vue@3.3.4) devDependencies: '@storybook/addon-actions': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-essentials': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-interactions': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-links': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-storysource': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/addons': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/blocks': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/core-events': - specifier: 7.4.6 - version: 7.4.6 + specifier: 7.5.0 + version: 7.5.0 '@storybook/jest': specifier: 0.2.3 version: 0.2.3(vitest@0.34.6) '@storybook/manager-api': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/preview-api': - specifier: 7.4.6 - version: 7.4.6 + specifier: 7.5.0 + version: 7.5.0 '@storybook/react': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) '@storybook/react-vite': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0)(rollup@4.1.4)(typescript@5.2.2)(vite@4.4.11) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0)(rollup@4.1.4)(typescript@5.2.2)(vite@4.4.11) '@storybook/testing-library': specifier: 0.2.2 version: 0.2.2 '@storybook/theming': - specifier: 7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0) + specifier: 7.5.0 + version: 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/types': - specifier: 7.4.6 - version: 7.4.6 + specifier: 7.5.0 + version: 7.5.0 '@storybook/vue3': - specifier: 7.4.6 - version: 7.4.6(@vue/compiler-core@3.3.4)(vue@3.3.4) + specifier: 7.5.0 + version: 7.5.0(@vue/compiler-core@3.3.4)(vue@3.3.4) '@storybook/vue3-vite': - specifier: 7.4.6 - version: 7.4.6(@vue/compiler-core@3.3.4)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.4.11)(vue@3.3.4) + specifier: 7.5.0 + version: 7.5.0(@vue/compiler-core@3.3.4)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.4.11)(vue@3.3.4) '@testing-library/vue': specifier: 7.0.0 version: 7.0.0(@vue/compiler-sfc@3.3.4)(vue@3.3.4) @@ -930,11 +930,11 @@ importers: specifier: 8.5.7 version: 8.5.7 '@typescript-eslint/eslint-plugin': - specifier: 6.7.5 - version: 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/parser': - specifier: 6.7.5 - version: 6.7.5(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(eslint@8.51.0)(typescript@5.2.2) '@vitest/coverage-v8': specifier: 0.34.6 version: 0.34.6(vitest@0.34.6) @@ -955,7 +955,7 @@ importers: version: 8.51.0 eslint-plugin-import: specifier: 2.28.1 - version: 2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.51.0) + version: 2.28.1(@typescript-eslint/parser@6.8.0)(eslint@8.51.0) eslint-plugin-vue: specifier: 9.17.0 version: 9.17.0(eslint@8.51.0) @@ -990,11 +990,11 @@ importers: specifier: 2.0.1 version: 2.0.1 storybook: - specifier: 7.4.6 - version: 7.4.6 + specifier: 7.5.0 + version: 7.5.0 storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.4.6)(@storybook/components@7.4.6)(@storybook/core-events@7.4.6)(@storybook/manager-api@7.4.6)(@storybook/preview-api@7.4.6)(@storybook/theming@7.4.6)(@storybook/types@7.4.6)(react-dom@18.2.0)(react@18.2.0) + version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.5.0)(@storybook/components@7.4.6)(@storybook/core-events@7.5.0)(@storybook/manager-api@7.5.0)(@storybook/preview-api@7.5.0)(@storybook/theming@7.5.0)(@storybook/types@7.5.0)(react-dom@18.2.0)(react@18.2.0) summaly: specifier: github:misskey-dev/summaly version: github.com/misskey-dev/summaly/d2d8db49943ccb201c1b1b283e9d0a630519fac7 @@ -1133,11 +1133,11 @@ importers: specifier: 20.8.6 version: 20.8.6 '@typescript-eslint/eslint-plugin': - specifier: 6.7.5 - version: 6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/parser': - specifier: 6.7.5 - version: 6.7.5(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(eslint@8.51.0)(typescript@5.2.2) eslint: specifier: 8.51.0 version: 8.51.0 @@ -1173,8 +1173,8 @@ importers: version: link:../misskey-js devDependencies: '@typescript-eslint/parser': - specifier: 6.7.5 - version: 6.7.5(eslint@8.51.0)(typescript@5.2.2) + specifier: 6.8.0 + version: 6.8.0(eslint@8.51.0)(typescript@5.2.2) '@typescript/lib-webworker': specifier: npm:@types/serviceworker@0.0.67 version: /@types/serviceworker@0.0.67 @@ -1183,7 +1183,7 @@ importers: version: 8.51.0 eslint-plugin-import: specifier: 2.28.1 - version: 2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.51.0) + version: 2.28.1(@typescript-eslint/parser@6.8.0)(eslint@8.51.0) typescript: specifier: 5.2.2 version: 5.2.2 @@ -3093,7 +3093,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 - dev: false /@babel/template@7.22.5: resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} @@ -3138,29 +3137,29 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@bull-board/api@5.8.4(@bull-board/ui@5.8.4): - resolution: {integrity: sha512-uuB2ziEpMc6FrkqqRAqyqSh+yKx1ukTvxlgDenOimuLAiHlcPfhNLgYuYv3qzqWVaZdvUCLhiNqAvOdURoKT5A==} + /@bull-board/api@5.9.1(@bull-board/ui@5.9.1): + resolution: {integrity: sha512-xZzPYNw9Dp46It4vvZv3tmFScmUu/UT/jWQxYK9cvbkJRXh15rsZrbbR+/phUqou0NxRQGiHoFSZ1y5D107dIA==} peerDependencies: - '@bull-board/ui': 5.8.4 + '@bull-board/ui': 5.9.1 dependencies: - '@bull-board/ui': 5.8.4 + '@bull-board/ui': 5.9.1 redis-info: 3.1.0 dev: false - /@bull-board/fastify@5.8.4: - resolution: {integrity: sha512-so5huv/6WmFqenfm9es5vIOpg46nhwj6F5ZOikfyrUxKcfNdTBgLS0xzB5jnuPp5zp5dVBckH4EnIIgvpdF6cQ==} + /@bull-board/fastify@5.9.1: + resolution: {integrity: sha512-bMktkLGd83K2Wimv+ASBhjgBTOR7ZKQ6OsZsFoaV5xH0CbPlIZ/S0apwTlSSfT/tfBbilWKX9BrE0xta22mkrA==} dependencies: - '@bull-board/api': 5.8.4(@bull-board/ui@5.8.4) - '@bull-board/ui': 5.8.4 + '@bull-board/api': 5.9.1(@bull-board/ui@5.9.1) + '@bull-board/ui': 5.9.1 '@fastify/static': 6.11.2 '@fastify/view': 8.2.0 ejs: 3.1.9 dev: false - /@bull-board/ui@5.8.4: - resolution: {integrity: sha512-OBCwelyO5aptZUanZOSiHCK46Y3dNsCXMj4XXF8rNKx0sg/BMZMZzINjlpsCkgNNM5Lxl51OM1eYLjzZREvaAQ==} + /@bull-board/ui@5.9.1: + resolution: {integrity: sha512-lL93KVRTpLSl73KUFBw7sXOcCrqddGBbpiMKWEbViXxObIq68yFuhRrcfR7JeTSocLF5GsnqSVdSiNCZHmdNpw==} dependencies: - '@bull-board/api': 5.8.4(@bull-board/ui@5.8.4) + '@bull-board/api': 5.9.1(@bull-board/ui@5.9.1) dev: false /@canvas/image-data@1.0.0: @@ -4325,11 +4324,11 @@ packages: chalk: 4.1.2 dev: true - /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.2.2)(vite@4.4.11): - resolution: {integrity: sha512-ou4ZJSXMMWHqGS4g8uNRbC5TiTWxAgQZiVucoUrOCWuPrTbkpJbmVyIi9jU72SBry7gQtuMEDp4YR8EEXAg7VQ==} + /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.2.2)(vite@4.4.11): + resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==} peerDependencies: typescript: '>= 4.3.x' - vite: ^3.0.0 || ^4.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 peerDependenciesMeta: typescript: optional: true @@ -4783,13 +4782,13 @@ packages: /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 dev: true /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 dev: true /@radix-ui/react-arrow@1.0.3(react-dom@18.2.0)(react@18.2.0): @@ -4805,7 +4804,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4824,7 +4823,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) @@ -4842,7 +4841,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 react: 18.2.0 dev: true @@ -4855,7 +4854,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 react: 18.2.0 dev: true @@ -4868,7 +4867,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 react: 18.2.0 dev: true @@ -4885,7 +4884,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) @@ -4904,7 +4903,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 react: 18.2.0 dev: true @@ -4921,7 +4920,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) @@ -4938,7 +4937,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) react: 18.2.0 dev: true @@ -4956,7 +4955,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@floating-ui/react-dom': 2.0.2(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-arrow': 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) @@ -4984,7 +4983,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -5003,7 +5002,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-slot': 1.0.2(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -5022,7 +5021,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) @@ -5049,7 +5048,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) @@ -5088,7 +5087,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -5103,7 +5102,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) react: 18.2.0 dev: true @@ -5121,7 +5120,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-direction': 1.0.1(react@18.2.0) @@ -5146,7 +5145,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) @@ -5167,7 +5166,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-direction': 1.0.1(react@18.2.0) @@ -5188,7 +5187,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 react: 18.2.0 dev: true @@ -5201,7 +5200,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) react: 18.2.0 dev: true @@ -5215,7 +5214,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) react: 18.2.0 dev: true @@ -5229,7 +5228,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 react: 18.2.0 dev: true @@ -5242,7 +5241,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 react: 18.2.0 dev: true @@ -5255,7 +5254,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/rect': 1.0.1 react: 18.2.0 dev: true @@ -5269,7 +5268,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) react: 18.2.0 dev: true @@ -5287,7 +5286,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -5296,7 +5295,7 @@ packages: /@radix-ui/rect@1.0.1: resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 dev: true /@rollup/plugin-alias@5.0.1(rollup@4.1.4): @@ -6000,8 +5999,8 @@ packages: resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} dev: false - /@storybook/addon-actions@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-SsqZr3js5NinKPnC8AeNI7Ij+Q6fIl9tRdRmSulEgjksjOg7E5S1/Wsn5Bb2CCgj7MaX6VxGyC7s3XskQtDiIQ==} + /@storybook/addon-actions@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-eeHIFpZXGyhkfmrbHRf3rndL+ppFqlKTgN74y+UfFaAWNUhV3caXxRbHV3BbcPSLkRAsNShBH9hTNTlUAHSVjA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6011,14 +6010,14 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 dequal: 2.0.3 lodash: 4.17.21 polished: 4.2.2 @@ -6034,8 +6033,8 @@ packages: - '@types/react-dom' dev: true - /@storybook/addon-backgrounds@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-+LHTZB/ZYMAzkyD5ZxSriBsqmsrvIaW/Nnd/BeuXGbkrVKKqM0qAKiFZAfjc2WchA1piVNy0/1Rsf+kuYCEiJw==} + /@storybook/addon-backgrounds@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Yu/eFHZIfyAhK28GKKcIBwj/9+hRem8pSdI3N0FJuOhErmaE0zg6VDUBzkgLa/Fn9SwC5PNyAeLAtxssg1KSNg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6045,14 +6044,14 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -6062,8 +6061,8 @@ packages: - '@types/react-dom' dev: true - /@storybook/addon-controls@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-4lq3sycEUIsK8SUWDYc60QgF4vV9FZZ3lDr6M7j2W9bOnvGw49d2fbdlnq+bX1ZprZZ9VgglQpBAorQB3BXZRw==} + /@storybook/addon-controls@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-X56Pd+0GH1A8ddVsziJQaJ8qCaxsWK0aLCKH5li9GLtnyIGHvd5+KvvfYEbjTkeJv3d9J7X0D4uTAH1/dsmI8w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6073,16 +6072,16 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.4.6 - '@storybook/core-events': 7.4.6 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/blocks': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.5.0 + '@storybook/core-events': 7.5.0 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.5.0 + '@storybook/preview-api': 7.5.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 lodash: 4.17.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -6094,27 +6093,27 @@ packages: - supports-color dev: true - /@storybook/addon-docs@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-dLaub+XWFq4hChw+xfuF9yYg0Txp77FUawKoAigccfjWXx+OOhRV3XTuAcknpXkYq94GWynHgUFXosXT9kbDNA==} + /@storybook/addon-docs@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-lgrum81iJT+i85kO3uOR4wR1t05x4SmJLCB2cyYohCIafiOiV4FuyYFhvT9N6UhHByOfrWgpipKgKg6zsmV2eg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@jest/transform': 29.7.0 '@mdx-js/react': 2.3.0(react@18.2.0) - '@storybook/blocks': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/csf-plugin': 7.4.6 - '@storybook/csf-tools': 7.4.6 + '@storybook/blocks': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/csf-plugin': 7.5.0 + '@storybook/csf-tools': 7.5.0 '@storybook/global': 5.0.0 '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.4.6 - '@storybook/postinstall': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/react-dom-shim': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/node-logger': 7.5.0 + '@storybook/postinstall': 7.5.0 + '@storybook/preview-api': 7.5.0 + '@storybook/react-dom-shim': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 fs-extra: 11.1.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -6128,25 +6127,25 @@ packages: - supports-color dev: true - /@storybook/addon-essentials@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-dWodufrt71TK7ELkeIvVae/x4PzECUlbOm57Iqqt4yQCyR291CgvI4PjeB8un2HbpcXCGZ+N/Oj3YkytvzBi4A==} + /@storybook/addon-essentials@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CKPHdQBP6psTVb3NHsP8cWSUcAA4kwzT8SrJxKddn4ecqmWJWeZo5g5y3WuqVQHlv3edpluJLQYehcVibcljag==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/addon-actions': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-backgrounds': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-controls': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-docs': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-highlight': 7.4.6 - '@storybook/addon-measure': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-outline': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-toolbars': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-viewport': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.4.6 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.4.6 - '@storybook/preview-api': 7.4.6 + '@storybook/addon-actions': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-backgrounds': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-controls': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-docs': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-highlight': 7.5.0 + '@storybook/addon-measure': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-outline': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-toolbars': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-viewport': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.5.0 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.5.0 + '@storybook/preview-api': 7.5.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 @@ -6157,16 +6156,16 @@ packages: - supports-color dev: true - /@storybook/addon-highlight@7.4.6: - resolution: {integrity: sha512-zCufxxD2KS5VwczxfkcBxe1oR/juTTn2H1Qm8kYvWCJQx3UxzX0+G9cwafbpV7eivqaufLweEwROkH+0KjAtkQ==} + /@storybook/addon-highlight@7.5.0: + resolution: {integrity: sha512-6SlEkGCZ/LnEcbN6oE2Au3fgI9VfULErWQ36bx+sV6WWTb1EoooiD7ZJJzobrcOAriSyfWoctO5DF4W+X9I8lg==} dependencies: - '@storybook/core-events': 7.4.6 + '@storybook/core-events': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.4.6 + '@storybook/preview-api': 7.5.0 dev: true - /@storybook/addon-interactions@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-zVZYrEPZPhNrXBuPqM7HbQvr6jwsje1sbCYj3wnp83U5wjciuqrngqHIlaSZ30zOWSfRVyzbyqL+JQZKA58BNA==} + /@storybook/addon-interactions@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-OnmFJdzoww8jhiaxY/C/tmppkMRna6f4FKrhqeBytXRai8/PmH+a6tbjrKD8ywtAIt+1MVIxY/oXxXulHtBv8Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6176,16 +6175,16 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.4.6 - '@storybook/core-events': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.5.0 + '@storybook/core-events': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 7.4.6 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/instrumenter': 7.5.0 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 jest-mock: 27.5.1 polished: 4.2.2 react: 18.2.0 @@ -6198,8 +6197,8 @@ packages: - supports-color dev: true - /@storybook/addon-links@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-BPygElZKX+CPI9Se6GJNk1dYc5oxuhA+vHigO1tBqhiM6VkHyFP3cvezJNQvpNYhkUnu3cxnZXb3UJnlRbPY3g==} + /@storybook/addon-links@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-1j0I80k8V1sSGN3faduj9uFk0ThgT4qAYyA/5q2YYA4y6V/K8ywJVOR3nv5j7ueTeBD/gUaoncn+NosusrhRNQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6209,22 +6208,22 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/core-events': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/core-events': 7.5.0 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/router': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/router': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-measure@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-nCymMLaHnxv8TE3yEM1A9Tulb1NuRXRNmtsdHTkjv7P1aWCxZo8A/GZaottKe/GLT8jSRjZ+dnpYWrbAhw6wTQ==} + /@storybook/addon-measure@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-zzHrQpn+burEr37hV1QV7yA1M33wBa38dUe+RLNYkS9g22BXYYZ/uVUhljpmA9DhZCUNJqYbXWi+ad4XMPE6+Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6234,13 +6233,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/types': 7.5.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) tiny-invariant: 1.3.1 @@ -6249,8 +6248,8 @@ packages: - '@types/react-dom' dev: true - /@storybook/addon-outline@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-errNUblRVDLpuEaHQPr/nsrnsUkD2ARmXawkRvizgDWLIDMDJYjTON3MUCaVx3x+hlZ3I6X//G5TVcma8tCc8A==} + /@storybook/addon-outline@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-iVcyFi2N2NEZRytUg8wSiXS9UE9wA8/prs/sIsQ7Y34vHm1UaqAd8KxCE/fhHFNYw4UyHEEDUyTfci/jNrNQYA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6260,13 +6259,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/types': 7.5.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 @@ -6275,8 +6274,8 @@ packages: - '@types/react-dom' dev: true - /@storybook/addon-storysource@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-qkfwvh/pgVBReuWqO25WyaD7jd6LVqhoIJ6rBWnmx+NBpTds+h3Yt3UJCHgvweIrfSF8J3IqzaTxmmNjnkcrRw==} + /@storybook/addon-storysource@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-D6MfSOjyNNZP1fvnEU6nO5jbgFoMHPvRFXpyYTp9Je2s/mCOjQ/p3elKnVg0tHIcVLoh0aJVutJoW3kkKeNfdw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6286,13 +6285,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/router': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/source-loader': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/router': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/source-loader': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) estraverse: 5.3.0 prop-types: 15.8.1 react: 18.2.0 @@ -6304,8 +6303,8 @@ packages: - '@types/react-dom' dev: true - /@storybook/addon-toolbars@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-L9m2FBcKeteGq7qIYsMJr0LEfiH7Wdrv5IDcldZTn68eZUJTh1p4GdJZcOmzX1P5IFRr76hpu03iWsNlWQjpbQ==} + /@storybook/addon-toolbars@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-RLONWIJE7myVL3DzWZDWnnmb53C1OitCiO3mDt678xyK5ZrFCOV9cznckXASx1wNJVt3P9OOW1N2UY7wul72+Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6315,11 +6314,11 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: @@ -6327,8 +6326,8 @@ packages: - '@types/react-dom' dev: true - /@storybook/addon-viewport@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-INDtk54j7bi7NgxMfd2ATmbA0J7nAd6X8itMkLIyPuPJtx8bYHPDORyemDOd0AojgmAdTOAyUtDYdI/PFeo4Cw==} + /@storybook/addon-viewport@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-NXnjHQFKgeFsWOaJE0fl2THgejxDqx8axy4Prtc3ePcoVa/UrMu11G3iEcCaLhDJU7RDNM6CODgifYpH6gyKWg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6338,13 +6337,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) memoizerific: 1.11.3 prop-types: 15.8.1 react: 18.2.0 @@ -6354,36 +6353,36 @@ packages: - '@types/react-dom' dev: true - /@storybook/addons@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-c+4awrtwNlJayFdgLkEXa5H2Gj+KNlxuN+Z5oDAdZBLqXI8g0gn7eYO2F/eCSIDWdd/+zcU2uq57XPFKc8veHQ==} + /@storybook/addons@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-ENvleXaJfOUVfWlh+T/318+UpmHfdQz5nB7QxkgK+AX7mQ3tPC41oUivwuEaVE6lP4BsijBtJBrGHEnA29xhUg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/types': 7.5.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/blocks@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-HxBSAeOiTZW2jbHQlo1upRWFgoMsaAyKijUFf5MwwMNIesXCuuTGZDJ3xTABwAVLK2qC9Ektfbo0CZCiPVuDRQ==} + /@storybook/blocks@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-4poS7lQVKhitWKl0TPECMszOMtNamsbNvZdAZ188U/p1EzTrqLg+RT9HtsB8q8Y0owx29Nh5LdfhNOddpx23ig==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.4.6 + '@storybook/channels': 7.5.0 + '@storybook/client-logger': 7.5.0 + '@storybook/components': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.5.0 '@storybook/csf': 0.1.0 - '@storybook/docs-tools': 7.4.6 + '@storybook/docs-tools': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 '@types/lodash': 4.14.191 color-convert: 2.0.1 dequal: 2.0.3 @@ -6405,13 +6404,13 @@ packages: - supports-color dev: true - /@storybook/builder-manager@7.4.6: - resolution: {integrity: sha512-zylZCD2rmyLOOFBFmUgtJg6UNUKmRNgXiig1XApzS2TkIbTZP827DsVEUl0ey/lskCe0uArkrEBR6ICba8p/Rw==} + /@storybook/builder-manager@7.5.0: + resolution: {integrity: sha512-nj+n36i7Mds4RIyGJqvOB+Z47zfgbMes+6Gd6reT1vC22Yda5nAITnd2vxbYfv/sUPhIBBfuFZ/eogomgYCjKg==} dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 7.4.6 - '@storybook/manager': 7.4.6 - '@storybook/node-logger': 7.4.6 + '@storybook/core-common': 7.5.0 + '@storybook/manager': 7.5.0 + '@storybook/node-logger': 7.5.0 '@types/ejs': 3.1.2 '@types/find-cache-dir': 3.2.1 '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.18.17) @@ -6429,12 +6428,12 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.4.6(typescript@5.2.2)(vite@4.4.11): - resolution: {integrity: sha512-xV9STYK+TkqWWTf2ydm6jx+7P70fjD2UPd1XTUw08uKszIjhuuxk+bG/OF5R1E25mPunAKXm6kBFh351AKejBg==} + /@storybook/builder-vite@7.5.0(typescript@5.2.2)(vite@4.4.11): + resolution: {integrity: sha512-XqiXECAhIDhUryhcPfWfmrvCA2R9p4cebXdyH5Op17yKQ10Bp+OxDWXZlOY/PHdq2KBVhC8CF3Yp7JXCWk8BHw==} peerDependencies: '@preact/preset-vite': '*' typescript: '>= 4.3.x' - vite: ^3.0.0 || ^4.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 vite-plugin-glimmerx: '*' peerDependenciesMeta: '@preact/preset-vite': @@ -6444,15 +6443,14 @@ packages: vite-plugin-glimmerx: optional: true dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/core-common': 7.4.6 - '@storybook/csf-plugin': 7.4.6 - '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.4.6 - '@storybook/preview': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/channels': 7.5.0 + '@storybook/client-logger': 7.5.0 + '@storybook/core-common': 7.5.0 + '@storybook/csf-plugin': 7.5.0 + '@storybook/node-logger': 7.5.0 + '@storybook/preview': 7.5.0 + '@storybook/preview-api': 7.5.0 + '@storybook/types': 7.5.0 '@types/find-cache-dir': 3.2.1 browser-assert: 1.2.1 es-module-lexer: 0.9.3 @@ -6460,8 +6458,6 @@ packages: find-cache-dir: 3.3.2 fs-extra: 11.1.1 magic-string: 0.30.3 - remark-external-links: 8.0.0 - remark-slug: 6.1.0 rollup: 3.29.4 typescript: 5.2.2 vite: 4.4.11(@types/node@20.8.6)(sass@1.69.3)(terser@5.21.0) @@ -6481,22 +6477,33 @@ packages: tiny-invariant: 1.3.1 dev: true - /@storybook/cli@7.4.6: - resolution: {integrity: sha512-rRwaH8pOL+FHz/pJMEkNpMH2xvZvWsrl7obBYw26NQiHmiVSAkfHJicndSN1mwc+p5w+9iXthrgzbLtSAOSvkA==} + /@storybook/channels@7.5.0: + resolution: {integrity: sha512-/7QJS1UA7TX3uhZqCpjv4Ib8nfMnDOJrBWvjiXiUONaRcSk/he5X+W1Zz/c7dgt+wkYuAh+evjc7glIaBhVNVQ==} + dependencies: + '@storybook/client-logger': 7.5.0 + '@storybook/core-events': 7.5.0 + '@storybook/global': 5.0.0 + qs: 6.11.1 + telejson: 7.2.0 + tiny-invariant: 1.3.1 + dev: true + + /@storybook/cli@7.5.0: + resolution: {integrity: sha512-f14q6sqHhDf7bFS0o/ZTgN2tM00Q0cMGMmGFXTQSCh0HXJUS4ujy/FADL+x62wUylIdr1HkIw+ONWMMqHuenEA==} hasBin: true dependencies: '@babel/core': 7.22.11 '@babel/preset-env': 7.22.9(@babel/core@7.22.11) '@babel/types': 7.22.17 '@ndelangen/get-tarball': 3.0.7 - '@storybook/codemod': 7.4.6 - '@storybook/core-common': 7.4.6 - '@storybook/core-events': 7.4.6 - '@storybook/core-server': 7.4.6 - '@storybook/csf-tools': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@storybook/telemetry': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/codemod': 7.5.0 + '@storybook/core-common': 7.5.0 + '@storybook/core-events': 7.5.0 + '@storybook/core-server': 7.5.0 + '@storybook/csf-tools': 7.5.0 + '@storybook/node-logger': 7.5.0 + '@storybook/telemetry': 7.5.0 + '@storybook/types': 7.5.0 '@types/semver': 7.5.3 '@yarnpkg/fslib': 2.10.3 '@yarnpkg/libzip': 2.3.0 @@ -6539,16 +6546,22 @@ packages: '@storybook/global': 5.0.0 dev: true - /@storybook/codemod@7.4.6: - resolution: {integrity: sha512-lxmwEpwksCaAq96APN2YlooSDfKjJ1vKzN5Ni2EqQzf2TEXl7XQjLacHd7OOaII1kfsy+D5gNG4N5wBo7Ub30g==} + /@storybook/client-logger@7.5.0: + resolution: {integrity: sha512-JV7J9vc69f9Il4uW62NIeweUU7O38VwFWxtCkhd0bcBA/9RG0go4M2avzxYYEAe9kIOX9IBBk8WGzMacwW4gKQ==} + dependencies: + '@storybook/global': 5.0.0 + dev: true + + /@storybook/codemod@7.5.0: + resolution: {integrity: sha512-QdjFdD1OK+LqhYwNMh60/kgSt9VZIgH2TBUeXrPlCK6gfcZBrCB0ktgtuM8Zk/ROktq09pZoVDxqFi0AbEUPew==} dependencies: '@babel/core': 7.22.11 '@babel/preset-env': 7.22.9(@babel/core@7.22.11) '@babel/types': 7.22.17 '@storybook/csf': 0.1.0 - '@storybook/csf-tools': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/csf-tools': 7.5.0 + '@storybook/node-logger': 7.5.0 + '@storybook/types': 7.5.0 '@types/cross-spawn': 6.0.2 cross-spawn: 7.0.3 globby: 11.1.0 @@ -6583,26 +6596,49 @@ packages: - '@types/react-dom' dev: true - /@storybook/core-client@7.4.6: - resolution: {integrity: sha512-tfgxAHeCvMcs6DsVgtb4hQSDaCHeAPJOsoyhb47eDQfk4OmxzriM0qWucJV5DePSMi+KutX/rN2u0JxfOuN68g==} + /@storybook/components@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-6lmZ6PbS27xN32vTJ/NvgaiKkFIQRzZuBeBIg2u+FoAEgCiCwRXjZKe/O8NZC2Xr0uf97+7U2P0kD4Hwr9SNhw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/preview-api': 7.4.6 + '@radix-ui/react-select': 1.2.2(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toolbar': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.5.0 + '@storybook/csf': 0.1.0 + '@storybook/global': 5.0.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 + memoizerific: 1.11.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + use-resize-observer: 9.1.0(react-dom@18.2.0)(react@18.2.0) + util-deprecate: 1.0.2 + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' dev: true - /@storybook/core-common@7.4.6: - resolution: {integrity: sha512-05MJFmOM86qvTLtgDskokIFz9txe0Lbhq4L3by1FtF0GwgH+p+W6I94KI7c6ANER+kVZkXQZhiRzwBFnVTW+Cg==} + /@storybook/core-client@7.5.0: + resolution: {integrity: sha512-lnlPhsHnjK3tQ6jgTL/4TqIsxqznMQ0p7lSnUfhfccc2lGtMO/Ez/xIiTGoJQssJxuJE3d4sj3wRgYvuTDGQYw==} dependencies: - '@storybook/core-events': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/preview-api': 7.5.0 + dev: true + + /@storybook/core-common@7.5.0: + resolution: {integrity: sha512-Gw3/rzRb5+XbwqBcr2ZNaIYGEp+WNTwaBOnMs4yp2SCrNIb0P+i3BxlVQdgABaq43EI3/bksowT6hei0jyhGhw==} + dependencies: + '@storybook/core-events': 7.5.0 + '@storybook/node-logger': 7.5.0 + '@storybook/types': 7.5.0 '@types/find-cache-dir': 3.2.1 - '@types/node': 16.18.46 + '@types/node': 18.17.15 '@types/node-fetch': 2.6.4 '@types/pretty-hrtime': 1.0.1 chalk: 4.1.2 esbuild: 0.18.17 - esbuild-register: 3.4.2(esbuild@0.18.17) + esbuild-register: 3.5.0(esbuild@0.18.17) file-system-cache: 2.3.0 find-cache-dir: 3.3.2 find-up: 5.0.0 @@ -6627,26 +6663,32 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/core-server@7.4.6: - resolution: {integrity: sha512-jqmRTGCJ1W0WReImivkisPVaLFT5sjtLnFoAk0feHp6QS5j7EYOPN7CYzliyQmARWTLUEXOVaFf3VD6nJZQhJQ==} + /@storybook/core-events@7.5.0: + resolution: {integrity: sha512-FsD+clTzayqprbVllnL8LLch+uCslJFDgsv7Zh99/zoi7OHtHyauoCZkdLBSiDzgc84qS41dY19HqX1/y7cnOw==} + dependencies: + ts-dedent: 2.2.0 + dev: true + + /@storybook/core-server@7.5.0: + resolution: {integrity: sha512-7QT8uzwSJOsv9PASQ6ywepYkcEYFB7+S7Cj/0nFMh3Vl9vW96LXvEHLAo9CUhSxdEKWeTnD8DS5+j90dLhQFCA==} dependencies: '@aw-web-design/x-default-browser': 1.4.126 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 7.4.6 - '@storybook/channels': 7.4.6 - '@storybook/core-common': 7.4.6 - '@storybook/core-events': 7.4.6 + '@storybook/builder-manager': 7.5.0 + '@storybook/channels': 7.5.0 + '@storybook/core-common': 7.5.0 + '@storybook/core-events': 7.5.0 '@storybook/csf': 0.1.0 - '@storybook/csf-tools': 7.4.6 + '@storybook/csf-tools': 7.5.0 '@storybook/docs-mdx': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/telemetry': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/manager': 7.5.0 + '@storybook/node-logger': 7.5.0 + '@storybook/preview-api': 7.5.0 + '@storybook/telemetry': 7.5.0 + '@storybook/types': 7.5.0 '@types/detect-port': 1.3.2 - '@types/node': 16.18.46 + '@types/node': 18.17.15 '@types/pretty-hrtime': 1.0.1 '@types/semver': 7.5.3 better-opn: 3.0.2 @@ -6678,24 +6720,24 @@ packages: - utf-8-validate dev: true - /@storybook/csf-plugin@7.4.6: - resolution: {integrity: sha512-yi7Qa4NSqKOyiJTWCxlB0ih2ijXq6oY5qZKW6MuMMBP14xJNRGLbH5KabpfXgN2T7YECcOWG1uWaGj2veJb1KA==} + /@storybook/csf-plugin@7.5.0: + resolution: {integrity: sha512-kghaEFYvQISdAjQddeicSuvBFMeuuLNtpmMkuoLQzULF7e/Tws6zLCYsjGevqlnqXD0iW2XM/j9q4M5L/mWc5A==} dependencies: - '@storybook/csf-tools': 7.4.6 + '@storybook/csf-tools': 7.5.0 unplugin: 1.4.0 transitivePeerDependencies: - supports-color dev: true - /@storybook/csf-tools@7.4.6: - resolution: {integrity: sha512-ocKpcIUtTBy6hlLY34RUFQyX403cWpB2gGfqvkHbpGe2BQj7EyV0zpWnjsfVxvw+M9OWlCdxHWDOPUgXM33ELw==} + /@storybook/csf-tools@7.5.0: + resolution: {integrity: sha512-KOHbFNSwwc7KTdNz/6yO7S2pxbr7sH6nqfolS6/l+pod45WvRH3VhyqlDIIeX7ESIhfCw87ExC96hNDL3TojCw==} dependencies: '@babel/generator': 7.22.10 '@babel/parser': 7.22.16 '@babel/traverse': 7.22.11 '@babel/types': 7.22.17 '@storybook/csf': 0.1.0 - '@storybook/types': 7.4.6 + '@storybook/types': 7.5.0 fs-extra: 11.1.1 recast: 0.23.1 ts-dedent: 2.2.0 @@ -6713,12 +6755,12 @@ packages: resolution: {integrity: sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==} dev: true - /@storybook/docs-tools@7.4.6: - resolution: {integrity: sha512-nZj1L/8WwKWWJ41FW4MaKGajZUtrhnr9UwflRCkQJaWhAKmDfOb5M5TqI93uCOULpFPOm5wpoMBz2IHInQ2Lrg==} + /@storybook/docs-tools@7.5.0: + resolution: {integrity: sha512-NFhqbXj6Wv5YypMwDkt0z9xcfWD7M3wZhr8Z9XcXDlUUPjBrdv0cHt3rfHwEXpTfFyunbK41KQZZ3JkjiAjgTg==} dependencies: - '@storybook/core-common': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/core-common': 7.5.0 + '@storybook/preview-api': 7.5.0 + '@storybook/types': 7.5.0 '@types/doctrine': 0.0.3 doctrine: 3.0.0 lodash: 4.17.21 @@ -6737,14 +6779,14 @@ packages: resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} dev: true - /@storybook/instrumenter@7.4.6: - resolution: {integrity: sha512-K5atRoVFCl6HEgkSxIbwygpzgE/iROc7BrtJ3z3a7E70sanFr6Jxt6Egu6fz2QkL3ef4EWpXMnle2vhEfG29pA==} + /@storybook/instrumenter@7.5.0: + resolution: {integrity: sha512-AyutK7uxZbgaF3/Fe+XwKbNxceEThDMi+T/FVIwJ98Ju0VqoIRefg8dbm98K6XyulYyZqmdP+C1/HdNl6Gbltg==} dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/core-events': 7.4.6 + '@storybook/channels': 7.5.0 + '@storybook/client-logger': 7.5.0 + '@storybook/core-events': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.4.6 + '@storybook/preview-api': 7.5.0 dev: true /@storybook/jest@0.2.3(vitest@0.34.6): @@ -6760,20 +6802,20 @@ packages: - vitest dev: true - /@storybook/manager-api@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-inrm3DIbCp8wjXSN/wK6e6i2ysQ/IEmtC7IN0OJ7vdrp+USCooPT448SQTUmVctUGCFmOU3fxXByq8g77oIi7w==} + /@storybook/manager-api@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-n9EaJTThsuFiBDs+GcmNBHnvLhH0znJQprhIQqHNVnosCs/7sloYUzWZzZvPwfnfPvRR7ostEEMXvriaYXYdJQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/core-events': 7.4.6 + '@storybook/channels': 7.5.0 + '@storybook/client-logger': 7.5.0 + '@storybook/core-events': 7.5.0 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/router': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/router': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 @@ -6785,31 +6827,31 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/manager@7.4.6: - resolution: {integrity: sha512-kA1hUDxpn1i2SO9OinvLvVXDeL4xgJkModp+pbE8IXv4NJWReNq1ecMeQCzPLS3Sil2gnrullQ9uYXsnZ9bxxA==} + /@storybook/manager@7.5.0: + resolution: {integrity: sha512-M4h4b0Y4aZ1sRGaZuJXgvPZHqu7vN/wgWB5yPcSwJqH1+DlPxYXYnPKGERgaEUUVKJV3oWQD2qZ+UpDeTgI5UQ==} dev: true /@storybook/mdx2-csf@1.0.0: resolution: {integrity: sha512-dBAnEL4HfxxJmv7LdEYUoZlQbWj9APZNIbOaq0tgF8XkxiIbzqvgB0jhL/9UOrysSDbQWBiCRTu2wOVxedGfmw==} dev: true - /@storybook/node-logger@7.4.6: - resolution: {integrity: sha512-djZb310Q27GviDug1XBv0jOEDLCiwr4hhDE0aifCEKZpfNCi/EaP31nbWimFzZwxu4hE/YAPWExzScruR1zw9Q==} + /@storybook/node-logger@7.5.0: + resolution: {integrity: sha512-Og3hdB1bjpVCXhmlhvpgVxUfCQGd0DCguXf5qhn2kX4a+D++dxJ8YqzVJ5JQCacI9bCKITV6W9JSGseWcBaXBg==} dev: true - /@storybook/postinstall@7.4.6: - resolution: {integrity: sha512-TqI5BucPAGRWrkh55BYiG2/gHLFtC0In4cuu0GsUzB/1jc4i51npLRorCwhmT7r7YliGl5F7JaP0Bni/qHN3Lg==} + /@storybook/postinstall@7.5.0: + resolution: {integrity: sha512-SHpBItwar7qDZO7BBSqTNQK0yNy+RUROZUhW6wlVvsgVhIGF1bgA4pgpW1iMyfPmmGyNekE1BJjN+v8rjq9s6A==} dev: true - /@storybook/preview-api@7.4.6: - resolution: {integrity: sha512-byUS/Opt3ytWD4cWz3sNEKw5Yks8MkQgRN+GDSyIomaEAQkLAM0rchPC0MYjwCeUSecV7IIQweNX5RbV4a34BA==} + /@storybook/preview-api@7.5.0: + resolution: {integrity: sha512-+DubgKwYFk532FKDB6sEGaG47wr0t137aIQSjbNwVmXXxj0QY0zIAThtERx7w6eHS7ZjOs6xlLEZhzC4FI525g==} dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/core-events': 7.4.6 + '@storybook/channels': 7.5.0 + '@storybook/client-logger': 7.5.0 + '@storybook/core-events': 7.5.0 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/types': 7.4.6 + '@storybook/types': 7.5.0 '@types/qs': 6.9.7 dequal: 2.0.3 lodash: 4.17.21 @@ -6820,12 +6862,12 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/preview@7.4.6: - resolution: {integrity: sha512-2RPXusJ4CTDrIipIKKvbotD7fP0+8VzoFjImunflIrzN9rni+2rq5eMjqlXAaB+77w064zIR4uDUzI9fxsMDeQ==} + /@storybook/preview@7.5.0: + resolution: {integrity: sha512-KPhx43pRgIb6UhqjsF0sUG5c3GG2dwzTzjN1/sj0QbPMghZ3b7xKGrCu6VSlsXoWQtcwisMHETFnowk0Ba/AMg==} dev: true - /@storybook/react-dom-shim@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-DSq8l9FDocUF1ooVI+TF83pddj1LynE/Hv0/y8XZhc3IgJ/HkuOQuUmfz29ezgfAi9gFYUR8raTIBi3/xdoRmw==} + /@storybook/react-dom-shim@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-OzJhXg1En/9D9vKvD2t0EcYcuHFzrLTA9kEUWt/eP3Ww41kndfJoZca33JZr17iuKksVAZ8ucETMnkL3yO+ybA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6834,23 +6876,22 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.4.6(react-dom@18.2.0)(react@18.2.0)(rollup@4.1.4)(typescript@5.2.2)(vite@4.4.11): - resolution: {integrity: sha512-jkjnrf3FxzR5wcmebXRPflrsM4WIDjWyW/NVFJwxi5PeIOk7fE7/QAPrm4NFRUu2Q7DeuH3oLKsw8bigvUI9RA==} + /@storybook/react-vite@7.5.0(react-dom@18.2.0)(react@18.2.0)(rollup@4.1.4)(typescript@5.2.2)(vite@4.4.11): + resolution: {integrity: sha512-MnXeO1P+D9l6tZoS9wvC0YwSb8Ur05haUw66I2EJgYVmszbWmAv1XI7lYmfTqBj8bfFXk4DbUdIOVvBMfmIIZg==} engines: {node: '>=16'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - vite: ^3.0.0 || ^4.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.2.2)(vite@4.4.11) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.2.2)(vite@4.4.11) '@rollup/pluginutils': 5.0.5(rollup@4.1.4) - '@storybook/builder-vite': 7.4.6(typescript@5.2.2)(vite@4.4.11) - '@storybook/react': 7.4.6(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) + '@storybook/builder-vite': 7.5.0(typescript@5.2.2)(vite@4.4.11) + '@storybook/react': 7.5.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) '@vitejs/plugin-react': 3.1.0(vite@4.4.11) - ast-types: 0.14.2 magic-string: 0.30.3 react: 18.2.0 - react-docgen: 6.0.0-alpha.3 + react-docgen: 6.0.4 react-dom: 18.2.0(react@18.2.0) vite: 4.4.11(@types/node@20.8.6)(sass@1.69.3)(terser@5.21.0) transitivePeerDependencies: @@ -6862,8 +6903,8 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@7.4.6(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2): - resolution: {integrity: sha512-w0dVo64baFFPTGpUOWFqkKsu6pQincoymegSNgqaBd5DxEyMDRiRoTWSJHMKE9BwgE8SyWhRkP1ak1mkccSOhQ==} + /@storybook/react@7.5.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2): + resolution: {integrity: sha512-1oD8sYqBZwtfBKR8zZqfhjRong4wN/4PLYMzs5wl4kYugNOeauD8zWSztnIorxzDrl2yjpwnWlRy9wXN/8FI8g==} engines: {node: '>=16.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6873,16 +6914,16 @@ packages: typescript: optional: true dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/core-client': 7.4.6 - '@storybook/docs-tools': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/core-client': 7.5.0 + '@storybook/docs-tools': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.4.6 - '@storybook/react-dom-shim': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/preview-api': 7.5.0 + '@storybook/react-dom-shim': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 - '@types/node': 16.18.46 + '@types/node': 18.17.15 acorn: 7.4.1 acorn-jsx: 5.3.2(acorn@7.4.1) acorn-walk: 7.2.0 @@ -6902,27 +6943,27 @@ packages: - supports-color dev: true - /@storybook/router@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Vl1esrHkcHxDKqc+HY7+6JQpBPW3zYvGk0cQ2rxVMhWdLZTAz1hss9DqzN9tFnPyfn0a1Q77EpMySkUrvWKKNQ==} + /@storybook/router@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-NzPwjndmOEOUL8jK5kUrSvRUIcN5Z+h+l0Z8g4I56RoEhNTcKeOW4jbcT4WKnR9H455dti8HAcTV/4x59GpgxQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/client-logger': 7.4.6 + '@storybook/client-logger': 7.5.0 memoizerific: 1.11.3 qs: 6.11.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/source-loader@7.4.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-tBso55luaKIsZmIsgYyT7HJcjbgjxf0pdzbYqdThZhY3oSl3d56xbcFDCWW+yWjFONuFY8RGPCT7iGywwmaBdQ==} + /@storybook/source-loader@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-0u31uiIPV56QxXZoZjAVtcQQ405JnfL+1N495Ob82VUFG3gpDlgkUAwFbsTdJjv7RI0CgmpMLsbJjjW4E/ZR/g==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@storybook/csf': 0.1.0 - '@storybook/types': 7.4.6 + '@storybook/types': 7.5.0 estraverse: 5.3.0 lodash: 4.17.21 prettier: 2.8.8 @@ -6930,12 +6971,12 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/telemetry@7.4.6: - resolution: {integrity: sha512-c8p/C1NIH8EMBviZkBCx8MMDk6rrITJ+b29DEp5MaWSRlklIVyhGiC4RPIRv6sxJwlD41PnqWVFtfu2j2eXLdQ==} + /@storybook/telemetry@7.5.0: + resolution: {integrity: sha512-dvc1cjxHYGNfLEvh8eQI/R2KtMft0kUs6TJ2uXZdIX4+WqWG6mfn75sP8eyC1tcjkdslS6AmFWTfgt9EVcIPQA==} dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/core-common': 7.4.6 - '@storybook/csf-tools': 7.4.6 + '@storybook/client-logger': 7.5.0 + '@storybook/core-common': 7.5.0 + '@storybook/csf-tools': 7.5.0 chalk: 4.1.2 detect-package-manager: 2.0.1 fetch-retry: 5.0.4 @@ -6968,6 +7009,20 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true + /@storybook/theming@7.5.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-uTo97oh+pvmlfsZocFq5qae0zGo0VGk7oiBqNSSw6CiTqE1rIuSxoPrMAY+oCTWCUZV7DjONIGvpnGl2QALsAw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) + '@storybook/client-logger': 7.5.0 + '@storybook/global': 5.0.0 + memoizerific: 1.11.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + /@storybook/types@7.4.6: resolution: {integrity: sha512-6QLXtMVsFZFpzPkdGWsu/iuc8na9dnS67AMOBKm5qCLPwtUJOYkwhMdFRSSeJthLRpzV7JLAL8Kwvl7MFP3QSw==} dependencies: @@ -6977,17 +7032,26 @@ packages: file-system-cache: 2.3.0 dev: true - /@storybook/vue3-vite@7.4.6(@vue/compiler-core@3.3.4)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.4.11)(vue@3.3.4): - resolution: {integrity: sha512-r/mUDdCifpN99Cqmvm7IvPZGnur7lYiTxbQPhV8NdRBpQGxm3JC0life9yIvvHV9mYRCjn5MEzC65zWx03Nzig==} + /@storybook/types@7.5.0: + resolution: {integrity: sha512-fiOUnHKFi/UZSfvc53F0WEQCiquqcSqslL3f5EffwQRiXfeXlGavJb0kU03BO+CvOXcliRn6qKSF2dL0Rgb7Xw==} + dependencies: + '@storybook/channels': 7.5.0 + '@types/babel__core': 7.20.0 + '@types/express': 4.17.17 + file-system-cache: 2.3.0 + dev: true + + /@storybook/vue3-vite@7.5.0(@vue/compiler-core@3.3.4)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.4.11)(vue@3.3.4): + resolution: {integrity: sha512-Mmyeu2bZGdwA6xXDFKzybOxaEPHhB01ezznlTljaVkVNRAYcxzOna+z6INKfP0LYz3anqSDl4vB5g5b05M7gCA==} engines: {node: ^14.18 || >=16} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - vite: ^3.0.0 || ^4.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - '@storybook/builder-vite': 7.4.6(typescript@5.2.2)(vite@4.4.11) - '@storybook/core-server': 7.4.6 - '@storybook/vue3': 7.4.6(@vue/compiler-core@3.3.4)(vue@3.3.4) + '@storybook/builder-vite': 7.5.0(typescript@5.2.2)(vite@4.4.11) + '@storybook/core-server': 7.5.0 + '@storybook/vue3': 7.5.0(@vue/compiler-core@3.3.4)(vue@3.3.4) '@vitejs/plugin-vue': 4.4.0(vite@4.4.11)(vue@3.3.4) magic-string: 0.30.3 react: 18.2.0 @@ -7006,18 +7070,18 @@ packages: - vue dev: true - /@storybook/vue3@7.4.6(@vue/compiler-core@3.3.4)(vue@3.3.4): - resolution: {integrity: sha512-Azv/GhmPlAUy8UbXZHKubrBlKhGimuJTT2O6zUvIzggR6sJdsRmdWaEv2S90ZpMBkVYyyM9oKS1fZ4eKi/Ds8g==} + /@storybook/vue3@7.5.0(@vue/compiler-core@3.3.4)(vue@3.3.4): + resolution: {integrity: sha512-Z1VhHCUMq2cITyK5Yvkcjgajulz23OdXi/m3sRiyhSOGhaRU2iyfM1yUoymk+3WU0cIBe0CsA4uA9A/PFsW6RA==} engines: {node: '>=16.0.0'} peerDependencies: '@vue/compiler-core': ^3.0.0 vue: ^3.0.0 dependencies: - '@storybook/core-client': 7.4.6 - '@storybook/docs-tools': 7.4.6 + '@storybook/core-client': 7.5.0 + '@storybook/docs-tools': 7.5.0 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/preview-api': 7.5.0 + '@storybook/types': 7.5.0 '@vue/compiler-core': 3.3.4 lodash: 4.17.21 ts-dedent: 2.2.0 @@ -7515,14 +7579,14 @@ packages: engines: {node: '>=14.17'} dev: true - /@types/accepts@1.3.5: - resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==} + /@types/accepts@1.3.6: + resolution: {integrity: sha512-6+qlUg57yfE9OO63wnsJXLeq9cG3gSHBBIxNMOjNrbDRlDnm/NaR7RctfYcVCPq+j7d+MwOxqVEludH5+FKrlg==} dependencies: '@types/node': 20.8.6 dev: true - /@types/archiver@5.3.3: - resolution: {integrity: sha512-0ABdVcXL6jOwNGY+hjWPqrxUvKelBEwNLcuv/SV2vZ4YCH8w9NttFCt+/QqI5zgMX+iX/XqVy89/r7EmLJmMpQ==} + /@types/archiver@5.3.4: + resolution: {integrity: sha512-Lj7fLBIMwYFgViVVZHEdExZC3lVYsl+QL0VmdNdIzGZH544jHveYWij6qdnBgJQDnR7pMKliN9z2cPZFEbhyPw==} dependencies: '@types/readdir-glob': 1.1.1 dev: true @@ -7564,12 +7628,12 @@ packages: '@babel/types': 7.22.17 dev: true - /@types/bcryptjs@2.4.4: - resolution: {integrity: sha512-9wlJI7k5gRyJEC4yrV7DubzNQFTPiykYxUA6lBtsk5NlOfW9oWLJ1HdIA4YtE+6C3i3mTpDQQEosJ2rVZfBWnw==} + /@types/bcryptjs@2.4.5: + resolution: {integrity: sha512-tOF6TivOIvq+TWQm78335CMdyVJhpBG3NUdWQDAp95ax4E2rSKbws/ELHLk5EBoucwx/tHt3/hhLOHwWJgVrSw==} dev: true - /@types/body-parser@1.19.3: - resolution: {integrity: sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==} + /@types/body-parser@1.19.4: + resolution: {integrity: sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==} dependencies: '@types/connect': 3.4.35 '@types/node': 20.8.6 @@ -7604,8 +7668,8 @@ packages: resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} dev: true - /@types/color-convert@2.0.1: - resolution: {integrity: sha512-GwXanrvq/tBHJtudbl1lSy9Ybt7KS9+rA+YY3bcuIIM+d6jSHUr+5yjO83gtiRpuaPiBccwFjSnAK2qSrIPA7w==} + /@types/color-convert@2.0.2: + resolution: {integrity: sha512-KGRIgCxwcgazts4MXRCikPbIMzBpjfdgEZSy8TRHU/gtg+f9sOfHdtK8unPfxIoBtyd2aTTwINVLSNENlC8U8A==} dependencies: '@types/color-name': 1.1.1 dev: true @@ -7620,8 +7684,8 @@ packages: '@types/node': 20.8.6 dev: true - /@types/content-disposition@0.5.6: - resolution: {integrity: sha512-GmShTb4qA9+HMPPaV2+Up8tJafgi38geFi7vL4qAM7k8BwjoelgHZqEUKJZLvughUw22h6vD/wvwN4IUCaWpDA==} + /@types/content-disposition@0.5.7: + resolution: {integrity: sha512-V9/5u21RHFR1zfdm3rQ6pJUKV+zSSVQt+yq16i1YhdivVzWgPEoKedc3GdT8aFjsqQbakdxuy3FnEdePUQOamQ==} dev: true /@types/cookie@0.4.1: @@ -7656,6 +7720,10 @@ packages: resolution: {integrity: sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==} dev: true + /@types/doctrine@0.0.6: + resolution: {integrity: sha512-KlEqPtaNBHBJ2/fVA4yLdD0Tc8zw34pKU4K5SHBIEwtLJ8xxumIC1xeG+4S+/9qhVj2MqC7O3Ld8WvDG4HqlgA==} + dev: true + /@types/ejs@3.1.2: resolution: {integrity: sha512-ZmiaE3wglXVWBM9fyVC17aGPkLo/UgaOjEiI2FXQfyczrCefORPxIe+2dVmnmk3zkVIbizjrlQzmPGhSYGXG5g==} dev: true @@ -7697,7 +7765,7 @@ packages: /@types/express@4.17.17: resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} dependencies: - '@types/body-parser': 1.19.3 + '@types/body-parser': 1.19.4 '@types/express-serve-static-core': 4.17.33 '@types/qs': 6.9.7 '@types/serve-static': 1.15.1 @@ -7871,10 +7939,6 @@ packages: node-fetch: 3.3.2 dev: true - /@types/node@16.18.46: - resolution: {integrity: sha512-Mnq3O9Xz52exs3mlxMcQuA7/9VFe/dXcrgAyfjLkABIqxXKOgBRjyazTxUbjsxDa4BP7hhPliyjVTP9RDP14xg==} - dev: true - /@types/node@18.17.15: resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==} dev: true @@ -7994,6 +8058,10 @@ packages: resolution: {integrity: sha512-8/ynozXfy9NZ8JhQRSTb0HMuu5Isl547Mih1fMEpNLi9coPcI16UdvIdSqssMgQEdbWsgQIPkLpkpAcK4DEZ3Q==} dev: true + /@types/resolve@1.20.4: + resolution: {integrity: sha512-BKGK0T1VgB1zD+PwQR4RRf0ais3NyvH1qjLUrHI5SEiccYaJrhLstLuoXFWJ+2Op9whGizSPUMGPJY/Qtb/A2w==} + dev: true + /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: @@ -8185,8 +8253,8 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@6.7.5(@typescript-eslint/parser@6.7.5)(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==} + /@typescript-eslint/eslint-plugin@6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2): + resolution: {integrity: sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -8197,11 +8265,11 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.7.5(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/scope-manager': 6.7.5 - '@typescript-eslint/type-utils': 6.7.5(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.7.5(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.7.5 + '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/type-utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.8.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.51.0 graphemer: 1.4.0 @@ -8235,8 +8303,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.7.5(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==} + /@typescript-eslint/parser@6.8.0(eslint@8.51.0)(typescript@5.2.2): + resolution: {integrity: sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -8245,10 +8313,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.7.5 - '@typescript-eslint/types': 6.7.5 - '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.7.5 + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.8.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.51.0 typescript: 5.2.2 @@ -8264,12 +8332,12 @@ packages: '@typescript-eslint/visitor-keys': 6.7.2 dev: true - /@typescript-eslint/scope-manager@6.7.5: - resolution: {integrity: sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==} + /@typescript-eslint/scope-manager@6.8.0: + resolution: {integrity: sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.7.5 - '@typescript-eslint/visitor-keys': 6.7.5 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/visitor-keys': 6.8.0 dev: true /@typescript-eslint/type-utils@6.7.2(eslint@8.49.0)(typescript@5.1.6): @@ -8292,8 +8360,8 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils@6.7.5(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==} + /@typescript-eslint/type-utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): + resolution: {integrity: sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -8302,8 +8370,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2) - '@typescript-eslint/utils': 6.7.5(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) + '@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) debug: 4.3.4(supports-color@8.1.1) eslint: 8.51.0 ts-api-utils: 1.0.1(typescript@5.2.2) @@ -8317,8 +8385,8 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/types@6.7.5: - resolution: {integrity: sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==} + /@typescript-eslint/types@6.8.0: + resolution: {integrity: sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==} engines: {node: ^16.0.0 || >=18.0.0} dev: true @@ -8343,8 +8411,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.7.5(typescript@5.2.2): - resolution: {integrity: sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==} + /@typescript-eslint/typescript-estree@6.8.0(typescript@5.2.2): + resolution: {integrity: sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -8352,8 +8420,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.7.5 - '@typescript-eslint/visitor-keys': 6.7.5 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/visitor-keys': 6.8.0 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 @@ -8383,8 +8451,8 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.7.5(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==} + /@typescript-eslint/utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): + resolution: {integrity: sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -8392,9 +8460,9 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.3 - '@typescript-eslint/scope-manager': 6.7.5 - '@typescript-eslint/types': 6.7.5 - '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) eslint: 8.51.0 semver: 7.5.4 transitivePeerDependencies: @@ -8410,11 +8478,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@6.7.5: - resolution: {integrity: sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==} + /@typescript-eslint/visitor-keys@6.8.0: + resolution: {integrity: sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.7.5 + '@typescript-eslint/types': 6.8.0 eslint-visitor-keys: 3.4.3 dev: true @@ -9665,25 +9733,6 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - /c8@7.13.0: - resolution: {integrity: sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==} - engines: {node: '>=10.12.0'} - hasBin: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@istanbuljs/schema': 0.1.3 - find-up: 5.0.0 - foreground-child: 2.0.0 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.1 - istanbul-reports: 3.1.5 - rimraf: 3.0.2 - test-exclude: 6.0.0 - v8-to-istanbul: 9.1.0 - yargs: 16.2.0 - yargs-parser: 20.2.9 - dev: true - /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -10075,6 +10124,7 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + dev: false /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} @@ -11225,8 +11275,8 @@ packages: resolution: {integrity: sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==} dev: true - /esbuild-register@3.4.2(esbuild@0.18.17): - resolution: {integrity: sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==} + /esbuild-register@3.5.0(esbuild@0.18.17): + resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} peerDependencies: esbuild: '>=0.12 <1' dependencies: @@ -11369,7 +11419,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.7)(eslint@8.51.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-node@0.3.7)(eslint@8.51.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -11390,7 +11440,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.7.5(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) debug: 3.2.7(supports-color@5.5.0) eslint: 8.51.0 eslint-import-resolver-node: 0.3.7 @@ -11398,7 +11448,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.51.0): + /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.8.0)(eslint@8.51.0): resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} engines: {node: '>=4'} peerDependencies: @@ -11408,7 +11458,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.7.5(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) array-includes: 3.1.6 array.prototype.findlastindex: 1.2.2 array.prototype.flat: 1.3.1 @@ -11417,7 +11467,7 @@ packages: doctrine: 2.1.0 eslint: 8.51.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.7)(eslint@8.51.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-node@0.3.7)(eslint@8.51.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -11594,17 +11644,6 @@ packages: engines: {node: '>=4.0'} dev: true - /estree-to-babel@3.2.1: - resolution: {integrity: sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==} - engines: {node: '>=8.3.0'} - dependencies: - '@babel/traverse': 7.22.11 - '@babel/types': 7.22.17 - c8: 7.13.0 - transitivePeerDependencies: - - supports-color - dev: true - /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -12169,14 +12208,6 @@ packages: is-callable: 1.2.7 dev: true - /foreground-child@2.0.0: - resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} - engines: {node: '>=8.0.0'} - dependencies: - cross-spawn: 7.0.3 - signal-exit: 3.0.7 - dev: true - /foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} @@ -16152,7 +16183,7 @@ packages: resolution: {integrity: sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==} engines: {node: '>=10'} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 dev: true /postcss-calc@9.0.1(postcss@8.4.31): @@ -16996,21 +17027,20 @@ packages: typescript: 5.2.2 dev: true - /react-docgen@6.0.0-alpha.3: - resolution: {integrity: sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA==} - engines: {node: '>=12.0.0'} - hasBin: true + /react-docgen@6.0.4: + resolution: {integrity: sha512-gF+p+1ZwC2eO66bt763Tepmh5q9kDiFIrqW3YjUV/a+L96h0m5+/wSFQoOHL2cffyrPMZMxP03IgbggJ11QbOw==} + engines: {node: '>=14.18.0'} dependencies: '@babel/core': 7.22.11 - '@babel/generator': 7.22.10 - ast-types: 0.14.2 - commander: 2.20.3 + '@babel/traverse': 7.22.11 + '@babel/types': 7.22.17 + '@types/babel__core': 7.20.0 + '@types/babel__traverse': 7.20.0 + '@types/doctrine': 0.0.6 + '@types/resolve': 1.20.4 doctrine: 3.0.0 - estree-to-babel: 3.2.1 - neo-async: 2.6.2 - node-dir: 0.1.17 resolve: 1.22.3 - strip-indent: 3.0.0 + strip-indent: 4.0.0 transitivePeerDependencies: - supports-color dev: true @@ -17121,7 +17151,7 @@ packages: peerDependencies: react: '>= 0.14.0' dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 highlight.js: 10.7.3 lowlight: 1.20.0 prismjs: 1.29.0 @@ -17316,7 +17346,7 @@ packages: /regenerator-transform@0.15.1: resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.23.1 dev: true /regexp.prototype.flags@1.4.3: @@ -18243,11 +18273,11 @@ packages: resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==} dev: true - /storybook@7.4.6: - resolution: {integrity: sha512-YkFSpnR47j5zz7yElA+2axLjXN7K7TxDGJRHHlqXmG5iQ0PXzmjrj2RxMDKFz4Ybp/QjEUoJ4rx//ESEY0Nb5A==} + /storybook@7.5.0: + resolution: {integrity: sha512-dmvQNSuoHq1KrPcK8siApBi5n5reSf6RFAlLHYD+nhM+EP6SL2fXdVjP6ZynTUMRu1NQ5YR/oJhz/SsBzJNkcA==} hasBin: true dependencies: - '@storybook/cli': 7.4.6 + '@storybook/cli': 7.5.0 transitivePeerDependencies: - bufferutil - encoding @@ -18425,6 +18455,13 @@ packages: min-indent: 1.0.1 dev: true + /strip-indent@4.0.0: + resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==} + engines: {node: '>=12'} + dependencies: + min-indent: 1.0.1 + dev: true + /strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} @@ -18519,8 +18556,8 @@ packages: resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} dev: true - /systeminformation@5.21.11: - resolution: {integrity: sha512-dIJEGoP5W7k4JJGje/b+inJrOL5hV9LPsUi5ndBvJydI80CVEcu2DZYgt6prdRErDi2SA4SqYd/WMR4b+u34mA==} + /systeminformation@5.21.12: + resolution: {integrity: sha512-fxMFr6qNqB8MG6tDsVDSdeQoPIwbFy/fQ3p51LWQYqt6PB1CeWrhcKW0c6U6UtoXuwpNawMDb7wlCkTmLXczCw==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -20106,6 +20143,7 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.9 + dev: false /yargs@17.6.2: resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} @@ -20172,7 +20210,7 @@ packages: sharp: 0.31.3 dev: false - github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.4.6)(@storybook/components@7.4.6)(@storybook/core-events@7.4.6)(@storybook/manager-api@7.4.6)(@storybook/preview-api@7.4.6)(@storybook/theming@7.4.6)(@storybook/types@7.4.6)(react-dom@18.2.0)(react@18.2.0): + github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.5.0)(@storybook/components@7.4.6)(@storybook/core-events@7.5.0)(@storybook/manager-api@7.5.0)(@storybook/preview-api@7.5.0)(@storybook/theming@7.5.0)(@storybook/types@7.5.0)(react-dom@18.2.0)(react@18.2.0): resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640} id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640 name: storybook-addon-misskey-theme @@ -20193,13 +20231,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.4.6(react-dom@18.2.0)(react@18.2.0) + '@storybook/blocks': 7.5.0(react-dom@18.2.0)(react@18.2.0) '@storybook/components': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.4.6 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/core-events': 7.5.0 + '@storybook/manager-api': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.5.0 + '@storybook/theming': 7.5.0(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.5.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true