diff options
Diffstat (limited to '')
140 files changed, 4078 insertions, 1807 deletions
diff --git a/.config/cypress-devcontainer.yml b/.config/cypress-devcontainer.yml index 91dce35155..3907615f73 100644 --- a/.config/cypress-devcontainer.yml +++ b/.config/cypress-devcontainer.yml @@ -2,6 +2,19 @@ # Misskey configuration #â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â” +# ┌────────────────────────┠+#───┘ Initial Setup Password └───────────────────────────────────────────────────── + +# Password to initiate setting up admin account. +# It will not be used after the initial setup is complete. +# +# Be sure to change this when you set up Misskey via the Internet. +# +# The provider of the service who sets up Misskey on behalf of the customer should +# set this value to something unique when generating the Misskey config file, +# and provide it to the customer. +setupPassword: example_password_please_change_this_or_you_will_get_hacked + # ┌─────┠#───┘ URL └───────────────────────────────────────────────────── diff --git a/.config/example.yml b/.config/example.yml index 7080159117..60a6a0aa71 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -59,6 +59,20 @@ # # publishTarballInsteadOfProvideRepositoryUrl: true +# ┌────────────────────────┠+#───┘ Initial Setup Password └───────────────────────────────────────────────────── + +# Password to initiate setting up admin account. +# It will not be used after the initial setup is complete. +# +# Be sure to change this when you set up Misskey via the Internet. +# +# The provider of the service who sets up Misskey on behalf of the customer should +# set this value to something unique when generating the Misskey config file, +# and provide it to the customer. +# +# setupPassword: example_password_please_change_this_or_you_will_get_hacked + # ┌─────┠#───┘ URL └───────────────────────────────────────────────────── diff --git a/.github/misskey/test.yml b/.github/misskey/test.yml index 7a4aa4ae6c..3c807e8b9e 100644 --- a/.github/misskey/test.yml +++ b/.github/misskey/test.yml @@ -1,5 +1,7 @@ url: 'http://misskey.local' +setupPassword: example_password_please_change_this_or_you_will_get_hacked + # ãƒãƒ¼ã‚«ãƒ«ã§ãƒ†ã‚¹ãƒˆã™ã‚‹ã¨ãã«ãƒãƒ¼ãƒˆã‚’被らãªã„よã†ã«ã™ã‚‹ãŸã‚デフォルトã®ã‚‚ã®ã¨ã¯å¤‰ãˆã‚‹(以下åŒã˜) port: 61812 diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml index 5afd7d2714..f26c9a4d45 100644 --- a/.github/workflows/check-misskey-js-autogen.yml +++ b/.github/workflows/check-misskey-js-autogen.yml @@ -21,6 +21,7 @@ jobs: uses: actions/checkout@v4.1.1 with: submodules: true + persist-credentials: false ref: refs/pull/${{ github.event.pull_request.number }}/merge - name: setup pnpm @@ -57,7 +58,7 @@ jobs: name: generated-misskey-js path: packages/misskey-js/generator/built/autogen - # pull_request_target safety: permissions: read-all, and there are no secrets used in this job + # pull_request_target safety: permissions: read-all, and no user codes are executed get-actual-misskey-js: runs-on: ubuntu-latest permissions: @@ -68,6 +69,7 @@ jobs: uses: actions/checkout@v4.1.1 with: submodules: true + persist-credentials: false ref: refs/pull/${{ github.event.pull_request.number }}/merge - name: Upload From Merged @@ -131,3 +133,7 @@ jobs: mode: delete message: "Thank you!" create_if_not_exists: false + + - name: Make failure if changes are detected + if: steps.check-changes.outputs.changes == 'true' + run: exit 1 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 07d9af12f7..90eb268dda 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -75,7 +75,7 @@ jobs: - run: corepack enable - run: pnpm i --frozen-lockfile - name: Restore eslint cache - uses: actions/cache@v4.0.2 + uses: actions/cache@v4.1.0 with: path: ${{ env.eslint-cache-path }} key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fbb46786e..b32f63a3c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,35 @@ +## 2024.10.0 + +### Note +- ã‚»ã‚ュリティå‘上ã®ãŸã‚ã€ã‚µãƒ¼ãƒãƒ¼åˆæœŸè¨å®šæ™‚ã«ä½¿ç”¨ã™ã‚‹åˆæœŸãƒ‘スワードをè¨å®šã§ãるよã†ã«ãªã‚Šã¾ã—ãŸã€‚今後Misskeyサーãƒãƒ¼ã‚’æ–°ãŸã«è¨ç½®ã™ã‚‹éš›ã«ã¯ã€åˆå›žã®èµ·å‹•å‰ã«ã‚³ãƒ³ãƒ•ィグファイルã®`setupPassword`をコメントアウトã—ã€åˆæœŸãƒ‘スワードをè¨å®šã™ã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚(ã™ã§ã«åˆæœŸè¨å®šã‚’完了ã—ã¦ã„るサーãƒãƒ¼ã«ã¤ã„ã¦ã¯ã€ã“ã®å¤‰æ›´ã«ä¼´ã„対応ã™ã‚‹å¿…è¦ã¯ã‚りã¾ã›ã‚“) + - ホスティングサービスをé‹å–¶ã—ã¦ã„ã‚‹å ´åˆã¯ã€ã‚³ãƒ³ãƒ•ィグファイルを構築ã™ã‚‹éš›ã«`setupPassword`をランダムãªå€¤ã«è¨å®šã—ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€šçŸ¥ã™ã‚‹ã‚ˆã†ã«ã‚·ã‚¹ãƒ†ãƒ ã‚’æ›´æ–°ã™ã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚ + - ãªãŠã€åˆæœŸãƒ‘スワードãŒè¨å®šã•れã¦ã„ãªã„å ´åˆã§ã‚‚åˆæœŸè¨å®šã‚’行ã†ã“ã¨ãŒå¯èƒ½ã§ã™ï¼ˆUI上ã§åˆæœŸãƒ‘スワードã®å…¥åŠ›æ¬„ã‚’ç©ºæ¬„ã«ã™ã‚‹ã¨ç¶šè¡Œã§ãã¾ã™ï¼‰ã€‚ +- ユーザーデータをèªã¿è¾¼ã‚€éš›ã®åž‹ãŒä¸€éƒ¨å¤‰æ›´ã•れã¾ã—ãŸã€‚ + - `twoFactorEnabled`, `usePasswordLessLogin`, `securityKeys`: 自分ã¨ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿ãƒ¼ä»¥å¤–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‹ã‚‰ã¯å–å¾—ã§ããªããªã‚Šã¾ã—㟠+ +### General +- Feat: サーãƒãƒ¼åˆæœŸè¨å®šæ™‚ã«åˆæœŸãƒ‘スワードをè¨å®šã§ãるよã†ã« +- Feat: é€šå ±ã«ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒŽãƒ¼ãƒˆã‚’残ã›ã‚‹ã‚ˆã†ã« +- Feat: é€šå ±ã®è§£æ±ºç¨®åˆ¥ã‚’è¨å®šã§ãるよã†ã« +- Enhance: é€šå ±ã®è§£æ±ºã¨è»¢é€ã‚’個別ã«è¡Œãˆã‚‹ã‚ˆã†ã« +- Enhance: ã‚»ã‚ュリティå‘上ã®ãŸã‚ã€ã‚µã‚¤ãƒ³ã‚¤ãƒ³æ™‚ã‚‚CAPTCHAを求ã‚るよã†ã«ãªã‚Šã¾ã—㟠+- Enhance: ä¾å˜é–¢ä¿‚ã®æ›´æ–° +- Enhance: l10nã®æ›´æ–° +- Enhance: Playã®ã€Œäººæ°—ã€ã‚¿ãƒ–ã§10件以上表示å¯èƒ½ã« #14399 +- Fix: 連åˆã®ãƒ›ãƒ¯ã‚¤ãƒˆãƒªã‚¹ãƒˆãŒæ£å¸¸ã«ç™»éŒ²ã•れãªã„å•é¡Œã‚’ä¿®æ£ + +### Client +- Enhance: デザインã®èª¿æ•´ +- Enhance: ãƒã‚°ã‚¤ãƒ³ç”»é¢ã®èªè¨¼ãƒ•ãƒãƒ¼ã‚’改善 +- Fix: クライアント上ã§ã®æ™‚間ベースã®å®Ÿç¸¾ç²å¾—動作ãŒå®Ÿç¸¾ç²å¾—後も発動ã—ã¦ã„ãŸå•é¡Œã‚’ä¿®æ£ + (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/657) + +### Server +- Enhance: ã‚»ã‚ュリティå‘上ã®ãŸã‚ã€ãƒã‚°ã‚¤ãƒ³æ™‚ã«ãƒ¡ãƒ¼ãƒ«é€šçŸ¥ã‚’行ã†ã‚ˆã†ã« +- Enhance: 自分ã¨ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿ãƒ¼ä»¥å¤–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‹ã‚‰äºŒè¦ç´ èªè¨¼é–¢é€£ã®ãƒ‡ãƒ¼ã‚¿ãŒå–å¾—ã§ããªã„よã†ã« +- Enhance: é€šå ±ãŠã‚ˆã³é€šå ±è§£æ±ºæ™‚ã«é€å‡ºã•れるSystemWebhookã«ãƒ¦ãƒ¼ã‚¶æƒ…å ±ã‚’å«ã‚るよã†ã« ( #14697 ) +- Fix: `admin/abuse-user-reports`エンドãƒã‚¤ãƒ³ãƒˆã®ã‚¹ã‚ーマãŒé–“é•ã£ã¦ã„ãŸå•é¡Œã‚’ä¿®æ£ + ## 2024.9.0 ### General diff --git a/cypress/e2e/basic.cy.ts b/cypress/e2e/basic.cy.ts index d2525e0a7d..d2efbf709c 100644 --- a/cypress/e2e/basic.cy.ts +++ b/cypress/e2e/basic.cy.ts @@ -23,6 +23,7 @@ describe('Before setup instance', () => { cy.intercept('POST', '/api/admin/accounts/create').as('signup'); + cy.get('[data-cy-admin-initial-password] input').type('example_password_please_change_this_or_you_will_get_hacked'); cy.get('[data-cy-admin-username] input').type('admin'); cy.get('[data-cy-admin-password] input').type('admin1234'); cy.get('[data-cy-admin-ok]').click(); @@ -119,11 +120,16 @@ describe('After user signup', () => { it('signin', () => { cy.visitHome(); - cy.intercept('POST', '/api/signin').as('signin'); + cy.intercept('POST', '/api/signin-flow').as('signin'); cy.get('[data-cy-signin]').click(); - cy.get('[data-cy-signin-username] input').type('alice'); - // Enterã‚ーã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã§ãã‚‹ã‹ã®ç¢ºèªã‚‚å…¼ãã‚‹ + + cy.get('[data-cy-signin-page-input]').should('be.visible', { timeout: 1000 }); + // Enterã‚ーã§ç¶šè¡Œã§ãã‚‹ã‹ã®ç¢ºèªã‚‚å…¼ãã‚‹ + cy.get('[data-cy-signin-username] input').type('alice{enter}'); + + cy.get('[data-cy-signin-page-password]').should('be.visible', { timeout: 10000 }); + // Enterã‚ーã§ç¶šè¡Œã§ãã‚‹ã‹ã®ç¢ºèªã‚‚å…¼ãã‚‹ cy.get('[data-cy-signin-password] input').type('alice1234{enter}'); cy.wait('@signin'); @@ -138,8 +144,9 @@ describe('After user signup', () => { cy.visitHome(); cy.get('[data-cy-signin]').click(); - cy.get('[data-cy-signin-username] input').type('alice'); - cy.get('[data-cy-signin-password] input').type('alice1234{enter}'); + + cy.get('[data-cy-signin-page-input]').should('be.visible', { timeout: 1000 }); + cy.get('[data-cy-signin-username] input').type('alice{enter}'); // TODO: cypressã«ãƒ–ラウザã®è¨€èªžæŒ‡å®šã§ãる機能ãŒå®Ÿè£…ã•れ次第英語ã®ã¿ãƒ†ã‚¹ãƒˆã™ã‚‹ã‚ˆã†ã«ã™ã‚‹ cy.contains(/アカウントãŒå‡çµã•れã¦ã„ã¾ã™|This account has been suspended due to/gi); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 281f2e6ccd..197ff963ac 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -48,16 +48,19 @@ Cypress.Commands.add('registerUser', (username, password, isAdmin = false) => { cy.request('POST', route, { username: username, password: password, + ...(isAdmin ? { setupPassword: 'example_password_please_change_this_or_you_will_get_hacked' } : {}), }).its('body').as(username); }); Cypress.Commands.add('login', (username, password) => { cy.visitHome(); - cy.intercept('POST', '/api/signin').as('signin'); + cy.intercept('POST', '/api/signin-flow').as('signin'); cy.get('[data-cy-signin]').click(); - cy.get('[data-cy-signin-username] input').type(username); + cy.get('[data-cy-signin-page-input]').should('be.visible', { timeout: 1000 }); + cy.get('[data-cy-signin-username] input').type(`${username}{enter}`); + cy.get('[data-cy-signin-page-password]').should('be.visible', { timeout: 10000 }); cy.get('[data-cy-signin-password] input').type(`${password}{enter}`); cy.wait('@signin').as('signedIn'); diff --git a/packages/frontend/src/components/MkAbuseReport.stories.impl.ts b/idea/MkAbuseReport.stories.impl.ts index cf09c96fd4..717bceb23d 100644 --- a/packages/frontend/src/components/MkAbuseReport.stories.impl.ts +++ b/idea/MkAbuseReport.stories.impl.ts @@ -7,8 +7,8 @@ import { action } from '@storybook/addon-actions'; import { StoryObj } from '@storybook/vue3'; import { HttpResponse, http } from 'msw'; -import { abuseUserReport } from '../../.storybook/fakes.js'; -import { commonHandlers } from '../../.storybook/mocks.js'; +import { abuseUserReport } from '../packages/frontend/.storybook/fakes.js'; +import { commonHandlers } from '../packages/frontend/.storybook/mocks.js'; import MkAbuseReport from './MkAbuseReport.vue'; export const Default = { render(args) { diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index b6bfbfa682..d95600cb1f 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -626,10 +626,7 @@ abuseReported: "Ø£ÙØ±Ø³Ù„ البلاغ، شكرًا لك" reporter: "Ø§Ù„Ù…ÙØ¨Ù„ّغ" reporteeOrigin: "أصل البلاغ" reporterOrigin: "أصل Ø§Ù„Ù…ÙØ¨Ù„ّغ" -forwardReport: "وجّه البلاغ إلى المثيل البعيد" -forwardReportIsAnonymous: "ÙÙŠ المثيل البعيد سيظهر المبلّغ ÙƒØØ³Ø§Ø¨ مجهول." send: "أرسل" -abuseMarkAsResolved: "علّم البلاغ كمØÙ„ول" openInNewTab: "Ø§ÙØªØ ÙÙŠ لسان جديد" defaultNavigationBehaviour: "سلوك Ø§Ù„Ù…Ù„Ø§ØØ© Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ" editTheseSettingsMayBreakAccount: "تعديل هذه الإعدادات قد يسبب عطبًا Ù„ØØ³Ø§Ø¨Ùƒ" @@ -1533,6 +1530,7 @@ _notification: reaction: "Ø§Ù„ØªÙØ§Ø¹Ù„" receiveFollowRequest: "طلبات المتابعة" followRequestAccepted: "طلبات المتابعة المقبولة" + login: "Ù„ÙØ¬" app: "إشعارات التطبيقات المرتبطة" _actions: followBack: "تابعك بالمثل" diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 0d9e4e116c..ab0ee74bb4 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -624,10 +624,7 @@ abuseReported: "আপনার অà¦à¦¿à¦¯à§‹à¦—টি দাখিল করà reporter: "অà¦à¦¿à¦¯à§‹à¦—কারী" reporteeOrigin: "অà¦à¦¿à¦¯à§‹à¦—টির উৎস" reporterOrigin: "অà¦à¦¿à¦¯à§‹à¦—কারীর উৎস" -forwardReport: "রিমোট ইনà§à¦¸à¦¤à§à¦¯à¦¾à¦¨à§à¦¸à§‡ অà¦à¦¿à¦¯à§‹à¦—টি পাঠান" -forwardReportIsAnonymous: "আপনার তথà§à¦¯ রিমোট ইনà§à¦¸à¦¤à§à¦¯à¦¾à¦¨à§à¦¸à§‡ পাঠানো হবে না à¦à¦¬à¦‚ à¦à¦•টি বেনামী সিসà§à¦Ÿà§‡à¦® অà§à¦¯à¦¾à¦•াউনà§à¦Ÿ হিসাবে পà§à¦°à¦¦à¦°à§à¦¶à¦¿à¦¤ হবে।" send: "পাঠান" -abuseMarkAsResolved: "অà¦à¦¿à¦¯à§‹à¦—টিকে সমাধাকৃত হিসাবে চিহà§à¦¨à¦¿à¦¤ করà§à¦¨" openInNewTab: "নতà§à¦¨ টà§à¦¯à¦¾à¦¬à§‡ খà§à¦²à§à¦¨" openInSideView: "সাইড à¦à¦¿à¦‰à¦¤à§‡ খà§à¦²à§à¦¨" defaultNavigationBehaviour: "ডিফলà§à¦Ÿ নেà¦à¦¿à¦—েশন" @@ -1313,6 +1310,7 @@ _notification: pollEnded: "পোল শেষ" receiveFollowRequest: "পà§à¦°à¦¾à¦ªà§à¦¤ অনà§à¦¸à¦°à¦£à§‡à¦° অনà§à¦°à§‹à¦§à¦¸à¦®à§‚হ" followRequestAccepted: "গৃহীত অনà§à¦¸à¦°à¦£à§‡à¦° অনà§à¦°à§‹à¦§à¦¸à¦®à§‚হ" + login: "পà§à¦°à¦¬à§‡à¦¶ করà§à¦¨" app: "লিঙà§à¦• করা অà§à¦¯à¦¾à¦ª থেকে বিজà§à¦žà¦ªà§à¦¤à¦¿" _actions: followBack: "ফলো বà§à¦¯à¦¾à¦• করেছে" diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 9d4ef016ce..ad5fde37bc 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -8,6 +8,8 @@ search: "Cercar" notifications: "Notificacions" username: "Nom d'usuari" password: "Contrasenya" +initialPasswordForSetup: "Contrasenya inicial per la configuració inicial" +initialPasswordIsIncorrect: "La contrasenya no és correcta." forgotPassword: "Contrasenya oblidada" fetchingAsApObject: "Cercant en el Fediverse..." ok: "OK" @@ -236,6 +238,8 @@ silencedInstances: "Instà ncies silenciades" silencedInstancesDescription: "Llista els enllaços d'amfitrió de les instà ncies que vols silenciar. Tots els comptes de les instà ncies llistades s'establiran com silenciades i només podran fer sol·licitacions de seguiment, i no podran mencionar als comptes locals si no els segueixen. Això no afectarà les instà ncies bloquejades." mediaSilencedInstances: "Instà ncies amb els arxius silenciats" mediaSilencedInstancesDescription: "Llista els noms dels servidors que vulguis silenciar els arxius, un servidor per lÃnia. Tots els comptes que pertanyin als servidors llistats seran tractats com sensibles i no podran fer servir emojis personalitzats. Això no tindrà efecte sobre els servidors blocats." +federationAllowedHosts: "Llista de servidors federats" +federationAllowedHostsDescription: "Llista dels servidors amb els quals es federa." muteAndBlock: "Silencia i bloca" mutedUsers: "Usuaris silenciats" blockedUsers: "Usuaris bloquejats" @@ -334,6 +338,7 @@ renameFolder: "Canvia el nom de la carpeta" deleteFolder: "Elimina la carpeta" folder: "Carpeta " addFile: "Afegeix un fitxer" +showFile: "Mostrar fitxer" emptyDrive: "La teva unitat és buida" emptyFolder: "La carpeta està buida" unableToDelete: "No es pot eliminar" @@ -509,6 +514,10 @@ uiLanguage: "Idioma de l'interfÃcie" aboutX: "Respecte a {x}" emojiStyle: "Estil d'emoji" native: "Nadiu" +menuStyle: "Estil de menú" +style: "Estil" +drawer: "Calaix" +popup: "Emergent" showNoteActionsOnlyHover: "Només mostra accions de la nota en passar amb el cursor" showReactionsCount: "Mostra el nombre de reaccions a les publicacions" noHistory: "No hi ha un registre previ" @@ -709,10 +718,7 @@ abuseReported: "La teva denúncia s'ha enviat. Moltes grà cies." reporter: "Denunciant " reporteeOrigin: "Origen de la denúncia " reporterOrigin: "Origen del denunciant" -forwardReport: "Transferir la denúncia a una instà ncia remota" -forwardReportIsAnonymous: "En lloc del teu compte, es farà servir un compte anònim com a denunciant al servidor remot." send: "Envia" -abuseMarkAsResolved: "Marca la denúncia com a resolta" openInNewTab: "Obre a una pestanya nova" openInSideView: "Obre a una vista lateral" defaultNavigationBehaviour: "Navegació per defecte" @@ -914,6 +920,7 @@ followersVisibility: "Visibilitat dels seguidors" continueThread: "Veure la continuació del fil" deleteAccountConfirm: "Això eliminarà el teu compte irreversiblement. Procedir?" incorrectPassword: "Contrasenya incorrecta." +incorrectTotp: "La contrasenya no és correcta, o ha caducat." voteConfirm: "Confirma el teu vot \"{choice}\"" hide: "Amagar" useDrawerReactionPickerForMobile: "Mostrar el selector de reaccions com un calaix al mòbil " @@ -1268,6 +1275,15 @@ fromX: "De {x}" genEmbedCode: "Obtenir el codi per incrustar" noteOfThisUser: "Notes d'aquest usuari" clipNoteLimitExceeded: "No es poden afegir més notes a aquest clip." +performance: "Rendiment" +modified: "Modificat" +discard: "Descarta" +thereAreNChanges: "Hi ha(n) {n} canvi(s)" +signinWithPasskey: "Inicia sessió amb Passkey" +unknownWebAuthnKey: "Passkey desconeguda" +passkeyVerificationFailed: "La verificació a fallat" +passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verificació de la passkey a estat correcta, però s'ha deshabilitat l'inici de sessió sense contrasenya." +messageToFollower: "Missatge als meus seguidors" _delivery: status: "Estat d'entrega " stop: "Suspés" @@ -2235,6 +2251,9 @@ _profile: changeBanner: "Canviar el bà ner " verifiedLinkDescription: "Escrivint una adreça URL que enllaci a aquest perfil, una icona de propietat verificada es mostrarà al costat del camp." avatarDecorationMax: "Pot afegir un mà xim de {max} decoracions." + followedMessage: "Missatge als nous seguidors" + followedMessageDescription: "Es pot configurar un missatge curt que es mostra a l'altra persona quan comença a seguir-te." + followedMessageDescriptionForLockedAccount: "Si comencen a seguir-te es mostra un missatge de quan es permet aquesta sol·licitud. " _exportOrImport: allNotes: "Totes les publicacions" favoritedNotes: "Notes preferides" @@ -2373,6 +2392,7 @@ _notification: renotedBySomeUsers: "L'han impulsat {n} usuaris" followedBySomeUsers: "Et segueixen {n} usuaris" flushNotification: "Netejar notificacions" + exportOfXCompleted: "Completada l'exportació de {n}" _types: all: "Tots" note: "Notes noves" @@ -2387,6 +2407,9 @@ _notification: followRequestAccepted: "Petició de seguiment acceptada" roleAssigned: "Rol donat" achievementEarned: "Assoliment desbloquejat" + exportCompleted: "Exportació completada" + login: "Iniciar sessió" + test: "Prova la notificació" app: "Notificacions d'aplicacions" _actions: followBack: "t'ha seguit també" diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index 4a27ed7635..4233a68f17 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -657,10 +657,7 @@ abuseReported: "Nahlášenà bylo odesláno. DÄ›kujeme pÅ™evelice." reporter: "Nahlásil" reporteeOrigin: "Původ nahlášenÃ" reporterOrigin: "Původ nahlasovaÄe" -forwardReport: "PÅ™eposlat nahlášenà do vzdálené instance" -forwardReportIsAnonymous: "MÃsto vaÅ¡eho úÄtu se ve vzdálené instanci zobrazà anonymnà systémový úÄet jako nahlaÅ¡ovaÄ." send: "Odeslat" -abuseMarkAsResolved: "OznaÄit nahlášenà jako vyÅ™eÅ¡ené" openInNewTab: "OtevÅ™Ãt v nové kartÄ›" openInSideView: "OtevÅ™Ãt v boÄnÃm panelu" defaultNavigationBehaviour: "Výchozà chovánà navigace" @@ -1962,6 +1959,7 @@ _notification: receiveFollowRequest: "Obdržené žádosti o sledovánÃ" followRequestAccepted: "PÅ™ijaté žádosti o sledovánÃ" achievementEarned: "ÚspÄ›ch odemÄen" + login: "PÅ™ihlásit se" app: "Oznámenà z propojených aplikacÃ" _actions: followBack: "vás zaÄal sledovat zpÄ›t" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 453f6308f6..35a04b453c 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -686,10 +686,7 @@ abuseReported: "Deine Meldung wurde versendet. Vielen Dank." reporter: "Melder" reporteeOrigin: "Herkunft des Gemeldeten" reporterOrigin: "Herkunft des Meldenden" -forwardReport: "Meldung an fremde Instanz weiterleiten" -forwardReportIsAnonymous: "Anstatt deines Benutzerkontos wird bei der fremden Instanz ein anonymes Systemkonto als Melder angezeigt." send: "Senden" -abuseMarkAsResolved: "Meldung als gelöst markieren" openInNewTab: "In neuem Tab öffnen" openInSideView: "In Seitenansicht öffnen" defaultNavigationBehaviour: "Standardnavigationsverhalten" @@ -2141,6 +2138,7 @@ _notification: receiveFollowRequest: "Erhaltene Follow-Anfragen" followRequestAccepted: "Akzeptierte Follow-Anfragen" achievementEarned: "Errungenschaft freigeschaltet" + login: "Anmelden" app: "Benachrichtigungen von Apps" _actions: followBack: "folgt dir nun auch" diff --git a/locales/el-GR.yml b/locales/el-GR.yml index 5eca348e18..4657842ca5 100644 --- a/locales/el-GR.yml +++ b/locales/el-GR.yml @@ -378,6 +378,7 @@ _notification: renote: "Κοινοποίηση σημειώματος" quote: "ΠαÏάθεση" reaction: "ΑντιδÏάσεις" + login: "ΣÏνδεση" _actions: reply: "Απάντηση" renote: "Κοινοποίηση σημειώματος" diff --git a/locales/en-US.yml b/locales/en-US.yml index ad81376f89..126f769644 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -8,6 +8,9 @@ search: "Search" notifications: "Notifications" username: "Username" password: "Password" +initialPasswordForSetup: "Initial password for setup" +initialPasswordIsIncorrect: "Initial password for setup is incorrect" +initialPasswordForSetupDescription: "Use the password you entered in the configuration file if you installed Misskey yourself.\n If you are using a Misskey hosting service, use the password provided.\n If you have not set a password, leave it blank to continue." forgotPassword: "Forgot password" fetchingAsApObject: "Fetching from the Fediverse..." ok: "OK" @@ -109,7 +112,7 @@ enterEmoji: "Enter an emoji" renote: "Renote" unrenote: "Remove renote" renoted: "Renoted." -renotedToX: "Renote to {name}." +renotedToX: "Renoted to {name}." cantRenote: "This post can't be renoted." cantReRenote: "A renote can't be renoted." quote: "Quote" @@ -236,6 +239,8 @@ silencedInstances: "Silenced instances" silencedInstancesDescription: "List the host names of the servers that you want to silence, separated by a new line. All accounts belonging to the listed servers will be treated as silenced, and can only make follow requests, and cannot mention local accounts if not followed. This will not affect the blocked servers." mediaSilencedInstances: "Media-silenced servers" mediaSilencedInstancesDescription: "List the host names of the servers that you want to media-silence, separated by a new line. All accounts belonging to the listed servers will be treated as sensitive, and can't use custom emojis. This will not affect the blocked servers." +federationAllowedHosts: "Federation allowed servers" +federationAllowedHostsDescription: "Specify the hostnames of the servers you want to allow federation separated by line breaks." muteAndBlock: "Mutes and Blocks" mutedUsers: "Muted users" blockedUsers: "Blocked users" @@ -334,6 +339,7 @@ renameFolder: "Rename this folder" deleteFolder: "Delete this folder" folder: "Folder" addFile: "Add a file" +showFile: "Show files" emptyDrive: "Your Drive is empty" emptyFolder: "This folder is empty" unableToDelete: "Unable to delete" @@ -448,6 +454,7 @@ totpDescription: "Use an authenticator app to enter one-time passwords" moderator: "Moderator" moderation: "Moderation" moderationNote: "Moderation note" +moderationNoteDescription: "You can fill in notes that will be shared only among moderators." addModerationNote: "Add moderation note" moderationLogs: "Moderation logs" nUsersMentioned: "Mentioned by {n} users" @@ -509,6 +516,10 @@ uiLanguage: "User interface language" aboutX: "About {x}" emojiStyle: "Emoji style" native: "Native" +menuStyle: "Menu style" +style: "Style" +drawer: "Drawer" +popup: "Pop up" showNoteActionsOnlyHover: "Only show note actions on hover" showReactionsCount: "See the number of reactions in notes" noHistory: "No history available" @@ -591,6 +602,8 @@ ascendingOrder: "Ascending" descendingOrder: "Descending" scratchpad: "Scratchpad" scratchpadDescription: "The Scratchpad provides an environment for AiScript experiments. You can write, execute, and check the results of it interacting with Misskey in it." +uiInspector: "UI inspector" +uiInspectorDescription: "You can see the UI component server list on memory. UI component will be generated by Ui:C: function." output: "Output" script: "Script" disablePagesScript: "Disable AiScript on Pages" @@ -707,10 +720,7 @@ abuseReported: "Your report has been sent. Thank you very much." reporter: "Reporter" reporteeOrigin: "Reportee Origin" reporterOrigin: "Reporter Origin" -forwardReport: "Forward report to remote instance" -forwardReportIsAnonymous: "Instead of your account, an anonymous system account will be displayed as reporter at the remote instance." send: "Send" -abuseMarkAsResolved: "Mark report as resolved" openInNewTab: "Open in new tab" openInSideView: "Open in side view" defaultNavigationBehaviour: "Default navigation behavior" @@ -912,6 +922,7 @@ followersVisibility: "Visibility of followers" continueThread: "View thread continuation" deleteAccountConfirm: "This will irreversibly delete your account. Proceed?" incorrectPassword: "Incorrect password." +incorrectTotp: "The one-time password is incorrect or has expired." voteConfirm: "Confirm your vote for \"{choice}\"?" hide: "Hide" useDrawerReactionPickerForMobile: "Display reaction picker as drawer on mobile" @@ -1125,7 +1136,7 @@ options: "Options" specifyUser: "Specific user" lookupConfirm: "Do you want to look up?" openTagPageConfirm: "Do you want to open a hashtag page?" -specifyHost: "Specify a host" +specifyHost: "Specific host" failedToPreviewUrl: "Could not preview" update: "Update" rolesThatCanBeUsedThisEmojiAsReaction: "Roles that can use this emoji as reaction" @@ -1266,6 +1277,23 @@ fromX: "From {x}" genEmbedCode: "Generate embed code" noteOfThisUser: "Notes by this user" clipNoteLimitExceeded: "No more notes can be added to this clip." +performance: "Performance" +modified: "Modified" +discard: "Discard" +thereAreNChanges: "There are {n} change(s)" +signinWithPasskey: "Sign in with Passkey" +unknownWebAuthnKey: "Unknown Passkey" +passkeyVerificationFailed: "Passkey verification has failed." +passkeyVerificationSucceededButPasswordlessLoginDisabled: "Passkey verification has succeeded but password-less login is disabled." +messageToFollower: "Message to followers" +target: "Target" +_abuseUserReport: + forward: "Forward" + forwardDescription: "Forward the report to a remote server as an anonymous system account." + resolve: "Resolve" + accept: "Accept" + reject: "Reject" + resolveTutorial: "If the report is legitimate in content, select \"Accept\" to mark the case as resolved in the affirmative.\nIf the content of the report is not legitimate, select \"Reject\" to mark the case as resolved in the negative." _delivery: status: "Delivery status" stop: "Suspended" @@ -1400,6 +1428,7 @@ _serverSettings: fanoutTimelineDescription: "Greatly increases performance of timeline retrieval and reduces load on the database when enabled. In exchange, memory usage of Redis will increase. Consider disabling this in case of low server memory or server instability." fanoutTimelineDbFallback: "Fallback to database" fanoutTimelineDbFallbackDescription: "When enabled, the timeline will fall back to the database for additional queries if the timeline is not cached. Disabling it further reduces the server load by eliminating the fallback process, but limits the range of timelines that can be retrieved." + reactionsBufferingDescription: "When enabled, performance during reaction creation will be greatly improved, reducing the load on the database. However, Redis memory usage will increase." inquiryUrl: "Inquiry URL" inquiryUrlDescription: "Specify a URL for the inquiry form to the server maintainer or a web page for the contact information." _accountMigration: @@ -1718,7 +1747,7 @@ _role: canManageAvatarDecorations: "Manage avatar decorations" driveCapacity: "Drive capacity" alwaysMarkNsfw: "Always mark files as NSFW" - canUpdateBioMedia: "Allow to edit an icon or a banner image" + canUpdateBioMedia: "Can edit an icon or a banner image" pinMax: "Maximum number of pinned notes" antennaMax: "Maximum number of antennas" wordMuteMax: "Maximum number of characters allowed in word mutes" @@ -1733,6 +1762,11 @@ _role: canSearchNotes: "Usage of note search" canUseTranslator: "Translator usage" avatarDecorationLimit: "Maximum number of avatar decorations that can be applied" + canImportAntennas: "Allow importing antennas" + canImportBlocking: "Allow importing blocking" + canImportFollowing: "Allow importing following" + canImportMuting: "Allow importing muting" + canImportUserLists: "Allow importing lists" _condition: roleAssignedTo: "Assigned to manual roles" isLocal: "Local user" @@ -2227,6 +2261,9 @@ _profile: changeBanner: "Change banner" verifiedLinkDescription: "By entering an URL that contains a link to your profile here, an ownership verification icon can be displayed next to the field." avatarDecorationMax: "You can add up to {max} decorations." + followedMessage: "Message when you are followed" + followedMessageDescription: "You can set a short message to be displayed to the recipient when they follow you." + followedMessageDescriptionForLockedAccount: "If you have set up that follow requests require approval, this will be displayed when you grant a follow request." _exportOrImport: allNotes: "All notes" favoritedNotes: "Favorite notes" @@ -2365,6 +2402,8 @@ _notification: renotedBySomeUsers: "Renote from {n} users" followedBySomeUsers: "Followed by {n} users" flushNotification: "Clear notifications" + exportOfXCompleted: "Export of {x} has been completed" + login: "Someone logged in" _types: all: "All" note: "New notes" @@ -2379,6 +2418,9 @@ _notification: followRequestAccepted: "Accepted follow requests" roleAssigned: "Role given" achievementEarned: "Achievement unlocked" + exportCompleted: "The export has been completed" + login: "Sign In" + test: "Notification test" app: "Notifications from linked apps" _actions: followBack: "followed you back" @@ -2441,21 +2483,22 @@ _webhookSettings: reaction: "When receiving a reaction" mention: "When being mentioned" _systemEvents: - abuseReport: "When received a new abuse report" - abuseReportResolved: "When resolved abuse report" + abuseReport: "When received a new report" + abuseReportResolved: "When resolved report" userCreated: "When user is created" deleteConfirm: "Are you sure you want to delete the Webhook?" + testRemarks: "Click the button to the right of the switch to send a test Webhook with dummy data." _abuseReport: _notificationRecipient: - createRecipient: "Add a recipient for abuse reports" - modifyRecipient: "Edit a recipient for abuse reports" + createRecipient: "Add a recipient for reports" + modifyRecipient: "Edit a recipient for reports" recipientType: "Notification type" _recipientType: mail: "Email" webhook: "Webhook" _captions: - mail: "Send the email to moderators' email addresses when you receive abuse." - webhook: "Send a notification to SystemWebhook when you receive or resolve abuse." + mail: "Send the email to moderators' email addresses when you receive reports." + webhook: "Send a notification to System Webhook when you receive or resolve reports." keywords: "Keywords" notifiedUser: "Users to notify" notifiedWebhook: "Webhook to use" @@ -2488,6 +2531,8 @@ _moderationLogTypes: markSensitiveDriveFile: "File marked as sensitive" unmarkSensitiveDriveFile: "File unmarked as sensitive" resolveAbuseReport: "Report resolved" + forwardAbuseReport: "Report forwarded" + updateAbuseReportNote: "Moderation note of a report updated" createInvitation: "Invite generated" createAd: "Ad created" deleteAd: "Ad deleted" @@ -2495,18 +2540,18 @@ _moderationLogTypes: createAvatarDecoration: "Avatar decoration created" updateAvatarDecoration: "Avatar decoration updated" deleteAvatarDecoration: "Avatar decoration deleted" - unsetUserAvatar: "Unset this user's avatar" - unsetUserBanner: "Unset this user's banner" - createSystemWebhook: "Create SystemWebhook" - updateSystemWebhook: "Update SystemWebhook" - deleteSystemWebhook: "Delete SystemWebhook" - createAbuseReportNotificationRecipient: "Create a recipient for abuse reports" - updateAbuseReportNotificationRecipient: "Update recipients for abuse reports" - deleteAbuseReportNotificationRecipient: "Delete a recipient for abuse reports" - deleteAccount: "Delete the account" - deletePage: "Delete the page" - deleteFlash: "Delete Play" - deleteGalleryPost: "Delete the gallery post" + unsetUserAvatar: "User avatar unset" + unsetUserBanner: "User banner unset" + createSystemWebhook: "System Webhook created" + updateSystemWebhook: "System Webhook updated" + deleteSystemWebhook: "System Webhook deleted" + createAbuseReportNotificationRecipient: "Recipient for reports created" + updateAbuseReportNotificationRecipient: "Recipient for reports updated" + deleteAbuseReportNotificationRecipient: "Recipient for reports deleted" + deleteAccount: "Account deleted" + deletePage: "Page deleted" + deleteFlash: "Play deleted" + deleteGalleryPost: "Gallery post deleted" _fileViewer: title: "File details" type: "File type" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 66cab3e957..de9ea0c32a 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -700,10 +700,7 @@ abuseReported: "Se ha enviado el reporte. Muchas gracias." reporter: "Reportador" reporteeOrigin: "Reportar a" reporterOrigin: "Origen del reporte" -forwardReport: "Transferir un informe a una instancia remota" -forwardReportIsAnonymous: "No puede ver su información de la instancia remota y aparecerá como una cuenta anónima del sistema" send: "Enviar" -abuseMarkAsResolved: "Marcar reporte como resuelto" openInNewTab: "Abrir en una Nueva Pestaña" openInSideView: "Abrir en una vista al costado" defaultNavigationBehaviour: "Navegación por defecto" @@ -2343,6 +2340,7 @@ _notification: followRequestAccepted: "El seguimiento fue aceptado" roleAssigned: "Rol asignado" achievementEarned: "Logro desbloqueado" + login: "Iniciar sesión" app: "Notificaciones desde aplicaciones" _actions: followBack: "Te sigue de vuelta" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 0cf4b65c38..7dfc64d63f 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -691,10 +691,7 @@ abuseReported: "Le rapport est envoyé. Merci." reporter: "Signalé par" reporteeOrigin: "Origine du signalement" reporterOrigin: "Signalé par" -forwardReport: "Transférer le signalement à l’instance distante" -forwardReportIsAnonymous: "L'instance distante ne sera pas en mesure de voir vos informations et apparaîtra comme un compte anonyme du système." send: "Envoyer" -abuseMarkAsResolved: "Marquer le signalement comme résolu" openInNewTab: "Ouvrir dans un nouvel onglet" openInSideView: "Ouvrir en vue latérale" defaultNavigationBehaviour: "Navigation par défaut" @@ -2037,6 +2034,7 @@ _notification: followRequestAccepted: "Demande d'abonnement acceptée" roleAssigned: "Rôle reçu" achievementEarned: "Déverrouillage d'accomplissement" + login: "Se connecter" app: "Notifications provenant des apps" _actions: followBack: "Suivre" diff --git a/locales/hu-HU.yml b/locales/hu-HU.yml index 023a91494d..acc27ed092 100644 --- a/locales/hu-HU.yml +++ b/locales/hu-HU.yml @@ -96,6 +96,7 @@ _notification: renote: "Renote" quote: "Idézet" reaction: "Reakciók" + login: "Bejelentkezés" _actions: renote: "Renote" _deck: diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 55ca9d91ac..fbfedb89e3 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -702,10 +702,7 @@ abuseReported: "Laporan kamu telah dikirimkan. Terima kasih." reporter: "Pelapor" reporteeOrigin: "Yang dilaporkan" reporterOrigin: "Pelapor" -forwardReport: "Teruskan laporan ke instansi luar" -forwardReportIsAnonymous: "Untuk melindungi privasi akun kamu, akun anonim dari sistem akan digunakan sebagai pelapor pada instansi luar." send: "Kirim" -abuseMarkAsResolved: "Tandai laporan sebagai selesai" openInNewTab: "Buka di tab baru" openInSideView: "Buka di tampilan samping" defaultNavigationBehaviour: "Navigasi bawaan" @@ -2354,6 +2351,7 @@ _notification: followRequestAccepted: "Permintaan mengikuti disetujui" roleAssigned: "Peran Diberikan" achievementEarned: "Pencapaian didapatkan" + login: "Masuk" app: "Notifikasi dari aplikasi tertaut" _actions: followBack: "Ikuti Kembali" diff --git a/locales/index.d.ts b/locales/index.d.ts index 32c5a21648..d502c5b432 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -49,6 +49,20 @@ export interface Locale extends ILocale { */ "password": string; /** + * åˆæœŸè¨å®šé–‹å§‹ç”¨ãƒ‘スワード + */ + "initialPasswordForSetup": string; + /** + * åˆæœŸè¨å®šé–‹å§‹ç”¨ã®ãƒ‘スワードãŒé•ã„ã¾ã™ã€‚ + */ + "initialPasswordIsIncorrect": string; + /** + * Misskeyを自分ã§ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ãŸå ´åˆã¯ã€è¨å®šãƒ•ァイルã«å…¥åŠ›ã—ãŸãƒ‘スワードを使用ã—ã¦ãã ã•ã„。 + * Misskeyã®ãƒ›ã‚¹ãƒ†ã‚£ãƒ³ã‚°ã‚µãƒ¼ãƒ“スãªã©ã‚’使用ã—ã¦ã„ã‚‹å ´åˆã¯ã€æä¾›ã•れãŸãƒ‘スワードを使用ã—ã¦ãã ã•ã„。 + * パスワードをè¨å®šã—ã¦ã„ãªã„å ´åˆã¯ã€ç©ºæ¬„ã«ã—ãŸã¾ã¾ç¶šè¡Œã—ã¦ãã ã•ã„。 + */ + "initialPasswordForSetupDescription": string; + /** * パスワードを忘れ㟠*/ "forgotPassword": string; @@ -1821,6 +1835,10 @@ export interface Locale extends ILocale { */ "moderationNote": string; /** + * モデレーター間ã§ã ã‘共有ã•れるメモを記入ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ + */ + "moderationNoteDescription": string; + /** * ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒŽãƒ¼ãƒˆã‚’è¿½åŠ ã™ã‚‹ */ "addModerationNote": string; @@ -2881,22 +2899,10 @@ export interface Locale extends ILocale { */ "reporterOrigin": string; /** - * リモートサーãƒãƒ¼ã«é€šå ±ã‚’転é€ã™ã‚‹ - */ - "forwardReport": string; - /** - * リモートサーãƒãƒ¼ã‹ã‚‰ã¯ã‚ãªãŸã®æƒ…å ±ã¯è¦‹ã‚Œãšã€åŒ¿åã®ã‚·ã‚¹ãƒ†ãƒ アカウントã¨ã—ã¦è¡¨ç¤ºã•れã¾ã™ã€‚ - */ - "forwardReportIsAnonymous": string; - /** * é€ä¿¡ */ "send": string; /** - * 対応済ã¿ã«ã™ã‚‹ - */ - "abuseMarkAsResolved": string; - /** * æ–°ã—ã„タブã§é–‹ã */ "openInNewTab": string; @@ -3701,6 +3707,10 @@ export interface Locale extends ILocale { */ "incorrectPassword": string; /** + * ワンタイムパスワードãŒé–“é•ã£ã¦ã„ã‚‹ã‹ã€æœŸé™åˆ‡ã‚Œã«ãªã£ã¦ã„ã¾ã™ã€‚ + */ + "incorrectTotp": string; + /** * 「{choice}ã€ã«æŠ•票ã—ã¾ã™ã‹ï¼Ÿ */ "voteConfirm": ParameterizedString<"choice">; @@ -5148,6 +5158,41 @@ export interface Locale extends ILocale { * パスã‚ãƒ¼ã®æ¤œè¨¼ã«æˆåŠŸã—ã¾ã—ãŸãŒã€ãƒ‘スワードレスãƒã‚°ã‚¤ãƒ³ãŒç„¡åйã«ãªã£ã¦ã„ã¾ã™ã€‚ */ "passkeyVerificationSucceededButPasswordlessLoginDisabled": string; + /** + * フォãƒãƒ¯ãƒ¼ã¸ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ + */ + "messageToFollower": string; + /** + * 対象 + */ + "target": string; + "_abuseUserReport": { + /** + * è»¢é€ + */ + "forward": string; + /** + * 匿åã®ã‚·ã‚¹ãƒ†ãƒ アカウントã¨ã—ã¦ã€ãƒªãƒ¢ãƒ¼ãƒˆã‚µãƒ¼ãƒãƒ¼ã«é€šå ±ã‚’転é€ã—ã¾ã™ã€‚ + */ + "forwardDescription": string; + /** + * 解決 + */ + "resolve": string; + /** + * æ˜¯èª + */ + "accept": string; + /** + * å¦èª + */ + "reject": string; + /** + * å†…å®¹ãŒæ£å½“ã§ã‚ã‚‹é€šå ±ã«å¯¾å¿œã—ãŸå ´åˆã¯ã€Œæ˜¯èªã€ã‚’é¸æŠžã—ã€è‚¯å®šçš„ã«ã‚±ãƒ¼ã‚¹ãŒè§£æ±ºã•れãŸã“ã¨ã‚’マークã—ã¾ã™ã€‚ + * å†…å®¹ãŒæ£å½“ã§ãªã„é€šå ±ã®å ´åˆã¯ã€Œå¦èªã€ã‚’é¸æŠžã—ã€å¦å®šçš„ã«ã‚±ãƒ¼ã‚¹ãŒè§£æ±ºã•れãŸã“ã¨ã‚’マークã—ã¾ã™ã€‚ + */ + "resolveTutorial": string; + }; "_delivery": { /** * é…信状態 @@ -9281,6 +9326,10 @@ export interface Locale extends ILocale { * {x}ã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãŒå®Œäº†ã—ã¾ã—㟠*/ "exportOfXCompleted": ParameterizedString<"x">; + /** + * ãƒã‚°ã‚¤ãƒ³ãŒã‚りã¾ã—㟠+ */ + "login": string; "_types": { /** * ã™ã¹ã¦ @@ -9339,6 +9388,10 @@ export interface Locale extends ILocale { */ "exportCompleted": string; /** + * ãƒã‚°ã‚¤ãƒ³ + */ + "login": string; + /** * 通知ã®ãƒ†ã‚¹ãƒˆ */ "test": string; @@ -9756,6 +9809,14 @@ export interface Locale extends ILocale { */ "resolveAbuseReport": string; /** + * é€šå ±ã‚’è»¢é€ + */ + "forwardAbuseReport": string; + /** + * é€šå ±ã®ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒŽãƒ¼ãƒˆæ›´æ–° + */ + "updateAbuseReportNote": string; + /** * æ‹›å¾…ã‚³ãƒ¼ãƒ‰ã‚’ä½œæˆ */ "createInvitation": string; diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 55b612cac5..004bb6e9fd 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -8,6 +8,9 @@ search: "Cerca" notifications: "Notifiche" username: "Nome utente" password: "Password" +initialPasswordForSetup: "Password iniziale, per avviare le impostazioni" +initialPasswordIsIncorrect: "Password iniziale, sbagliata." +initialPasswordForSetupDescription: "Se hai installato Misskey di persona, usa la password che hai indicato nel file di configurazione.\nSe stai utilizzando un servizio di hosting Misskey, usa la password fornita dal gestore.\nSe non hai una password preimpostata, lascia il campo vuoto e continua." forgotPassword: "Hai dimenticato la password?" fetchingAsApObject: "Recuperando dal Fediverso..." ok: "OK" @@ -236,6 +239,8 @@ 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." mediaSilencedInstances: "Istanze coi media silenziati" mediaSilencedInstancesDescription: "Elenca i nomi host delle istanze di cui vuoi silenziare i media, uno per riga. Tutti gli allegati dei profili nelle istanze silenziate per via degli allegati espliciti, verranno impostati come tali, le emoji personalizzate non saranno disponibili. Le istanze bloccate sono escluse." +federationAllowedHosts: "Server a cui consentire la federazione" +federationAllowedHostsDescription: "Indica gli host dei server a cui è consentita la federazione, uno per ogni linea." muteAndBlock: "Silenziare e bloccare" mutedUsers: "Profili silenziati" blockedUsers: "Profili bloccati" @@ -714,10 +719,7 @@ abuseReported: "La segnalazione è stata inviata. Grazie." reporter: "il corrispondente" reporteeOrigin: "Segnalazione a" reporterOrigin: "Segnalazione da" -forwardReport: "Inoltro di un report a un'istanza remota." -forwardReportIsAnonymous: "L'istanza remota non vedrà le tue informazioni, apparirai come profilo di sistema, anonimo." send: "Inviare" -abuseMarkAsResolved: "Risolvi segnalazione" openInNewTab: "Apri in una nuova scheda" openInSideView: "Apri in vista laterale" defaultNavigationBehaviour: "Navigazione preimpostata" @@ -919,6 +921,7 @@ followersVisibility: "Visibilità dei profili che ti seguono" continueThread: "Altre conversazioni" deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?" incorrectPassword: "La password è errata." +incorrectTotp: "Il codice OTP è sbagliato, oppure scaduto." voteConfirm: "Votare per「{choice}ã€?" hide: "Nascondere" useDrawerReactionPickerForMobile: "Mostra sul drawer da dispositivo mobile" @@ -1281,6 +1284,7 @@ signinWithPasskey: "Accedi con passkey" unknownWebAuthnKey: "Questa è una passkey sconosciuta." passkeyVerificationFailed: "La verifica della passkey non è riuscita." passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verifica della passkey è riuscita, ma l'accesso senza password è disabilitato." +messageToFollower: "Messaggio ai follower" _delivery: status: "Stato della consegna" stop: "Sospensione" @@ -2248,6 +2252,9 @@ _profile: changeBanner: "Cambia intestazione" verifiedLinkDescription: "Puoi verificare il tuo profilo mostrando una icona. Devi inserire la URL alla pagina che contiene un link al tuo profilo." avatarDecorationMax: "Puoi aggiungere fino a {max} decorazioni." + followedMessage: "Messaggio, quando qualcuno ti segue" + followedMessageDescription: "Puoi impostare un breve messaggio da mostrare agli altri profili quando ti seguono." + followedMessageDescriptionForLockedAccount: "Quando approvi una richiesta di follow, verrà visualizzato questo testo." _exportOrImport: allNotes: "Tutte le note" favoritedNotes: "Note preferite" @@ -2387,6 +2394,7 @@ _notification: followedBySomeUsers: "{n} follower" flushNotification: "Azzera le notifiche" exportOfXCompleted: "Abbiamo completato l'esportazione di {x}" + login: "Autenticazione avvenuta" _types: all: "Tutto" note: "Nuove Note" @@ -2402,6 +2410,7 @@ _notification: roleAssigned: "Ruolo concesso" achievementEarned: "Risultato raggiunto" exportCompleted: "Esportazione completata" + login: "Accedi" test: "Prova la notifica" app: "Notifiche da applicazioni" _actions: diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index eebc4c995f..678bc7e66b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -8,6 +8,9 @@ search: "検索" notifications: "通知" username: "ユーザーå" password: "パスワード" +initialPasswordForSetup: "åˆæœŸè¨å®šé–‹å§‹ç”¨ãƒ‘スワード" +initialPasswordIsIncorrect: "åˆæœŸè¨å®šé–‹å§‹ç”¨ã®ãƒ‘スワードãŒé•ã„ã¾ã™ã€‚" +initialPasswordForSetupDescription: "Misskeyを自分ã§ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ãŸå ´åˆã¯ã€è¨å®šãƒ•ァイルã«å…¥åŠ›ã—ãŸãƒ‘スワードを使用ã—ã¦ãã ã•ã„。\nMisskeyã®ãƒ›ã‚¹ãƒ†ã‚£ãƒ³ã‚°ã‚µãƒ¼ãƒ“スãªã©ã‚’使用ã—ã¦ã„ã‚‹å ´åˆã¯ã€æä¾›ã•れãŸãƒ‘スワードを使用ã—ã¦ãã ã•ã„。\nパスワードをè¨å®šã—ã¦ã„ãªã„å ´åˆã¯ã€ç©ºæ¬„ã«ã—ãŸã¾ã¾ç¶šè¡Œã—ã¦ãã ã•ã„。" forgotPassword: "パスワードを忘れãŸ" fetchingAsApObject: "連åˆã«ç…§ä¼šä¸" ok: "OK" @@ -451,6 +454,7 @@ totpDescription: "èªè¨¼ã‚¢ãƒ—リを使ã£ã¦ãƒ¯ãƒ³ã‚¿ã‚¤ãƒ ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ã‚’å… moderator: "モデレーター" moderation: "モデレーション" moderationNote: "モデレーションノート" +moderationNoteDescription: "モデレーター間ã§ã ã‘共有ã•れるメモを記入ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚" addModerationNote: "ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒŽãƒ¼ãƒˆã‚’è¿½åŠ ã™ã‚‹" moderationLogs: "モデãƒã‚°" nUsersMentioned: "{n}äººãŒæŠ•ç¨¿" @@ -716,10 +720,7 @@ abuseReported: "内容ãŒé€ä¿¡ã•れã¾ã—ãŸã€‚ã”å ±å‘Šã‚りãŒã¨ã†ã”ã–ã reporter: "é€šå ±è€…" reporteeOrigin: "é€šå ±å…ˆ" reporterOrigin: "é€šå ±å…ƒ" -forwardReport: "リモートサーãƒãƒ¼ã«é€šå ±ã‚’転é€ã™ã‚‹" -forwardReportIsAnonymous: "リモートサーãƒãƒ¼ã‹ã‚‰ã¯ã‚ãªãŸã®æƒ…å ±ã¯è¦‹ã‚Œãšã€åŒ¿åã®ã‚·ã‚¹ãƒ†ãƒ アカウントã¨ã—ã¦è¡¨ç¤ºã•れã¾ã™ã€‚" send: "é€ä¿¡" -abuseMarkAsResolved: "対応済ã¿ã«ã™ã‚‹" openInNewTab: "æ–°ã—ã„タブã§é–‹ã" openInSideView: "サイドビューã§é–‹ã" defaultNavigationBehaviour: "デフォルトã®ãƒŠãƒ“ゲーション" @@ -921,6 +922,7 @@ followersVisibility: "フォãƒãƒ¯ãƒ¼ã®å…¬é–‹ç¯„囲" continueThread: "ã•らã«ã‚¹ãƒ¬ãƒƒãƒ‰ã‚’見る" deleteAccountConfirm: "アカウントãŒå‰Šé™¤ã•れã¾ã™ã€‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ" incorrectPassword: "パスワードãŒé–“é•ã£ã¦ã„ã¾ã™ã€‚" +incorrectTotp: "ワンタイムパスワードãŒé–“é•ã£ã¦ã„ã‚‹ã‹ã€æœŸé™åˆ‡ã‚Œã«ãªã£ã¦ã„ã¾ã™ã€‚" voteConfirm: "「{choice}ã€ã«æŠ•票ã—ã¾ã™ã‹ï¼Ÿ" hide: "éš ã™" useDrawerReactionPickerForMobile: "モãƒã‚¤ãƒ«ãƒ‡ãƒã‚¤ã‚¹ã®ã¨ãドãƒãƒ¯ãƒ¼ã§è¡¨ç¤º" @@ -1283,6 +1285,16 @@ signinWithPasskey: "パスã‚ーã§ãƒã‚°ã‚¤ãƒ³" unknownWebAuthnKey: "登録ã•れã¦ã„ãªã„パスã‚ーã§ã™ã€‚" passkeyVerificationFailed: "パスã‚ãƒ¼ã®æ¤œè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚" passkeyVerificationSucceededButPasswordlessLoginDisabled: "パスã‚ãƒ¼ã®æ¤œè¨¼ã«æˆåŠŸã—ã¾ã—ãŸãŒã€ãƒ‘スワードレスãƒã‚°ã‚¤ãƒ³ãŒç„¡åйã«ãªã£ã¦ã„ã¾ã™ã€‚" +messageToFollower: "フォãƒãƒ¯ãƒ¼ã¸ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸" +target: "対象" + +_abuseUserReport: + forward: "転é€" + forwardDescription: "匿åã®ã‚·ã‚¹ãƒ†ãƒ アカウントã¨ã—ã¦ã€ãƒªãƒ¢ãƒ¼ãƒˆã‚µãƒ¼ãƒãƒ¼ã«é€šå ±ã‚’転é€ã—ã¾ã™ã€‚" + resolve: "解決" + accept: "是èª" + reject: "å¦èª" + resolveTutorial: "å†…å®¹ãŒæ£å½“ã§ã‚ã‚‹é€šå ±ã«å¯¾å¿œã—ãŸå ´åˆã¯ã€Œæ˜¯èªã€ã‚’é¸æŠžã—ã€è‚¯å®šçš„ã«ã‚±ãƒ¼ã‚¹ãŒè§£æ±ºã•れãŸã“ã¨ã‚’マークã—ã¾ã™ã€‚\nå†…å®¹ãŒæ£å½“ã§ãªã„é€šå ±ã®å ´åˆã¯ã€Œå¦èªã€ã‚’é¸æŠžã—ã€å¦å®šçš„ã«ã‚±ãƒ¼ã‚¹ãŒè§£æ±ºã•れãŸã“ã¨ã‚’マークã—ã¾ã™ã€‚" _delivery: status: "é…信状態" @@ -2450,6 +2462,7 @@ _notification: followedBySomeUsers: "{n}人ã«ãƒ•ã‚©ãƒãƒ¼ã•れã¾ã—ãŸ" flushNotification: "通知ã®å±¥æ´ã‚’リセットã™ã‚‹" exportOfXCompleted: "{x}ã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãŒå®Œäº†ã—ã¾ã—ãŸ" + login: "ãƒã‚°ã‚¤ãƒ³ãŒã‚りã¾ã—ãŸ" _types: all: "ã™ã¹ã¦" @@ -2466,6 +2479,7 @@ _notification: roleAssigned: "ãƒãƒ¼ãƒ«ãŒä»˜ä¸Žã•れãŸ" achievementEarned: "実績ã®ç²å¾—" exportCompleted: "エクスãƒãƒ¼ãƒˆãŒå®Œäº†ã—ãŸ" + login: "ãƒã‚°ã‚¤ãƒ³" test: "通知ã®ãƒ†ã‚¹ãƒˆ" app: "連æºã‚¢ãƒ—リã‹ã‚‰ã®é€šçŸ¥" @@ -2586,6 +2600,8 @@ _moderationLogTypes: markSensitiveDriveFile: "ファイルをセンシティブ付与" unmarkSensitiveDriveFile: "ファイルをセンシティブ解除" resolveAbuseReport: "é€šå ±ã‚’è§£æ±º" + forwardAbuseReport: "é€šå ±ã‚’è»¢é€" + updateAbuseReportNote: "é€šå ±ã®ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒŽãƒ¼ãƒˆæ›´æ–°" createInvitation: "招待コードを作æˆ" createAd: "広告を作æˆ" deleteAd: "広告を削除" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 660fa38e38..52a8f41380 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -707,10 +707,7 @@ abuseReported: "無事内容ãŒé€ä¿¡ã•れãŸã¿ãŸã„ã‚„ã§ã€‚ãŠãŠãã«ã€œã reporter: "é€šå ±è€…" reporteeOrigin: "é€šå ±å…ˆ" reporterOrigin: "é€šå ±å…ƒ" -forwardReport: "リモートサーãƒãƒ¼ã«é€šå ±ã‚’転é€ã™ã‚‹ã§" -forwardReportIsAnonymous: "リモートサーãƒãƒ¼ã‹ã‚‰ã¯ã‚ã‚“ãŸã®æƒ…å ±ã¯è¦‹ãˆã‚“ãªã£ã¦ã€åŒ¿åã®ã‚·ã‚¹ãƒ†ãƒ アカウントã¨ã—ã¦è¡¨ç¤ºã•れるã§ã€‚" send: "é€ä¿¡" -abuseMarkAsResolved: "対応ã—ãŸã§" openInNewTab: "æ–°ã—ã„タブã§é–‹ã" openInSideView: "サイドビューã§é–‹ã" defaultNavigationBehaviour: "デフォルトã®ãƒŠãƒ“ゲーション" @@ -2374,6 +2371,7 @@ _notification: followRequestAccepted: "フォãƒãƒ¼ãŒå—ç†ã•れãŸã§" roleAssigned: "ãƒãƒ¼ãƒ«ãŒä»˜ä¸Žã•れãŸ" achievementEarned: "実績ã®ç²å¾—" + login: "ãƒã‚°ã‚¤ãƒ³" app: "連æºã‚¢ãƒ—リã‹ã‚‰ã®é€šçŸ¥ã‚„" _actions: followBack: "フォãƒãƒ¼ãƒãƒƒã‚¯" diff --git a/locales/kn-IN.yml b/locales/kn-IN.yml index b3ad46f2b1..222599572a 100644 --- a/locales/kn-IN.yml +++ b/locales/kn-IN.yml @@ -77,6 +77,8 @@ _profile: username: "ಬಳಕೆಹೆಸರà³" _notification: youWereFollowed: "ಹಿಂಬಾಲಿಸಿದರà³" + _types: + login: "ಪà³à²°à²µà³‡à²¶" _actions: reply: "ಉತà³à²¤à²°à²¿à²¸à³" _deck: diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml index 082140f2e9..6c667b48da 100644 --- a/locales/ko-GS.yml +++ b/locales/ko-GS.yml @@ -601,8 +601,6 @@ reportAbuseOf: "{name}님얼 ì‹ ê³ í•˜ê¸°" reporter: "ì‹ ê³ í•œ 사람" reporteeOrigin: "ì‹ ê³ ë´ ì‚¬ëžŒ" reporterOrigin: "ì‹ ê³ í•œ ê³³" -forwardReport: "ì›¬ê² ì„œë²„ì— ì‹ ê³ ë³´ë‚´ê¸°" -forwardReportIsAnonymous: "ì›¬ê² ì„œë²„ì„œëŠ” 나으 ì •ë³´ëŸ´ 몬 ë³´ê³ ìµë©©ìœ¼ 시스템 ê²Œì •ì–´ë¡œ 보입니다." waitingFor: "{x}(ì–¼)럴 ì§€ë‹¬ë¦¬ê³ ìž‡ì‹ë‹ˆë‹¤" random: "무작ì´" system: "시스템" @@ -813,6 +811,7 @@ _notification: mention: "멘션" quote: "따오기" reaction: "반엉" + login: "로그ì¸" _actions: reply: "답하기" _deck: diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index f737a74d5d..757afe53f9 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -8,6 +8,9 @@ search: "검색" notifications: "알림" username: "ìœ ì €ëª…" password: "비밀번호" +initialPasswordForSetup: "초기 ì„¤ì •ìš© 비밀번호" +initialPasswordIsIncorrect: "초기 ì„¤ì •ìš© 비밀번호가 올바르지 않습니다." +initialPasswordForSetupDescription: "Misskey를 ì§ì ‘ 설치하는 경우, ì„¤ì • 파ì¼ì— ìž…ë ¥í•´ë‘” 비밀번호를 사용하세요.\nMisskey 설치를 ë„와주는 호스팅 서비스 ë“±ì„ ì‚¬ìš©í•˜ëŠ” 경우, 서비스 ì œê³µìžë¡œë¶€í„° ë°›ì€ ë¹„ë°€ë²ˆí˜¸ë¥¼ 사용하세요.\n비밀번호를 따로 ì„¤ì •í•˜ì§€ ì•Šì€ ê²½ìš°, ì•„ë¬´ê²ƒë„ ìž…ë ¥í•˜ì§€ ì•Šì•„ë„ ë©ë‹ˆë‹¤." forgotPassword: "비밀번호 ìž¬ì„¤ì •" fetchingAsApObject: "ì—°í•©ì—서 찾아보는 중" ok: "확ì¸" @@ -451,6 +454,7 @@ totpDescription: "ì¸ì¦ ì•±ì„ ì‚¬ìš©í•˜ì—¬ ì¼íšŒì„± 비밀번호 ìž…ë ¥" moderator: "모ë”ë ˆì´í„°" moderation: "ì¡°ì •" moderationNote: "ì¡°ì • 기ë¡" +moderationNoteDescription: "모ë”ë ˆì´í„° ì—í• ì„ ê°€ì§„ ìœ ì €ë§Œ ë³´ì´ëŠ” 메모를 ì ì„ ìˆ˜ 있습니다." addModerationNote: "ì¡°ì • ê¸°ë¡ ì¶”ê°€í•˜ê¸°" moderationLogs: "모ë”ë ˆì´ì…˜ 로그" nUsersMentioned: "{n}ëª…ì´ ì–¸ê¸‰í•¨" @@ -716,10 +720,7 @@ abuseReported: "ì‹ ê³ ë¥¼ 보냈습니다. ì‹ ê³ í•´ 주셔서 ê°ì‚¬í•©ë‹ˆë‹¤." reporter: "ì‹ ê³ ìž" reporteeOrigin: "í”¼ì‹ ê³ ìž" reporterOrigin: "ì‹ ê³ ìž" -forwardReport: "리모트 서버ì—ë„ ì‹ ê³ ë‚´ìš© 보내기" -forwardReportIsAnonymous: "리모트 서버ì—서는 ë‚˜ì˜ ì •ë³´ë¥¼ ë³¼ 수 없으며, ìµëª…ì˜ ì‹œìŠ¤í…œ ê³„ì •ìœ¼ë¡œ 표시ë©ë‹ˆë‹¤." send: "ì „ì†¡" -abuseMarkAsResolved: "í•´ê²°ë¨ìœ¼ë¡œ 표시" openInNewTab: "새 íƒì—서 열기" openInSideView: "사ì´ë“œë·°ë¡œ 열기" defaultNavigationBehaviour: "기본 íƒìƒ‰ ë™ìž‘" @@ -921,6 +922,7 @@ followersVisibility: "íŒ”ë¡œì›Œì˜ ê³µê°œ 범위" continueThread: "글타래 ë” ë³´ê¸°" deleteAccountConfirm: "ê³„ì •ì´ ì‚ì œë˜ê³ ë˜ëŒë¦´ 수 없게 ë©ë‹ˆë‹¤. 계ì†í•˜ì‹œê² 습니까? " incorrectPassword: "비밀번호가 올바르지 않습니다." +incorrectTotp: "OTP 번호가 í‹€ë ¸ê±°ë‚˜ ìœ íš¨ê¸°ê°„ì´ ë§Œë£Œë˜ì–´ ìžˆì„ ìˆ˜ 있습니다." voteConfirm: "\"{choice}\"ì— íˆ¬í‘œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?" hide: "숨기기" useDrawerReactionPickerForMobile: "모바ì¼ì—서 드로어 메뉴로 표시" @@ -1120,7 +1122,7 @@ preservedUsernames: "예약한 ì‚¬ìš©ìž ì´ë¦„" preservedUsernamesDescription: "ì˜ˆì•½í• ì‚¬ìš©ìžëª…ì„ í•œ ì¤„ì— í•˜ë‚˜ì”© ìž…ë ¥í•©ë‹ˆë‹¤. 여기ì—서 ì§€ì •í•œ 사용ìžëª…으로는 ê³„ì •ì„ ìƒì„±í• 수 없게 ë©ë‹ˆë‹¤. 단, ê´€ë¦¬ìž ê¶Œí•œìœ¼ë¡œ ê³„ì •ì„ ìƒì„±í• 때ì—는 해당ë˜ì§€ 않으며, ì´ë¯¸ 존재하는 ê³„ì •ë„ ì˜í–¥ì„ 받지 않습니다." createNoteFromTheFile: "ì´ íŒŒì¼ë¡œ 노트를 작성" archive: "ì•„ì¹´ì´ë¸Œ" -archived: "ë³´ê´€ë¨" +archived: "ì•„ì¹´ì´ë¸Œ ë¨" unarchive: "ë³´ê´€ 취소" channelArchiveConfirmTitle: "{name} 채ë„ì„ ë³´ì¡´í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" channelArchiveConfirmDescription: "보존한 채ë„ì€ ì±„ë„ ëª©ë¡ê³¼ 검색 ê²°ê³¼ì— í‘œì‹œë˜ì§€ 않으며 새로운 ë…¸íŠ¸ë„ ìž‘ì„±í• ìˆ˜ 없습니다." @@ -1283,6 +1285,15 @@ signinWithPasskey: "패스키로 로그ì¸" unknownWebAuthnKey: "등ë¡ë˜ì§€ ì•Šì€ íŒ¨ìŠ¤í‚¤ìž…ë‹ˆë‹¤." passkeyVerificationFailed: "패스키 ê²€ì¦ì„ 실패했습니다." passkeyVerificationSucceededButPasswordlessLoginDisabled: "패스키를 ê²€ì¦í–ˆìœ¼ë‚˜, 비밀번호 ì—†ì´ ë¡œê·¸ì¸í•˜ê¸°ê°€ êº¼ì ¸ 있습니다." +messageToFollower: "íŒ”ë¡œì›Œì— ë³´ë‚¼ 메시지" +target: "대ìƒ" +_abuseUserReport: + forward: "ì „ë‹¬" + forwardDescription: "ìµëª… 시스템 ê³„ì •ì„ ì‚¬ìš©í•˜ì—¬ 리모트 ì„œë²„ì— ì‹ ê³ ë‚´ìš©ì„ ì „ë‹¬í• ìˆ˜ 있습니다." + resolve: "í•´ê²°ë¨" + accept: "ì¸ìš©" + reject: "기ê°" + resolveTutorial: "ì ì ˆí•œ ì‹ ê³ ë‚´ìš©ì— ëŒ€ì‘한 경우, \"ì¸ìš©\"ì„ ì„ íƒí•˜ì—¬ \"í•´ê²°ë¨\"으로 기ë¡í•©ë‹ˆë‹¤.\nì ì ˆí•˜ì§€ ì•Šì€ ì‹ ê³ ë¥¼ ë°›ì€ ê²½ìš°, \"기ê°\"ì„ ì„ íƒí•˜ì—¬ \"기ê°\"으로 기ë¡í•©ë‹ˆë‹¤." _delivery: status: "ì „ì†¡ ìƒíƒœ" stop: "ì •ì§€ë¨" @@ -1989,7 +2000,7 @@ _sfx: _soundSettings: driveFile: "드ë¼ì´ë¸Œì— 있는 오디오를 사용" driveFileWarn: "드ë¼ì´ë¸Œì— 있는 파ì¼ì„ ì„ íƒí•˜ì„¸ìš”." - driveFileTypeWarn: "ì´ íŒŒì¼ì€ ì§€ì›ë˜ì§€ 않습니다." + driveFileTypeWarn: "ì´ íŒŒì´" driveFileTypeWarnDescription: "오디오 파ì¼ì„ ì„ íƒí•˜ì„¸ìš”." driveFileDurationWarn: "오디오가 너무 ê¹ë‹ˆë‹¤" driveFileDurationWarnDescription: "긴 오디오로 ì„¤ì •í• ê²½ìš° 미스키 ì‚¬ìš©ì— ì§€ìž¥ì´ ê°ˆ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. ê·¸ëž˜ë„ ê´œì°®ìŠµë‹ˆê¹Œ?" @@ -2392,6 +2403,7 @@ _notification: followedBySomeUsers: "{n}명ì—게 팔로우ë¨" flushNotification: "알림 ì´ë ¥ì„ 초기화" exportOfXCompleted: "{x} ì¶”ì¶œì— ì„±ê³µí–ˆìŠµë‹ˆë‹¤." + login: "ë¡œê·¸ì¸ ì•Œë¦¼ì´ ìžˆìŠµë‹ˆë‹¤" _types: all: "ì „ë¶€" note: "사용ìžì˜ 새 글" @@ -2407,6 +2419,7 @@ _notification: roleAssigned: "ì—í• ì´ ë¶€ì—¬ ë¨" achievementEarned: "ë„ì „ ê³¼ì œ íšë“" exportCompleted: "ì¶”ì¶œì„ ì„±ê³µí•¨" + login: "로그ì¸" test: "알림 테스트" app: "ì—°ë™ëœ ì•±ì„ í†µí•œ 알림" _actions: @@ -2470,7 +2483,7 @@ _webhookSettings: reaction: "누군가 ë‚´ ë…¸íŠ¸ì— ë¦¬ì•¡ì…˜í–ˆì„ ë•Œ" mention: "누군가 나를 ë©˜ì…˜í–ˆì„ ë•Œ" _systemEvents: - abuseReport: "ìœ ì €ë¡œë¶€í„° ì‹ ê³ ë¥¼ ë°›ì•˜ì„ ë•Œ" + abuseReport: "ìœ ì €ë¡" abuseReportResolved: "ë°›ì€ ì‹ ê³ ë¥¼ ì²˜ë¦¬í–ˆì„ ë•Œ" userCreated: "ìœ ì €ê°€ ìƒì„±ë˜ì—ˆì„ 때" deleteConfirm: "Webhookì„ ì‚ì œí• ê¹Œìš”?" @@ -2518,6 +2531,8 @@ _moderationLogTypes: markSensitiveDriveFile: "파ì¼ì— 열람주ì˜ë¥¼ ì„¤ì •" unmarkSensitiveDriveFile: "파ì¼ì— 열람주ì˜ë¥¼ í•´ì œ" resolveAbuseReport: "ì‹ ê³ ì²˜ë¦¬" + forwardAbuseReport: "ì‹ ê³ ì „ë‹¬" + updateAbuseReportNote: "ì‹ ê³ ì¡°ì • 노트 ê°±ì‹ " createInvitation: "초대 코드 ìƒì„±" createAd: "ê´‘ê³ ìƒì„±" deleteAd: "ê´‘ê³ ì‚ì œ" @@ -2657,7 +2672,7 @@ _urlPreviewSetting: timeoutDescription: "미리보기를 ë¡œë”©í•˜ëŠ”ë° ê±¸ë¦¬ëŠ” ì‹œê°„ì´ ì •í•œ 시간보다 오래 걸리는 경우, 미리보기를 ìƒì„±í•˜ì§€ 않습니다." maximumContentLength: "Content-Lengthì˜ ìµœëŒ€ì¹˜ (byte)" maximumContentLengthDescription: "Content-Lengthê°€ ì´ ê°’ì„ ë„˜ì–´ì„œë©´ 미리보기를 ìƒì„±í•˜ì§€ 않습니다." - requireContentLength: "Content-Length를 ì–»ì—ˆì„ ë•Œë§Œ 미리보기 만들기" + requireContentLength: "Content-Length를 받아온 경우ì—ë§Œ " requireContentLengthDescription: "ìƒëŒ€ 서버가 Content-Length를 ë˜ëŒë ¤ì£¼ì§€ 않는다면 미리보기를 만들지 않습니다." userAgent: "User-Agent" userAgentDescription: "미리보기를 ì–»ì„ ë•Œ 사용한 User-Agent를 ì„¤ì •í•©ë‹ˆë‹¤. 비어 있다면 ê¸°ë³¸ê°’ì˜ User-Agent를 사용합니다." diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml index 1bead5635d..b100d0300f 100644 --- a/locales/lo-LA.yml +++ b/locales/lo-LA.yml @@ -456,6 +456,7 @@ _notification: renote: "Renote" quote: "àºà»‰àº²àº‡àºàºµàº‡" reaction: "Reaction" + login: "ເຂົ້າ​ສູ່​ລະ​ບົບ" _actions: reply: "ຕàºàºšâ€‹àºàº±àºš" renote: "Renote" diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index eb48cf72da..dde3035357 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -486,6 +486,7 @@ _notification: renote: "Herdelen" quote: "Quote" reaction: "Reacties" + login: "Inloggen" _actions: reply: "Antwoord" renote: "Herdelen" diff --git a/locales/no-NO.yml b/locales/no-NO.yml index cd00ecf9ab..c5f61db745 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -701,6 +701,7 @@ _notification: renote: "Renotes" quote: "Sitater" reaction: "Reaksjoner" + login: "Logg inn" _actions: reply: "Svar" renote: "Renote" diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index f586ff2bff..117434ad32 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -689,10 +689,7 @@ abuseReported: "Twoje zgÅ‚oszenie zostaÅ‚o wysÅ‚ane. DziÄ™kujemy." reporter: "ZgÅ‚aszajÄ…cy" reporteeOrigin: "Pochodzenie zgÅ‚oszonego" reporterOrigin: "Pochodzenie zgÅ‚aszajÄ…cego" -forwardReport: "Przekaż zgÅ‚oszenie do innej instancji" -forwardReportIsAnonymous: "Zamiast twojego konta, anonimowe konto systemowe bÄ™dzie wyÅ›wietlone jako zgÅ‚aszajÄ…cy na instancji zdalnej." send: "WyÅ›lij" -abuseMarkAsResolved: "Oznacz zgÅ‚oszenie jako rozwiÄ…zane" openInNewTab: "Otwórz w nowej karcie" openInSideView: "Otwórz w bocznym widoku" defaultNavigationBehaviour: "DomyÅ›lne zachowanie nawigacji" @@ -1509,6 +1506,7 @@ _notification: reaction: "Reakcja" receiveFollowRequest: "Otrzymano proÅ›bÄ™ o możliwość obserwacji" followRequestAccepted: "PrzyjÄ™to proÅ›bÄ™ o możliwość obserwacji" + login: "Zaloguj siÄ™" app: "Powiadomienia z aplikacji" _actions: followBack: "zaobserwowaÅ‚ ciÄ™ z powrotem" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index 34de5066f3..98d42eb44a 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -1,5 +1,5 @@ --- -_lang_: "日本語" +_lang_: "Português" headlineMisskey: "Uma rede ligada por notas" introMisskey: "Bem-vindo! O Misskey é um serviço de microblog descentralizado de código aberto.\nCrie \"notas\" para compartilhar o que está acontecendo agora ou para se expressar com todos à sua volta 📡\nVocê também pode adicionar rapidamente reações à s notas de outras pessoas usando a função \"Reações\" ðŸ‘\nVamos explorar um novo mundo 🚀" poweredByMisskeyDescription: "{name} é uma instância da plataforma de código aberto <b>Misskey</b>." @@ -707,10 +707,7 @@ abuseReported: "Denúncia enviada. Obrigado por sua ajuda." reporter: "Denunciante" reporteeOrigin: "Origem da denúncia" reporterOrigin: "Origem do denunciante" -forwardReport: "Encaminhar a denúncia para o servidor remoto" -forwardReportIsAnonymous: "No servidor remoto, suas informações não serão visÃveis, e você será apresentado como uma conta do sistema anônima." send: "Enviar" -abuseMarkAsResolved: "Marcar denúncia como resolvida" openInNewTab: "Abrir em nova aba" openInSideView: "Abrir em visão lateral" defaultNavigationBehaviour: "Navegação padrão" @@ -1061,7 +1058,7 @@ resetPasswordConfirm: "Deseja realmente mudar a sua senha?" sensitiveWords: "Palavras sensÃveis" sensitiveWordsDescription: "A visibilidade de todas as notas contendo as palavras configuradas será colocadas como \"InÃcio\" automaticamente. Você pode listar várias delas separando-as por linha." sensitiveWordsDescription2: "Utilizar espaços irá criar expressões aditivas (AND) e cercar palavras-chave com barras irá transformá-las em expressões regulares (RegEx)" -prohibitedWords: "Palavras proibÃdas" +prohibitedWords: "Palavras proibidas" prohibitedWordsDescription: "Habilita um erro ao tentar publicar uma nota contendo as palavras escolhidas. Várias palavras podem ser escolhidas, separando-as por linha." prohibitedWordsDescription2: "Utilizar espaços irá criar expressões aditivas (AND) e cercar palavras-chave com barras irá transformá-las em expressões regulares (RegEx)" hiddenTags: "Hashtags escondidas" @@ -1419,7 +1416,7 @@ _achievements: _types: _notes1: title: "Configurando o meu misskey" - description: "Post uma nota pela primeira vez" + description: "Poste uma nota pela primeira vez" flavor: "Divirta-se com o Misskey!" _notes10: title: "Algumas notas" @@ -2376,6 +2373,7 @@ _notification: followRequestAccepted: "Aceitou pedidos de seguidor" roleAssigned: "Cargo dado" achievementEarned: "Conquista desbloqueada" + login: "Iniciar sessão" app: "Notificações de aplicativos conectados" _actions: followBack: "te seguiu de volta" diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index a5f8057860..3cc09aa5c2 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -625,10 +625,7 @@ abuseReported: "Raportul tău a fost trimis. MulÈ›umim." reporter: "Raportorul" reporteeOrigin: "Originea raportatului" reporterOrigin: "Originea raportorului" -forwardReport: "RedirecÈ›ionează raportul către instanÈ›a externă" -forwardReportIsAnonymous: "ÃŽn locul contului tău, va fi afiÈ™at un cont anonim, de sistem, ca raportor către instanÈ›a externă." send: "Trimite" -abuseMarkAsResolved: "Marchează raportul ca rezolvat" openInNewTab: "Deschide în tab nou" openInSideView: "Deschide în vedere laterală" defaultNavigationBehaviour: "Comportament de navigare implicit" @@ -714,6 +711,7 @@ _notification: renote: "Re-notează" quote: "Citează" reaction: "ReacÈ›ie" + login: "Autentifică-te" _actions: reply: "Răspunde" renote: "Re-notează" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index cdc4898a3b..befb537105 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -700,10 +700,7 @@ abuseReported: "Жалоба отправлена. Большое ÑпаÑибо reporter: "Сообщивший" reporteeOrigin: "О ком Ñообщено" reporterOrigin: "Кто Ñообщил" -forwardReport: "Отправить жалобу на инÑÑ‚Ð°Ð½Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð°." -forwardReportIsAnonymous: "Жалоба на удалённый инÑÑ‚Ð°Ð½Ñ Ð±ÑƒÐ´ÐµÑ‚ отправлена анонимно. ВмеÑто ваших данных у Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ‚ÐµÐ»Ñ Ð±ÑƒÐ´ÐµÑ‚ отображена ÑиÑÑ‚ÐµÐ¼Ð½Ð°Ñ ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ." send: "Отправить" -abuseMarkAsResolved: "Отметить жалобу как решённую" openInNewTab: "Открыть в новой вкладке" openInSideView: "Открывать в боковой колонке" defaultNavigationBehaviour: "Поведение навигации по умолчанию" @@ -2046,6 +2043,7 @@ _notification: receiveFollowRequest: "Получен Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подпиÑку" followRequestAccepted: "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подпиÑку одобрен" achievementEarned: "Получение доÑтижений" + login: "Войти" app: "Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· приложений" _actions: followBack: "отвечает взаимной подпиÑкой" diff --git a/locales/si-LK.yml b/locales/si-LK.yml index e130d68ed8..c43f3d860d 100644 --- a/locales/si-LK.yml +++ b/locales/si-LK.yml @@ -17,3 +17,6 @@ _sfx: note: "à¶±à·à¶§à·Š" _profile: username: "පරිà·à·“ලක à¶±à·à¶¸à¶º" +_notification: + _types: + login: "පිවිසෙන්න" diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index eb1675bdb0..8cb73e1303 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -631,10 +631,7 @@ abuseReported: "VaÅ¡e nahlásenie je odoslané. Veľmi pekne Äakujeme." reporter: "Nahlásil" reporteeOrigin: "Pôvod nahláseného" reporterOrigin: "Pôvod nahlasovaÄa" -forwardReport: "PreposlaÅ¥ nahlásenie na server" -forwardReportIsAnonymous: "Namiesto vášho úÄtu bude zobrazený anonymný systémový úÄet na vzdialenom serveri ako autor nahlásenia." send: "PoslaÅ¥" -abuseMarkAsResolved: "OznaÄiÅ¥ nahlásenia ako vyrieÅ¡ené" openInNewTab: "OtvoriÅ¥ v novom tabe" openInSideView: "OtvoriÅ¥ v boÄnom paneli" defaultNavigationBehaviour: "Predvolené správanie navigácie" @@ -1409,6 +1406,7 @@ _notification: pollEnded: "Hlasovanie skonÄilo" receiveFollowRequest: "DoruÄené žiadosti o sledovanie" followRequestAccepted: "Schválené žiadosti o sledovanie" + login: "PrihlásiÅ¥ sa" app: "Oznámenia z prepojených aplikáciÃ" _actions: followBack: "SledovaÅ¥ späť\n" diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index c1a998b8fb..5a0de660e8 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -562,6 +562,7 @@ _notification: renote: "Omnotera" quote: "Citat" reaction: "Reaktioner" + login: "Logga in" _actions: reply: "Svara" renote: "Omnotera" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index f5d29a2ce5..31eee2bccc 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -707,10 +707,7 @@ abuseReported: "เราได้ส่งรายงานขà¸à¸‡à¸„ุณà reporter: "ผู้รายงาน" reporteeOrigin: "ปลายทางรายงาน" reporterOrigin: "à¹à¸«à¸¥à¹ˆà¸‡à¸œà¸¹à¹‰à¸£à¸²à¸¢à¸‡à¸²à¸™" -forwardReport: "ส่งต่à¸à¸£à¸²à¸¢à¸‡à¸²à¸™à¹„ปยังเซิร์ฟเวà¸à¸£à¹Œà¸£à¸°à¸¢à¸°à¹„à¸à¸¥" -forwardReportIsAnonymous: "ข้à¸à¸¡à¸¹à¸¥à¸‚à¸à¸‡à¸„ุณจะไม่ปราà¸à¸à¸šà¸™à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸à¸£à¹Œà¸£à¸°à¸¢à¸°à¹„à¸à¸¥à¹à¸¥à¸°à¸›à¸£à¸²à¸à¸à¹€à¸›à¹‡à¸™à¸šà¸±à¸à¸Šà¸µà¸£à¸°à¸šà¸šà¸—ี่ไม่ระบุชื่à¸" send: "ส่ง" -abuseMarkAsResolved: "ทำเครื่à¸à¸‡à¸«à¸¡à¸²à¸¢à¸£à¸²à¸¢à¸‡à¸²à¸™à¸§à¹ˆà¸²à¹à¸à¹‰à¹„ขà¹à¸¥à¹‰à¸§" openInNewTab: "เปิดในà¹à¸—็บใหม่" openInSideView: "เปิดในมุมมà¸à¸‡à¸”้านข้าง" defaultNavigationBehaviour: "พฤติà¸à¸£à¸£à¸¡à¸à¸²à¸£à¸™à¸³à¸—างที่เป็นค่าเริ่มต้น" @@ -2374,6 +2371,7 @@ _notification: followRequestAccepted: "à¸à¸™à¸¸à¸¡à¸±à¸•ิให้ติดตามà¹à¸¥à¹‰à¸§" roleAssigned: "ให้บทบาท" achievementEarned: "ปลดล็à¸à¸à¸„วามสำเร็จà¹à¸¥à¹‰à¸§" + login: "เข้าสู่ระบบ" app: "à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•ืà¸à¸™à¸ˆà¸²à¸à¹à¸à¸›à¸—ี่มีลิงà¸à¹Œ" _actions: followBack: "ติดตามà¸à¸¥à¸±à¸šà¸”้วย" diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index cf6729a81d..fe2f158ff6 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -446,6 +446,7 @@ _notification: reaction: "Tepkiler" receiveFollowRequest: "Takip isteÄŸi alındı" followRequestAccepted: "Takip isteÄŸi kabul edildi" + login: "GiriÅŸ Yap " _actions: reply: "yanıt" renote: "vazgeçme" diff --git a/locales/ug-CN.yml b/locales/ug-CN.yml index e48f64511c..fef26040a5 100644 --- a/locales/ug-CN.yml +++ b/locales/ug-CN.yml @@ -17,3 +17,6 @@ _2fa: renewTOTPCancel: "ئۇنى توختىتىÚ" _widgets: profile: "profile" +_notification: + _types: + login: "كىرىش" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index e51156ce22..974508b3a7 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -630,10 +630,7 @@ abuseReported: "ДÑкуємо, вашу Ñкаргу було відправлРreporter: "Репортер" reporteeOrigin: "Про кого повідомлено" reporterOrigin: "Хто повідомив" -forwardReport: "ПереÑлати звіт на віддалений інÑтанÑ" -forwardReportIsAnonymous: "ЗаміÑть вашого облікового запиÑу анонімний ÑиÑтемний обліковий Ð·Ð°Ð¿Ð¸Ñ Ð±ÑƒÐ´Ðµ відображатиÑÑ Ñк доповідач на віддаленому інÑтанÑÑ–" send: "Відправити" -abuseMarkAsResolved: "Позначити Ñкаргу Ñк вирішену" openInNewTab: "Відкрити в новій вкладці" openInSideView: "Відкрити збоку" defaultNavigationBehaviour: "Поведінка навігації за замовчуваннÑм" @@ -1587,6 +1584,7 @@ _notification: reaction: "Реакції" receiveFollowRequest: "Запити на підпиÑку" followRequestAccepted: "ПрийнÑті підпиÑки" + login: "Увійти" app: "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ додатків" _actions: reply: "ВідповіÑти" diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml index cf2e5f2fe7..37a550008a 100644 --- a/locales/uz-UZ.yml +++ b/locales/uz-UZ.yml @@ -629,10 +629,7 @@ abuseReported: "Shikoyatingiz yetkazildi. Ma'lumot uchun rahmat." reporter: "Shikoyat qiluvchi" reporteeOrigin: "Xabarning kelib chiqishi" reporterOrigin: "Xabarchining joylashuvi" -forwardReport: "Xabarni masofadagi serverga yuborish" -forwardReportIsAnonymous: "Sizning yuborayotgan xabaringiz o'z akkountingiz emas balki anonim tarzda qoladi" send: "Yuborish" -abuseMarkAsResolved: "Yuborilgan xabarni hal qilingan deb belgilash" openInNewTab: "Yangi tab da ochish" openInSideView: "Yon panelda ochish" defaultNavigationBehaviour: "Standart navigatsiya harakati" @@ -1057,6 +1054,7 @@ _notification: quote: "Iqtibos keltirish" reaction: "Reaktsiyalar" receiveFollowRequest: "Qabul qilingan kuzatuv so'rovlari" + login: "Kirish" _actions: reply: "Javob berish" renote: "Qayta qayd qilish" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index f3979bbd3c..6cf9b3f278 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -675,10 +675,7 @@ abuseReported: "Báo cáo đã được gá»i. Cảm Æ¡n bạn nhiá»u." reporter: "Ngưá»i báo cáo" reporteeOrigin: "Bị báo cáo" reporterOrigin: "Máy chá»§ ngưá»i báo cáo" -forwardReport: "Chuyển tiếp báo cáo cho máy chá»§ từ xa" -forwardReportIsAnonymous: "Thay vì tà i khoản cá»§a bạn, má»™t tà i khoản hệ thống ẩn danh sẽ được hiển thị dưới dạng ngưá»i báo cáo ở máy chá»§ từ xa." send: "Gá»i" -abuseMarkAsResolved: "Äánh dấu đã xá» lý" openInNewTab: "Mở trong tab má»›i" openInSideView: "Mở trong thanh bên" defaultNavigationBehaviour: "Thao tác Ä‘iá»u hướng mặc định" @@ -1878,6 +1875,7 @@ _notification: receiveFollowRequest: "Yêu cầu theo dõi" followRequestAccepted: "Yêu cầu theo dõi được chấp nháºn" achievementEarned: "Hoà n thà nh Achievement" + login: "Äăng nháºp" app: "Từ app liên kết" _actions: followBack: "đã theo dõi lại bạn" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 0d76361d6f..09feca5b4e 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -8,6 +8,9 @@ search: "æœç´¢" notifications: "通知" username: "用户å" password: "密ç " +initialPasswordForSetup: "åˆå§‹åŒ–密ç " +initialPasswordIsIncorrect: "åˆå§‹åŒ–密ç 䏿£ç¡®" +initialPasswordForSetupDescription: "如果是自己安装的 Misskey,请输入é…置文件里设好的密ç 。\n如果使用的是 Misskey 的托管æœåŠ¡ç‰ï¼Œè¯·è¾“å…¥æœåС商æä¾›çš„密ç 。\n如果没有设置密ç ,请留空并继ç»ã€‚" forgotPassword: "忘记密ç " fetchingAsApObject: "在è”邦宇宙查询ä¸..." ok: "OK" @@ -90,7 +93,7 @@ followsYou: "æ£åœ¨å…³æ³¨ä½ " createList: "创建列表" manageLists: "管ç†åˆ—表" error: "错误" -somethingHappened: "出现了一些问题ï¼" +somethingHappened: "出错了" retry: "é‡è¯•" pageLoadError: "页é¢åŠ è½½å¤±è´¥ã€‚" pageLoadErrorDescription: "这通常是由于网络或æµè§ˆå™¨ç¼“å˜çš„åŽŸå› ã€‚è¯·æ¸…é™¤ç¼“å˜æˆ–ç‰å¾…片刻åŽé‡è¯•。" @@ -167,7 +170,7 @@ emojiUrl: "emoji 地å€" addEmoji: "æ·»åŠ è¡¨æƒ…ç¬¦å·" settingGuide: "推èé…ç½®" cacheRemoteFiles: "缓å˜è¿œç¨‹æ–‡ä»¶" -cacheRemoteFilesDescription: "å¯ç”¨æ¤è®¾å®šæ—¶ï¼Œå°†åœ¨æ¤æœåŠ¡å™¨ä¸Šç¼“å˜è¿œç¨‹æ–‡ä»¶ã€‚虽然å¯ä»¥åŠ å¿«å›¾ç‰‡æ˜¾ç¤ºçš„é€Ÿåº¦ï¼Œä½†æ˜¯ç›¸å¯¹çš„ä¼šæ¶ˆè€—å¤§é‡çš„æœåŠ¡å™¨å˜å‚¨ç©ºé—´ã€‚用户角色内的网盘容é‡å†³å®šäº†è¿™ä¸ªè¿œç¨‹ç”¨æˆ·èƒ½åœ¨æœåŠ¡å™¨ä¸Šä¿ç•™ä¿ç•™å¤šå°‘缓å˜ã€‚当超出了这个é™åˆ¶æ—¶ï¼Œæ—§çš„æ–‡ä»¶å°†ä»Žç¼“å˜ä¸è¢«åˆ 除,æˆä¸ºé“¾æŽ¥ã€‚当ç¦ç”¨æ¤è®¾å®šæ—¶ï¼Œåˆ™æ˜¯ä»Žä¸€å¼€å§‹å°±å°†è¿œç¨‹æ–‡ä»¶ä¿ç•™ä¸ºé“¾æŽ¥ã€‚æ¤æ—¶æŽ¨èå°† default.yml çš„ proxyRemoteFiles 设置为 true 以优化缩略图生æˆåŠä¿æŠ¤ç”¨æˆ·éšç§ã€‚" +cacheRemoteFilesDescription: "å¯ç”¨æ¤è®¾å®šæ—¶ï¼Œå°†åœ¨æ¤æœåŠ¡å™¨ä¸Šç¼“å˜è¿œç¨‹æ–‡ä»¶ã€‚虽然å¯ä»¥åŠ å¿«å›¾ç‰‡æ˜¾ç¤ºçš„é€Ÿåº¦ï¼Œä½†æ˜¯ç›¸å¯¹çš„ä¼šæ¶ˆè€—å¤§é‡çš„æœåŠ¡å™¨å˜å‚¨ç©ºé—´ã€‚用户角色内的网盘容é‡å†³å®šäº†è¿™ä¸ªè¿œç¨‹ç”¨æˆ·èƒ½åœ¨æœåŠ¡å™¨ä¸Šä¿ç•™å¤šå°‘缓å˜ã€‚当超出了这个é™åˆ¶æ—¶ï¼Œæ—§çš„æ–‡ä»¶å°†ä»Žç¼“å˜ä¸è¢«åˆ 除,æˆä¸ºé“¾æŽ¥ã€‚当ç¦ç”¨æ¤è®¾å®šæ—¶ï¼Œåˆ™æ˜¯ä»Žä¸€å¼€å§‹å°±å°†è¿œç¨‹æ–‡ä»¶ä¿ç•™ä¸ºé“¾æŽ¥ã€‚æ¤æ—¶æŽ¨èå°† default.yml çš„ proxyRemoteFiles 设置为 true 以优化缩略图生æˆåŠä¿æŠ¤ç”¨æˆ·éšç§ã€‚" youCanCleanRemoteFilesCache: "å¯ä»¥ä½¿ç”¨æ–‡ä»¶ç®¡ç†çš„ðŸ—‘ï¸æŒ‰é’®æ¥åˆ 除所有的缓å˜ã€‚" cacheRemoteSensitiveFiles: "缓å˜è¿œç¨‹æ•感媒体文件" cacheRemoteSensitiveFilesDescription: "如果ç¦ç”¨è¿™é¡¹è®¾å®šï¼Œè¿œç¨‹æœåŠ¡å™¨çš„æ•æ„Ÿåª’体将ä¸ä¼šè¢«ç¼“å˜ï¼Œè€Œæ˜¯ç›´æŽ¥é“¾æŽ¥ã€‚" @@ -236,6 +239,8 @@ silencedInstances: "被é™éŸ³çš„æœåŠ¡å™¨" silencedInstancesDescription: "设置è¦é™éŸ³çš„æœåŠ¡å™¨ï¼Œä»¥æ¢è¡Œåˆ†éš”。被é™éŸ³çš„æœåŠ¡å™¨å†…æ‰€æœ‰çš„è´¦æˆ·å°†é»˜è®¤å¤„äºŽã€Œé™éŸ³ã€çжæ€ï¼Œä»…能å‘é€å…³æ³¨è¯·æ±‚,并且在未关注状æ€ä¸‹æ— 法æåŠæœ¬åœ°è´¦æˆ·ã€‚被阻æ¢çš„实例ä¸å—å½±å“。" mediaSilencedInstances: "å·²éšè—媒体文件的æœåС噍" mediaSilencedInstancesDescription: "设置è¦éšè—媒体文件的æœåŠ¡å™¨ï¼Œä»¥æ¢è¡Œåˆ†éš”。被设置为éšè—媒体文件æœåŠ¡å™¨å†…æ‰€æœ‰è´¦å·çš„æ–‡ä»¶å‡æŒ‰ç…§ã€Œæ•感内容ã€å¤„ç†ï¼Œä¸”å°†æ— æ³•ä½¿ç”¨è‡ªå®šä¹‰è¡¨æƒ…ç¬¦å·ã€‚被阻æ¢çš„实例ä¸å—å½±å“。" +federationAllowedHosts: "å…许è”åˆçš„æœåŠ¡å™¨" +federationAllowedHostsDescription: "设定å…许è”åˆçš„æœåŠ¡å™¨ï¼Œä»¥æ¢è¡Œåˆ†éš”。" muteAndBlock: "é™éŸ³/拉黑" mutedUsers: "å·²é™éŸ³ç”¨æˆ·" blockedUsers: "已拉黑的用户" @@ -449,6 +454,7 @@ totpDescription: "使用验è¯å™¨è¾“入一次性密ç " moderator: "监察员" moderation: "管ç†" moderationNote: "管ç†ç¬”è®°" +moderationNoteDescription: "å¯ä»¥ç”¨æ¥è®°å½•仅在管ç†å‘˜ä¹‹é—´å…±äº«çš„笔记。" addModerationNote: "æ·»åŠ ç®¡ç†ç¬”è®°" moderationLogs: "ç®¡ç†æ—¥å¿—" nUsersMentioned: "{n} 被æåˆ°" @@ -512,6 +518,7 @@ emojiStyle: "表情符å·çš„æ ·å¼" native: "原生" menuStyle: "èœå•æ ·å¼" style: "æ ·å¼" +drawer: "抽屉" popup: "弹窗" showNoteActionsOnlyHover: "ä»…åœ¨æ‚¬åœæ—¶æ˜¾ç¤ºå¸–åæ“ä½œ" showReactionsCount: "显示帖å的回应数" @@ -713,10 +720,7 @@ abuseReported: "内容已å‘é€ã€‚感谢您æäº¤ä¿¡æ¯ã€‚" reporter: "举报者" reporteeOrigin: "ä¸¾æŠ¥æ¥æº" reporterOrigin: "ä¸¾æŠ¥è€…æ¥æº" -forwardReport: "将该举报信æ¯è½¬å‘给远程æœåС噍" -forwardReportIsAnonymous: "在远程实例上显示的报告者是匿å的系统账å·ï¼Œè€Œä¸æ˜¯æ‚¨çš„è´¦å·ã€‚" send: "å‘é€" -abuseMarkAsResolved: "处ç†å®Œæ¯•" openInNewTab: "åœ¨æ–°æ ‡ç¾é¡µä¸æ‰“å¼€" openInSideView: "在侧边æ 䏿‰“å¼€" defaultNavigationBehaviour: "默认导航" @@ -918,6 +922,7 @@ followersVisibility: "关注者的公开范围" continueThread: "查看更多帖å" deleteAccountConfirm: "å°†è¦åˆ 除账户。是å¦ç¡®è®¤ï¼Ÿ" incorrectPassword: "密ç 错误" +incorrectTotp: "一次性密ç 䏿£ç¡®æˆ–已过期" voteConfirm: "确定投给 “{choice}†?" hide: "éšè—" useDrawerReactionPickerForMobile: "在移动设备上使用抽屉显示" @@ -1194,10 +1199,10 @@ followingOrFollower: "å…³æ³¨ä¸æˆ–关注者" fileAttachedOnly: "ä»…é™åª’体" showRepliesToOthersInTimeline: "在时间线ä¸åŒ…å«ç»™åˆ«äººçš„回å¤" hideRepliesToOthersInTimeline: "在时间线ä¸éšè—给别人的回å¤" -showRepliesToOthersInTimelineAll: "在时间线ä¸åŒ…å«çŽ°åœ¨å…³æ³¨çš„æ‰€æœ‰äººçš„å›žå¤" -hideRepliesToOthersInTimelineAll: "在时间线ä¸éšè—现在关注的所有人的回å¤" -confirmShowRepliesAll: "æ¤æ“作ä¸å¯æ’¤é”€ã€‚确认è¦åœ¨æ—¶é—´çº¿ä¸åŒ…å«çŽ°åœ¨å…³æ³¨çš„æ‰€æœ‰äººçš„å›žå¤å—?" -confirmHideRepliesAll: "æ¤æ“作ä¸å¯æ’¤é”€ã€‚确认è¦åœ¨æ—¶é—´çº¿ä¸éšè—现在关注的所有人的回å¤å—?" +showRepliesToOthersInTimelineAll: "åœ¨æ—¶é—´çº¿ä¸æ˜¾ç¤ºæ‰€æœ‰çŽ°åœ¨å…³æ³¨çš„äººçš„å›žå¤" +hideRepliesToOthersInTimelineAll: "在时间线ä¸éšè—所有现在关注的人的回å¤" +confirmShowRepliesAll: "æ¤æ“作ä¸å¯æ’¤é”€ã€‚确认è¦åœ¨æ—¶é—´çº¿ä¸æ˜¾ç¤ºæ‰€æœ‰çŽ°åœ¨å…³æ³¨çš„äººçš„å›žå¤å—?" +confirmHideRepliesAll: "æ¤æ“作ä¸å¯æ’¤é”€ã€‚确认è¦åœ¨æ—¶é—´çº¿ä¸éšè—所有现在关注的人的回å¤å—?" externalServices: "外部æœåŠ¡" sourceCode: "æºä»£ç " sourceCodeIsNotYetProvided: "还未æä¾›æºä»£ç 。è¦è§£å†³æ¤é—®é¢˜è¯·è”系管ç†å‘˜ã€‚" @@ -1273,10 +1278,22 @@ genEmbedCode: "生æˆåµŒå…¥ä»£ç " noteOfThisUser: "æ¤ç”¨æˆ·çš„帖å" clipNoteLimitExceeded: "æ— æ³•å†å¾€æ¤ä¾¿ç¾å†…æ·»åŠ æ›´å¤šå¸–å" performance: "性能" +modified: "æœ‰å˜æ›´" +discard: "å–æ¶ˆ" +thereAreNChanges: "有 {n} 处更改" signinWithPasskey: "使用通行密钥登录" unknownWebAuthnKey: "æ¤é€šè¡Œå¯†é’¥æœªæ³¨å†Œã€‚" passkeyVerificationFailed: "验è¯é€šè¡Œå¯†é’¥å¤±è´¥ã€‚" passkeyVerificationSucceededButPasswordlessLoginDisabled: "é€šè¡Œå¯†é’¥éªŒè¯æˆåŠŸï¼Œä½†è´¦æˆ·æœªå¼€å¯æ— 密ç 登录。" +messageToFollower: "给关注者的消æ¯" +target: "对象" +_abuseUserReport: + forward: "转å‘" + forwardDescription: "ç›®æ ‡æ˜¯åŒ¿å系统账户,将把举报转å‘给远程æœåŠ¡å™¨ã€‚" + resolve: "解决" + accept: "确认" + reject: "æ‹’ç»" + resolveTutorial: "如果举报内容有ç†ä¸”已解决,选择「确认ã€å°†æ¡ˆä»¶ä»¥è‚¯å®šçš„æ€åº¦æ ‡è®°ä¸ºå·²è§£å†³ã€‚\n如果举报内容站ä¸ä½è„šï¼Œé€‰æ‹©ã€Œæ‹’ç»ã€å°†æ¡ˆä»¶ä»¥å¦å®šçš„æ€åº¦æ ‡è®°ä¸ºå·²è§£å†³ã€‚" _delivery: status: "投递状æ€" stop: "åœæ¢æŠ•递" @@ -1613,7 +1630,7 @@ _achievements: _postedAt0min0sec: title: "报时" description: "在 0 点å‘布一篇帖å" - flavor: "æŠ¥æ—¶ä¿¡å·æœ€åŽä¸€å“,零点整" + flavor: "嘟 · 嘟 · 嘟 · 哔——" _selfQuote: title: "自我引用" description: "引用了自己的帖å" @@ -2244,6 +2261,9 @@ _profile: changeBanner: "修改横幅" verifiedLinkDescription: "如果将内容设置为 URL,当链接所指å‘的网页内包å«è‡ªå·±çš„个人资料链接时,å¯ä»¥æ˜¾ç¤ºä¸€ä¸ªå·²éªŒè¯å›¾æ ‡ã€‚" avatarDecorationMax: "æœ€å¤šå¯æ·»åŠ {max} 个挂件" + followedMessage: "被关注时显示的消æ¯" + followedMessageDescription: "å¯ä»¥è®¾ç½®è¢«å…³æ³¨æ—¶å‘å¯¹æ–¹æ˜¾ç¤ºçš„çŸæ¶ˆæ¯ã€‚" + followedMessageDescriptionForLockedAccount: "éœ€è¦æ‰¹å‡†æ‰èƒ½å…³æ³¨çš„æƒ…å†µä¸‹ï¼Œæ¶ˆæ¯æ˜¯åœ¨è¢«è¯·æ±‚è¢«æ‰¹å‡†åŽæ˜¾ç¤ºã€‚" _exportOrImport: allNotes: "所有帖å" favoritedNotes: "æ”¶è—的帖å" @@ -2383,6 +2403,7 @@ _notification: followedBySomeUsers: "被 {n} 人关注" flushNotification: "é‡ç½®é€šçŸ¥åކå²" exportOfXCompleted: "å·²å®Œæˆ {x} 个导出" + login: "有新的登录" _types: all: "全部" note: "用户的新帖å" @@ -2398,6 +2419,7 @@ _notification: roleAssigned: "授予的角色" achievementEarned: "å–å¾—çš„æˆå°±" exportCompleted: "已完æˆå¯¼å‡º" + login: "登录" test: "测试通知" app: "å…³è”应用的通知" _actions: @@ -2509,6 +2531,8 @@ _moderationLogTypes: markSensitiveDriveFile: "æ ‡è®°ç½‘ç›˜æ–‡ä»¶ä¸ºæ•æ„Ÿåª’体" unmarkSensitiveDriveFile: "å–æ¶ˆæ ‡è®°ç½‘ç›˜æ–‡ä»¶ä¸ºæ•æ„Ÿåª’体" resolveAbuseReport: "处ç†ä¸¾æŠ¥" + forwardAbuseReport: "转å‘举报" + updateAbuseReportNote: "更新举报用管ç†ç¬”è®°" createInvitation: "生æˆé‚€è¯·ç " createAd: "创建了广告" deleteAd: "åˆ é™¤äº†å¹¿å‘Š" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 74c03befd1..5e8a5d8f8d 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -8,6 +8,9 @@ search: "æœå°‹" notifications: "通知" username: "使用者å稱" password: "密碼" +initialPasswordForSetup: "åˆå§‹è¨å®šç”¨çš„密碼" +initialPasswordIsIncorrect: "åˆå§‹è¨å®šç”¨çš„密碼錯誤。" +initialPasswordForSetupDescription: "如果您自己安è£äº† Misskey,請使用您在è¨å®šæª”ä¸è¼¸å…¥çš„密碼。\n如果您使用 Misskey 的託管æœå‹™ä¹‹é¡žçš„æœå‹™ï¼Œè«‹ä½¿ç”¨æä¾›çš„密碼。\n如果您尚未è¨å®šå¯†ç¢¼ï¼Œè«‹å°‡å…¶ç•™ç©ºä¸¦ç¹¼çºŒã€‚" forgotPassword: "忘記密碼" fetchingAsApObject: "從è¯é‚¦å®‡å®™å–å¾—ä¸..." ok: "OK" @@ -716,10 +719,7 @@ abuseReported: "檢舉完æˆã€‚æ„Ÿè¬æ‚¨çš„å ±å‘Šã€‚" reporter: "檢舉者" reporteeOrigin: "檢舉來æº" reporterOrigin: "檢舉者來æº" -forwardReport: "å°‡å ±å‘Šè½‰é€çµ¦é 端伺æœå™¨" -forwardReportIsAnonymous: "在é 端實例上看ä¸åˆ°æ‚¨çš„è³‡è¨Šï¼Œé¡¯ç¤ºçš„å ±å‘Šè€…æ˜¯åŒ¿å的系统帳戶。" send: "發é€" -abuseMarkAsResolved: "處ç†å®Œç•¢" openInNewTab: "在新分é ä¸é–‹å•Ÿ" openInSideView: "åœ¨å´æ¬„ä¸é–‹å•Ÿ" defaultNavigationBehaviour: "é è¨å°Žèˆª" @@ -921,6 +921,7 @@ followersVisibility: "追隨者的å¯è¦‹æ€§" continueThread: "查看更多貼文" deleteAccountConfirm: "å°‡è¦åˆªé™¤å¸³æˆ¶ã€‚是å¦ç¢ºå®šï¼Ÿ" incorrectPassword: "密碼錯誤。" +incorrectTotp: "ä¸€æ¬¡æ€§å¯†ç¢¼éŒ¯èª¤ï¼Œæˆ–è€…å·²éŽæœŸã€‚" voteConfirm: "確定投給「{choice}ã€ï¼Ÿ" hide: "éš±è—" useDrawerReactionPickerForMobile: "在移動è¨å‚™ä¸Šä½¿ç”¨æŠ½å±œé¡¯ç¤º" @@ -1283,6 +1284,7 @@ signinWithPasskey: "使用密碼金鑰登入" unknownWebAuthnKey: "未註冊的金鑰。" passkeyVerificationFailed: "é©—è‰é‡‘鑰失敗。" passkeyVerificationSucceededButPasswordlessLoginDisabled: "é›–ç„¶é©—è‰é‡‘é‘°æˆåŠŸï¼Œä½†æ˜¯ç„¡å¯†ç¢¼ç™»å…¥çš„æ–¹å¼æ˜¯åœç”¨çš„。" +messageToFollower: "給追隨者的訊æ¯" _delivery: status: "傳é€ç‹€æ…‹" stop: "åœæ¢ç™¼é€" @@ -2392,6 +2394,7 @@ _notification: followedBySomeUsers: "被{n}人追隨了" flushNotification: "é‡ç½®é€šçŸ¥æ·å²ç´€éŒ„" exportOfXCompleted: "{x} 的匯出已完æˆã€‚" + login: "已登入" _types: all: "全部 " note: "使用者的最新貼文" @@ -2407,6 +2410,7 @@ _notification: roleAssigned: "已授予角色" achievementEarned: "ç²å¾—æˆå°±" exportCompleted: "已完æˆåŒ¯å‡ºã€‚" + login: "登入" test: "通知測試" app: "應用程å¼é€šçŸ¥" _actions: diff --git a/package.json b/package.json index edc1d7e318..3afd84253a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2024.9.0", + "version": "2024.10.0", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/backend/assets/tabler-badges/login-2.png b/packages/backend/assets/tabler-badges/login-2.png Binary files differnew file mode 100644 index 0000000000..f3ca8de3dd --- /dev/null +++ b/packages/backend/assets/tabler-badges/login-2.png diff --git a/packages/backend/migration/1728085812127-refine-abuse-user-report.js b/packages/backend/migration/1728085812127-refine-abuse-user-report.js new file mode 100644 index 0000000000..57cbfdcf6d --- /dev/null +++ b/packages/backend/migration/1728085812127-refine-abuse-user-report.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class RefineAbuseUserReport1728085812127 { + name = 'RefineAbuseUserReport1728085812127' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "moderationNote" character varying(8192) NOT NULL DEFAULT ''`); + await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "resolvedAs" character varying(128)`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "resolvedAs"`); + await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "moderationNote"`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index 6eed6fc725..c6e31797f8 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -71,20 +71,20 @@ "@bull-board/fastify": "6.0.0", "@bull-board/ui": "6.0.0", "@discordapp/twemoji": "15.1.0", - "@fastify/accepts": "5.0.0", - "@fastify/cookie": "10.0.0", - "@fastify/cors": "10.0.0", - "@fastify/express": "4.0.0", + "@fastify/accepts": "5.0.1", + "@fastify/cookie": "10.0.1", + "@fastify/cors": "10.0.1", + "@fastify/express": "4.0.1", "@fastify/http-proxy": "10.0.0", - "@fastify/multipart": "9.0.0", - "@fastify/static": "8.0.0", - "@fastify/view": "10.0.0", + "@fastify/multipart": "9.0.1", + "@fastify/static": "8.0.1", + "@fastify/view": "10.0.1", "@misskey-dev/sharp-read-bmp": "1.2.0", "@misskey-dev/summaly": "5.1.0", "@napi-rs/canvas": "0.1.56", - "@nestjs/common": "10.4.3", - "@nestjs/core": "10.4.3", - "@nestjs/testing": "10.4.3", + "@nestjs/common": "10.4.4", + "@nestjs/core": "10.4.4", + "@nestjs/testing": "10.4.4", "@peertube/http-signature": "1.7.0", "@sentry/node": "8.20.0", "@sentry/profiling-node": "8.20.0", @@ -101,7 +101,7 @@ "bcryptjs": "2.4.3", "blurhash": "2.0.5", "body-parser": "1.20.3", - "bullmq": "5.13.2", + "bullmq": "5.15.0", "cacheable-lookup": "7.0.0", "cbor": "9.0.2", "chalk": "5.3.0", @@ -149,7 +149,7 @@ "oauth2orize": "1.12.0", "oauth2orize-pkce": "0.1.2", "os-utils": "0.0.14", - "otpauth": "9.3.2", + "otpauth": "9.3.4", "parse5": "7.1.2", "pg": "8.13.0", "pkce-challenge": "4.1.0", @@ -166,7 +166,7 @@ "rename": "1.0.4", "rss-parser": "3.13.0", "rxjs": "7.8.1", - "sanitize-html": "2.13.0", + "sanitize-html": "2.13.1", "secure-json-parse": "2.7.0", "sharp": "0.33.5", "slacc": "0.0.10", @@ -187,14 +187,14 @@ }, "devDependencies": { "@jest/globals": "29.7.0", - "@nestjs/platform-express": "10.4.3", + "@nestjs/platform-express": "10.4.4", "@simplewebauthn/types": "10.0.0", "@swc/jest": "0.2.36", "@types/accepts": "1.3.7", "@types/archiver": "6.0.2", "@types/bcryptjs": "2.4.6", "@types/body-parser": "1.19.5", - "@types/color-convert": "2.0.3", + "@types/color-convert": "2.0.4", "@types/content-disposition": "0.5.8", "@types/fluent-ffmpeg": "2.1.26", "@types/htmlescape": "1.1.3", diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index 97ba79c574..42f1033b9d 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -63,6 +63,8 @@ type Source = { publishTarballInsteadOfProvideRepositoryUrl?: boolean; + setupPassword?: string; + proxy?: string; proxySmtp?: string; proxyBypassHosts?: string[]; @@ -152,6 +154,7 @@ export type Config = { version: string; publishTarballInsteadOfProvideRepositoryUrl: boolean; + setupPassword: string | undefined; host: string; hostname: string; scheme: string; @@ -232,6 +235,7 @@ export function loadConfig(): Config { return { version, publishTarballInsteadOfProvideRepositoryUrl: !!config.publishTarballInsteadOfProvideRepositoryUrl, + setupPassword: config.setupPassword, url: url.origin, port: config.port ?? parseInt(process.env.PORT ?? '', 10), socket: config.socket, diff --git a/packages/backend/src/core/AbuseReportNotificationService.ts b/packages/backend/src/core/AbuseReportNotificationService.ts index fe2c63e7d6..fb7c7bd2c3 100644 --- a/packages/backend/src/core/AbuseReportNotificationService.ts +++ b/packages/backend/src/core/AbuseReportNotificationService.ts @@ -22,6 +22,7 @@ import { RoleService } from '@/core/RoleService.js'; import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; import { SystemWebhookService } from '@/core/SystemWebhookService.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { IdService } from './IdService.js'; @Injectable() @@ -42,6 +43,7 @@ export class AbuseReportNotificationService implements OnApplicationShutdown { private emailService: EmailService, private moderationLogService: ModerationLogService, private globalEventService: GlobalEventService, + private userEntityService: UserEntityService, ) { this.redisForSub.on('message', this.onMessage); } @@ -135,6 +137,26 @@ export class AbuseReportNotificationService implements OnApplicationShutdown { return; } + const usersMap = await this.userEntityService.packMany( + [ + ...new Set([ + ...abuseReports.map(it => it.reporter ?? it.reporterId), + ...abuseReports.map(it => it.targetUser ?? it.targetUserId), + ...abuseReports.map(it => it.assignee ?? it.assigneeId), + ].filter(x => x != null)), + ], + null, + { schema: 'UserLite' }, + ).then(it => new Map(it.map(it => [it.id, it]))); + const convertedReports = abuseReports.map(it => { + return { + ...it, + reporter: usersMap.get(it.reporterId), + targetUser: usersMap.get(it.targetUserId), + assignee: it.assigneeId ? usersMap.get(it.assigneeId) : null, + }; + }); + const recipientWebhookIds = await this.fetchWebhookRecipients() .then(it => it .filter(it => it.isActive && it.systemWebhookId && it.method === 'webhook') @@ -142,7 +164,7 @@ export class AbuseReportNotificationService implements OnApplicationShutdown { .filter(x => x != null)); for (const webhookId of recipientWebhookIds) { await Promise.all( - abuseReports.map(it => { + convertedReports.map(it => { return this.systemWebhookService.enqueueSystemWebhook( webhookId, type, diff --git a/packages/backend/src/core/AbuseReportService.ts b/packages/backend/src/core/AbuseReportService.ts index 69c51509ba..73baad5499 100644 --- a/packages/backend/src/core/AbuseReportService.ts +++ b/packages/backend/src/core/AbuseReportService.ts @@ -20,8 +20,10 @@ export class AbuseReportService { constructor( @Inject(DI.abuseUserReportsRepository) private abuseUserReportsRepository: AbuseUserReportsRepository, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, + private idService: IdService, private abuseReportNotificationService: AbuseReportNotificationService, private queueService: QueueService, @@ -77,16 +79,16 @@ export class AbuseReportService { * - SystemWebhook * * @param params é€šå ±å†…å®¹. ã‚‚ã—複数件ã®é€šå ±ã«å¯¾å¿œã—ãŸæ™‚ã®ãŸã‚ã«ã€ã‚らã‹ã˜ã‚複数件を処ç†ã§ãã‚‹å‰æã§è€ƒãˆã‚‹ - * @param operator é€šå ±ã‚’å‡¦ç†ã—ãŸãƒ¦ãƒ¼ã‚¶ + * @param moderator é€šå ±ã‚’å‡¦ç†ã—ãŸãƒ¦ãƒ¼ã‚¶ * @see AbuseReportNotificationService.notify */ @bindThis public async resolve( params: { reportId: string; - forward: boolean; + resolvedAs: MiAbuseUserReport['resolvedAs']; }[], - operator: MiUser, + moderator: MiUser, ) { const paramsMap = new Map(params.map(it => [it.reportId, it])); const reports = await this.abuseUserReportsRepository.findBy({ @@ -99,25 +101,15 @@ export class AbuseReportService { await this.abuseUserReportsRepository.update(report.id, { resolved: true, - assigneeId: operator.id, - forwarded: ps.forward && report.targetUserHost !== null, + assigneeId: moderator.id, + resolvedAs: ps.resolvedAs, }); - if (ps.forward && report.targetUserHost != null) { - const actor = await this.instanceActorService.getInstanceActor(); - const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId }); - - // eslint-disable-next-line - const flag = this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment); - const contextAssignedFlag = this.apRendererService.addContext(flag); - this.queueService.deliver(actor, contextAssignedFlag, targetUser.inbox, false); - } - this.moderationLogService - .log(operator, 'resolveAbuseReport', { + .log(moderator, 'resolveAbuseReport', { reportId: report.id, report: report, - forwarded: ps.forward && report.targetUserHost !== null, + resolvedAs: ps.resolvedAs, }) .then(); } @@ -125,4 +117,62 @@ export class AbuseReportService { return this.abuseUserReportsRepository.findBy({ id: In(reports.map(it => it.id)) }) .then(reports => this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReportResolved')); } + + @bindThis + public async forward( + reportId: MiAbuseUserReport['id'], + moderator: MiUser, + ) { + const report = await this.abuseUserReportsRepository.findOneByOrFail({ id: reportId }); + + if (report.targetUserHost == null) { + throw new Error('The target user host is null.'); + } + + if (report.forwarded) { + throw new Error('The report has already been forwarded.'); + } + + await this.abuseUserReportsRepository.update(report.id, { + forwarded: true, + }); + + const actor = await this.instanceActorService.getInstanceActor(); + const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId }); + + const flag = this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment); + const contextAssignedFlag = this.apRendererService.addContext(flag); + this.queueService.deliver(actor, contextAssignedFlag, targetUser.inbox, false); + + this.moderationLogService + .log(moderator, 'forwardAbuseReport', { + reportId: report.id, + report: report, + }) + .then(); + } + + @bindThis + public async update( + reportId: MiAbuseUserReport['id'], + params: { + moderationNote?: MiAbuseUserReport['moderationNote']; + }, + moderator: MiUser, + ) { + const report = await this.abuseUserReportsRepository.findOneByOrFail({ id: reportId }); + + await this.abuseUserReportsRepository.update(report.id, { + moderationNote: params.moderationNote, + }); + + if (params.moderationNote != null && report.moderationNote !== params.moderationNote) { + this.moderationLogService.log(moderator, 'updateAbuseReportNote', { + reportId: report.id, + report: report, + before: report.moderationNote, + after: params.moderationNote, + }); + } + } } diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index 3b3c35f976..734d135648 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -14,6 +14,7 @@ import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationSe import { SystemWebhookService } from '@/core/SystemWebhookService.js'; import { UserSearchService } from '@/core/UserSearchService.js'; import { WebhookTestService } from '@/core/WebhookTestService.js'; +import { FlashService } from '@/core/FlashService.js'; import { AccountMoveService } from './AccountMoveService.js'; import { AccountUpdateService } from './AccountUpdateService.js'; import { AiService } from './AiService.js'; @@ -217,6 +218,7 @@ const $SystemWebhookService: Provider = { provide: 'SystemWebhookService', useEx const $WebhookTestService: Provider = { provide: 'WebhookTestService', useExisting: WebhookTestService }; const $UtilityService: Provider = { provide: 'UtilityService', useExisting: UtilityService }; const $FileInfoService: Provider = { provide: 'FileInfoService', useExisting: FileInfoService }; +const $FlashService: Provider = { provide: 'FlashService', useExisting: FlashService }; const $SearchService: Provider = { provide: 'SearchService', useExisting: SearchService }; const $ClipService: Provider = { provide: 'ClipService', useExisting: ClipService }; const $FeaturedService: Provider = { provide: 'FeaturedService', useExisting: FeaturedService }; @@ -367,6 +369,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting WebhookTestService, UtilityService, FileInfoService, + FlashService, SearchService, ClipService, FeaturedService, @@ -513,6 +516,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $WebhookTestService, $UtilityService, $FileInfoService, + $FlashService, $SearchService, $ClipService, $FeaturedService, @@ -660,6 +664,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting WebhookTestService, UtilityService, FileInfoService, + FlashService, SearchService, ClipService, FeaturedService, diff --git a/packages/backend/src/core/FlashService.ts b/packages/backend/src/core/FlashService.ts new file mode 100644 index 0000000000..2a98225382 --- /dev/null +++ b/packages/backend/src/core/FlashService.ts @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { DI } from '@/di-symbols.js'; +import { type FlashsRepository } from '@/models/_.js'; + +/** + * MisskeyPlay関係ã®Service + */ +@Injectable() +export class FlashService { + constructor( + @Inject(DI.flashsRepository) + private flashRepository: FlashsRepository, + ) { + } + + /** + * 人気ã®ã‚ã‚‹Play一覧をå–å¾—ã™ã‚‹. + */ + public async featured(opts?: { offset?: number, limit: number }) { + const builder = this.flashRepository.createQueryBuilder('flash') + .andWhere('flash.likedCount > 0') + .andWhere('flash.visibility = :visibility', { visibility: 'public' }) + .addOrderBy('flash.likedCount', 'DESC') + .addOrderBy('flash.updatedAt', 'DESC') + .addOrderBy('flash.id', 'DESC'); + + if (opts?.offset) { + builder.skip(opts.offset); + } + + builder.take(opts?.limit ?? 10); + + return await builder.getMany(); + } +} diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 89e3eafa0e..0ce57f16e6 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -218,7 +218,7 @@ export class NoteCreateService implements OnApplicationShutdown { private utilityService: UtilityService, private userBlockingService: UserBlockingService, ) { - this.updateNotesCountQueue = new CollapsedQueue(60 * 1000 * 5, this.collapseNotesCount, this.performUpdateNotesCount); + this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount); } @bindThis diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index c2764f30e8..4c45b95a64 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -15,8 +15,14 @@ import { QueueService } from '@/core/QueueService.js'; const oneDayMillis = 24 * 60 * 60 * 1000; -function generateAbuseReport(override?: Partial<MiAbuseUserReport>): MiAbuseUserReport { - return { +type AbuseUserReportDto = Omit<MiAbuseUserReport, 'targetUser' | 'reporter' | 'assignee'> & { + targetUser: Packed<'UserLite'> | null, + reporter: Packed<'UserLite'> | null, + assignee: Packed<'UserLite'> | null, +}; + +function generateAbuseReport(override?: Partial<MiAbuseUserReport>): AbuseUserReportDto { + const result: MiAbuseUserReport = { id: 'dummy-abuse-report1', targetUserId: 'dummy-target-user', targetUser: null, @@ -29,8 +35,17 @@ function generateAbuseReport(override?: Partial<MiAbuseUserReport>): MiAbuseUser comment: 'This is a dummy report for testing purposes.', targetUserHost: null, reporterHost: null, + resolvedAs: null, + moderationNote: 'foo', ...override, }; + + return { + ...result, + targetUser: result.targetUser ? toPackedUserLite(result.targetUser) : null, + reporter: result.reporter ? toPackedUserLite(result.reporter) : null, + assignee: result.assignee ? toPackedUserLite(result.assignee) : null, + }; } function generateDummyUser(override?: Partial<MiUser>): MiUser { @@ -268,7 +283,8 @@ const dummyUser3 = generateDummyUser({ @Injectable() export class WebhookTestService { - public static NoSuchWebhookError = class extends Error {}; + public static NoSuchWebhookError = class extends Error { + }; constructor( private userWebhookService: UserWebhookService, diff --git a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts index a13c244c19..70ead890ab 100644 --- a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts +++ b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts @@ -53,6 +53,8 @@ export class AbuseUserReportEntityService { schema: 'UserDetailedNotMe', }) : null, forwarded: report.forwarded, + resolvedAs: report.resolvedAs, + moderationNote: report.moderationNote, }); } diff --git a/packages/backend/src/core/entities/FlashEntityService.ts b/packages/backend/src/core/entities/FlashEntityService.ts index 4aa7104c1e..7b0150f5b6 100644 --- a/packages/backend/src/core/entities/FlashEntityService.ts +++ b/packages/backend/src/core/entities/FlashEntityService.ts @@ -5,10 +5,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; -import type { FlashsRepository, FlashLikesRepository } from '@/models/_.js'; -import { awaitAll } from '@/misc/prelude/await-all.js'; +import type { FlashLikesRepository, FlashsRepository } from '@/models/_.js'; import type { Packed } from '@/misc/json-schema.js'; -import type { } from '@/models/Blocking.js'; import type { MiUser } from '@/models/User.js'; import type { MiFlash } from '@/models/Flash.js'; import { bindThis } from '@/decorators.js'; @@ -20,10 +18,8 @@ export class FlashEntityService { constructor( @Inject(DI.flashsRepository) private flashsRepository: FlashsRepository, - @Inject(DI.flashLikesRepository) private flashLikesRepository: FlashLikesRepository, - private userEntityService: UserEntityService, private idService: IdService, ) { @@ -34,25 +30,36 @@ export class FlashEntityService { src: MiFlash['id'] | MiFlash, me?: { id: MiUser['id'] } | null | undefined, hint?: { - packedUser?: Packed<'UserLite'> + packedUser?: Packed<'UserLite'>, + likedFlashIds?: MiFlash['id'][], }, ): Promise<Packed<'Flash'>> { const meId = me ? me.id : null; const flash = typeof src === 'object' ? src : await this.flashsRepository.findOneByOrFail({ id: src }); - return await awaitAll({ + // { schema: 'UserDetailed' } ã™ã‚‹ã¨ç„¡é™ãƒ«ãƒ¼ãƒ—ã™ã‚‹ã®ã§æ³¨æ„ + const user = hint?.packedUser ?? await this.userEntityService.pack(flash.user ?? flash.userId, me); + + let isLiked = undefined; + if (meId) { + isLiked = hint?.likedFlashIds + ? hint.likedFlashIds.includes(flash.id) + : await this.flashLikesRepository.exists({ where: { flashId: flash.id, userId: meId } }); + } + + return { id: flash.id, createdAt: this.idService.parse(flash.id).date.toISOString(), updatedAt: flash.updatedAt.toISOString(), userId: flash.userId, - user: hint?.packedUser ?? this.userEntityService.pack(flash.user ?? flash.userId, me), // { schema: 'UserDetailed' } ã™ã‚‹ã¨ç„¡é™ãƒ«ãƒ¼ãƒ—ã™ã‚‹ã®ã§æ³¨æ„ + user: user, title: flash.title, summary: flash.summary, script: flash.script, visibility: flash.visibility, likedCount: flash.likedCount, - isLiked: meId ? await this.flashLikesRepository.exists({ where: { flashId: flash.id, userId: meId } }) : undefined, - }); + isLiked: isLiked, + }; } @bindThis @@ -63,7 +70,19 @@ export class FlashEntityService { const _users = flashes.map(({ user, userId }) => user ?? userId); const _userMap = await this.userEntityService.packMany(_users, me) .then(users => new Map(users.map(u => [u.id, u]))); - return Promise.all(flashes.map(flash => this.pack(flash, me, { packedUser: _userMap.get(flash.userId) }))); + const _likedFlashIds = me + ? await this.flashLikesRepository.createQueryBuilder('flashLike') + .select('flashLike.flashId') + .where('flashLike.userId = :userId', { userId: me.id }) + .getRawMany<{ flashLike_flashId: string }>() + .then(likes => [...new Set(likes.map(like => like.flashLike_flashId))]) + : []; + return Promise.all( + flashes.map(flash => this.pack(flash, me, { + packedUser: _userMap.get(flash.userId), + likedFlashIds: _likedFlashIds, + })), + ); } } diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 69e2d6fc89..c9939adf11 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -545,11 +545,6 @@ export class UserEntityService implements OnModuleInit { publicReactions: this.isLocalUser(user) ? profile!.publicReactions : false, // https://github.com/misskey-dev/misskey/issues/12964 followersVisibility: profile!.followersVisibility, followingVisibility: profile!.followingVisibility, - twoFactorEnabled: profile!.twoFactorEnabled, - usePasswordLessLogin: profile!.usePasswordLessLogin, - securityKeys: profile!.twoFactorEnabled - ? this.userSecurityKeysRepository.countBy({ userId: user.id }).then(result => result >= 1) - : false, roles: this.roleService.getUserRoles(user.id).then(roles => roles.filter(role => role.isPublic).sort((a, b) => b.displayOrder - a.displayOrder).map(role => ({ id: role.id, name: role.name, @@ -564,6 +559,14 @@ export class UserEntityService implements OnModuleInit { moderationNote: iAmModerator ? (profile!.moderationNote ?? '') : undefined, } : {}), + ...(isDetailed && (isMe || iAmModerator) ? { + twoFactorEnabled: profile!.twoFactorEnabled, + usePasswordLessLogin: profile!.usePasswordLessLogin, + securityKeys: profile!.twoFactorEnabled + ? this.userSecurityKeysRepository.countBy({ userId: user.id }).then(result => result >= 1) + : false, + } : {}), + ...(isDetailed && isMe ? { avatarId: user.avatarId, bannerId: user.bannerId, diff --git a/packages/backend/src/models/AbuseUserReport.ts b/packages/backend/src/models/AbuseUserReport.ts index 0615fd7eb5..cb5672e4ac 100644 --- a/packages/backend/src/models/AbuseUserReport.ts +++ b/packages/backend/src/models/AbuseUserReport.ts @@ -50,6 +50,9 @@ export class MiAbuseUserReport { }) public resolved: boolean; + /** + * リモートサーãƒãƒ¼ã«è»¢é€ã—ãŸã‹ã©ã†ã‹ + */ @Column('boolean', { default: false, }) @@ -60,6 +63,21 @@ export class MiAbuseUserReport { }) public comment: string; + @Column('varchar', { + length: 8192, default: '', + }) + public moderationNote: string; + + /** + * accept æ˜¯èª ... é€šå ±å†…å®¹ãŒæ£å½“ã§ã‚りã€è‚¯å®šçš„ã«å¯¾å¿œã•れ㟠+ * reject å¦èª ... é€šå ±å†…å®¹ãŒæ£å½“ã§ãªãã€å¦å®šçš„ã«å¯¾å¿œã•れ㟠+ * null ... ãã®ä»– + */ + @Column('varchar', { + length: 128, nullable: true, + }) + public resolvedAs: 'accept' | 'reject' | null; + //#region Denormalized fields @Index() @Column('varchar', { diff --git a/packages/backend/src/models/Flash.ts b/packages/backend/src/models/Flash.ts index a1469a0d94..5db7dca992 100644 --- a/packages/backend/src/models/Flash.ts +++ b/packages/backend/src/models/Flash.ts @@ -7,6 +7,9 @@ import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typ import { id } from './util/id.js'; import { MiUser } from './User.js'; +export const flashVisibility = ['public', 'private'] as const; +export type FlashVisibility = typeof flashVisibility[number]; + @Entity('flash') export class MiFlash { @PrimaryColumn(id()) @@ -63,5 +66,5 @@ export class MiFlash { @Column('varchar', { length: 512, default: 'public', }) - public visibility: 'public' | 'private'; + public visibility: FlashVisibility; } diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts index c1d3d42134..b7f8e94d69 100644 --- a/packages/backend/src/models/Notification.ts +++ b/packages/backend/src/models/Notification.ts @@ -3,12 +3,12 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { userExportableEntities } from '@/types.js'; import { MiUser } from './User.js'; import { MiNote } from './Note.js'; import { MiAccessToken } from './AccessToken.js'; import { MiRole } from './Role.js'; import { MiDriveFile } from './DriveFile.js'; -import { userExportableEntities } from '@/types.js'; export type MiNotification = { type: 'note'; @@ -87,6 +87,10 @@ export type MiNotification = { exportedEntity: typeof userExportableEntities[number]; fileId: MiDriveFile['id']; } | { + type: 'login'; + id: string; + createdAt: string; +} | { type: 'app'; id: string; createdAt: string; diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index 2645010491..cddaf4bc83 100644 --- a/packages/backend/src/models/json-schema/notification.ts +++ b/packages/backend/src/models/json-schema/notification.ts @@ -329,6 +329,16 @@ export const packedNotificationSchema = { type: { type: 'string', optional: false, nullable: false, + enum: ['login'], + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, enum: ['app'], }, body: { diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 16c8a5a097..9cffd680f2 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -346,21 +346,6 @@ export const packedUserDetailedNotMeOnlySchema = { nullable: false, optional: false, enum: ['public', 'followers', 'private'], }, - twoFactorEnabled: { - type: 'boolean', - nullable: false, optional: false, - default: false, - }, - usePasswordLessLogin: { - type: 'boolean', - nullable: false, optional: false, - default: false, - }, - securityKeys: { - type: 'boolean', - nullable: false, optional: false, - default: false, - }, roles: { type: 'array', nullable: false, optional: false, @@ -382,6 +367,18 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'string', nullable: false, optional: true, }, + twoFactorEnabled: { + type: 'boolean', + nullable: false, optional: true, + }, + usePasswordLessLogin: { + type: 'boolean', + nullable: false, optional: true, + }, + securityKeys: { + type: 'boolean', + nullable: false, optional: true, + }, //#region relations isFollowing: { type: 'boolean', @@ -630,6 +627,21 @@ export const packedMeDetailedOnlySchema = { nullable: false, optional: false, ref: 'RolePolicies', }, + twoFactorEnabled: { + type: 'boolean', + nullable: false, optional: false, + default: false, + }, + usePasswordLessLogin: { + type: 'boolean', + nullable: false, optional: false, + default: false, + }, + securityKeys: { + type: 'boolean', + nullable: false, optional: false, + default: false, + }, //#region secrets email: { type: 'string', diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index 09d51bec72..a77c968395 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -59,7 +59,7 @@ export class InboxProcessorService implements OnApplicationShutdown { private queueLoggerService: QueueLoggerService, ) { this.logger = this.queueLoggerService.logger.createSubLogger('inbox'); - this.updateInstanceQueue = new CollapsedQueue(60 * 1000 * 5, this.collapseUpdateInstanceJobs, this.performUpdateInstance); + this.updateInstanceQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseUpdateInstanceJobs, this.performUpdateInstance); } @bindThis diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts index 709a044601..be63635efe 100644 --- a/packages/backend/src/server/api/ApiServerService.ts +++ b/packages/backend/src/server/api/ApiServerService.ts @@ -118,25 +118,27 @@ export class ApiServerService { 'hcaptcha-response'?: string; 'g-recaptcha-response'?: string; 'turnstile-response'?: string; + 'm-captcha-response'?: string; } }>('/signup', (request, reply) => this.signupApiService.signup(request, reply)); fastify.post<{ Body: { username: string; - password: string; + password?: string; token?: string; - signature?: string; - authenticatorData?: string; - clientDataJSON?: string; - credentialId?: string; - challengeId?: string; + credential?: AuthenticationResponseJSON; + 'hcaptcha-response'?: string; + 'g-recaptcha-response'?: string; + 'turnstile-response'?: string; + 'm-captcha-response'?: string; }; - }>('/signin', (request, reply) => this.signinApiService.signin(request, reply)); + }>('/signin-flow', (request, reply) => this.signinApiService.signin(request, reply)); fastify.post<{ Body: { credential?: AuthenticationResponseJSON; + context?: string; }; }>('/signin-with-passkey', (request, reply) => this.signinWithPasskeyApiService.signin(request, reply)); diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 08a0468ab2..3557fa40a5 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -68,6 +68,8 @@ import * as ep___admin_relays_list from './endpoints/admin/relays/list.js'; import * as ep___admin_relays_remove from './endpoints/admin/relays/remove.js'; import * as ep___admin_resetPassword from './endpoints/admin/reset-password.js'; import * as ep___admin_resolveAbuseUserReport from './endpoints/admin/resolve-abuse-user-report.js'; +import * as ep___admin_forwardAbuseUserReport from './endpoints/admin/forward-abuse-user-report.js'; +import * as ep___admin_updateAbuseUserReport from './endpoints/admin/update-abuse-user-report.js'; import * as ep___admin_sendEmail from './endpoints/admin/send-email.js'; import * as ep___admin_serverInfo from './endpoints/admin/server-info.js'; import * as ep___admin_showModerationLogs from './endpoints/admin/show-moderation-logs.js'; @@ -453,6 +455,8 @@ const $admin_relays_list: Provider = { provide: 'ep:admin/relays/list', useClass const $admin_relays_remove: Provider = { provide: 'ep:admin/relays/remove', useClass: ep___admin_relays_remove.default }; const $admin_resetPassword: Provider = { provide: 'ep:admin/reset-password', useClass: ep___admin_resetPassword.default }; const $admin_resolveAbuseUserReport: Provider = { provide: 'ep:admin/resolve-abuse-user-report', useClass: ep___admin_resolveAbuseUserReport.default }; +const $admin_forwardAbuseUserReport: Provider = { provide: 'ep:admin/forward-abuse-user-report', useClass: ep___admin_forwardAbuseUserReport.default }; +const $admin_updateAbuseUserReport: Provider = { provide: 'ep:admin/update-abuse-user-report', useClass: ep___admin_updateAbuseUserReport.default }; const $admin_sendEmail: Provider = { provide: 'ep:admin/send-email', useClass: ep___admin_sendEmail.default }; const $admin_serverInfo: Provider = { provide: 'ep:admin/server-info', useClass: ep___admin_serverInfo.default }; const $admin_showModerationLogs: Provider = { provide: 'ep:admin/show-moderation-logs', useClass: ep___admin_showModerationLogs.default }; @@ -842,6 +846,8 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $admin_relays_remove, $admin_resetPassword, $admin_resolveAbuseUserReport, + $admin_forwardAbuseUserReport, + $admin_updateAbuseUserReport, $admin_sendEmail, $admin_serverInfo, $admin_showModerationLogs, @@ -1225,6 +1231,8 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $admin_relays_remove, $admin_resetPassword, $admin_resolveAbuseUserReport, + $admin_forwardAbuseUserReport, + $admin_updateAbuseUserReport, $admin_sendEmail, $admin_serverInfo, $admin_showModerationLogs, diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts index edac9b3beb..0d24ffa56a 100644 --- a/packages/backend/src/server/api/SigninApiService.ts +++ b/packages/backend/src/server/api/SigninApiService.ts @@ -5,12 +5,14 @@ import { Inject, Injectable } from '@nestjs/common'; import bcrypt from 'bcryptjs'; -import * as OTPAuth from 'otpauth'; import { IsNull } from 'typeorm'; +import * as Misskey from 'misskey-js'; import { DI } from '@/di-symbols.js'; import type { + MiMeta, SigninsRepository, UserProfilesRepository, + UserSecurityKeysRepository, UsersRepository, } from '@/models/_.js'; import type { Config } from '@/config.js'; @@ -20,6 +22,8 @@ import { IdService } from '@/core/IdService.js'; import { bindThis } from '@/decorators.js'; import { WebAuthnService } from '@/core/WebAuthnService.js'; import { UserAuthService } from '@/core/UserAuthService.js'; +import { CaptchaService } from '@/core/CaptchaService.js'; +import { FastifyReplyError } from '@/misc/fastify-reply-error.js'; import { RateLimiterService } from './RateLimiterService.js'; import { SigninService } from './SigninService.js'; import type { AuthenticationResponseJSON } from '@simplewebauthn/types'; @@ -31,12 +35,18 @@ export class SigninApiService { @Inject(DI.config) private config: Config, + @Inject(DI.meta) + private meta: MiMeta, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, @Inject(DI.userProfilesRepository) private userProfilesRepository: UserProfilesRepository, + @Inject(DI.userSecurityKeysRepository) + private userSecurityKeysRepository: UserSecurityKeysRepository, + @Inject(DI.signinsRepository) private signinsRepository: SigninsRepository, @@ -45,6 +55,7 @@ export class SigninApiService { private signinService: SigninService, private userAuthService: UserAuthService, private webAuthnService: WebAuthnService, + private captchaService: CaptchaService, ) { } @@ -53,9 +64,13 @@ export class SigninApiService { request: FastifyRequest<{ Body: { username: string; - password: string; + password?: string; token?: string; credential?: AuthenticationResponseJSON; + 'hcaptcha-response'?: string; + 'g-recaptcha-response'?: string; + 'turnstile-response'?: string; + 'm-captcha-response'?: string; }; }>, reply: FastifyReply, @@ -92,11 +107,6 @@ export class SigninApiService { return; } - if (typeof password !== 'string') { - reply.code(400); - return; - } - if (token != null && typeof token !== 'string') { reply.code(400); return; @@ -121,11 +131,32 @@ export class SigninApiService { } const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); + const securityKeysAvailable = await this.userSecurityKeysRepository.countBy({ userId: user.id }).then(result => result >= 1); + + if (password == null) { + reply.code(200); + if (profile.twoFactorEnabled) { + return { + finished: false, + next: 'password', + } satisfies Misskey.entities.SigninFlowResponse; + } else { + return { + finished: false, + next: 'captcha', + } satisfies Misskey.entities.SigninFlowResponse; + } + } + + if (typeof password !== 'string') { + reply.code(400); + return; + } // Compare password const same = await bcrypt.compare(password, profile.password!); - const fail = async (status?: number, failure?: { id: string }) => { + const fail = async (status?: number, failure?: { id: string; }) => { // Append signin history await this.signinsRepository.insert({ id: this.idService.gen(), @@ -139,6 +170,32 @@ export class SigninApiService { }; if (!profile.twoFactorEnabled) { + if (process.env.NODE_ENV !== 'test') { + if (this.meta.enableHcaptcha && this.meta.hcaptchaSecretKey) { + await this.captchaService.verifyHcaptcha(this.meta.hcaptchaSecretKey, body['hcaptcha-response']).catch(err => { + throw new FastifyReplyError(400, err); + }); + } + + if (this.meta.enableMcaptcha && this.meta.mcaptchaSecretKey && this.meta.mcaptchaSitekey && this.meta.mcaptchaInstanceUrl) { + await this.captchaService.verifyMcaptcha(this.meta.mcaptchaSecretKey, this.meta.mcaptchaSitekey, this.meta.mcaptchaInstanceUrl, body['m-captcha-response']).catch(err => { + throw new FastifyReplyError(400, err); + }); + } + + if (this.meta.enableRecaptcha && this.meta.recaptchaSecretKey) { + await this.captchaService.verifyRecaptcha(this.meta.recaptchaSecretKey, body['g-recaptcha-response']).catch(err => { + throw new FastifyReplyError(400, err); + }); + } + + if (this.meta.enableTurnstile && this.meta.turnstileSecretKey) { + await this.captchaService.verifyTurnstile(this.meta.turnstileSecretKey, body['turnstile-response']).catch(err => { + throw new FastifyReplyError(400, err); + }); + } + } + if (same) { return this.signinService.signin(request, reply, user); } else { @@ -180,7 +237,7 @@ export class SigninApiService { id: '93b86c4b-72f9-40eb-9815-798928603d1e', }); } - } else { + } else if (securityKeysAvailable) { if (!same && !profile.usePasswordLessLogin) { return await fail(403, { id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c', @@ -190,7 +247,23 @@ export class SigninApiService { const authRequest = await this.webAuthnService.initiateAuthentication(user.id); reply.code(200); - return authRequest; + return { + finished: false, + next: 'passkey', + authRequest, + } satisfies Misskey.entities.SigninFlowResponse; + } else { + if (!same || !profile.twoFactorEnabled) { + return await fail(403, { + id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c', + }); + } else { + reply.code(200); + return { + finished: false, + next: 'totp', + } satisfies Misskey.entities.SigninFlowResponse; + } } // never get here } diff --git a/packages/backend/src/server/api/SigninService.ts b/packages/backend/src/server/api/SigninService.ts index 70306c3113..640356b50c 100644 --- a/packages/backend/src/server/api/SigninService.ts +++ b/packages/backend/src/server/api/SigninService.ts @@ -4,13 +4,16 @@ */ import { Inject, Injectable } from '@nestjs/common'; +import * as Misskey from 'misskey-js'; import { DI } from '@/di-symbols.js'; -import type { SigninsRepository } from '@/models/_.js'; +import type { SigninsRepository, UserProfilesRepository } from '@/models/_.js'; import { IdService } from '@/core/IdService.js'; import type { MiLocalUser } from '@/models/User.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { SigninEntityService } from '@/core/entities/SigninEntityService.js'; import { bindThis } from '@/decorators.js'; +import { EmailService } from '@/core/EmailService.js'; +import { NotificationService } from '@/core/NotificationService.js'; import type { FastifyRequest, FastifyReply } from 'fastify'; @Injectable() @@ -19,7 +22,12 @@ export class SigninService { @Inject(DI.signinsRepository) private signinsRepository: SigninsRepository, + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + private signinEntityService: SigninEntityService, + private emailService: EmailService, + private notificationService: NotificationService, private idService: IdService, private globalEventService: GlobalEventService, ) { @@ -28,7 +36,8 @@ export class SigninService { @bindThis public signin(request: FastifyRequest, reply: FastifyReply, user: MiLocalUser) { setImmediate(async () => { - // Append signin history + this.notificationService.createNotification(user.id, 'login', {}); + const record = await this.signinsRepository.insertOne({ id: this.idService.gen(), userId: user.id, @@ -37,15 +46,22 @@ export class SigninService { success: true, }); - // Publish signin event this.globalEventService.publishMainStream(user.id, 'signin', await this.signinEntityService.pack(record)); + + const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); + if (profile.email && profile.emailVerified) { + this.emailService.sendEmail(profile.email, 'New login / ãƒã‚°ã‚¤ãƒ³ãŒã‚りã¾ã—ãŸ', + 'There is a new login. If you do not recognize this login, update the security status of your account, including changing your password. / æ–°ã—ã„ãƒã‚°ã‚¤ãƒ³ãŒã‚りã¾ã—ãŸã€‚ã“ã®ãƒã‚°ã‚¤ãƒ³ã«å¿ƒå½“ãŸã‚ŠãŒãªã„å ´åˆã¯ã€ãƒ‘スワードを変更ã™ã‚‹ãªã©ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®ã‚»ã‚ュリティ状態を更新ã—ã¦ãã ã•ã„。', + 'There is a new login. If you do not recognize this login, update the security status of your account, including changing your password. / æ–°ã—ã„ãƒã‚°ã‚¤ãƒ³ãŒã‚りã¾ã—ãŸã€‚ã“ã®ãƒã‚°ã‚¤ãƒ³ã«å¿ƒå½“ãŸã‚ŠãŒãªã„å ´åˆã¯ã€ãƒ‘スワードを変更ã™ã‚‹ãªã©ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®ã‚»ã‚ュリティ状態を更新ã—ã¦ãã ã•ã„。'); + } }); reply.code(200); return { + finished: true, id: user.id, - i: user.token, - }; + i: user.token!, + } satisfies Misskey.entities.SigninFlowResponse; } } diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 2462781f7b..49b07d6ced 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -74,6 +74,8 @@ import * as ep___admin_relays_list from './endpoints/admin/relays/list.js'; import * as ep___admin_relays_remove from './endpoints/admin/relays/remove.js'; import * as ep___admin_resetPassword from './endpoints/admin/reset-password.js'; import * as ep___admin_resolveAbuseUserReport from './endpoints/admin/resolve-abuse-user-report.js'; +import * as ep___admin_forwardAbuseUserReport from './endpoints/admin/forward-abuse-user-report.js'; +import * as ep___admin_updateAbuseUserReport from './endpoints/admin/update-abuse-user-report.js'; import * as ep___admin_sendEmail from './endpoints/admin/send-email.js'; import * as ep___admin_serverInfo from './endpoints/admin/server-info.js'; import * as ep___admin_showModerationLogs from './endpoints/admin/show-moderation-logs.js'; @@ -457,6 +459,8 @@ const eps = [ ['admin/relays/remove', ep___admin_relays_remove], ['admin/reset-password', ep___admin_resetPassword], ['admin/resolve-abuse-user-report', ep___admin_resolveAbuseUserReport], + ['admin/forward-abuse-user-report', ep___admin_forwardAbuseUserReport], + ['admin/update-abuse-user-report', ep___admin_updateAbuseUserReport], ['admin/send-email', ep___admin_sendEmail], ['admin/server-info', ep___admin_serverInfo], ['admin/show-moderation-logs', ep___admin_showModerationLogs], diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts index cf3f257ca6..0dbfaae054 100644 --- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts +++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts @@ -71,9 +71,22 @@ export const meta = { }, assignee: { type: 'object', - nullable: true, optional: true, + nullable: true, optional: false, ref: 'UserDetailedNotMe', }, + forwarded: { + type: 'boolean', + nullable: false, optional: false, + }, + resolvedAs: { + type: 'string', + nullable: true, optional: false, + enum: ['accept', 'reject', null], + }, + moderationNote: { + type: 'string', + nullable: false, optional: false, + }, }, }, }, @@ -88,7 +101,6 @@ export const paramDef = { state: { type: 'string', nullable: true, default: null }, reporterOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' }, targetUserOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' }, - forwarded: { type: 'boolean', default: false }, }, required: [], } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts index a7e8a3b018..d30131a62f 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts @@ -12,11 +12,27 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { InstanceActorService } from '@/core/InstanceActorService.js'; import { localUsernameSchema, passwordSchema } from '@/models/User.js'; import { DI } from '@/di-symbols.js'; +import type { Config } from '@/config.js'; +import { ApiError } from '@/server/api/error.js'; import { Packed } from '@/misc/json-schema.js'; export const meta = { tags: ['admin'], + errors: { + accessDenied: { + message: 'Access denied.', + code: 'ACCESS_DENIED', + id: '1fb7cb09-d46a-4fff-b8df-057708cce513', + }, + + wrongInitialPassword: { + message: 'Initial password is incorrect.', + code: 'INCORRECT_INITIAL_PASSWORD', + id: '97147c55-1ae1-4f6f-91d6-e1c3e0e76d62', + }, + }, + res: { type: 'object', optional: false, nullable: false, @@ -35,6 +51,7 @@ export const paramDef = { properties: { username: localUsernameSchema, password: passwordSchema, + setupPassword: { type: 'string', nullable: true }, }, required: ['username', 'password'], } as const; @@ -42,6 +59,9 @@ export const paramDef = { @Injectable() export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export constructor( + @Inject(DI.config) + private config: Config, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -52,7 +72,23 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- super(meta, paramDef, async (ps, _me, token) => { const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null; const realUsers = await this.instanceActorService.realLocalUsersPresent(); - if ((realUsers && !me?.isRoot) || token !== null) throw new Error('access denied'); + + if (!realUsers && me == null && token == null) { + // åˆå›žã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—ã®å ´åˆ + if (this.config.setupPassword != null) { + // åˆæœŸãƒ‘スワードãŒè¨å®šã•れã¦ã„ã‚‹å ´åˆ + if (ps.setupPassword !== this.config.setupPassword) { + // åˆæœŸãƒ‘スワードãŒé•ã†å ´åˆ + throw new ApiError(meta.errors.wrongInitialPassword); + } + } else if (ps.setupPassword != null && ps.setupPassword.trim() !== '') { + // åˆæœŸãƒ‘スワードãŒè¨å®šã•れã¦ã„ãªã„ã®ã«åˆæœŸãƒ‘スワードãŒå…¥åŠ›ã•れãŸå ´åˆ + throw new ApiError(meta.errors.wrongInitialPassword); + } + } else if ((realUsers && !me?.isRoot) || token !== null) { + // åˆå›žã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—ã§ã¯ãªãã€ç®¡ç†è€…ã§ãªã„å ´åˆ or 外部トークンを使用ã—ã¦ã„ã‚‹å ´åˆ + throw new ApiError(meta.errors.accessDenied); + } const { account, secret } = await this.signupService.signup({ username: ps.username, diff --git a/packages/backend/src/server/api/endpoints/admin/forward-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/forward-abuse-user-report.ts new file mode 100644 index 0000000000..3e42c91fed --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/forward-abuse-user-report.ts @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { AbuseUserReportsRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '@/server/api/error.js'; +import { AbuseReportService } from '@/core/AbuseReportService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + kind: 'write:admin:resolve-abuse-user-report', + + errors: { + noSuchAbuseReport: { + message: 'No such abuse report.', + code: 'NO_SUCH_ABUSE_REPORT', + id: '8763e21b-d9bc-40be-acf6-54c1a6986493', + kind: 'server', + httpStatusCode: 404, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + reportId: { type: 'string', format: 'misskey:id' }, + }, + required: ['reportId'], +} as const; + +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.abuseUserReportsRepository) + private abuseUserReportsRepository: AbuseUserReportsRepository, + private abuseReportService: AbuseReportService, + ) { + super(meta, paramDef, async (ps, me) => { + const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId }); + if (!report) { + throw new ApiError(meta.errors.noSuchAbuseReport); + } + + await this.abuseReportService.forward(report.id, me); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts index 9b79100fcf..554d324ff2 100644 --- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts +++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts @@ -32,7 +32,7 @@ export const paramDef = { type: 'object', properties: { reportId: { type: 'string', format: 'misskey:id' }, - forward: { type: 'boolean', default: false }, + resolvedAs: { type: 'string', enum: ['accept', 'reject', null], nullable: true }, }, required: ['reportId'], } as const; @@ -50,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- throw new ApiError(meta.errors.noSuchAbuseReport); } - await this.abuseReportService.resolve([{ reportId: report.id, forward: ps.forward }], me); + await this.abuseReportService.resolve([{ reportId: report.id, resolvedAs: ps.resolvedAs ?? null }], me); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/update-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/update-abuse-user-report.ts new file mode 100644 index 0000000000..73d4b843f0 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/update-abuse-user-report.ts @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { AbuseUserReportsRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '@/server/api/error.js'; +import { AbuseReportService } from '@/core/AbuseReportService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + kind: 'write:admin:resolve-abuse-user-report', + + errors: { + noSuchAbuseReport: { + message: 'No such abuse report.', + code: 'NO_SUCH_ABUSE_REPORT', + id: '15f51cf5-46d1-4b1d-a618-b35bcbed0662', + kind: 'server', + httpStatusCode: 404, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + reportId: { type: 'string', format: 'misskey:id' }, + moderationNote: { type: 'string' }, + }, + required: ['reportId'], +} as const; + +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.abuseUserReportsRepository) + private abuseUserReportsRepository: AbuseUserReportsRepository, + private abuseReportService: AbuseReportService, + ) { + super(meta, paramDef, async (ps, me) => { + const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId }); + if (!report) { + throw new ApiError(meta.errors.noSuchAbuseReport); + } + + await this.abuseReportService.update(report.id, { + moderationNote: ps.moderationNote, + }, me); + }); + } +} 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 daef236397..9ffae840b6 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -652,7 +652,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- } if (Array.isArray(ps.federationHosts)) { - set.blockedHosts = ps.federationHosts.filter(Boolean).map(x => x.toLowerCase()); + set.federationHosts = ps.federationHosts.filter(Boolean).map(x => x.toLowerCase()); } const before = await this.metaService.fetch(true); diff --git a/packages/backend/src/server/api/endpoints/flash/featured.ts b/packages/backend/src/server/api/endpoints/flash/featured.ts index c2d6ab5085..9a0cb461f2 100644 --- a/packages/backend/src/server/api/endpoints/flash/featured.ts +++ b/packages/backend/src/server/api/endpoints/flash/featured.ts @@ -8,6 +8,7 @@ import type { FlashsRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { FlashEntityService } from '@/core/entities/FlashEntityService.js'; import { DI } from '@/di-symbols.js'; +import { FlashService } from '@/core/FlashService.js'; export const meta = { tags: ['flash'], @@ -27,26 +28,25 @@ export const meta = { export const paramDef = { type: 'object', - properties: {}, + properties: { + offset: { type: 'integer', minimum: 0, default: 0 }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, required: [], } as const; @Injectable() export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.flashsRepository) - private flashsRepository: FlashsRepository, - + private flashService: FlashService, private flashEntityService: FlashEntityService, ) { super(meta, paramDef, async (ps, me) => { - const query = this.flashsRepository.createQueryBuilder('flash') - .andWhere('flash.likedCount > 0') - .orderBy('flash.likedCount', 'DESC'); - - const flashs = await query.limit(10).getMany(); - - return await this.flashEntityService.packMany(flashs, me); + const result = await this.flashService.featured({ + offset: ps.offset, + limit: ps.limit, + }); + return await this.flashEntityService.packMany(result, me); }); } } diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index 5854c6b392..df3cfee171 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -17,6 +17,7 @@ * roleAssigned - ãƒãƒ¼ãƒ«ãŒä»˜ä¸Žã•れ㟠* achievementEarned - 実績をç²å¾— * exportCompleted - エクスãƒãƒ¼ãƒˆãŒå®Œäº† + * login - ãƒã‚°ã‚¤ãƒ³ * app - アプリ通知 * test - テスト通知(サーãƒãƒ¼å´ï¼‰ */ @@ -34,6 +35,7 @@ export const notificationTypes = [ 'roleAssigned', 'achievementEarned', 'exportCompleted', + 'login', 'app', 'test', ] as const; @@ -97,6 +99,8 @@ export const moderationLogTypes = [ 'markSensitiveDriveFile', 'unmarkSensitiveDriveFile', 'resolveAbuseReport', + 'forwardAbuseReport', + 'updateAbuseReportNote', 'createInvitation', 'createAd', 'updateAd', @@ -265,7 +269,18 @@ export type ModerationLogPayloads = { resolveAbuseReport: { reportId: string; report: any; - forwarded: boolean; + forwarded?: boolean; + resolvedAs?: string | null; + }; + forwardAbuseReport: { + reportId: string; + report: any; + }; + updateAbuseReportNote: { + reportId: string; + report: any; + before: string; + after: string; }; createInvitation: { invitations: any[]; diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index 06548fa7da..48e1bababb 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -136,13 +136,7 @@ describe('2è¦ç´ èªè¨¼', () => { keyName: string, credentialId: Buffer, requestOptions: PublicKeyCredentialRequestOptionsJSON, - }): { - username: string, - password: string, - credential: AuthenticationResponseJSON, - 'g-recaptcha-response'?: string | null, - 'hcaptcha-response'?: string | null, - } => { + }): misskey.entities.SigninFlowRequest => { // AuthenticatorAssertionResponse.authenticatorData // https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAssertionResponse/authenticatorData const authenticatorData = Buffer.concat([ @@ -202,17 +196,21 @@ describe('2è¦ç´ èªè¨¼', () => { }, alice); assert.strictEqual(doneResponse.status, 200); - const usersShowResponse = await api('users/show', { - username, - }, alice); - assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual((usersShowResponse.body as unknown as { twoFactorEnabled: boolean }).twoFactorEnabled, true); + const signinWithoutTokenResponse = await api('signin-flow', { + ...signinParam(), + }); + assert.strictEqual(signinWithoutTokenResponse.status, 200); + assert.deepStrictEqual(signinWithoutTokenResponse.body, { + finished: false, + next: 'totp', + }); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), token: otpToken(registerResponse.body.secret), }); assert.strictEqual(signinResponse.status, 200); + assert.strictEqual(signinResponse.body.finished, true); assert.notEqual(signinResponse.body.i, undefined); // 後片付㑠@@ -253,27 +251,23 @@ describe('2è¦ç´ èªè¨¼', () => { assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url')); assert.strictEqual(keyDoneResponse.body.name, keyName); - const usersShowResponse = await api('users/show', { - username, - }); - assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual((usersShowResponse.body as unknown as { securityKeys: boolean }).securityKeys, true); - - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), }); assert.strictEqual(signinResponse.status, 200); - assert.strictEqual(signinResponse.body.i, undefined); - assert.notEqual((signinResponse.body as unknown as { challenge: unknown | undefined }).challenge, undefined); - assert.notEqual((signinResponse.body as unknown as { allowCredentials: unknown | undefined }).allowCredentials, undefined); - assert.strictEqual((signinResponse.body as unknown as { allowCredentials: {id: string}[] }).allowCredentials[0].id, credentialId.toString('base64url')); + assert.strictEqual(signinResponse.body.finished, false); + assert.strictEqual(signinResponse.body.next, 'passkey'); + assert.notEqual(signinResponse.body.authRequest.challenge, undefined); + assert.notEqual(signinResponse.body.authRequest.allowCredentials, undefined); + assert.strictEqual(signinResponse.body.authRequest.allowCredentials && signinResponse.body.authRequest.allowCredentials[0]?.id, credentialId.toString('base64url')); - const signinResponse2 = await api('signin', signinWithSecurityKeyParam({ + const signinResponse2 = await api('signin-flow', signinWithSecurityKeyParam({ keyName, credentialId, - requestOptions: signinResponse.body, - } as any)); + requestOptions: signinResponse.body.authRequest, + })); assert.strictEqual(signinResponse2.status, 200); + assert.strictEqual(signinResponse2.body.finished, true); assert.notEqual(signinResponse2.body.i, undefined); // 後片付㑠@@ -315,28 +309,30 @@ describe('2è¦ç´ èªè¨¼', () => { }, alice); assert.strictEqual(passwordLessResponse.status, 204); - const usersShowResponse = await api('users/show', { - username, - }); - assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual((usersShowResponse.body as unknown as { usePasswordLessLogin: boolean }).usePasswordLessLogin, true); + const iResponse = await api('i', {}, alice); + assert.strictEqual(iResponse.status, 200); + assert.strictEqual(iResponse.body.usePasswordLessLogin, true); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), password: '', }); assert.strictEqual(signinResponse.status, 200); - assert.strictEqual(signinResponse.body.i, undefined); + assert.strictEqual(signinResponse.body.finished, false); + assert.strictEqual(signinResponse.body.next, 'passkey'); + assert.notEqual(signinResponse.body.authRequest.challenge, undefined); + assert.notEqual(signinResponse.body.authRequest.allowCredentials, undefined); - const signinResponse2 = await api('signin', { + const signinResponse2 = await api('signin-flow', { ...signinWithSecurityKeyParam({ keyName, credentialId, - requestOptions: signinResponse.body, + requestOptions: signinResponse.body.authRequest, } as any), password: '', }); assert.strictEqual(signinResponse2.status, 200); + assert.strictEqual(signinResponse2.body.finished, true); assert.notEqual(signinResponse2.body.i, undefined); // 後片付㑠@@ -424,11 +420,11 @@ describe('2è¦ç´ èªè¨¼', () => { assert.strictEqual(keyDoneResponse.status, 200); // テストã®å®Ÿè¡Œé †ã«ã‚ˆã£ã¦ã¯è¤‡æ•°æ®‹ã£ã¦ã‚‹ã®ã§å…¨éƒ¨æ¶ˆã™ - const iResponse = await api('i', { + const beforeIResponse = await api('i', { }, alice); - assert.strictEqual(iResponse.status, 200); - assert.ok(iResponse.body.securityKeysList); - for (const key of iResponse.body.securityKeysList) { + assert.strictEqual(beforeIResponse.status, 200); + assert.ok(beforeIResponse.body.securityKeysList); + for (const key of beforeIResponse.body.securityKeysList) { const removeKeyResponse = await api('i/2fa/remove-key', { token: otpToken(registerResponse.body.secret), password, @@ -437,17 +433,16 @@ describe('2è¦ç´ èªè¨¼', () => { assert.strictEqual(removeKeyResponse.status, 200); } - const usersShowResponse = await api('users/show', { - username, - }); - assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual((usersShowResponse.body as unknown as { securityKeys: boolean }).securityKeys, false); + const afterIResponse = await api('i', {}, alice); + assert.strictEqual(afterIResponse.status, 200); + assert.strictEqual(afterIResponse.body.securityKeys, false); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), token: otpToken(registerResponse.body.secret), }); assert.strictEqual(signinResponse.status, 200); + assert.strictEqual(signinResponse.body.finished, true); assert.notEqual(signinResponse.body.i, undefined); // 後片付㑠@@ -468,11 +463,9 @@ describe('2è¦ç´ èªè¨¼', () => { }, alice); assert.strictEqual(doneResponse.status, 200); - const usersShowResponse = await api('users/show', { - username, - }); - assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual((usersShowResponse.body as unknown as { twoFactorEnabled: boolean }).twoFactorEnabled, true); + const iResponse = await api('i', {}, alice); + assert.strictEqual(iResponse.status, 200); + assert.strictEqual(iResponse.body.twoFactorEnabled, true); const unregisterResponse = await api('i/2fa/unregister', { token: otpToken(registerResponse.body.secret), @@ -480,10 +473,11 @@ describe('2è¦ç´ èªè¨¼', () => { }, alice); assert.strictEqual(unregisterResponse.status, 204); - const signinResponse = await api('signin', { + const signinResponse = await api('signin-flow', { ...signinParam(), }); assert.strictEqual(signinResponse.status, 200); + assert.strictEqual(signinResponse.body.finished, true); assert.notEqual(signinResponse.body.i, undefined); // 後片付㑠diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts index 5aaec7f6f9..b91d77c398 100644 --- a/packages/backend/test/e2e/endpoints.ts +++ b/packages/backend/test/e2e/endpoints.ts @@ -66,9 +66,9 @@ describe('Endpoints', () => { }); }); - describe('signin', () => { + describe('signin-flow', () => { test('é–“é•ã£ãŸãƒ‘スワードã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã§ããªã„', async () => { - const res = await api('signin', { + const res = await api('signin-flow', { username: 'test1', password: 'bar', }); @@ -77,7 +77,7 @@ describe('Endpoints', () => { }); test('クエリをインジェクションã§ããªã„', async () => { - const res = await api('signin', { + const res = await api('signin-flow', { username: 'test1', // @ts-expect-error password must be string password: { @@ -89,7 +89,7 @@ describe('Endpoints', () => { }); test('æ£ã—ã„æƒ…å ±ã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã§ãã‚‹', async () => { - const res = await api('signin', { + const res = await api('signin-flow', { username: 'test1', password: 'test1', }); diff --git a/packages/backend/test/e2e/synalio/abuse-report.ts b/packages/backend/test/e2e/synalio/abuse-report.ts index 6ce6e47781..c98d199f35 100644 --- a/packages/backend/test/e2e/synalio/abuse-report.ts +++ b/packages/backend/test/e2e/synalio/abuse-report.ts @@ -157,7 +157,6 @@ describe('[シナリオ] ãƒ¦ãƒ¼ã‚¶é€šå ±', () => { const webhookBody2 = await captureWebhook(async () => { await resolveAbuseReport({ reportId: webhookBody1.body.id, - forward: false, }, admin); }); @@ -214,7 +213,6 @@ describe('[シナリオ] ãƒ¦ãƒ¼ã‚¶é€šå ±', () => { const webhookBody2 = await captureWebhook(async () => { await resolveAbuseReport({ reportId: abuseReportId, - forward: false, }, admin); }); @@ -257,7 +255,6 @@ describe('[シナリオ] ãƒ¦ãƒ¼ã‚¶é€šå ±', () => { const webhookBody2 = await captureWebhook(async () => { await resolveAbuseReport({ reportId: webhookBody1.body.id, - forward: false, }, admin); }).catch(e => e.message); @@ -288,7 +285,6 @@ describe('[シナリオ] ãƒ¦ãƒ¼ã‚¶é€šå ±', () => { const webhookBody2 = await captureWebhook(async () => { await resolveAbuseReport({ reportId: abuseReportId, - forward: false, }, admin); }).catch(e => e.message); @@ -319,7 +315,6 @@ describe('[シナリオ] ãƒ¦ãƒ¼ã‚¶é€šå ±', () => { const webhookBody2 = await captureWebhook(async () => { await resolveAbuseReport({ reportId: abuseReportId, - forward: false, }, admin); }).catch(e => e.message); @@ -350,7 +345,6 @@ describe('[シナリオ] ãƒ¦ãƒ¼ã‚¶é€šå ±', () => { const webhookBody2 = await captureWebhook(async () => { await resolveAbuseReport({ reportId: abuseReportId, - forward: false, }, admin); }).catch(e => e.message); diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 8ebe9af792..822ca14ae6 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -83,9 +83,6 @@ describe('ユーザー', () => { publicReactions: user.publicReactions, followingVisibility: user.followingVisibility, followersVisibility: user.followersVisibility, - twoFactorEnabled: user.twoFactorEnabled, - usePasswordLessLogin: user.usePasswordLessLogin, - securityKeys: user.securityKeys, roles: user.roles, memo: user.memo, }); @@ -149,6 +146,9 @@ describe('ユーザー', () => { achievements: user.achievements, loggedInDays: user.loggedInDays, policies: user.policies, + twoFactorEnabled: user.twoFactorEnabled, + usePasswordLessLogin: user.usePasswordLessLogin, + securityKeys: user.securityKeys, ...(security ? { email: user.email, emailVerified: user.emailVerified, @@ -343,9 +343,6 @@ describe('ユーザー', () => { assert.strictEqual(response.publicReactions, true); assert.strictEqual(response.followingVisibility, 'public'); assert.strictEqual(response.followersVisibility, 'public'); - assert.strictEqual(response.twoFactorEnabled, false); - assert.strictEqual(response.usePasswordLessLogin, false); - assert.strictEqual(response.securityKeys, false); assert.deepStrictEqual(response.roles, []); assert.strictEqual(response.memo, null); @@ -385,6 +382,9 @@ describe('ユーザー', () => { assert.deepStrictEqual(response.achievements, []); assert.deepStrictEqual(response.loggedInDays, 0); assert.deepStrictEqual(response.policies, DEFAULT_POLICIES); + assert.strictEqual(response.twoFactorEnabled, false); + assert.strictEqual(response.usePasswordLessLogin, false); + assert.strictEqual(response.securityKeys, false); assert.notStrictEqual(response.email, undefined); assert.strictEqual(response.emailVerified, false); assert.deepStrictEqual(response.securityKeysList, []); @@ -618,6 +618,9 @@ describe('ユーザー', () => { { label: 'Moderatorã«ãªã£ã¦ã„ã‚‹', user: () => userModerator, me: () => userModerator, selector: (user: misskey.entities.MeDetailed) => user.isModerator }, // @ts-expect-error UserDetailedNotMe doesn't include isModerator { label: '自分以外ã‹ã‚‰è¦‹ãŸã¨ãã¯Moderatorã‹åˆ¤å®šã§ããªã„', user: () => userModerator, selector: (user: misskey.entities.UserDetailedNotMe) => user.isModerator, expected: () => undefined }, + { label: '自分ã‹ã‚‰è¦‹ãŸå ´åˆã«äºŒè¦ç´ èªè¨¼é–¢é€£ã®ãƒ—ãƒãƒ‘ティãŒã‚»ãƒƒãƒˆã•れã¦ã„ã‚‹', user: () => alice, me: () => alice, selector: (user: misskey.entities.MeDetailed) => user.twoFactorEnabled, expected: () => false }, + { label: '自分以外ã‹ã‚‰è¦‹ãŸå ´åˆã«äºŒè¦ç´ èªè¨¼é–¢é€£ã®ãƒ—ãƒãƒ‘ティãŒã‚»ãƒƒãƒˆã•れã¦ã„ãªã„', user: () => alice, me: () => bob, selector: (user: misskey.entities.UserDetailedNotMe) => user.twoFactorEnabled, expected: () => undefined }, + { label: 'モデレーターã‹ã‚‰è¦‹ãŸå ´åˆã«äºŒè¦ç´ èªè¨¼é–¢é€£ã®ãƒ—ãƒãƒ‘ティãŒã‚»ãƒƒãƒˆã•れã¦ã„ã‚‹', user: () => alice, me: () => userModerator, selector: (user: misskey.entities.UserDetailedNotMe) => user.twoFactorEnabled, expected: () => false }, { label: 'サイレンスã«ãªã£ã¦ã„ã‚‹', user: () => userSilenced, selector: (user: misskey.entities.UserDetailed) => user.isSilenced }, // FIXME: è½ã¡ã‚‹ //{ label: 'サスペンドã«ãªã£ã¦ã„ã‚‹', user: () => userSuspended, selector: (user: misskey.entities.UserDetailed) => user.isSuspended }, diff --git a/packages/backend/test/unit/AbuseReportNotificationService.ts b/packages/backend/test/unit/AbuseReportNotificationService.ts index e971659070..235af29f0d 100644 --- a/packages/backend/test/unit/AbuseReportNotificationService.ts +++ b/packages/backend/test/unit/AbuseReportNotificationService.ts @@ -5,6 +5,7 @@ import { jest } from '@jest/globals'; import { Test, TestingModule } from '@nestjs/testing'; +import { randomString } from '../utils.js'; import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; import { AbuseReportNotificationRecipientRepository, @@ -25,7 +26,7 @@ import { ModerationLogService } from '@/core/ModerationLogService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js'; import { SystemWebhookService } from '@/core/SystemWebhookService.js'; -import { randomString } from '../utils.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; process.env.NODE_ENV = 'test'; @@ -111,6 +112,9 @@ describe('AbuseReportNotificationService', () => { provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }), }, { + provide: UserEntityService, useFactory: () => ({ pack: (v: any) => v }), + }, + { provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }), }, { diff --git a/packages/backend/test/unit/FlashService.ts b/packages/backend/test/unit/FlashService.ts new file mode 100644 index 0000000000..12ffaf3421 --- /dev/null +++ b/packages/backend/test/unit/FlashService.ts @@ -0,0 +1,152 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Test, TestingModule } from '@nestjs/testing'; +import { FlashService } from '@/core/FlashService.js'; +import { IdService } from '@/core/IdService.js'; +import { FlashsRepository, MiFlash, MiUser, UserProfilesRepository, UsersRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { GlobalModule } from '@/GlobalModule.js'; + +describe('FlashService', () => { + let app: TestingModule; + let service: FlashService; + + // -------------------------------------------------------------------------------------- + + let flashsRepository: FlashsRepository; + let usersRepository: UsersRepository; + let userProfilesRepository: UserProfilesRepository; + let idService: IdService; + + // -------------------------------------------------------------------------------------- + + let root: MiUser; + let alice: MiUser; + let bob: MiUser; + + // -------------------------------------------------------------------------------------- + + async function createFlash(data: Partial<MiFlash>) { + return flashsRepository.insert({ + id: idService.gen(), + updatedAt: new Date(), + userId: root.id, + title: 'title', + summary: 'summary', + script: 'script', + permissions: [], + likedCount: 0, + ...data, + }).then(x => flashsRepository.findOneByOrFail(x.identifiers[0])); + } + + async function createUser(data: Partial<MiUser> = {}) { + const user = await usersRepository + .insert({ + id: idService.gen(), + ...data, + }) + .then(x => usersRepository.findOneByOrFail(x.identifiers[0])); + + await userProfilesRepository.insert({ + userId: user.id, + }); + + return user; + } + + // -------------------------------------------------------------------------------------- + + beforeEach(async () => { + app = await Test.createTestingModule({ + imports: [ + GlobalModule, + ], + providers: [ + FlashService, + IdService, + ], + }).compile(); + + service = app.get(FlashService); + + flashsRepository = app.get(DI.flashsRepository); + usersRepository = app.get(DI.usersRepository); + userProfilesRepository = app.get(DI.userProfilesRepository); + idService = app.get(IdService); + + root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true }); + alice = await createUser({ username: 'alice', usernameLower: 'alice', isRoot: false }); + bob = await createUser({ username: 'bob', usernameLower: 'bob', isRoot: false }); + }); + + afterEach(async () => { + await usersRepository.delete({}); + await userProfilesRepository.delete({}); + await flashsRepository.delete({}); + }); + + afterAll(async () => { + await app.close(); + }); + + // -------------------------------------------------------------------------------------- + + describe('featured', () => { + test('should return featured flashes', async () => { + const flash1 = await createFlash({ likedCount: 1 }); + const flash2 = await createFlash({ likedCount: 2 }); + const flash3 = await createFlash({ likedCount: 3 }); + + const result = await service.featured({ + offset: 0, + limit: 10, + }); + + expect(result).toEqual([flash3, flash2, flash1]); + }); + + test('should return featured flashes public visibility only', async () => { + const flash1 = await createFlash({ likedCount: 1, visibility: 'public' }); + const flash2 = await createFlash({ likedCount: 2, visibility: 'public' }); + const flash3 = await createFlash({ likedCount: 3, visibility: 'private' }); + + const result = await service.featured({ + offset: 0, + limit: 10, + }); + + expect(result).toEqual([flash2, flash1]); + }); + + test('should return featured flashes with offset', async () => { + const flash1 = await createFlash({ likedCount: 1 }); + const flash2 = await createFlash({ likedCount: 2 }); + const flash3 = await createFlash({ likedCount: 3 }); + + const result = await service.featured({ + offset: 1, + limit: 10, + }); + + expect(result).toEqual([flash2, flash1]); + }); + + test('should return featured flashes with limit', async () => { + const flash1 = await createFlash({ likedCount: 1 }); + const flash2 = await createFlash({ likedCount: 2 }); + const flash3 = await createFlash({ likedCount: 3 }); + + const result = await service.featured({ + offset: 0, + limit: 2, + }); + + expect(result).toEqual([flash3, flash2]); + }); + }); +}); diff --git a/packages/frontend-embed/package.json b/packages/frontend-embed/package.json index 9e720b9835..cb62191c3b 100644 --- a/packages/frontend-embed/package.json +++ b/packages/frontend-embed/package.json @@ -18,7 +18,7 @@ "@tabler/icons-webfont": "3.3.0", "@twemoji/parser": "15.1.1", "@vitejs/plugin-vue": "5.1.4", - "@vue/compiler-sfc": "3.5.10", + "@vue/compiler-sfc": "3.5.11", "astring": "1.9.0", "buraha": "0.0.1", "estree-walker": "3.0.3", @@ -27,8 +27,8 @@ "frontend-shared": "workspace:*", "punycode": "2.3.1", "rollup": "4.22.5", - "sass": "1.79.3", - "shiki": "1.12.0", + "sass": "1.79.4", + "shiki": "1.21.0", "tinycolor2": "1.6.0", "tsc-alias": "1.8.10", "tsconfig-paths": "4.2.0", @@ -36,7 +36,7 @@ "uuid": "10.0.0", "json5": "2.2.3", "vite": "5.4.8", - "vue": "3.5.10" + "vue": "3.5.11" }, "devDependencies": { "@misskey-dev/summaly": "5.1.0", @@ -51,10 +51,10 @@ "@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/parser": "7.17.0", "@vitest/coverage-v8": "1.6.0", - "@vue/runtime-core": "3.5.10", + "@vue/runtime-core": "3.5.11", "acorn": "8.12.1", "cross-env": "7.0.3", - "eslint-plugin-import": "2.30.0", + "eslint-plugin-import": "2.31.0", "eslint-plugin-vue": "9.28.0", "fast-glob": "3.3.2", "happy-dom": "10.0.3", diff --git a/packages/frontend-embed/src/components/EmCustomEmoji.vue b/packages/frontend-embed/src/components/EmCustomEmoji.vue index e4149cf363..59b670cdc6 100644 --- a/packages/frontend-embed/src/components/EmCustomEmoji.vue +++ b/packages/frontend-embed/src/components/EmCustomEmoji.vue @@ -38,8 +38,6 @@ const props = defineProps<{ host?: string | null; url?: string; useOriginalSize?: boolean; - menu?: boolean; - menuReaction?: boolean; fallbackToImage?: boolean; }>(); diff --git a/packages/frontend-embed/src/components/EmMfm.ts b/packages/frontend-embed/src/components/EmMfm.ts index b2bcf4597e..59f0d495e6 100644 --- a/packages/frontend-embed/src/components/EmMfm.ts +++ b/packages/frontend-embed/src/components/EmMfm.ts @@ -6,6 +6,7 @@ import { VNode, h, SetupContext, provide } from 'vue'; import * as mfm from 'mfm-js'; import * as Misskey from 'misskey-js'; +import { host } from '@@/js/config.js'; import EmUrl from '@/components/EmUrl.vue'; import EmTime from '@/components/EmTime.vue'; import EmLink from '@/components/EmLink.vue'; @@ -13,7 +14,6 @@ import EmMention from '@/components/EmMention.vue'; import EmEmoji from '@/components/EmEmoji.vue'; import EmCustomEmoji from '@/components/EmCustomEmoji.vue'; import EmA from '@/components/EmA.vue'; -import { host } from '@@/js/config.js'; function safeParseFloat(str: unknown): number | null { if (typeof str !== 'string' || str === '') return null; @@ -41,9 +41,6 @@ type MfmProps = { rootScale?: number; nyaize?: boolean | 'respect'; parsedNodes?: mfm.MfmNode[] | null; - enableEmojiMenu?: boolean; - enableEmojiMenuReaction?: boolean; - linkNavigationBehavior?: string; }; type MfmEvents = { @@ -52,8 +49,6 @@ type MfmEvents = { // eslint-disable-next-line import/no-default-export export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEvents>['emit'] }) { - provide('linkNavigationBehavior', props.linkNavigationBehavior); - const isNote = props.isNote ?? true; const shouldNyaize = props.nyaize ? props.nyaize === 'respect' ? props.author?.isCat : false : false; @@ -397,8 +392,6 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven normal: props.plain, host: null, useOriginalSize: scale >= 2.5, - menu: props.enableEmojiMenu, - menuReaction: props.enableEmojiMenuReaction, fallbackToImage: false, })]; } else { diff --git a/packages/frontend-embed/vite.config.ts b/packages/frontend-embed/vite.config.ts index 64e67401c2..2dbee488c5 100644 --- a/packages/frontend-embed/vite.config.ts +++ b/packages/frontend-embed/vite.config.ts @@ -91,6 +91,11 @@ export function getConfig(): UserConfig { } }, }, + preprocessorOptions: { + scss: { + api: 'modern-compiler', + }, + }, }, define: { diff --git a/packages/frontend-shared/js/const.ts b/packages/frontend-shared/js/const.ts index aec4a4a58b..4fe5cbb205 100644 --- a/packages/frontend-shared/js/const.ts +++ b/packages/frontend-shared/js/const.ts @@ -68,6 +68,7 @@ export const notificationTypes = [ 'roleAssigned', 'achievementEarned', 'exportCompleted', + 'login', 'test', 'app', ] as const; diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx index 42d1a10f0a..f2bdc631d2 100644 --- a/packages/frontend/.storybook/generate.tsx +++ b/packages/frontend/.storybook/generate.tsx @@ -397,7 +397,18 @@ function toStories(component: string): Promise<string> { const globs = await Promise.all([ glob('src/components/global/Mk*.vue'), glob('src/components/global/RouterView.vue'), - glob('src/components/Mk[A-E]*.vue'), + glob('src/components/MkAbuseReportWindow.vue'), + glob('src/components/MkAccountMoved.vue'), + glob('src/components/MkAchievements.vue'), + glob('src/components/MkAnalogClock.vue'), + glob('src/components/MkAnimBg.vue'), + glob('src/components/MkAnnouncementDialog.vue'), + glob('src/components/MkAntennaEditor.vue'), + glob('src/components/MkAntennaEditorDialog.vue'), + glob('src/components/MkAsUi.vue'), + glob('src/components/MkAutocomplete.vue'), + glob('src/components/MkAvatars.vue'), + glob('src/components/Mk[B-E]*.vue'), glob('src/components/MkFlashPreview.vue'), glob('src/components/MkGalleryPostPreview.vue'), glob('src/components/MkSignupServerRules.vue'), diff --git a/packages/frontend/package.json b/packages/frontend/package.json index d3909babfd..3226a554a9 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -28,7 +28,7 @@ "@tabler/icons-webfont": "3.3.0", "@twemoji/parser": "15.1.1", "@vitejs/plugin-vue": "5.1.4", - "@vue/compiler-sfc": "3.5.10", + "@vue/compiler-sfc": "3.5.11", "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.11", "astring": "1.9.0", "broadcast-channel": "7.0.0", @@ -39,12 +39,13 @@ "chartjs-chart-matrix": "2.0.1", "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.0.1", - "chromatic": "11.10.4", + "chromatic": "11.11.0", "compare-versions": "6.1.1", "cropperjs": "2.0.0-rc.2", "date-fns": "2.30.0", "estree-walker": "3.0.3", "eventemitter3": "5.0.1", + "frontend-shared": "workspace:*", "idb-keyval": "6.2.1", "insert-text-at-cursor": "0.3.0", "is-file-animated": "1.0.2", @@ -54,13 +55,12 @@ "misskey-bubble-game": "workspace:*", "misskey-js": "workspace:*", "misskey-reversi": "workspace:*", - "frontend-shared": "workspace:*", "photoswipe": "5.4.4", "punycode": "2.3.1", "rollup": "4.22.5", - "sanitize-html": "2.13.0", + "sanitize-html": "2.13.1", "sass": "1.79.3", - "shiki": "1.12.0", + "shiki": "1.21.0", "strict-event-emitter-types": "2.0.0", "textarea-caret": "3.1.0", "three": "0.169.0", @@ -72,30 +72,31 @@ "uuid": "10.0.0", "v-code-diff": "1.13.1", "vite": "5.4.8", - "vue": "3.5.10", + "vue": "3.5.11", "vuedraggable": "next" }, "devDependencies": { "@misskey-dev/summaly": "5.1.0", - "@storybook/addon-actions": "8.3.3", - "@storybook/addon-essentials": "8.3.3", - "@storybook/addon-interactions": "8.3.3", - "@storybook/addon-links": "8.3.3", - "@storybook/addon-mdx-gfm": "8.3.3", - "@storybook/addon-storysource": "8.3.3", - "@storybook/blocks": "8.3.3", - "@storybook/components": "8.3.3", - "@storybook/core-events": "8.3.3", - "@storybook/manager-api": "8.3.3", - "@storybook/preview-api": "8.3.3", - "@storybook/react": "8.3.3", - "@storybook/react-vite": "8.3.3", - "@storybook/test": "8.3.3", - "@storybook/theming": "8.3.3", - "@storybook/types": "8.3.3", - "@storybook/vue3": "8.3.3", - "@storybook/vue3-vite": "8.3.3", + "@storybook/addon-actions": "8.3.4", + "@storybook/addon-essentials": "8.3.4", + "@storybook/addon-interactions": "8.3.4", + "@storybook/addon-links": "8.3.4", + "@storybook/addon-mdx-gfm": "8.3.4", + "@storybook/addon-storysource": "8.3.4", + "@storybook/blocks": "8.3.4", + "@storybook/components": "8.3.4", + "@storybook/core-events": "8.3.4", + "@storybook/manager-api": "8.3.4", + "@storybook/preview-api": "8.3.4", + "@storybook/react": "8.3.4", + "@storybook/react-vite": "8.3.4", + "@storybook/test": "8.3.4", + "@storybook/theming": "8.3.4", + "@storybook/types": "8.3.4", + "@storybook/vue3": "8.3.4", + "@storybook/vue3-vite": "8.3.4", "@testing-library/vue": "8.1.0", + "@types/canvas-confetti": "^1.6.4", "@types/estree": "1.0.6", "@types/matter-js": "0.19.7", "@types/micromatch": "4.0.9", @@ -110,11 +111,11 @@ "@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/parser": "7.17.0", "@vitest/coverage-v8": "1.6.0", - "@vue/runtime-core": "3.5.10", + "@vue/runtime-core": "3.5.11", "acorn": "8.12.1", "cross-env": "7.0.3", "cypress": "13.15.0", - "eslint-plugin-import": "2.30.0", + "eslint-plugin-import": "2.31.0", "eslint-plugin-vue": "9.28.0", "fast-glob": "3.3.2", "happy-dom": "10.0.3", @@ -128,7 +129,7 @@ "react-dom": "18.3.1", "seedrandom": "3.0.5", "start-server-and-test": "2.0.8", - "storybook": "8.3.3", + "storybook": "8.3.4", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "vite-plugin-turbosnap": "1.0.3", "vitest": "1.6.0", diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index ddd47ca448..76459ab330 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -230,19 +230,25 @@ export async function mainBoot() { claimAchievement('collectAchievements30'); } - window.setInterval(() => { - if (Math.floor(Math.random() * 20000) === 0) { - claimAchievement('justPlainLucky'); - } - }, 1000 * 10); + if (!claimedAchievements.includes('justPlainLucky')) { + window.setInterval(() => { + if (Math.floor(Math.random() * 20000) === 0) { + claimAchievement('justPlainLucky'); + } + }, 1000 * 10); + } - window.setTimeout(() => { - claimAchievement('client30min'); - }, 1000 * 60 * 30); + if (!claimedAchievements.includes('client30min')) { + window.setTimeout(() => { + claimAchievement('client30min'); + }, 1000 * 60 * 30); + } - window.setTimeout(() => { - claimAchievement('client60min'); - }, 1000 * 60 * 60); + if (!claimedAchievements.includes('client60min')) { + window.setTimeout(() => { + claimAchievement('client60min'); + }, 1000 * 60 * 60); + } // é‚ªé” //const lastUsed = miLocalStorage.getItem('lastUsed'); diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue index a28e7c2559..0278cb30f0 100644 --- a/packages/frontend/src/components/MkAbuseReport.vue +++ b/packages/frontend/src/components/MkAbuseReport.vue @@ -4,112 +4,153 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div class="bcekxzvu _margin _panel"> - <div class="target"> - <MkA v-user-preview="report.targetUserId" class="info" :to="`/admin/user/${report.targetUserId}`" :behavior="'window'"> - <MkAvatar class="avatar" :user="report.targetUser" indicator/> - <div class="names"> - <MkUserName class="name" :user="report.targetUser"/> - <MkAcct class="acct" :user="report.targetUser" style="display: block;"/> - </div> - </MkA> - <MkKeyValue> - <template #key>{{ i18n.ts.registeredDate }}</template> - <template #value>{{ dateString(report.targetUser.createdAt) }} (<MkTime :time="report.targetUser.createdAt"/>)</template> - </MkKeyValue> - </div> - <div class="detail"> - <div> - <Mfm :text="report.comment" :linkNavigationBehavior="'window'"/> +<MkFolder> + <template #icon> + <i v-if="report.resolved && report.resolvedAs === 'accept'" class="ti ti-check" style="color: var(--success)"></i> + <i v-else-if="report.resolved && report.resolvedAs === 'reject'" class="ti ti-x" style="color: var(--error)"></i> + <i v-else-if="report.resolved" class="ti ti-slash"></i> + <i v-else class="ti ti-exclamation-circle" style="color: var(--warn)"></i> + </template> + <template #label><MkAcct :user="report.targetUser"/> (by <MkAcct :user="report.reporter"/>)</template> + <template #caption>{{ report.comment }}</template> + <template #suffix><MkTime :time="report.createdAt"/></template> + <template #footer> + <div class="_buttons"> + <template v-if="!report.resolved"> + <MkButton @click="resolve('accept')"><i class="ti ti-check" style="color: var(--success)"></i> {{ i18n.ts._abuseUserReport.resolve }} ({{ i18n.ts._abuseUserReport.accept }})</MkButton> + <MkButton @click="resolve('reject')"><i class="ti ti-x" style="color: var(--error)"></i> {{ i18n.ts._abuseUserReport.resolve }} ({{ i18n.ts._abuseUserReport.reject }})</MkButton> + <MkButton @click="resolve(null)"><i class="ti ti-slash"></i> {{ i18n.ts._abuseUserReport.resolve }} ({{ i18n.ts.other }})</MkButton> + </template> + <template v-if="report.targetUser.host != null"> + <MkButton :disabled="report.forwarded" primary @click="forward"><i class="ti ti-corner-up-right"></i> {{ i18n.ts._abuseUserReport.forward }}</MkButton> + <div v-tooltip:dialog="i18n.ts._abuseUserReport.forwardDescription" class="_button _help"><i class="ti ti-help-circle"></i></div> + </template> + <button class="_button" style="margin-left: auto; width: 34px;" @click="showMenu"><i class="ti ti-dots"></i></button> </div> - <hr/> - <div>{{ i18n.ts.reporter }}: <MkA :to="`/admin/user/${report.reporter.id}`" class="_link" :behavior="'window'">@{{ report.reporter.username }}</MkA></div> + </template> + + <div :class="$style.root" class="_gaps_s"> + <MkFolder :withSpacer="false"> + <template #icon><MkAvatar :user="report.targetUser" style="width: 18px; height: 18px;"/></template> + <template #label>{{ i18n.ts.target }}: <MkAcct :user="report.targetUser"/></template> + <template #suffix>#{{ report.targetUserId.toUpperCase() }}</template> + + <div style="container-type: inline-size;"> + <RouterView :router="targetRouter"/> + </div> + </MkFolder> + + <MkFolder :defaultOpen="true"> + <template #icon><i class="ti ti-message-2"></i></template> + <template #label>{{ i18n.ts.details }}</template> + <div class="_gaps_s"> + <Mfm :text="report.comment" :linkNavigationBehavior="'window'"/> + </div> + </MkFolder> + + <MkFolder :withSpacer="false"> + <template #icon><MkAvatar :user="report.reporter" style="width: 18px; height: 18px;"/></template> + <template #label>{{ i18n.ts.reporter }}: <MkAcct :user="report.reporter"/></template> + <template #suffix>#{{ report.reporterId.toUpperCase() }}</template> + + <div style="container-type: inline-size;"> + <RouterView :router="reporterRouter"/> + </div> + </MkFolder> + + <MkFolder :defaultOpen="false"> + <template #icon><i class="ti ti-message-2"></i></template> + <template #label>{{ i18n.ts.moderationNote }}</template> + <template #suffix>{{ moderationNote.length > 0 ? '...' : i18n.ts.none }}</template> + <div class="_gaps_s"> + <MkTextarea v-model="moderationNote" manualSave> + <template #caption>{{ i18n.ts.moderationNoteDescription }}</template> + </MkTextarea> + </div> + </MkFolder> + <div v-if="report.assignee"> {{ i18n.ts.moderator }}: <MkAcct :user="report.assignee"/> </div> - <div><MkTime :time="report.createdAt"/></div> - <div class="action"> - <MkSwitch v-model="forward" :disabled="report.targetUser.host == null || report.resolved"> - {{ i18n.ts.forwardReport }} - <template #caption>{{ i18n.ts.forwardReportIsAnonymous }}</template> - </MkSwitch> - <MkButton v-if="!report.resolved" primary @click="resolve">{{ i18n.ts.abuseMarkAsResolved }}</MkButton> - </div> </div> -</div> +</MkFolder> </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { provide, ref, watch } from 'vue'; +import * as Misskey from 'misskey-js'; import MkButton from '@/components/MkButton.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import MkKeyValue from '@/components/MkKeyValue.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { dateString } from '@/filters/date.js'; +import MkFolder from '@/components/MkFolder.vue'; +import RouterView from '@/components/global/RouterView.vue'; +import { useRouterFactory } from '@/router/supplier'; +import MkTextarea from '@/components/MkTextarea.vue'; +import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; const props = defineProps<{ - report: any; + report: Misskey.entities.AdminAbuseUserReportsResponse[number]; }>(); const emit = defineEmits<{ (ev: 'resolved', reportId: string): void; }>(); -const forward = ref(props.report.forwarded); +const routerFactory = useRouterFactory(); +const targetRouter = routerFactory(`/admin/user/${props.report.targetUserId}`); +targetRouter.init(); +const reporterRouter = routerFactory(`/admin/user/${props.report.reporterId}`); +reporterRouter.init(); + +const moderationNote = ref(props.report.moderationNote ?? ''); -function resolve() { +watch(moderationNote, async () => { + os.apiWithDialog('admin/update-abuse-user-report', { + reportId: props.report.id, + moderationNote: moderationNote.value, + }).then(() => { + }); +}); + +function resolve(resolvedAs) { os.apiWithDialog('admin/resolve-abuse-user-report', { - forward: forward.value, reportId: props.report.id, + resolvedAs, }).then(() => { emit('resolved', props.report.id); }); } -</script> - -<style lang="scss" scoped> -.bcekxzvu { - display: flex; - - > .target { - width: 35%; - box-sizing: border-box; - text-align: left; - padding: 24px; - border-right: solid 1px var(--divider); - > .info { - display: flex; - box-sizing: border-box; - align-items: center; - padding: 14px; - border-radius: 8px; - --c: rgb(255 196 0 / 15%); - background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%); - background-size: 16px 16px; - - > .avatar { - width: 42px; - height: 42px; - } +function forward() { + os.apiWithDialog('admin/forward-abuse-user-report', { + reportId: props.report.id, + }).then(() => { - > .names { - margin-left: 0.3em; - padding: 0 8px; - flex: 1; + }); +} - > .name { - font-weight: bold; - } - } - } - } +function showMenu(ev: MouseEvent) { + os.popupMenu([{ + icon: 'ti ti-id', + text: 'Copy ID', + action: () => { + copyToClipboard(props.report.id); + }, + }, { + icon: 'ti ti-json', + text: 'Copy JSON', + action: () => { + copyToClipboard(JSON.stringify(props.report, null, '\t')); + }, + }], ev.currentTarget ?? ev.target); +} +</script> - > .detail { - flex: 1; - padding: 24px; - } +<style lang="scss" module> +.root { } </style> diff --git a/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts b/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts new file mode 100644 index 0000000000..6763f7c546 --- /dev/null +++ b/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts @@ -0,0 +1,83 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { StoryObj } from '@storybook/vue3'; +import MkExtensionInstaller from './MkExtensionInstaller.vue'; +import lightTheme from '@@/themes/_light.json5'; + +export const Plugin = { + render(args) { + return { + components: { + MkExtensionInstaller, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '<MkExtensionInstaller v-bind="props" />', + }; + }, + args: { + extension: { + type: 'plugin', + raw: '"do nothing"', + meta: { + name: 'do nothing plugin', + version: '1.0', + author: 'syuilo and misskey-project', + description: 'a plugin that does nothing', + permissions: ['read:account'], + config: { + 'doNothing': true, + }, + }, + }, + }, + parameters: { + layout: 'centered', + }, +} satisfies StoryObj<typeof MkExtensionInstaller>; + +export const Theme = { + render(args) { + return { + components: { + MkExtensionInstaller, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '<MkExtensionInstaller v-bind="props" />', + }; + }, + args: { + extension: { + type: 'theme', + raw: JSON.stringify(lightTheme), + meta: lightTheme, + }, + }, + parameters: { + layout: 'centered', + }, +} satisfies StoryObj<typeof MkExtensionInstaller>; diff --git a/packages/frontend/src/components/MkExtensionInstaller.vue b/packages/frontend/src/components/MkExtensionInstaller.vue new file mode 100644 index 0000000000..0f7acd69e7 --- /dev/null +++ b/packages/frontend/src/components/MkExtensionInstaller.vue @@ -0,0 +1,146 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div class="_gaps_m" :class="$style.extInstallerRoot"> + <div :class="$style.extInstallerIconWrapper"> + <i v-if="isPlugin" class="ti ti-plug"></i> + <i v-else-if="isTheme" class="ti ti-palette"></i> + <!-- 拡張用? --> + <i v-else class="ti ti-download"></i> + </div> + <h2 :class="$style.extInstallerTitle">{{ i18n.ts._externalResourceInstaller[`_${extension.type}`].title }}</h2> + <div :class="$style.extInstallerNormDesc">{{ i18n.ts._externalResourceInstaller.checkVendorBeforeInstall }}</div> + <MkInfo v-if="isPlugin" :warn="true">{{ i18n.ts._plugin.installWarn }}</MkInfo> + <FormSection> + <template #label>{{ i18n.ts._externalResourceInstaller[`_${extension.type}`].metaTitle }}</template> + <div class="_gaps_s"> + <FormSplit> + <MkKeyValue> + <template #key>{{ i18n.ts.name }}</template> + <template #value>{{ extension.meta.name }}</template> + </MkKeyValue> + <MkKeyValue> + <template #key>{{ i18n.ts.author }}</template> + <template #value>{{ extension.meta.author }}</template> + </MkKeyValue> + </FormSplit> + <MkKeyValue v-if="isPlugin"> + <template #key>{{ i18n.ts.description }}</template> + <template #value>{{ extension.meta.description ?? i18n.ts.none }}</template> + </MkKeyValue> + <MkKeyValue v-if="isPlugin"> + <template #key>{{ i18n.ts.version }}</template> + <template #value>{{ extension.meta.version }}</template> + </MkKeyValue> + <MkKeyValue v-if="isPlugin"> + <template #key>{{ i18n.ts.permission }}</template> + <template #value> + <ul v-if="extension.meta.permissions && extension.meta.permissions.length > 0" :class="$style.extInstallerKVList"> + <li v-for="permission in extension.meta.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li> + </ul> + <template v-else>{{ i18n.ts.none }}</template> + </template> + </MkKeyValue> + <MkKeyValue v-if="isTheme"> + <template #key>{{ i18n.ts._externalResourceInstaller._meta.base }}</template> + <template #value>{{ i18n.ts[extension.meta.base ?? 'none'] }}</template> + </MkKeyValue> + <MkFolder> + <template #icon><i class="ti ti-code"></i></template> + <template #label>{{ i18n.ts._plugin.viewSource }}</template> + + <MkCode :code="extension.raw"/> + </MkFolder> + </div> + </FormSection> + <slot name="additionalInfo"/> + <div class="_buttonsCenter"> + <MkButton primary @click="emits('confirm')"><i class="ti ti-check"></i> {{ i18n.ts.install }}</MkButton> + </div> +</div> +</template> + +<script lang="ts"> +export type Extension = { + type: 'plugin'; + raw: string; + meta: { + name: string; + version: string; + author: string; + description?: string; + permissions?: string[]; + config?: Record<string, any>; + }; +} | { + type: 'theme'; + raw: string; + meta: { + name: string; + author: string; + base?: 'light' | 'dark'; + }; +}; +</script> +<script lang="ts" setup> +import { computed } from 'vue'; +import MkButton from '@/components/MkButton.vue'; +import FormSection from '@/components/form/section.vue'; +import FormSplit from '@/components/form/split.vue'; +import MkCode from '@/components/MkCode.vue'; +import MkInfo from '@/components/MkInfo.vue'; +import MkFolder from '@/components/MkFolder.vue'; +import MkKeyValue from '@/components/MkKeyValue.vue'; +import { i18n } from '@/i18n.js'; + +const isPlugin = computed(() => props.extension.type === 'plugin'); +const isTheme = computed(() => props.extension.type === 'theme'); + +const props = defineProps<{ + extension: Extension; +}>(); + +const emits = defineEmits<{ + (ev: 'confirm'): void; +}>(); +</script> + +<style lang="scss" module> +.extInstallerRoot { + border-radius: var(--radius); + background: var(--panel); + padding: 1.5rem; +} + +.extInstallerIconWrapper { + width: 48px; + height: 48px; + font-size: 24px; + line-height: 48px; + text-align: center; + border-radius: 50%; + margin-left: auto; + margin-right: auto; + + background-color: var(--accentedBg); + color: var(--accent); +} + +.extInstallerTitle { + font-size: 1.2rem; + text-align: center; + margin: 0; +} + +.extInstallerNormDesc { + text-align: center; +} + +.extInstallerKVList { + margin-top: 0; + margin-bottom: 0; +} +</style> diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index a5f3069d45..8262ae5d0c 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -38,9 +38,12 @@ SPDX-License-Identifier: AGPL-3.0-only > <KeepAlive> <div v-show="opened"> - <MkSpacer :marginMin="14" :marginMax="22"> + <MkSpacer v-if="withSpacer" :marginMin="14" :marginMax="22"> <slot></slot> </MkSpacer> + <div v-else> + <slot></slot> + </div> <div v-if="$slots.footer" :class="$style.footer"> <slot name="footer"></slot> </div> @@ -59,9 +62,11 @@ import { defaultStore } from '@/store.js'; const props = withDefaults(defineProps<{ defaultOpen?: boolean; maxHeight?: number | null; + withSpacer?: boolean; }>(), { defaultOpen: false, maxHeight: null, + withSpacer: true, }); const getBgColor = (el: HTMLElement) => { diff --git a/packages/frontend/src/components/MkFukidashi.vue b/packages/frontend/src/components/MkFukidashi.vue new file mode 100644 index 0000000000..09825487bf --- /dev/null +++ b/packages/frontend/src/components/MkFukidashi.vue @@ -0,0 +1,100 @@ +<!-- +SPDX-FileCopyrightText: syuilo and other misskey contributors +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div + :class="[ + $style.root, + tail === 'left' ? $style.left : $style.right, + negativeMargin === true && $style.negativeMargin, + shadow === true && $style.shadow, + ]" +> + <div :class="$style.bg"> + <svg v-if="tail !== 'none'" :class="$style.tail" version="1.1" viewBox="0 0 14.597 14.58" xmlns="http://www.w3.org/2000/svg"> + <g transform="translate(-173.71 -87.184)"> + <path d="m188.19 87.657c-1.469 2.3218-3.9315 3.8312-6.667 4.0865-2.2309-1.7379-4.9781-2.6816-7.8061-2.6815h-5.1e-4v12.702h12.702v-5.1e-4c2e-5 -1.9998-0.47213-3.9713-1.378-5.754 2.0709-1.6834 3.2732-4.2102 3.273-6.8791-6e-5 -0.49375-0.0413-0.98662-0.1235-1.4735z" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-width=".33225" style="paint-order:stroke fill markers"/> + </g> + </svg> + <div :class="$style.content"> + <slot></slot> + </div> + </div> +</div> +</template> + +<script setup lang="ts"> +withDefaults(defineProps<{ + tail?: 'left' | 'right' | 'none'; + negativeMargin?: boolean; + shadow?: boolean; +}>(), { + tail: 'right', + negativeMargin: false, + shadow: false, +}); +</script> + +<style module lang="scss"> +.root { + --fukidashi-radius: var(--radius); + --fukidashi-bg: var(--panel); + + position: relative; + display: inline-block; + min-height: calc(var(--fukidashi-radius) * 2); + padding-top: calc(var(--fukidashi-radius) * .13); + + &.shadow { + filter: drop-shadow(0 4px 32px var(--shadow)); + } + + &.left { + padding-left: calc(var(--fukidashi-radius) * .13); + + &.negativeMargin { + margin-left: calc(calc(var(--fukidashi-radius) * .13) * -1); + } + } + + &.right { + padding-right: calc(var(--fukidashi-radius) * .13); + + &.negativeMargin { + margin-right: calc(calc(var(--fukidashi-radius) * .13) * -1); + } + } +} + +.bg { + width: 100%; + height: 100%; + background: var(--fukidashi-bg); + border-radius: var(--fukidashi-radius); +} + +.content { + position: relative; + padding: 8px 12px; +} + +.tail { + position: absolute; + top: 0; + display: block; + width: calc(var(--fukidashi-radius) * 1.13); + height: auto; + fill: var(--fukidashi-bg); +} + +.left .tail { + left: 0; + transform: rotateY(180deg); +} + +.right .tail { + right: 0; +} +</style> diff --git a/packages/frontend/src/components/MkMention.vue b/packages/frontend/src/components/MkMention.vue index 9d9661e816..71bd5addfb 100644 --- a/packages/frontend/src/components/MkMention.vue +++ b/packages/frontend/src/components/MkMention.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }" :behavior="navigationBehavior"> +<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :behavior="navigationBehavior"> <img :class="$style.icon" :src="avatarUrl" alt=""> <span> <span>@{{ username }}</span> @@ -16,7 +16,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { toUnicode } from 'punycode'; import { computed } from 'vue'; -import tinycolor from 'tinycolor2'; import { host as localHost } from '@@/js/config.js'; import { $i } from '@/account.js'; import { defaultStore } from '@/store.js'; @@ -37,11 +36,7 @@ const isMe = $i && ( `@${props.username}@${toUnicode(props.host)}` === `@${$i.username}@${toUnicode(localHost)}`.toLowerCase() ); -const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue(isMe ? '--mentionMe' : '--mention')); -bg.setAlpha(0.1); -const bgCss = bg.toRgbString(); - -const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages +const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar ? getStaticImageUrl(`/avatar/@${props.username}@${props.host}`) : `/avatar/@${props.username}@${props.host}`, ); @@ -53,9 +48,11 @@ const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages padding: 4px 8px 4px 4px; border-radius: 999px; color: var(--mention); + background: color(from var(--mention) srgb r g b / 0.1); &.isMe { color: var(--mentionMe); + background: color(from var(--mentionMe) srgb r g b / 0.1); } } diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index 890b99fcc2..14f6bdcc34 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -437,9 +437,11 @@ onBeforeUnmount(() => { &.big:not(.asDrawer) { > .menu { + min-width: 230px; + > .item { padding: 6px 20px; - font-size: 1em; + font-size: 0.95em; line-height: 24px; } } diff --git a/packages/frontend/src/components/MkNoteHeader.vue b/packages/frontend/src/components/MkNoteHeader.vue index 888c570571..a75b9ddd10 100644 --- a/packages/frontend/src/components/MkNoteHeader.vue +++ b/packages/frontend/src/components/MkNoteHeader.vue @@ -5,18 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <header :class="$style.root"> - <component :is="defaultStore.state.enableCondensedLine ? 'MkCondensedLine' : 'div'" :minScale="0.5" style="min-width: 0;"> - <div style="display: flex; white-space: nowrap; align-items: baseline;"> - <div v-if="mock" :class="$style.name"> - <MkUserName :user="note.user"/> - </div> - <MkA v-else v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)"> - <MkUserName :user="note.user"/> - </MkA> - <div v-if="note.user.isBot" :class="$style.isBot">bot</div> - <div :class="$style.username"><MkAcct :user="note.user"/></div> - </div> - </component> + <div v-if="mock" :class="$style.name"> + <MkUserName :user="note.user"/> + </div> + <MkA v-else v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)"> + <MkUserName :user="note.user"/> + </MkA> + <div v-if="note.user.isBot" :class="$style.isBot">bot</div> + <div :class="$style.username"><MkAcct :user="note.user"/></div> <div v-if="note.user.badgeRoles" :class="$style.badgeRoles"> <img v-for="(role, i) in note.user.badgeRoles" :key="i" v-tooltip="role.name" :class="$style.badgeRole" :src="role.iconUrl!"/> </div> diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index 12c2974de4..b27d883b85 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -7,13 +7,12 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.root"> <div :class="$style.head"> <MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/> - <MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/> + <MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/> <div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div> <div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div> <div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div> <img v-else-if="notification.type === 'test'" :class="$style.icon" :src="infoImageUrl"/> <MkAvatar v-else-if="'user' in notification" :class="$style.icon" :user="notification.user" link preview/> - <MkAvatar v-else-if="notification.type === 'exportCompleted'" :class="$style.icon" :user="$i" link preview/> <img v-else-if="'icon' in notification && notification.icon != null" :class="[$style.icon, $style.icon_app]" :src="notification.icon" alt=""/> <div :class="[$style.subIcon, { @@ -27,6 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only [$style.t_pollEnded]: notification.type === 'pollEnded', [$style.t_achievementEarned]: notification.type === 'achievementEarned', [$style.t_exportCompleted]: notification.type === 'exportCompleted', + [$style.t_login]: notification.type === 'login', [$style.t_roleAssigned]: notification.type === 'roleAssigned' && notification.role.iconUrl == null, }]" > @@ -40,6 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only <i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i> <i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i> <i v-else-if="notification.type === 'exportCompleted'" class="ti ti-archive"></i> + <i v-else-if="notification.type === 'login'" class="ti ti-login-2"></i> <template v-else-if="notification.type === 'roleAssigned'"> <img v-if="notification.role.iconUrl" style="height: 1.3em; vertical-align: -22%;" :src="notification.role.iconUrl" alt=""/> <i v-else class="ti ti-badges"></i> @@ -59,6 +60,7 @@ SPDX-License-Identifier: AGPL-3.0-only <span v-else-if="notification.type === 'note'">{{ i18n.ts._notification.newNote }}: <MkUserName :user="notification.note.user"/></span> <span v-else-if="notification.type === 'roleAssigned'">{{ i18n.ts._notification.roleAssigned }}</span> <span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span> + <span v-else-if="notification.type === 'login'">{{ i18n.ts._notification.login }}</span> <span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span> <span v-else-if="notification.type === 'exportCompleted'">{{ i18n.tsx._notification.exportOfXCompleted({ x: exportEntityName[notification.exportedEntity] }) }}</span> <MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA> @@ -225,6 +227,7 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification) --eventReactionHeart: var(--love); --eventReaction: #e99a0b; --eventAchievement: #cb9a11; + --eventLogin: #007aff; --eventOther: #88a6b7; } @@ -346,6 +349,12 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification) pointer-events: none; } +.t_login { + padding: 3px; + background: var(--eventLogin); + pointer-events: none; +} + .tail { flex: 1; min-width: 0; diff --git a/packages/frontend/src/components/MkPostFormAttaches.vue b/packages/frontend/src/components/MkPostFormAttaches.vue index 80b75a0875..42322fec3d 100644 --- a/packages/frontend/src/components/MkPostFormAttaches.vue +++ b/packages/frontend/src/components/MkPostFormAttaches.vue @@ -7,7 +7,14 @@ SPDX-License-Identifier: AGPL-3.0-only <div v-show="props.modelValue.length != 0" :class="$style.root"> <Sortable :modelValue="props.modelValue" :class="$style.files" itemKey="id" :animation="150" :delay="100" :delayOnTouchOnly="true" @update:modelValue="v => emit('update:modelValue', v)"> <template #item="{element}"> - <div :class="$style.file" @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)"> + <div + :class="$style.file" + role="button" + tabindex="0" + @click="showFileMenu(element, $event)" + @keydown.space.enter="showFileMenu(element, $event)" + @contextmenu.prevent="showFileMenu(element, $event)" + > <MkDriveFileThumbnail :data-id="element.id" :class="$style.thumbnail" :file="element" fit="cover"/> <div v-if="element.isSensitive" :class="$style.sensitive"> <i class="ti ti-eye-exclamation" style="margin: auto;"></i> @@ -133,7 +140,7 @@ async function crop(file: Misskey.entities.DriveFile): Promise<void> { emit('replaceFile', file, newFile); } -function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void { +function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent | KeyboardEvent): void { if (menuShowing) return; const isImage = file.type.startsWith('image/'); @@ -199,6 +206,10 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void { border-radius: 4px; overflow: hidden; cursor: move; + + &:focus-visible { + outline-offset: 4px; + } } .thumbnail { diff --git a/packages/frontend/src/components/MkSignin.input.vue b/packages/frontend/src/components/MkSignin.input.vue new file mode 100644 index 0000000000..6336b78c80 --- /dev/null +++ b/packages/frontend/src/components/MkSignin.input.vue @@ -0,0 +1,206 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div :class="$style.wrapper" data-cy-signin-page-input> + <div :class="$style.root"> + <div :class="$style.avatar"> + <i class="ti ti-user"></i> + </div> + + <!-- ãƒã‚°ã‚¤ãƒ³ç”»é¢ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ --> + <MkInfo v-if="message"> + {{ message }} + </MkInfo> + + <!-- 外部サーãƒãƒ¼ã¸ã®è»¢é€ --> + <div v-if="openOnRemote" class="_gaps_m"> + <div class="_gaps_s"> + <MkButton type="button" rounded primary style="margin: 0 auto;" @click="openRemote(openOnRemote)"> + {{ i18n.ts.continueOnRemote }} <i class="ti ti-external-link"></i> + </MkButton> + <button type="button" class="_button" :class="$style.instanceManualSelectButton" @click="specifyHostAndOpenRemote(openOnRemote)"> + {{ i18n.ts.specifyServerHost }} + </button> + </div> + <div :class="$style.orHr"> + <p :class="$style.orMsg">{{ i18n.ts.or }}</p> + </div> + </div> + + <!-- username入力 --> + <form class="_gaps_s" @submit.prevent="emit('usernameSubmitted', username)"> + <MkInput v-model="username" :placeholder="i18n.ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autocomplete="username webauthn" autofocus required data-cy-signin-username> + <template #prefix>@</template> + <template #suffix>@{{ host }}</template> + </MkInput> + <MkButton type="submit" large primary rounded style="margin: 0 auto;" data-cy-signin-page-input-continue>{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + </form> + + <!-- パスワードレスãƒã‚°ã‚¤ãƒ³ --> + <div :class="$style.orHr"> + <p :class="$style.orMsg">{{ i18n.ts.or }}</p> + </div> + <div> + <MkButton type="submit" style="margin: auto auto;" large rounded primary gradate @click="emit('passkeyClick', $event)"> + <i class="ti ti-device-usb" style="font-size: medium;"></i>{{ i18n.ts.signinWithPasskey }} + </MkButton> + </div> + </div> +</div> +</template> + +<script setup lang="ts"> +import { ref } from 'vue'; +import { toUnicode } from 'punycode/'; + +import { query, extractDomain } from '@@/js/url.js'; +import { host as configHost } from '@@/js/config.js'; +import type { OpenOnRemoteOptions } from '@/scripts/please-login.js'; +import { i18n } from '@/i18n.js'; +import * as os from '@/os.js'; + +import MkButton from '@/components/MkButton.vue'; +import MkInput from '@/components/MkInput.vue'; +import MkInfo from '@/components/MkInfo.vue'; + +const props = withDefaults(defineProps<{ + message?: string, + openOnRemote?: OpenOnRemoteOptions, +}>(), { + message: '', + openOnRemote: undefined, +}); + +const emit = defineEmits<{ + (ev: 'usernameSubmitted', v: string): void; + (ev: 'passkeyClick', v: MouseEvent): void; +}>(); + +const host = toUnicode(configHost); + +const username = ref(''); + +//#region Open on remote +function openRemote(options: OpenOnRemoteOptions, targetHost?: string): void { + switch (options.type) { + case 'web': + case 'lookup': { + let _path: string; + + if (options.type === 'lookup') { + // TODO: v2024.7.0以é™ãŒæµ¸é€ã—ã¦ããŸã‚‰æ£å¼ãªURLã«å¤‰æ›´ã™ã‚‹â–¼ + // _path = `/lookup?uri=${encodeURIComponent(_path)}`; + _path = `/authorize-follow?acct=${encodeURIComponent(options.url)}`; + } else { + _path = options.path; + } + + if (targetHost) { + window.open(`https://${targetHost}${_path}`, '_blank', 'noopener'); + } else { + window.open(`https://misskey-hub.net/mi-web/?path=${encodeURIComponent(_path)}`, '_blank', 'noopener'); + } + break; + } + case 'share': { + const params = query(options.params); + if (targetHost) { + window.open(`https://${targetHost}/share?${params}`, '_blank', 'noopener'); + } else { + window.open(`https://misskey-hub.net/share/?${params}`, '_blank', 'noopener'); + } + break; + } + } +} + +async function specifyHostAndOpenRemote(options: OpenOnRemoteOptions): Promise<void> { + const { canceled, result: hostTemp } = await os.inputText({ + title: i18n.ts.inputHostName, + placeholder: 'misskey.example.com', + }); + + if (canceled) return; + + let targetHost: string | null = hostTemp; + + // ドメイン部分ã ã‘ã‚’å–り出㙠+ targetHost = extractDomain(targetHost ?? ''); + if (targetHost == null) { + os.alert({ + type: 'error', + title: i18n.ts.invalidValue, + text: i18n.ts.tryAgain, + }); + return; + } + openRemote(options, targetHost); +} +//#endregion +</script> + +<style lang="scss" module> +.root { + display: flex; + flex-direction: column; + gap: 20px; +} + +.wrapper { + display: flex; + align-items: center; + width: 100%; + min-height: 336px; + + > .root { + width: 100%; + } +} + +.avatar { + margin: 0 auto; + background-color: color-mix(in srgb, var(--fg), transparent 85%); + color: color-mix(in srgb, var(--fg), transparent 25%); + text-align: center; + height: 64px; + width: 64px; + font-size: 24px; + line-height: 64px; + border-radius: 50%; +} + +.instanceManualSelectButton { + display: block; + text-align: center; + opacity: .7; + font-size: .8em; + + &:hover { + text-decoration: underline; + } +} + +.orHr { + position: relative; + margin: .4em auto; + width: 100%; + height: 1px; + background: var(--divider); +} + +.orMsg { + position: absolute; + top: -.6em; + display: inline-block; + padding: 0 1em; + background: var(--panel); + font-size: 0.8em; + color: var(--fgOnPanel); + margin: 0; + left: 50%; + transform: translateX(-50%); +} +</style> diff --git a/packages/frontend/src/components/MkSignin.passkey.vue b/packages/frontend/src/components/MkSignin.passkey.vue new file mode 100644 index 0000000000..0d68955fab --- /dev/null +++ b/packages/frontend/src/components/MkSignin.passkey.vue @@ -0,0 +1,92 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div :class="$style.wrapper"> + <div class="_gaps" :class="$style.root"> + <div class="_gaps_s"> + <div :class="$style.passkeyIcon"> + <i class="ti ti-fingerprint"></i> + </div> + <div :class="$style.passkeyDescription">{{ i18n.ts.useSecurityKey }}</div> + </div> + + <MkButton large primary rounded :disabled="queryingKey" style="margin: 0 auto;" @click="queryKey">{{ i18n.ts.retry }}</MkButton> + + <MkButton v-if="isPerformingPasswordlessLogin !== true" transparent rounded :disabled="queryingKey" style="margin: 0 auto;" @click="emit('useTotp')">{{ i18n.ts.useTotp }}</MkButton> + </div> +</div> +</template> + +<script setup lang="ts"> +import { ref, onMounted } from 'vue'; +import { get as webAuthnRequest } from '@github/webauthn-json/browser-ponyfill'; + +import { i18n } from '@/i18n.js'; + +import MkButton from '@/components/MkButton.vue'; + +import type { AuthenticationPublicKeyCredential } from '@github/webauthn-json/browser-ponyfill'; + +const props = defineProps<{ + credentialRequest: CredentialRequestOptions; + isPerformingPasswordlessLogin?: boolean; +}>(); + +const emit = defineEmits<{ + (ev: 'done', credential: AuthenticationPublicKeyCredential): void; + (ev: 'useTotp'): void; +}>(); + +const queryingKey = ref(true); + +async function queryKey() { + queryingKey.value = true; + await webAuthnRequest(props.credentialRequest) + .catch(() => { + return Promise.reject(null); + }) + .then((credential) => { + emit('done', credential); + }) + .finally(() => { + queryingKey.value = false; + }); +} + +onMounted(() => { + queryKey(); +}); +</script> + +<style lang="scss" module> +.wrapper { + display: flex; + align-items: center; + width: 100%; + min-height: 336px; + + > .root { + width: 100%; + } +} + +.passkeyIcon { + margin: 0 auto; + background-color: var(--accentedBg); + color: var(--accent); + text-align: center; + height: 64px; + width: 64px; + font-size: 24px; + line-height: 64px; + border-radius: 50%; +} + +.passkeyDescription { + text-align: center; + font-size: 1.1em; +} +</style> diff --git a/packages/frontend/src/components/MkSignin.password.vue b/packages/frontend/src/components/MkSignin.password.vue new file mode 100644 index 0000000000..2d79e2aeb1 --- /dev/null +++ b/packages/frontend/src/components/MkSignin.password.vue @@ -0,0 +1,181 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div :class="$style.wrapper" data-cy-signin-page-password> + <div class="_gaps" :class="$style.root"> + <div :class="$style.avatar" :style="{ backgroundImage: user ? `url('${user.avatarUrl}')` : undefined }"></div> + <div :class="$style.welcomeBackMessage"> + <I18n :src="i18n.ts.welcomeBackWithName" tag="span"> + <template #name><Mfm :text="user.name ?? user.username" :plain="true"/></template> + </I18n> + </div> + + <!-- password入力 --> + <form class="_gaps_s" @submit.prevent="onSubmit"> + <!-- ブラウザ オートコンプリート用 --> + <input type="hidden" name="username" autocomplete="username" :value="user.username"> + + <MkInput v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password webauthn" :withPasswordToggle="true" required autofocus data-cy-signin-password> + <template #prefix><i class="ti ti-lock"></i></template> + <template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template> + </MkInput> + + <div v-if="needCaptcha"> + <MkCaptcha v-if="instance.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" :class="$style.captcha" provider="hcaptcha" :sitekey="instance.hcaptchaSiteKey"/> + <MkCaptcha v-if="instance.enableMcaptcha" ref="mcaptcha" v-model="mCaptchaResponse" :class="$style.captcha" provider="mcaptcha" :sitekey="instance.mcaptchaSiteKey" :instanceUrl="instance.mcaptchaInstanceUrl"/> + <MkCaptcha v-if="instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" :class="$style.captcha" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/> + <MkCaptcha v-if="instance.enableTurnstile" ref="turnstile" v-model="turnstileResponse" :class="$style.captcha" provider="turnstile" :sitekey="instance.turnstileSiteKey"/> + </div> + + <MkButton type="submit" :disabled="needCaptcha && captchaFailed" large primary rounded style="margin: 0 auto;" data-cy-signin-page-password-continue>{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + </form> + </div> +</div> +</template> + +<script lang="ts"> +export type PwResponse = { + password: string; + captcha: { + hCaptchaResponse: string | null; + mCaptchaResponse: string | null; + reCaptchaResponse: string | null; + turnstileResponse: string | null; + }; +}; +</script> + +<script setup lang="ts"> +import { ref, computed, useTemplateRef, defineAsyncComponent } from 'vue'; +import * as Misskey from 'misskey-js'; + +import { instance } from '@/instance.js'; +import { i18n } from '@/i18n.js'; +import * as os from '@/os.js'; + +import MkButton from '@/components/MkButton.vue'; +import MkInput from '@/components/MkInput.vue'; +import MkCaptcha from '@/components/MkCaptcha.vue'; + +const props = defineProps<{ + user: Misskey.entities.UserDetailed; + needCaptcha: boolean; +}>(); + +const emit = defineEmits<{ + (ev: 'passwordSubmitted', v: PwResponse): void; +}>(); + +const password = ref(''); + +const hCaptcha = useTemplateRef('hcaptcha'); +const mCaptcha = useTemplateRef('mcaptcha'); +const reCaptcha = useTemplateRef('recaptcha'); +const turnstile = useTemplateRef('turnstile'); + +const hCaptchaResponse = ref<string | null>(null); +const mCaptchaResponse = ref<string | null>(null); +const reCaptchaResponse = ref<string | null>(null); +const turnstileResponse = ref<string | null>(null); + +const captchaFailed = computed((): boolean => { + return ( + (instance.enableHcaptcha && !hCaptchaResponse.value) || + (instance.enableMcaptcha && !mCaptchaResponse.value) || + (instance.enableRecaptcha && !reCaptchaResponse.value) || + (instance.enableTurnstile && !turnstileResponse.value) + ); +}); + +function resetPassword(): void { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkForgotPassword.vue')), {}, { + closed: () => dispose(), + }); +} + +function onSubmit() { + emit('passwordSubmitted', { + password: password.value, + captcha: { + hCaptchaResponse: hCaptchaResponse.value, + mCaptchaResponse: mCaptchaResponse.value, + reCaptchaResponse: reCaptchaResponse.value, + turnstileResponse: turnstileResponse.value, + }, + }); +} + +function resetCaptcha() { + hCaptcha.value?.reset(); + mCaptcha.value?.reset(); + reCaptcha.value?.reset(); + turnstile.value?.reset(); +} + +defineExpose({ + resetCaptcha, +}); +</script> + +<style lang="scss" module> +.wrapper { + display: flex; + align-items: center; + width: 100%; + min-height: 336px; + + > .root { + width: 100%; + } +} + +.avatar { + margin: 0 auto 0 auto; + width: 64px; + height: 64px; + background: #ddd; + background-position: center; + background-size: cover; + border-radius: 100%; +} + +.welcomeBackMessage { + text-align: center; + font-size: 1.1em; +} + +.instanceManualSelectButton { + display: block; + text-align: center; + opacity: .7; + font-size: .8em; + + &:hover { + text-decoration: underline; + } +} + +.orHr { + position: relative; + margin: .4em auto; + width: 100%; + height: 1px; + background: var(--divider); +} + +.orMsg { + position: absolute; + top: -.6em; + display: inline-block; + padding: 0 1em; + background: var(--panel); + font-size: 0.8em; + color: var(--fgOnPanel); + margin: 0; + left: 50%; + transform: translateX(-50%); +} +</style> diff --git a/packages/frontend/src/components/MkSignin.totp.vue b/packages/frontend/src/components/MkSignin.totp.vue new file mode 100644 index 0000000000..880c08315e --- /dev/null +++ b/packages/frontend/src/components/MkSignin.totp.vue @@ -0,0 +1,74 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div :class="$style.wrapper"> + <div class="_gaps" :class="$style.root"> + <div class="_gaps_s"> + <div :class="$style.totpIcon"> + <i class="ti ti-key"></i> + </div> + <div :class="$style.totpDescription">{{ i18n.ts['2fa'] }}</div> + </div> + + <!-- totp入力 --> + <form class="_gaps_s" @submit.prevent="emit('totpSubmitted', token)"> + <MkInput v-model="token" type="text" :pattern="isBackupCode ? '^[A-Z0-9]{32}$' :'^[0-9]{6}$'" autocomplete="one-time-code" required autofocus :spellcheck="false" :inputmode="isBackupCode ? undefined : 'numeric'"> + <template #label>{{ i18n.ts.token }} ({{ i18n.ts['2fa'] }})</template> + <template #prefix><i v-if="isBackupCode" class="ti ti-key"></i><i v-else class="ti ti-123"></i></template> + <template #caption><button class="_textButton" type="button" @click="isBackupCode = !isBackupCode">{{ isBackupCode ? i18n.ts.useTotp : i18n.ts.useBackupCode }}</button></template> + </MkInput> + + <MkButton type="submit" large primary rounded style="margin: 0 auto;">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + </form> + </div> +</div> +</template> + +<script setup lang="ts"> +import { ref } from 'vue'; + +import { i18n } from '@/i18n.js'; + +import MkButton from '@/components/MkButton.vue'; +import MkInput from '@/components/MkInput.vue'; + +const emit = defineEmits<{ + (ev: 'totpSubmitted', token: string): void; +}>(); + +const token = ref(''); +const isBackupCode = ref(false); +</script> + +<style lang="scss" module> +.wrapper { + display: flex; + align-items: center; + width: 100%; + min-height: 336px; + + > .root { + width: 100%; + } +} + +.totpIcon { + margin: 0 auto; + background-color: var(--accentedBg); + color: var(--accent); + text-align: center; + height: 64px; + width: 64px; + font-size: 24px; + line-height: 64px; + border-radius: 50%; +} + +.totpDescription { + text-align: center; + font-size: 1.1em; +} +</style> diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index 7942a84d66..26e1ac516c 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -4,239 +4,288 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<form :class="{ signing, totpLogin }" @submit.prevent="onSubmit"> - <div class="_gaps_m"> - <div v-show="withAvatar" :class="$style.avatar" :style="{ backgroundImage: user ? `url('${user.avatarUrl}')` : undefined, marginBottom: message ? '1.5em' : undefined }"></div> - <MkInfo v-if="message"> - {{ message }} - </MkInfo> - <div v-if="openOnRemote" class="_gaps_m"> - <div class="_gaps_s"> - <MkButton type="button" rounded primary style="margin: 0 auto;" @click="openRemote(openOnRemote)"> - {{ i18n.ts.continueOnRemote }} <i class="ti ti-external-link"></i> - </MkButton> - <button type="button" class="_button" :class="$style.instanceManualSelectButton" @click="specifyHostAndOpenRemote(openOnRemote)"> - {{ i18n.ts.specifyServerHost }} - </button> - </div> - <div :class="$style.orHr"> - <p :class="$style.orMsg">{{ i18n.ts.or }}</p> - </div> - </div> - <div v-if="!totpLogin" class="normal-signin _gaps_m"> - <MkInput v-model="username" :placeholder="i18n.ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autocomplete="username webauthn" autofocus required data-cy-signin-username @update:modelValue="onUsernameChange"> - <template #prefix>@</template> - <template #suffix>@{{ host }}</template> - </MkInput> - <MkInput v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password webauthn" :withPasswordToggle="true" required data-cy-signin-password> - <template #prefix><i class="ti ti-lock"></i></template> - <template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template> - </MkInput> - <MkButton type="submit" large primary rounded :disabled="signing" style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton> - </div> - <div v-if="totpLogin" class="2fa-signin" :class="{ securityKeys: user && user.securityKeys }"> - <div v-if="user && user.securityKeys" class="twofa-group tap-group"> - <p>{{ i18n.ts.useSecurityKey }}</p> - <MkButton v-if="!queryingKey" @click="query2FaKey"> - {{ i18n.ts.retry }} - </MkButton> - </div> - <div v-if="user && user.securityKeys" :class="$style.orHr"> - <p :class="$style.orMsg">{{ i18n.ts.or }}</p> - </div> - <div class="twofa-group totp-group _gaps"> - <MkInput v-model="token" type="text" :pattern="isBackupCode ? '^[A-Z0-9]{32}$' :'^[0-9]{6}$'" autocomplete="one-time-code" required :spellcheck="false" :inputmode="isBackupCode ? undefined : 'numeric'"> - <template #label>{{ i18n.ts.token }} ({{ i18n.ts['2fa'] }})</template> - <template #prefix><i v-if="isBackupCode" class="ti ti-key"></i><i v-else class="ti ti-123"></i></template> - <template #caption><button class="_textButton" type="button" @click="isBackupCode = !isBackupCode">{{ isBackupCode ? i18n.ts.useTotp : i18n.ts.useBackupCode }}</button></template> - </MkInput> - <MkButton type="submit" :disabled="signing" large primary rounded style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton> - </div> - </div> - <div v-if="!totpLogin && usePasswordLessLogin" :class="$style.orHr"> - <p :class="$style.orMsg">{{ i18n.ts.or }}</p> - </div> - <div v-if="!totpLogin && usePasswordLessLogin" class="twofa-group tap-group"> - <MkButton v-if="!queryingKey" type="submit" :disabled="signing" style="margin: auto auto;" rounded large primary @click="onPasskeyLogin"> - <i class="ti ti-device-usb" style="font-size: medium;"></i> - {{ signing ? i18n.ts.loggingIn : i18n.ts.signinWithPasskey }} - </MkButton> - <p v-if="queryingKey">{{ i18n.ts.useSecurityKey }}</p> - </div> +<div :class="$style.signinRoot"> + <Transition + mode="out-in" + :enterActiveClass="$style.transition_enterActive" + :leaveActiveClass="$style.transition_leaveActive" + :enterFromClass="$style.transition_enterFrom" + :leaveToClass="$style.transition_leaveTo" + + :inert="waiting" + > + <!-- 1. 外部サーãƒãƒ¼ã¸ã®è»¢é€ãƒ»username入力・パスã‚ー --> + <XInput + v-if="page === 'input'" + key="input" + :message="message" + :openOnRemote="openOnRemote" + + @usernameSubmitted="onUsernameSubmitted" + @passkeyClick="onPasskeyLogin" + /> + + <!-- 2. パスワード入力 --> + <XPassword + v-else-if="page === 'password'" + key="password" + ref="passwordPageEl" + + :user="userInfo!" + :needCaptcha="needCaptcha" + + @passwordSubmitted="onPasswordSubmitted" + /> + + <!-- 3. ワンタイムパスワード --> + <XTotp + v-else-if="page === 'totp'" + key="totp" + + @totpSubmitted="onTotpSubmitted" + /> + + <!-- 4. パスã‚ー --> + <XPasskey + v-else-if="page === 'passkey'" + key="passkey" + + :credentialRequest="credentialRequest!" + :isPerformingPasswordlessLogin="doingPasskeyFromInputPage" + + @done="onPasskeyDone" + @useTotp="onUseTotp" + /> + </Transition> + <div v-if="waiting" :class="$style.waitingRoot"> + <MkLoading/> </div> -</form> +</div> </template> -<script lang="ts" setup> -import { defineAsyncComponent, ref } from 'vue'; -import { toUnicode } from 'punycode/'; +<script setup lang="ts"> +import { nextTick, onBeforeUnmount, ref, shallowRef, useTemplateRef } from 'vue'; import * as Misskey from 'misskey-js'; -import { supported as webAuthnSupported, get as webAuthnRequest, parseRequestOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill'; -import { SigninWithPasskeyResponse } from 'misskey-js/entities.js'; -import { query, extractDomain } from '@@/js/url.js'; -import { host as configHost } from '@@/js/config.js'; -import MkDivider from './MkDivider.vue'; -import type { OpenOnRemoteOptions } from '@/scripts/please-login.js'; -import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js'; -import MkButton from '@/components/MkButton.vue'; -import MkInput from '@/components/MkInput.vue'; -import MkInfo from '@/components/MkInfo.vue'; -import * as os from '@/os.js'; +import { supported as webAuthnSupported, parseRequestOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill'; + import { misskeyApi } from '@/scripts/misskey-api.js'; +import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js'; import { login } from '@/account.js'; import { i18n } from '@/i18n.js'; +import * as os from '@/os.js'; -const signing = ref(false); -const user = ref<Misskey.entities.UserDetailed | null>(null); -const usePasswordLessLogin = ref<Misskey.entities.UserDetailed['usePasswordLessLogin']>(true); -const username = ref(''); -const password = ref(''); -const token = ref(''); -const host = ref(toUnicode(configHost)); -const totpLogin = ref(false); -const isBackupCode = ref(false); -const queryingKey = ref(false); -let credentialRequest: CredentialRequestOptions | null = null; -const passkey_context = ref(''); +import XInput from '@/components/MkSignin.input.vue'; +import XPassword, { type PwResponse } from '@/components/MkSignin.password.vue'; +import XTotp from '@/components/MkSignin.totp.vue'; +import XPasskey from '@/components/MkSignin.passkey.vue'; + +import type { AuthenticationPublicKeyCredential } from '@github/webauthn-json/browser-ponyfill'; +import type { OpenOnRemoteOptions } from '@/scripts/please-login.js'; const emit = defineEmits<{ - (ev: 'login', v: any): void; + (ev: 'login', v: Misskey.entities.SigninFlowResponse): void; }>(); const props = withDefaults(defineProps<{ - withAvatar?: boolean; autoSet?: boolean; message?: string, openOnRemote?: OpenOnRemoteOptions, }>(), { - withAvatar: true, autoSet: false, message: '', openOnRemote: undefined, }); -function onUsernameChange(): void { - misskeyApi('users/show', { - username: username.value, - }).then(userResponse => { - user.value = userResponse; - usePasswordLessLogin.value = userResponse.usePasswordLessLogin; - }, () => { - user.value = null; - usePasswordLessLogin.value = true; - }); -} +const page = ref<'input' | 'password' | 'totp' | 'passkey'>('input'); +const waiting = ref(false); -function onLogin(res: any): Promise<void> | void { - if (props.autoSet) { - return login(res.i); - } -} +const passwordPageEl = useTemplateRef('passwordPageEl'); +const needCaptcha = ref(false); -async function query2FaKey(): Promise<void> { - if (credentialRequest == null) return; - queryingKey.value = true; - await webAuthnRequest(credentialRequest) - .catch(() => { - queryingKey.value = false; - return Promise.reject(null); - }).then(credential => { - credentialRequest = null; - queryingKey.value = false; - signing.value = true; - return misskeyApi('signin', { - username: username.value, - password: password.value, - credential: credential.toJSON(), - }); - }).then(res => { - emit('login', res); - return onLogin(res); - }).catch(err => { - if (err === null) return; - os.alert({ - type: 'error', - text: i18n.ts.signinFailed, - }); - signing.value = false; - }); -} +const userInfo = ref<null | Misskey.entities.UserDetailed>(null); +const password = ref(''); + +//#region Passkey Passwordless +const credentialRequest = shallowRef<CredentialRequestOptions | null>(null); +const passkeyContext = ref(''); +const doingPasskeyFromInputPage = ref(false); function onPasskeyLogin(): void { - signing.value = true; if (webAuthnSupported()) { + doingPasskeyFromInputPage.value = true; + waiting.value = true; misskeyApi('signin-with-passkey', {}) - .then((res: SigninWithPasskeyResponse) => { - totpLogin.value = false; - signing.value = false; - queryingKey.value = true; - passkey_context.value = res.context ?? ''; - credentialRequest = parseRequestOptionsFromJSON({ + .then((res) => { + passkeyContext.value = res.context ?? ''; + credentialRequest.value = parseRequestOptionsFromJSON({ publicKey: res.option, }); + + page.value = 'passkey'; + waiting.value = false; }) - .then(() => queryPasskey()) - .catch(loginFailed); + .catch(onSigninApiError); } } -async function queryPasskey(): Promise<void> { - if (credentialRequest == null) return; - queryingKey.value = true; - console.log('Waiting passkey auth...'); - await webAuthnRequest(credentialRequest) - .catch((err) => { - console.warn('Passkey Auth fail!: ', err); - queryingKey.value = false; - return Promise.reject(null); - }).then(credential => { - credentialRequest = null; - queryingKey.value = false; - signing.value = true; - return misskeyApi('signin-with-passkey', { - credential: credential.toJSON(), - context: passkey_context.value, - }); - }).then((res: SigninWithPasskeyResponse) => { +function onPasskeyDone(credential: AuthenticationPublicKeyCredential): void { + waiting.value = true; + + if (doingPasskeyFromInputPage.value) { + misskeyApi('signin-with-passkey', { + credential: credential.toJSON(), + context: passkeyContext.value, + }).then((res) => { + if (res.signinResponse == null) { + onSigninApiError(); + return; + } emit('login', res.signinResponse); - return onLogin(res.signinResponse); + }).catch(onSigninApiError); + } else if (userInfo.value != null) { + tryLogin({ + username: userInfo.value.username, + password: password.value, + credential: credential.toJSON(), }); + } } -function onSubmit(): void { - signing.value = true; - if (!totpLogin.value && user.value && user.value.twoFactorEnabled) { - if (webAuthnSupported() && user.value.securityKeys) { - misskeyApi('signin', { - username: username.value, - password: password.value, - }).then(res => { - totpLogin.value = true; - signing.value = false; - credentialRequest = parseRequestOptionsFromJSON({ - publicKey: res, - }); - }) - .then(() => query2FaKey()) - .catch(loginFailed); - } else { - totpLogin.value = true; - signing.value = false; - } +function onUseTotp(): void { + page.value = 'totp'; +} +//#endregion + +async function onUsernameSubmitted(username: string) { + waiting.value = true; + + userInfo.value = await misskeyApi('users/show', { + username, + }).catch(() => null); + + await tryLogin({ + username, + }); +} + +async function onPasswordSubmitted(pw: PwResponse) { + waiting.value = true; + password.value = pw.password; + + if (userInfo.value == null) { + await os.alert({ + type: 'error', + title: i18n.ts.noSuchUser, + text: i18n.ts.signinFailed, + }); + waiting.value = false; + return; + } else { + await tryLogin({ + username: userInfo.value.username, + password: pw.password, + 'hcaptcha-response': pw.captcha.hCaptchaResponse, + 'm-captcha-response': pw.captcha.mCaptchaResponse, + 'g-recaptcha-response': pw.captcha.reCaptchaResponse, + 'turnstile-response': pw.captcha.turnstileResponse, + }); + } +} + +async function onTotpSubmitted(token: string) { + waiting.value = true; + + if (userInfo.value == null) { + await os.alert({ + type: 'error', + title: i18n.ts.noSuchUser, + text: i18n.ts.signinFailed, + }); + waiting.value = false; + return; } else { - misskeyApi('signin', { - username: username.value, + await tryLogin({ + username: userInfo.value.username, password: password.value, - token: user.value?.twoFactorEnabled ? token.value : undefined, - }).then(res => { + token, + }); + } +} + +async function tryLogin(req: Partial<Misskey.entities.SigninFlowRequest>): Promise<Misskey.entities.SigninFlowResponse> { + const _req = { + username: req.username ?? userInfo.value?.username, + ...req, + }; + + function assertIsSigninFlowRequest(x: Partial<Misskey.entities.SigninFlowRequest>): x is Misskey.entities.SigninFlowRequest { + return x.username != null; + } + + if (!assertIsSigninFlowRequest(_req)) { + throw new Error('Invalid request'); + } + + return await misskeyApi('signin-flow', _req).then(async (res) => { + if (res.finished) { emit('login', res); - onLogin(res); - }).catch(loginFailed); + await onLoginSucceeded(res); + } else { + switch (res.next) { + case 'captcha': { + needCaptcha.value = true; + page.value = 'password'; + break; + } + case 'password': { + needCaptcha.value = false; + page.value = 'password'; + break; + } + case 'totp': { + page.value = 'totp'; + break; + } + case 'passkey': { + if (webAuthnSupported()) { + credentialRequest.value = parseRequestOptionsFromJSON({ + publicKey: res.authRequest, + }); + page.value = 'passkey'; + } else { + page.value = 'totp'; + } + break; + } + } + + if (doingPasskeyFromInputPage.value === true) { + doingPasskeyFromInputPage.value = false; + page.value = 'input'; + password.value = ''; + } + passwordPageEl.value?.resetCaptcha(); + nextTick(() => { + waiting.value = false; + }); + } + return res; + }).catch((err) => { + onSigninApiError(err); + return Promise.reject(err); + }); +} + +async function onLoginSucceeded(res: Misskey.entities.SigninFlowResponse & { finished: true; }) { + if (props.autoSet) { + await login(res.i); } } -function loginFailed(err: any): void { - switch (err.id) { +function onSigninApiError(err?: any): void { + const id = err?.id ?? null; + + switch (id) { case '6cc579cc-885d-43d8-95c2-b8c7fc963280': { os.alert({ type: 'error', @@ -265,6 +314,14 @@ function loginFailed(err: any): void { }); break; } + case 'cdf1235b-ac71-46d4-a3a6-84ccce48df6f': { + os.alert({ + type: 'error', + title: i18n.ts.loginFailed, + text: i18n.ts.incorrectTotp, + }); + break; + } case '36b96a7d-b547-412d-aeed-2d611cdc8cdc': { os.alert({ type: 'error', @@ -273,6 +330,14 @@ function loginFailed(err: any): void { }); break; } + case '93b86c4b-72f9-40eb-9815-798928603d1e': { + os.alert({ + type: 'error', + title: i18n.ts.loginFailed, + text: i18n.ts.passkeyVerificationFailed, + }); + break; + } case 'b18c89a7-5b5e-4cec-bb5b-0419f332d430': { os.alert({ type: 'error', @@ -299,113 +364,55 @@ function loginFailed(err: any): void { } } - totpLogin.value = false; - signing.value = false; -} - -function resetPassword(): void { - const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkForgotPassword.vue')), {}, { - closed: () => dispose(), - }); -} - -function openRemote(options: OpenOnRemoteOptions, targetHost?: string): void { - switch (options.type) { - case 'web': - case 'lookup': { - let _path: string; - - if (options.type === 'lookup') { - // TODO: v2024.7.0以é™ãŒæµ¸é€ã—ã¦ããŸã‚‰æ£å¼ãªURLã«å¤‰æ›´ã™ã‚‹â–¼ - // _path = `/lookup?uri=${encodeURIComponent(_path)}`; - _path = `/authorize-follow?acct=${encodeURIComponent(options.url)}`; - } else { - _path = options.path; - } - - if (targetHost) { - window.open(`https://${targetHost}${_path}`, '_blank', 'noopener'); - } else { - window.open(`https://misskey-hub.net/mi-web/?path=${encodeURIComponent(_path)}`, '_blank', 'noopener'); - } - break; - } - case 'share': { - const params = query(options.params); - if (targetHost) { - window.open(`https://${targetHost}/share?${params}`, '_blank', 'noopener'); - } else { - window.open(`https://misskey-hub.net/share/?${params}`, '_blank', 'noopener'); - } - break; - } + if (doingPasskeyFromInputPage.value === true) { + doingPasskeyFromInputPage.value = false; + page.value = 'input'; + password.value = ''; } -} - -async function specifyHostAndOpenRemote(options: OpenOnRemoteOptions): Promise<void> { - const { canceled, result: hostTemp } = await os.inputText({ - title: i18n.ts.inputHostName, - placeholder: 'misskey.example.com', + passwordPageEl.value?.resetCaptcha(); + nextTick(() => { + waiting.value = false; }); - - if (canceled) return; - - let targetHost: string | null = hostTemp; - - // ドメイン部分ã ã‘ã‚’å–り出㙠- targetHost = extractDomain(targetHost); - if (targetHost == null) { - os.alert({ - type: 'error', - title: i18n.ts.invalidValue, - text: i18n.ts.tryAgain, - }); - return; - } - openRemote(options, targetHost); } + +onBeforeUnmount(() => { + password.value = ''; + needCaptcha.value = false; + userInfo.value = null; +}); </script> <style lang="scss" module> -.avatar { - margin: 0 auto 0 auto; - width: 64px; - height: 64px; - background: #ddd; - background-position: center; - background-size: cover; - border-radius: 100%; +.transition_enterActive, +.transition_leaveActive { + transition: opacity 0.3s cubic-bezier(0,0,.35,1), transform 0.3s cubic-bezier(0,0,.35,1); } - -.instanceManualSelectButton { - display: block; - text-align: center; - opacity: .7; - font-size: .8em; - - &:hover { - text-decoration: underline; - } +.transition_enterFrom { + opacity: 0; + transform: translateX(50px); } +.transition_leaveTo { + opacity: 0; + transform: translateX(-50px); +} + +.signinRoot { + overflow-x: hidden; + overflow-x: clip; -.orHr { position: relative; - margin: .4em auto; - width: 100%; - height: 1px; - background: var(--divider); } -.orMsg { +.waitingRoot { position: absolute; - top: -.6em; - display: inline-block; - padding: 0 1em; - background: var(--panel); - font-size: 0.8em; - color: var(--fgOnPanel); - margin: 0; - left: 50%; - transform: translateX(-50%); + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: color-mix(in srgb, var(--panel), transparent 50%); + display: flex; + justify-content: center; + align-items: center; + z-index: 1; } </style> diff --git a/packages/frontend/src/components/MkSigninDialog.vue b/packages/frontend/src/components/MkSigninDialog.vue index d48780e9de..8351d7d5e0 100644 --- a/packages/frontend/src/components/MkSigninDialog.vue +++ b/packages/frontend/src/components/MkSigninDialog.vue @@ -4,26 +4,29 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<MkModalWindow - ref="dialog" - :width="400" - :height="450" - @close="onClose" +<MkModal + ref="modal" + :preferType="'dialog'" + @click="onClose" @closed="emit('closed')" > - <template #header>{{ i18n.ts.login }}</template> - - <MkSpacer :marginMin="20" :marginMax="28"> - <MkSignin :autoSet="autoSet" :message="message" :openOnRemote="openOnRemote" @login="onLogin"/> - </MkSpacer> -</MkModalWindow> + <div :class="$style.root"> + <div :class="$style.header"> + <div :class="$style.headerText"><i class="ti ti-login-2"></i> {{ i18n.ts.login }}</div> + <button :class="$style.closeButton" class="_button" @click="onClose"><i class="ti ti-x"></i></button> + </div> + <div :class="$style.content"> + <MkSignin :autoSet="autoSet" :message="message" :openOnRemote="openOnRemote" @login="onLogin"/> + </div> + </div> +</MkModal> </template> <script lang="ts" setup> import { shallowRef } from 'vue'; import type { OpenOnRemoteOptions } from '@/scripts/please-login.js'; import MkSignin from '@/components/MkSignin.vue'; -import MkModalWindow from '@/components/MkModalWindow.vue'; +import MkModal from '@/components/MkModal.vue'; import { i18n } from '@/i18n.js'; withDefaults(defineProps<{ @@ -42,15 +45,62 @@ const emit = defineEmits<{ (ev: 'cancelled'): void; }>(); -const dialog = shallowRef<InstanceType<typeof MkModalWindow>>(); +const modal = shallowRef<InstanceType<typeof MkModal>>(); function onClose() { emit('cancelled'); - if (dialog.value) dialog.value.close(); + if (modal.value) modal.value.close(); } function onLogin(res) { emit('done', res); - if (dialog.value) dialog.value.close(); + if (modal.value) modal.value.close(); } </script> + +<style lang="scss" module> +.root { + overflow: auto; + margin: auto; + position: relative; + width: 100%; + max-width: 400px; + height: 100%; + max-height: 450px; + box-sizing: border-box; + background: var(--panel); + border-radius: var(--radius); +} + +.header { + position: sticky; + top: 0; + left: 0; + width: 100%; + height: 50px; + box-sizing: border-box; + display: flex; + align-items: center; + font-weight: bold; + backdrop-filter: var(--blur, blur(15px)); + background: var(--acrylicBg); + z-index: 1; +} + +.headerText { + padding: 0 20px; + box-sizing: border-box; +} + +.closeButton { + margin-left: auto; + padding: 16px; + font-size: 16px; + line-height: 16px; +} + +.content { + padding: 32px; + box-sizing: border-box; +} +</style> diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index 4ab4380ad5..ff096dc729 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -81,10 +81,10 @@ SPDX-License-Identifier: AGPL-3.0-only import { ref, computed } from 'vue'; import { toUnicode } from 'punycode/'; import * as Misskey from 'misskey-js'; +import * as config from '@@/js/config.js'; import MkButton from './MkButton.vue'; import MkInput from './MkInput.vue'; import MkCaptcha, { type Captcha } from '@/components/MkCaptcha.vue'; -import * as config from '@@/js/config.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { login } from '@/account.js'; @@ -98,13 +98,14 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'signup', user: Misskey.entities.SigninResponse): void; + (ev: 'signup', user: Misskey.entities.SigninFlowResponse): void; (ev: 'signupEmailPending'): void; }>(); const host = toUnicode(config.host); const hcaptcha = ref<Captcha | undefined>(); +const mcaptcha = ref<Captcha | undefined>(); const recaptcha = ref<Captcha | undefined>(); const turnstile = ref<Captcha | undefined>(); @@ -268,19 +269,25 @@ async function onSubmit(): Promise<void> { }); emit('signupEmailPending'); } else { - const res = await misskeyApi('signin', { + const res = await misskeyApi('signin-flow', { username: username.value, password: password.value, }); emit('signup', res); - if (props.autoSet) { + if (props.autoSet && res.finished) { return login(res.i); + } else { + os.alert({ + type: 'error', + text: i18n.ts.somethingHappened, + }); } } } catch { submitting.value = false; hcaptcha.value?.reset?.(); + mcaptcha.value?.reset?.(); recaptcha.value?.reset?.(); turnstile.value?.reset?.(); diff --git a/packages/frontend/src/components/MkSignupDialog.vue b/packages/frontend/src/components/MkSignupDialog.vue index 97310d32a6..4cccd99492 100644 --- a/packages/frontend/src/components/MkSignupDialog.vue +++ b/packages/frontend/src/components/MkSignupDialog.vue @@ -47,7 +47,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'done', res: Misskey.entities.SigninResponse): void; + (ev: 'done', res: Misskey.entities.SigninFlowResponse): void; (ev: 'closed'): void; }>(); @@ -55,7 +55,7 @@ const dialog = shallowRef<InstanceType<typeof MkModalWindow>>(); const isAcceptedServerRule = ref(false); -function onSignup(res: Misskey.entities.SigninResponse) { +function onSignup(res: Misskey.entities.SigninFlowResponse) { emit('done', res); dialog.value?.close(); } diff --git a/packages/frontend/src/components/global/MkMfm.ts b/packages/frontend/src/components/global/MkMfm.ts index d914492231..1beb8874e0 100644 --- a/packages/frontend/src/components/global/MkMfm.ts +++ b/packages/frontend/src/components/global/MkMfm.ts @@ -6,6 +6,7 @@ import { VNode, h, SetupContext, provide } from 'vue'; import * as mfm from 'mfm-js'; import * as Misskey from 'misskey-js'; +import { host } from '@@/js/config.js'; import MkUrl from '@/components/global/MkUrl.vue'; import MkTime from '@/components/global/MkTime.vue'; import MkLink from '@/components/MkLink.vue'; @@ -17,7 +18,6 @@ import MkCodeInline from '@/components/MkCodeInline.vue'; import MkGoogle from '@/components/MkGoogle.vue'; import MkSparkle from '@/components/MkSparkle.vue'; import MkA, { MkABehavior } from '@/components/global/MkA.vue'; -import { host } from '@@/js/config.js'; import { defaultStore } from '@/store.js'; function safeParseFloat(str: unknown): number | null { @@ -57,7 +57,8 @@ type MfmEvents = { // eslint-disable-next-line import/no-default-export export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEvents>['emit'] }) { - provide('linkNavigationBehavior', props.linkNavigationBehavior); + // ã“ã†ã—ãŸã„ã¨ã“ã‚ã ã‘ã© functional component 内ã§ã¯ provide ã¯ä½¿ãˆãªã„ + //provide('linkNavigationBehavior', props.linkNavigationBehavior); const isNote = props.isNote ?? true; const shouldNyaize = props.nyaize ? props.nyaize === 'respect' ? props.author?.isCat : false : false; @@ -350,6 +351,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven key: Math.random(), url: token.props.url, rel: 'nofollow noopener', + navigationBehavior: props.linkNavigationBehavior, })]; } @@ -358,6 +360,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven key: Math.random(), url: token.props.url, rel: 'nofollow noopener', + navigationBehavior: props.linkNavigationBehavior, }, genEl(token.children, scale, true))]; } @@ -366,6 +369,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven key: Math.random(), host: (token.props.host == null && props.author && props.author.host != null ? props.author.host : token.props.host) ?? host, username: token.props.username, + navigationBehavior: props.linkNavigationBehavior, })]; } @@ -374,6 +378,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven key: Math.random(), to: isNote ? `/tags/${encodeURIComponent(token.props.hashtag)}` : `/user-tags/${encodeURIComponent(token.props.hashtag)}`, style: 'color:var(--hashtag);', + behavior: props.linkNavigationBehavior, }, `#${token.props.hashtag}`)]; } diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue index 19bd794a5d..38bdfc52d4 100644 --- a/packages/frontend/src/components/global/RouterView.vue +++ b/packages/frontend/src/components/global/RouterView.vue @@ -27,6 +27,7 @@ import MkLoadingPage from '@/pages/_loading_.vue'; const props = defineProps<{ router?: IRouter; + nested?: boolean; }>(); const router = props.router ?? inject('router'); @@ -39,6 +40,8 @@ const currentDepth = inject('routerCurrentDepth', 0); provide('routerCurrentDepth', currentDepth + 1); function resolveNested(current: Resolved, d = 0): Resolved | null { + if (!props.nested) return current; + if (d === currentDepth) { return current; } else { diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index d40d1eee58..033634396e 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -53,6 +53,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkTextarea v-model="moderationNote" manualSave> <template #label>{{ i18n.ts.moderationNote }}</template> + <template #caption>{{ i18n.ts.moderationNoteDescription }}</template> </MkTextarea> <!-- @@ -205,6 +206,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, defineAsyncComponent, watch, ref } from 'vue'; import * as Misskey from 'misskey-js'; +import { url } from '@@/js/config.js'; import MkChart from '@/components/MkChart.vue'; import MkObjectView from '@/components/MkObjectView.vue'; import MkTextarea from '@/components/MkTextarea.vue'; @@ -220,7 +222,6 @@ import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue'; import MkInfo from '@/components/MkInfo.vue'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; -import { url } from '@@/js/config.js'; import { acct } from '@/filters/user.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import { i18n } from '@/i18n.js'; diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index 0b9847fed3..22173bb888 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -12,6 +12,10 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton link to="/admin/abuse-report-notification-recipient" primary>{{ i18n.ts.notificationSetting }}</MkButton> </div> + <MkInfo v-if="!defaultStore.reactiveState.abusesTutorial.value" closable @close="closeTutorial()"> + {{ i18n.ts._abuseUserReport.resolveTutorial }} + </MkInfo> + <div :class="$style.inputs" class="_gaps"> <MkSelect v-model="state" style="margin: 0; flex: 1;"> <template #label>{{ i18n.ts.state }}</template> @@ -44,8 +48,10 @@ SPDX-License-Identifier: AGPL-3.0-only </div> --> - <MkPagination v-slot="{items}" ref="reports" :pagination="pagination" style="margin-top: var(--margin);"> - <XAbuseReport v-for="report in items" :key="report.id" :report="report" @resolved="resolved"/> + <MkPagination v-slot="{items}" ref="reports" :pagination="pagination"> + <div class="_gaps"> + <XAbuseReport v-for="report in items" :key="report.id" :report="report" @resolved="resolved"/> + </div> </MkPagination> </div> </MkSpacer> @@ -54,7 +60,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, shallowRef, ref } from 'vue'; - import XHeader from './_header_.vue'; import MkSelect from '@/components/MkSelect.vue'; import MkPagination from '@/components/MkPagination.vue'; @@ -62,6 +67,8 @@ import XAbuseReport from '@/components/MkAbuseReport.vue'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkButton from '@/components/MkButton.vue'; +import MkInfo from '@/components/MkInfo.vue'; +import { defaultStore } from '@/store.js'; const reports = shallowRef<InstanceType<typeof MkPagination>>(); @@ -85,6 +92,10 @@ function resolved(reportId) { reports.value?.removeItem(reportId); } +function closeTutorial() { + defaultStore.set('abusesTutorial', false); +} + const headerActions = computed(() => []); const headerTabs = computed(() => []); diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index db87bd996d..61745e0ff3 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only </MkSpacer> </div> <div v-if="!(narrow && currentPage?.route.name == null)" class="main"> - <RouterView/> + <RouterView nested/> </div> </div> </template> diff --git a/packages/frontend/src/pages/admin/modlog.ModLog.vue b/packages/frontend/src/pages/admin/modlog.ModLog.vue index 64d7f25845..6cf95e936e 100644 --- a/packages/frontend/src/pages/admin/modlog.ModLog.vue +++ b/packages/frontend/src/pages/admin/modlog.ModLog.vue @@ -165,6 +165,11 @@ SPDX-License-Identifier: AGPL-3.0-only <CodeDiff :context="5" :hideHeader="true" :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/> </div> </template> + <template v-else-if="log.type === 'updateAbuseReportNote'"> + <div :class="$style.diff"> + <CodeDiff :context="5" :hideHeader="true" :oldString="log.info.before ?? ''" :newString="log.info.after ?? ''" maxHeight="300px"/> + </div> + </template> <details> <summary>raw</summary> diff --git a/packages/frontend/src/pages/admin/modlog.vue b/packages/frontend/src/pages/admin/modlog.vue index 8590ee1651..38610e7e92 100644 --- a/packages/frontend/src/pages/admin/modlog.vue +++ b/packages/frontend/src/pages/admin/modlog.vue @@ -20,9 +20,9 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <MkPagination v-slot="{items}" ref="logs" :pagination="pagination" style="margin-top: var(--margin);"> - <div class="_gaps_s"> - <XModLog v-for="item in items" :key="item.id" :log="item"/> - </div> + <MkDateSeparatedList v-slot="{ item }" :items="items" :noGap="false" style="--margin: 8px;"> + <XModLog :key="item.id" :log="item"/> + </MkDateSeparatedList> </MkPagination> </div> </MkSpacer> @@ -39,6 +39,7 @@ import MkInput from '@/components/MkInput.vue'; import MkPagination from '@/components/MkPagination.vue'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; +import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue'; const logs = shallowRef<InstanceType<typeof MkPagination>>(); diff --git a/packages/frontend/src/pages/admin/system-webhook.item.vue b/packages/frontend/src/pages/admin/system-webhook.item.vue index 4e767fba16..124790338c 100644 --- a/packages/frontend/src/pages/admin/system-webhook.item.vue +++ b/packages/frontend/src/pages/admin/system-webhook.item.vue @@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <MkFolder> <template #label>{{ entity.name || entity.url }}</template> + <template v-if="entity.name != null && entity.name != ''" #caption>{{ entity.url }}</template> <template #icon> <i v-if="!entity.isActive" class="ti ti-player-pause"/> <i v-else-if="entity.latestStatus === null" class="ti ti-circle"/> diff --git a/packages/frontend/src/pages/flash/flash-index.vue b/packages/frontend/src/pages/flash/flash-index.vue index f63a799365..2b85489706 100644 --- a/packages/frontend/src/pages/flash/flash-index.vue +++ b/packages/frontend/src/pages/flash/flash-index.vue @@ -55,7 +55,8 @@ const tab = ref('featured'); const featuredFlashsPagination = { endpoint: 'flash/featured' as const, - noPaging: true, + limit: 5, + offsetMode: true, }; const myFlashsPagination = { endpoint: 'flash/my' as const, diff --git a/packages/frontend/src/pages/install-extensions.vue b/packages/frontend/src/pages/install-extensions.vue index 4bee437f65..83f16fce68 100644 --- a/packages/frontend/src/pages/install-extensions.vue +++ b/packages/frontend/src/pages/install-extensions.vue @@ -8,76 +8,26 @@ SPDX-License-Identifier: AGPL-3.0-only <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <MkSpacer :contentMax="500"> <MkLoading v-if="uiPhase === 'fetching'"/> - <div v-else-if="uiPhase === 'confirm' && data" class="_gaps_m" :class="$style.extInstallerRoot"> - <div :class="$style.extInstallerIconWrapper"> - <i v-if="data.type === 'plugin'" class="ti ti-plug"></i> - <i v-else-if="data.type === 'theme'" class="ti ti-palette"></i> - <i v-else class="ti ti-download"></i> - </div> - <h2 :class="$style.extInstallerTitle">{{ i18n.ts._externalResourceInstaller[`_${data.type}`].title }}</h2> - <div :class="$style.extInstallerNormDesc">{{ i18n.ts._externalResourceInstaller.checkVendorBeforeInstall }}</div> - <MkInfo v-if="data.type === 'plugin'" :warn="true">{{ i18n.ts._plugin.installWarn }}</MkInfo> - <FormSection> - <template #label>{{ i18n.ts._externalResourceInstaller[`_${data.type}`].metaTitle }}</template> - <div class="_gaps_s"> - <FormSplit> + <MkExtensionInstaller v-else-if="uiPhase === 'confirm' && data" :extension="data" @confirm="install()"> + <template #additionalInfo> + <FormSection> + <template #label>{{ i18n.ts._externalResourceInstaller._vendorInfo.title }}</template> + <div class="_gaps_s"> <MkKeyValue> - <template #key>{{ i18n.ts.name }}</template> - <template #value>{{ data.meta?.name }}</template> + <template #key>{{ i18n.ts._externalResourceInstaller._vendorInfo.endpoint }}</template> + <template #value><MkUrl :url="url" :showUrlPreview="false"></MkUrl></template> </MkKeyValue> <MkKeyValue> - <template #key>{{ i18n.ts.author }}</template> - <template #value>{{ data.meta?.author }}</template> + <template #key>{{ i18n.ts._externalResourceInstaller._vendorInfo.hashVerify }}</template> + <template #value> + <!-- ã“ã®ç”»é¢ãŒå‡ºã¦ã„る時点ã§ãƒãƒƒã‚·ãƒ¥ã®æ¤œè¨¼ã«ã¯æˆåŠŸã—ã¦ã„ã‚‹ --> + <i class="ti ti-check" style="color: var(--accent)"></i> + </template> </MkKeyValue> - </FormSplit> - <MkKeyValue v-if="data.type === 'plugin'"> - <template #key>{{ i18n.ts.description }}</template> - <template #value>{{ data.meta?.description }}</template> - </MkKeyValue> - <MkKeyValue v-if="data.type === 'plugin'"> - <template #key>{{ i18n.ts.version }}</template> - <template #value>{{ data.meta?.version }}</template> - </MkKeyValue> - <MkKeyValue v-if="data.type === 'plugin'"> - <template #key>{{ i18n.ts.permission }}</template> - <template #value> - <ul :class="$style.extInstallerKVList"> - <li v-for="permission in data.meta?.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li> - </ul> - </template> - </MkKeyValue> - <MkKeyValue v-if="data.type === 'theme' && data.meta?.base"> - <template #key>{{ i18n.ts._externalResourceInstaller._meta.base }}</template> - <template #value>{{ i18n.ts[data.meta.base] }}</template> - </MkKeyValue> - <MkFolder> - <template #icon><i class="ti ti-code"></i></template> - <template #label>{{ i18n.ts._plugin.viewSource }}</template> - - <MkCode :code="data.raw ?? ''"/> - </MkFolder> - </div> - </FormSection> - <FormSection> - <template #label>{{ i18n.ts._externalResourceInstaller._vendorInfo.title }}</template> - <div class="_gaps_s"> - <MkKeyValue> - <template #key>{{ i18n.ts._externalResourceInstaller._vendorInfo.endpoint }}</template> - <template #value><MkUrl :url="url ?? ''" :showUrlPreview="false"></MkUrl></template> - </MkKeyValue> - <MkKeyValue> - <template #key>{{ i18n.ts._externalResourceInstaller._vendorInfo.hashVerify }}</template> - <template #value> - <!--ã“ã®ç”»é¢ãŒå‡ºã¦ã„る時点ã§ãƒãƒƒã‚·ãƒ¥ã®æ¤œè¨¼ã«ã¯æˆåŠŸã—ã¦ã„ã‚‹--> - <i class="ti ti-check" style="color: var(--accent)"></i> - </template> - </MkKeyValue> - </div> - </FormSection> - <div class="_buttonsCenter"> - <MkButton primary @click="install()"><i class="ti ti-check"></i> {{ i18n.ts.install }}</MkButton> - </div> - </div> + </div> + </FormSection> + </template> + </MkExtensionInstaller> <div v-else-if="uiPhase === 'error'" class="_gaps_m" :class="[$style.extInstallerRoot, $style.error]"> <div :class="$style.extInstallerIconWrapper"> <i class="ti ti-circle-x"></i> @@ -96,14 +46,11 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, computed, onActivated, onDeactivated, nextTick } from 'vue'; import MkLoading from '@/components/global/MkLoading.vue'; +import MkExtensionInstaller, { type Extension } from '@/components/MkExtensionInstaller.vue'; import MkButton from '@/components/MkButton.vue'; -import FormSection from '@/components/form/section.vue'; -import FormSplit from '@/components/form/split.vue'; -import MkCode from '@/components/MkCode.vue'; -import MkUrl from '@/components/global/MkUrl.vue'; -import MkInfo from '@/components/MkInfo.vue'; -import MkFolder from '@/components/MkFolder.vue'; import MkKeyValue from '@/components/MkKeyValue.vue'; +import MkUrl from '@/components/global/MkUrl.vue'; +import FormSection from '@/components/form/section.vue'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { AiScriptPluginMeta, parsePluginMeta, installPlugin } from '@/scripts/install-plugin.js'; @@ -124,24 +71,7 @@ const errorKV = ref<{ const url = ref<string | null>(null); const hash = ref<string | null>(null); -const data = ref<{ - type: 'plugin' | 'theme'; - raw: string; - meta?: { - // Plugin & Theme Common - name: string; - author: string; - - // Plugin - description?: string; - version?: string; - permissions?: string[]; - config?: Record<string, any>; - - // Theme - base?: 'light' | 'dark'; - }; -} | null>(null); +const data = ref<Extension | null>(null); function goBack(): void { history.back(); @@ -227,7 +157,7 @@ async function fetch() { data.value = { type: 'theme', meta: { - description, + // description, // 使用ã•れã¦ã„ãªã„ ...meta, }, raw: res.data, @@ -353,9 +283,4 @@ definePageMetadata(() => ({ .extInstallerNormDesc { text-align: center; } - -.extInstallerKVList { - margin-top: 0; - margin-bottom: 0; -} </style> diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue index c69530b343..6cec3f9d45 100644 --- a/packages/frontend/src/pages/instance-info.vue +++ b/packages/frontend/src/pages/instance-info.vue @@ -51,6 +51,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton @click="refreshMetadata"><i class="ti ti-refresh"></i> Refresh metadata</MkButton> <MkTextarea v-model="moderationNote" manualSave> <template #label>{{ i18n.ts.moderationNote }}</template> + <template #caption>{{ i18n.ts.moderationNoteDescription }}</template> </MkTextarea> </div> </FormSection> diff --git a/packages/frontend/src/pages/settings/apps.vue b/packages/frontend/src/pages/settings/apps.vue index 0e0c1f4c0c..68e36ef1bb 100644 --- a/packages/frontend/src/pages/settings/apps.vue +++ b/packages/frontend/src/pages/settings/apps.vue @@ -14,30 +14,39 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <template #default="{items}"> <div class="_gaps"> - <div v-for="token in items" :key="token.id" class="_panel" :class="$style.app"> - <img v-if="token.iconUrl" :class="$style.appIcon" :src="token.iconUrl" alt=""/> - <div :class="$style.appBody"> - <div :class="$style.appName">{{ token.name }}</div> - <div>{{ token.description }}</div> - <MkKeyValue oneline> - <template #key>{{ i18n.ts.installedDate }}</template> - <template #value><MkTime :time="token.createdAt"/></template> - </MkKeyValue> - <MkKeyValue oneline> - <template #key>{{ i18n.ts.lastUsedDate }}</template> - <template #value><MkTime :time="token.lastUsedAt"/></template> - </MkKeyValue> - <details> - <summary>{{ i18n.ts.details }}</summary> + <MkFolder v-for="token in items" :key="token.id" :defaultOpen="true"> + <template #icon> + <img v-if="token.iconUrl" :class="$style.appIcon" :src="token.iconUrl" alt=""/> + <i v-else class="ti ti-plug"/> + </template> + <template #label>{{ token.name }}</template> + <template #caption>{{ token.description }}</template> + <template #suffix><MkTime :time="token.lastUsedAt"/></template> + <template #footer> + <MkButton danger @click="revoke(token)"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton> + </template> + + <div class="_gaps_s"> + <div v-if="token.description">{{ token.description }}</div> + <div> + <MkKeyValue oneline> + <template #key>{{ i18n.ts.installedDate }}</template> + <template #value><MkTime :time="token.createdAt" :mode="'detail'"/></template> + </MkKeyValue> + <MkKeyValue oneline> + <template #key>{{ i18n.ts.lastUsedDate }}</template> + <template #value><MkTime :time="token.lastUsedAt" :mode="'detail'"/></template> + </MkKeyValue> + </div> + <MkFolder> + <template #label>{{ i18n.ts.permission }}</template> + <template #suffix>{{ Object.keys(token.permission).length === 0 ? i18n.ts.none : Object.keys(token.permission).length }}</template> <ul> <li v-for="p in token.permission" :key="p">{{ i18n.ts._permissions[p] }}</li> </ul> - </details> - <div> - <MkButton inline danger @click="revoke(token)"><i class="ti ti-trash"></i></MkButton> - </div> + </MkFolder> </div> - </div> + </MkFolder> </div> </template> </FormPagination> @@ -52,6 +61,7 @@ import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkKeyValue from '@/components/MkKeyValue.vue'; import MkButton from '@/components/MkButton.vue'; +import MkFolder from '@/components/MkFolder.vue'; import { infoImageUrl } from '@/instance.js'; const list = ref<InstanceType<typeof FormPagination>>(); @@ -82,26 +92,9 @@ definePageMetadata(() => ({ </script> <style lang="scss" module> -.app { - display: flex; - padding: 16px; -} - .appIcon { - display: block; - flex-shrink: 0; - margin: 0 12px 0 0; - width: 50px; - height: 50px; - border-radius: 8px; -} - -.appBody { - width: calc(100% - 62px); - position: relative; -} - -.appName { - font-weight: bold; + width: 20px; + height: 20px; + border-radius: 4px; } </style> diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index 7d16740a3e..96a95f1635 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <div v-if="!(narrow && currentPage?.route.name == null)" class="main"> <div class="bkzroven" style="container-type: inline-size;"> - <RouterView/> + <RouterView nested/> </div> </div> </div> diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 9e6cd04365..19c5d892de 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -46,14 +46,17 @@ SPDX-License-Identifier: AGPL-3.0-only <MkFolder> <template #icon><i class="ti ti-list"></i></template> <template #label>{{ i18n.ts._profile.metadataEdit }}</template> - - <div :class="$style.metadataRoot"> - <div :class="$style.metadataMargin"> - <MkButton :disabled="fields.length >= 16" inline style="margin-right: 8px;" @click="addField"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> - <MkButton v-if="!fieldEditMode" :disabled="fields.length <= 1" inline danger style="margin-right: 8px;" @click="fieldEditMode = !fieldEditMode"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton> - <MkButton v-else inline style="margin-right: 8px;" @click="fieldEditMode = !fieldEditMode"><i class="ti ti-arrows-sort"></i> {{ i18n.ts.rearrange }}</MkButton> - <MkButton inline primary @click="saveFields"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> + <template #footer> + <div class="_buttons"> + <MkButton primary @click="saveFields"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> + <MkButton :disabled="fields.length >= 16" @click="addField"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> + <MkButton v-if="!fieldEditMode" :disabled="fields.length <= 1" danger @click="fieldEditMode = !fieldEditMode"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton> + <MkButton v-else @click="fieldEditMode = !fieldEditMode"><i class="ti ti-arrows-sort"></i> {{ i18n.ts.rearrange }}</MkButton> </div> + </template> + + <div :class="$style.metadataRoot" class="_gaps_s"> + <MkInfo>{{ i18n.ts._profile.verifiedLinkDescription }}</MkInfo> <Sortable v-model="fields" @@ -65,24 +68,20 @@ SPDX-License-Identifier: AGPL-3.0-only @end="e => e.item.classList.remove('active')" > <template #item="{element, index}"> - <div :class="$style.fieldDragItem"> + <div v-panel :class="$style.fieldDragItem"> <button v-if="!fieldEditMode" class="_button" :class="$style.dragItemHandle" tabindex="-1"><i class="ti ti-menu"></i></button> <button v-if="fieldEditMode" :disabled="fields.length <= 1" class="_button" :class="$style.dragItemRemove" @click="deleteField(index)"><i class="ti ti-x"></i></button> <div :class="$style.dragItemForm"> <FormSplit :minWidth="200"> - <MkInput v-model="element.name" small> - <template #label>{{ i18n.ts._profile.metadataLabel }}</template> + <MkInput v-model="element.name" small :placeholder="i18n.ts._profile.metadataLabel"> </MkInput> - <MkInput v-model="element.value" small> - <template #label>{{ i18n.ts._profile.metadataContent }}</template> + <MkInput v-model="element.value" small :placeholder="i18n.ts._profile.metadataContent"> </MkInput> </FormSplit> </div> </div> </template> </Sortable> - - <MkInfo>{{ i18n.ts._profile.verifiedLinkDescription }}</MkInfo> </div> </MkFolder> <template #caption>{{ i18n.ts._profile.metadataDescription }}</template> @@ -310,19 +309,11 @@ definePageMetadata(() => ({ container-type: inline-size; } -.metadataMargin { - margin-bottom: 1.5em; -} - .fieldDragItem { display: flex; - padding-bottom: .75em; + padding: 10px; align-items: flex-end; - border-bottom: solid 0.5px var(--divider); - - &:last-child { - border-bottom: 0; - } + border-radius: 6px; /* (drag button) 32px + (drag button margin) 8px + (input width) 200px * 2 + (input gap) 12px = 452px */ @container (max-width: 452px) { diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index ae8ac88361..111df41127 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -48,9 +48,10 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> <div v-if="user.followedMessage != null" class="followedMessage"> - <div style="border: solid 1px var(--love); border-radius: 6px; background: color-mix(in srgb, var(--love), transparent 90%); padding: 6px 8px;"> - <Mfm :text="user.followedMessage" :author="user"/> - </div> + <MkFukidashi class="fukidashi" :tail="narrow ? 'none' : 'left'" negativeMargin shadow> + <div class="messageHeader">{{ i18n.ts.messageToFollower }}</div> + <div><MkSparkle><Mfm :plain="true" :text="user.followedMessage" :author="user"/></MkSparkle></div> + </MkFukidashi> </div> <div v-if="user.roles.length > 0" class="roles"> <span v-for="role in user.roles" :key="role.id" v-tooltip="role.description" class="role" :style="{ '--color': role.color }"> @@ -63,6 +64,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div v-if="iAmModerator" class="moderationNote"> <MkTextarea v-if="editModerationNote || (moderationNote != null && moderationNote !== '')" v-model="moderationNote" manualSave> <template #label>{{ i18n.ts.moderationNote }}</template> + <template #caption>{{ i18n.ts.moderationNoteDescription }}</template> </MkTextarea> <div v-else> <MkButton small @click="editModerationNote = true">{{ i18n.ts.addModerationNote }}</MkButton> @@ -158,15 +160,16 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { defineAsyncComponent, computed, onMounted, onUnmounted, nextTick, watch, ref } from 'vue'; import * as Misskey from 'misskey-js'; +import { getScrollPosition } from '@@/js/scroll.js'; import MkNote from '@/components/MkNote.vue'; import MkFollowButton from '@/components/MkFollowButton.vue'; import MkAccountMoved from '@/components/MkAccountMoved.vue'; +import MkFukidashi from '@/components/MkFukidashi.vue'; import MkRemoteCaution from '@/components/MkRemoteCaution.vue'; import MkTextarea from '@/components/MkTextarea.vue'; import MkOmit from '@/components/MkOmit.vue'; import MkInfo from '@/components/MkInfo.vue'; import MkButton from '@/components/MkButton.vue'; -import { getScrollPosition } from '@@/js/scroll.js'; import { getUserMenu } from '@/scripts/get-user-menu.js'; import number from '@/filters/number.js'; import { userPage } from '@/filters/user.js'; @@ -180,6 +183,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js'; import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js'; import { useRouter } from '@/router/supplier.js'; import { getStaticImageUrl } from '@/scripts/media-proxy.js'; +import MkSparkle from '@/components/MkSparkle.vue'; function calcAge(birthdate: string): number { const date = new Date(birthdate); @@ -467,7 +471,18 @@ onUnmounted(() => { > .followedMessage { padding: 24px 24px 0 154px; - font-size: 0.9em; + + > .fukidashi { + display: block; + --fukidashi-bg: color-mix(in srgb, var(--accent), var(--panel) 85%); + --fukidashi-radius: 16px; + font-size: 0.9em; + + .messageHeader { + opacity: 0.7; + font-size: 0.85em; + } + } } > .roles { diff --git a/packages/frontend/src/pages/welcome.setup.vue b/packages/frontend/src/pages/welcome.setup.vue index a227c7c4bc..dd258aad98 100644 --- a/packages/frontend/src/pages/welcome.setup.vue +++ b/packages/frontend/src/pages/welcome.setup.vue @@ -14,6 +14,10 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <div class="_gaps_m" style="padding: 32px;"> <div>{{ i18n.ts.intro }}</div> + <MkInput v-model="setupPassword" type="password" data-cy-admin-initial-password> + <template #label>{{ i18n.ts.initialPasswordForSetup }} <div v-tooltip:dialog="i18n.ts.initialPasswordForSetupDescription" class="_button _help"><i class="ti ti-help-circle"></i></div></template> + <template #prefix><i class="ti ti-lock"></i></template> + </MkInput> <MkInput v-model="username" pattern="^[a-zA-Z0-9_]{1,20}$" :spellcheck="false" required data-cy-admin-username> <template #label>{{ i18n.ts.username }}</template> <template #prefix>@</template> @@ -36,9 +40,9 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; +import { host, version } from '@@/js/config.js'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; -import { host, version } from '@@/js/config.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { login } from '@/account.js'; @@ -47,6 +51,7 @@ import MkAnimBg from '@/components/MkAnimBg.vue'; const username = ref(''); const password = ref(''); +const setupPassword = ref(''); const submitting = ref(false); function submit() { @@ -56,14 +61,27 @@ function submit() { misskeyApi('admin/accounts/create', { username: username.value, password: password.value, + setupPassword: setupPassword.value === '' ? null : setupPassword.value, }).then(res => { return login(res.token); - }).catch(() => { + }).catch((err) => { submitting.value = false; + let title = i18n.ts.somethingHappened; + let text = err.message + '\n' + err.id; + + if (err.code === 'ACCESS_DENIED') { + title = i18n.ts.permissionDeniedError; + text = i18n.ts.operationForbidden; + } else if (err.code === 'INCORRECT_INITIAL_PASSWORD') { + title = i18n.ts.permissionDeniedError; + text = i18n.ts.incorrectPassword; + } + os.alert({ type: 'error', - text: i18n.ts.somethingHappened, + title, + text, }); }); } @@ -74,8 +92,8 @@ function submit() { min-height: 100svh; padding: 32px 32px 64px 32px; box-sizing: border-box; -display: grid; -place-content: center; + display: grid; + place-content: center; } .form { diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 1ddcca5afe..cb52938980 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -78,6 +78,10 @@ export const defaultStore = markRaw(new Storage('base', { global: false, }, }, + abusesTutorial: { + where: 'account', + default: false, + }, keepCw: { where: 'account', default: true, @@ -222,7 +226,7 @@ export const defaultStore = markRaw(new Storage('base', { }, animatedMfm: { where: 'device', - default: false, + default: !window.matchMedia('(prefers-reduced-motion)').matches, }, advancedMfm: { where: 'device', diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index e982df8ffd..504562a91e 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -109,6 +109,11 @@ export function getConfig(): UserConfig { } }, }, + preprocessorOptions: { + scss: { + api: 'modern-compiler', + }, + }, }, define: { diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index a5f12b41f4..1da8e4e613 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -4,7 +4,9 @@ ```ts +import type { AuthenticationResponseJSON } from '@simplewebauthn/types'; import { EventEmitter } from 'eventemitter3'; +import type { PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/types'; // Warning: (ae-forgotten-export) The symbol "components" needs to be exported by the entry point index.d.ts // @@ -212,6 +214,9 @@ type AdminFederationRemoveAllFollowingRequest = operations['admin___federation__ type AdminFederationUpdateInstanceRequest = operations['admin___federation___update-instance']['requestBody']['content']['application/json']; // @public (undocumented) +type AdminForwardAbuseUserReportRequest = operations['admin___forward-abuse-user-report']['requestBody']['content']['application/json']; + +// @public (undocumented) type AdminGetIndexStatsResponse = operations['admin___get-index-stats']['responses']['200']['content']['application/json']; // @public (undocumented) @@ -377,6 +382,9 @@ type AdminUnsetUserBannerRequest = operations['admin___unset-user-banner']['requ type AdminUnsuspendUserRequest = operations['admin___unsuspend-user']['requestBody']['content']['application/json']; // @public (undocumented) +type AdminUpdateAbuseUserReportRequest = operations['admin___update-abuse-user-report']['requestBody']['content']['application/json']; + +// @public (undocumented) type AdminUpdateMetaRequest = operations['admin___update-meta']['requestBody']['content']['application/json']; // @public (undocumented) @@ -1156,13 +1164,25 @@ export type Endpoints = Overwrite<Endpoints_2, { req: SignupPendingRequest; res: SignupPendingResponse; }; - 'signin': { - req: SigninRequest; - res: SigninResponse; + 'signin-flow': { + req: SigninFlowRequest; + res: SigninFlowResponse; }; 'signin-with-passkey': { req: SigninWithPasskeyRequest; - res: SigninWithPasskeyResponse; + res: { + $switch: { + $cases: [ + [ + { + context: string; + }, + SigninWithPasskeyResponse + ] + ]; + $default: SigninWithPasskeyInitResponse; + }; + }; }; 'admin/roles/create': { req: Overwrite<AdminRolesCreateRequest, { @@ -1194,10 +1214,11 @@ declare namespace entities { SignupResponse, SignupPendingRequest, SignupPendingResponse, - SigninRequest, + SigninFlowRequest, + SigninFlowResponse, SigninWithPasskeyRequest, + SigninWithPasskeyInitResponse, SigninWithPasskeyResponse, - SigninResponse, PartialRolePolicyOverride, EmptyRequest, EmptyResponse, @@ -1283,6 +1304,8 @@ declare namespace entities { AdminResetPasswordRequest, AdminResetPasswordResponse, AdminResolveAbuseUserReportRequest, + AdminForwardAbuseUserReportRequest, + AdminUpdateAbuseUserReportRequest, AdminSendEmailRequest, AdminServerInfoResponse, AdminShowModerationLogsRequest, @@ -1665,6 +1688,7 @@ declare namespace entities { FlashCreateRequest, FlashCreateResponse, FlashDeleteRequest, + FlashFeaturedRequest, FlashFeaturedResponse, FlashLikeRequest, FlashShowRequest, @@ -1915,6 +1939,9 @@ type FlashCreateResponse = operations['flash___create']['responses']['200']['con type FlashDeleteRequest = operations['flash___delete']['requestBody']['content']['application/json']; // @public (undocumented) +type FlashFeaturedRequest = operations['flash___featured']['requestBody']['content']['application/json']; + +// @public (undocumented) type FlashFeaturedResponse = operations['flash___featured']['responses']['200']['content']['application/json']; // @public (undocumented) @@ -2528,6 +2555,12 @@ type ModerationLog = { type: 'resolveAbuseReport'; info: ModerationLogPayloads['resolveAbuseReport']; } | { + type: 'forwardAbuseReport'; + info: ModerationLogPayloads['forwardAbuseReport']; +} | { + type: 'updateAbuseReportNote'; + info: ModerationLogPayloads['updateAbuseReportNote']; +} | { type: 'unsetUserAvatar'; info: ModerationLogPayloads['unsetUserAvatar']; } | { @@ -2566,7 +2599,7 @@ type ModerationLog = { }); // @public (undocumented) -export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost"]; +export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost"]; // @public (undocumented) type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json']; @@ -3023,29 +3056,46 @@ type ServerStatsLog = ServerStats[]; type Signin = components['schemas']['Signin']; // @public (undocumented) -type SigninRequest = { +type SigninFlowRequest = { username: string; - password: string; + password?: string; token?: string; + credential?: AuthenticationResponseJSON; + 'hcaptcha-response'?: string | null; + 'g-recaptcha-response'?: string | null; + 'turnstile-response'?: string | null; + 'm-captcha-response'?: string | null; }; // @public (undocumented) -type SigninResponse = { +type SigninFlowResponse = { + finished: true; id: User['id']; i: string; +} | { + finished: false; + next: 'captcha' | 'password' | 'totp'; +} | { + finished: false; + next: 'passkey'; + authRequest: PublicKeyCredentialRequestOptionsJSON; +}; + +// @public (undocumented) +type SigninWithPasskeyInitResponse = { + option: PublicKeyCredentialRequestOptionsJSON; + context: string; }; // @public (undocumented) type SigninWithPasskeyRequest = { - credential?: object; + credential?: AuthenticationResponseJSON; context?: string; }; // @public (undocumented) type SigninWithPasskeyResponse = { - option?: object; - context?: string; - signinResponse?: SigninResponse; + signinResponse: SigninFlowResponse; }; // @public (undocumented) @@ -3069,6 +3119,7 @@ type SignupRequest = { 'hcaptcha-response'?: string | null; 'g-recaptcha-response'?: string | null; 'turnstile-response'?: string | null; + 'm-captcha-response'?: string | null; }; // @public (undocumented) @@ -3346,7 +3397,7 @@ type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody'][' // Warnings were encountered during analysis: // -// src/entities.ts:49:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts +// src/entities.ts:50:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:220:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:230:4 - (ae-forgotten-export) The symbol "ReversiUpdateSettings" 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 684ae381f0..a7e04d6dac 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2024.9.0", + "version": "2024.10.0", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", @@ -57,6 +57,7 @@ "built" ], "dependencies": { + "@simplewebauthn/types": "10.0.0", "eventemitter3": "5.0.1", "reconnecting-websocket": "4.4.0" } diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index 4c3f2e1578..838949f8e1 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -3,8 +3,9 @@ import { UserDetailed } from './autogen/models.js'; import { AdminRolesCreateRequest, AdminRolesCreateResponse, UsersShowRequest } from './autogen/entities.js'; import { PartialRolePolicyOverride, - SigninRequest, - SigninResponse, + SigninFlowRequest, + SigninFlowResponse, + SigninWithPasskeyInitResponse, SigninWithPasskeyRequest, SigninWithPasskeyResponse, SignupPendingRequest, @@ -80,14 +81,26 @@ export type Endpoints = Overwrite< res: SignupPendingResponse; }, // api.jsonã«ã¯è¼‰ã›ãªã„ã‚‚ã®ãªã®ã§ã“ã“ã§å®šç¾© - 'signin': { - req: SigninRequest; - res: SigninResponse; + 'signin-flow': { + req: SigninFlowRequest; + res: SigninFlowResponse; }, 'signin-with-passkey': { req: SigninWithPasskeyRequest; - res: SigninWithPasskeyResponse; - } + res: { + $switch: { + $cases: [ + [ + { + context: string; + }, + SigninWithPasskeyResponse, + ], + ]; + $default: SigninWithPasskeyInitResponse; + }, + }, + }, 'admin/roles/create': { req: Overwrite<AdminRolesCreateRequest, { policies: PartialRolePolicyOverride }>; res: AdminRolesCreateResponse; diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index 1d96196d1c..e2c7cbba52 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -694,6 +694,28 @@ declare module '../api.js' { /** * No description provided. * + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* + */ + request<E extends 'admin/forward-abuse-user-report', P extends Endpoints[E]['req']>( + endpoint: E, + params: P, + credential?: string | null, + ): Promise<SwitchCaseResponseType<E, P>>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* + */ + request<E extends 'admin/update-abuse-user-report', P extends Endpoints[E]['req']>( + endpoint: E, + params: P, + credential?: string | null, + ): Promise<SwitchCaseResponseType<E, P>>; + + /** + * No description provided. + * * **Credential required**: *Yes* / **Permission**: *write:admin:send-email* */ request<E extends 'admin/send-email', P extends Endpoints[E]['req']>( diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 42c74599a5..d0367d8496 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -83,6 +83,8 @@ import type { AdminResetPasswordRequest, AdminResetPasswordResponse, AdminResolveAbuseUserReportRequest, + AdminForwardAbuseUserReportRequest, + AdminUpdateAbuseUserReportRequest, AdminSendEmailRequest, AdminServerInfoResponse, AdminShowModerationLogsRequest, @@ -465,6 +467,7 @@ import type { FlashCreateRequest, FlashCreateResponse, FlashDeleteRequest, + FlashFeaturedRequest, FlashFeaturedResponse, FlashLikeRequest, FlashShowRequest, @@ -638,6 +641,8 @@ export type Endpoints = { 'admin/relays/remove': { req: AdminRelaysRemoveRequest; res: EmptyResponse }; 'admin/reset-password': { req: AdminResetPasswordRequest; res: AdminResetPasswordResponse }; 'admin/resolve-abuse-user-report': { req: AdminResolveAbuseUserReportRequest; res: EmptyResponse }; + 'admin/forward-abuse-user-report': { req: AdminForwardAbuseUserReportRequest; res: EmptyResponse }; + 'admin/update-abuse-user-report': { req: AdminUpdateAbuseUserReportRequest; res: EmptyResponse }; 'admin/send-email': { req: AdminSendEmailRequest; res: EmptyResponse }; 'admin/server-info': { req: EmptyRequest; res: AdminServerInfoResponse }; 'admin/show-moderation-logs': { req: AdminShowModerationLogsRequest; res: AdminShowModerationLogsResponse }; @@ -889,7 +894,7 @@ export type Endpoints = { 'pages/update': { req: PagesUpdateRequest; res: EmptyResponse }; 'flash/create': { req: FlashCreateRequest; res: FlashCreateResponse }; 'flash/delete': { req: FlashDeleteRequest; res: EmptyResponse }; - 'flash/featured': { req: EmptyRequest; res: FlashFeaturedResponse }; + 'flash/featured': { req: FlashFeaturedRequest; res: FlashFeaturedResponse }; 'flash/like': { req: FlashLikeRequest; res: EmptyResponse }; 'flash/show': { req: FlashShowRequest; res: FlashShowResponse }; 'flash/unlike': { req: FlashUnlikeRequest; res: EmptyResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index 87ed653d44..ced87c4c7e 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -86,6 +86,8 @@ export type AdminRelaysRemoveRequest = operations['admin___relays___remove']['re export type AdminResetPasswordRequest = operations['admin___reset-password']['requestBody']['content']['application/json']; export type AdminResetPasswordResponse = operations['admin___reset-password']['responses']['200']['content']['application/json']; export type AdminResolveAbuseUserReportRequest = operations['admin___resolve-abuse-user-report']['requestBody']['content']['application/json']; +export type AdminForwardAbuseUserReportRequest = operations['admin___forward-abuse-user-report']['requestBody']['content']['application/json']; +export type AdminUpdateAbuseUserReportRequest = operations['admin___update-abuse-user-report']['requestBody']['content']['application/json']; export type AdminSendEmailRequest = operations['admin___send-email']['requestBody']['content']['application/json']; export type AdminServerInfoResponse = operations['admin___server-info']['responses']['200']['content']['application/json']; export type AdminShowModerationLogsRequest = operations['admin___show-moderation-logs']['requestBody']['content']['application/json']; @@ -468,6 +470,7 @@ export type PagesUpdateRequest = operations['pages___update']['requestBody']['co export type FlashCreateRequest = operations['flash___create']['requestBody']['content']['application/json']; export type FlashCreateResponse = operations['flash___create']['responses']['200']['content']['application/json']; export type FlashDeleteRequest = operations['flash___delete']['requestBody']['content']['application/json']; +export type FlashFeaturedRequest = operations['flash___featured']['requestBody']['content']['application/json']; export type FlashFeaturedResponse = operations['flash___featured']['responses']['200']['content']['application/json']; export type FlashLikeRequest = operations['flash___like']['requestBody']['content']['application/json']; export type FlashShowRequest = operations['flash___show']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 0dff85183f..76ef7ea1fb 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -576,6 +576,24 @@ export type paths = { */ post: operations['admin___resolve-abuse-user-report']; }; + '/admin/forward-abuse-user-report': { + /** + * admin/forward-abuse-user-report + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* + */ + post: operations['admin___forward-abuse-user-report']; + }; + '/admin/update-abuse-user-report': { + /** + * admin/update-abuse-user-report + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* + */ + post: operations['admin___update-abuse-user-report']; + }; '/admin/send-email': { /** * admin/send-email @@ -3782,16 +3800,13 @@ export type components = { followingVisibility: 'public' | 'followers' | 'private'; /** @enum {string} */ followersVisibility: 'public' | 'followers' | 'private'; - /** @default false */ - twoFactorEnabled: boolean; - /** @default false */ - usePasswordLessLogin: boolean; - /** @default false */ - securityKeys: boolean; roles: components['schemas']['RoleLite'][]; followedMessage?: string | null; memo: string | null; moderationNote?: string; + twoFactorEnabled?: boolean; + usePasswordLessLogin?: boolean; + securityKeys?: boolean; isFollowing?: boolean; isFollowed?: boolean; hasPendingFollowRequestFromYou?: boolean; @@ -3972,6 +3987,12 @@ export type components = { }[]; loggedInDays: number; policies: components['schemas']['RolePolicies']; + /** @default false */ + twoFactorEnabled: boolean; + /** @default false */ + usePasswordLessLogin: boolean; + /** @default false */ + securityKeys: boolean; email?: string | null; emailVerified?: boolean | null; securityKeysList?: { @@ -4288,7 +4309,14 @@ export type components = { exportedEntity: 'antenna' | 'blocking' | 'clip' | 'customEmoji' | 'favorite' | 'following' | 'muting' | 'note' | 'userList'; /** Format: id */ fileId: string; - }) | ({ + }) | { + /** Format: id */ + id: string; + /** Format: date-time */ + createdAt: string; + /** @enum {string} */ + type: 'login'; + } | ({ /** Format: id */ id: string; /** Format: date-time */ @@ -5177,6 +5205,8 @@ export type operations = { urlPreviewRequireContentLength: boolean; urlPreviewUserAgent: string | null; urlPreviewSummaryProxyUrl: string | null; + federation: string; + federationHosts: string[]; }; }; }; @@ -5240,8 +5270,6 @@ export type operations = { * @enum {string} */ targetUserOrigin?: 'combined' | 'local' | 'remote'; - /** @default false */ - forwarded?: boolean; }; }; }; @@ -5268,7 +5296,11 @@ export type operations = { assigneeId: string | null; reporter: components['schemas']['UserDetailedNotMe']; targetUser: components['schemas']['UserDetailedNotMe']; - assignee?: components['schemas']['UserDetailedNotMe'] | null; + assignee: components['schemas']['UserDetailedNotMe'] | null; + forwarded: boolean; + /** @enum {string|null} */ + resolvedAs: 'accept' | 'reject' | null; + moderationNote: string; })[]; }; }; @@ -5602,6 +5634,7 @@ export type operations = { 'application/json': { username: string; password: string; + setupPassword?: string | null; }; }; }; @@ -8680,8 +8713,113 @@ export type operations = { 'application/json': { /** Format: misskey:id */ reportId: string; - /** @default false */ - forward?: boolean; + /** @enum {string|null} */ + resolvedAs?: 'accept' | 'reject' | null; + }; + }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/forward-abuse-user-report + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* + */ + 'admin___forward-abuse-user-report': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + reportId: string; + }; + }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/update-abuse-user-report + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* + */ + 'admin___update-abuse-user-report': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + reportId: string; + moderationNote?: string; }; }; }; @@ -9428,6 +9566,9 @@ export type operations = { urlPreviewRequireContentLength?: boolean; urlPreviewUserAgent?: string | null; urlPreviewSummaryProxyUrl?: string | null; + /** @enum {string} */ + federation?: 'all' | 'none' | 'specified'; + federationHosts?: string[]; }; }; }; @@ -18545,8 +18686,8 @@ export type operations = { untilId?: string; /** @default true */ markAsRead?: boolean; - includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'app' | 'test' | 'pollVote' | 'groupInvited')[]; - excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'app' | 'test' | 'pollVote' | 'groupInvited')[]; + includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'pollVote' | 'groupInvited')[]; + excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'pollVote' | 'groupInvited')[]; }; }; }; @@ -18613,8 +18754,8 @@ export type operations = { untilId?: string; /** @default true */ markAsRead?: boolean; - includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[]; - excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[]; + includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[]; + excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[]; }; }; }; @@ -23783,6 +23924,16 @@ export type operations = { * **Credential required**: *No* */ flash___featured: { + requestBody: { + content: { + 'application/json': { + /** @default 0 */ + offset?: number; + /** @default 10 */ + limit?: number; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index b4fbcffa97..c5911a70eb 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -142,6 +142,8 @@ export const moderationLogTypes = [ 'markSensitiveDriveFile', 'unmarkSensitiveDriveFile', 'resolveAbuseReport', + 'forwardAbuseReport', + 'updateAbuseReportNote', 'createInvitation', 'createAd', 'updateAd', @@ -330,7 +332,18 @@ export type ModerationLogPayloads = { resolveAbuseReport: { reportId: string; report: ReceivedAbuseReport; - forwarded: boolean; + forwarded?: boolean; + resolvedAs?: string | null; + }; + forwardAbuseReport: { + reportId: string; + report: ReceivedAbuseReport; + }; + updateAbuseReportNote: { + reportId: string; + report: ReceivedAbuseReport; + before: string; + after: string; }; createInvitation: { invitations: InviteCode[]; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 64ed90cbb1..2ffee40fba 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -10,6 +10,7 @@ import { User, UserDetailedNotMe, } from './autogen/models.js'; +import type { AuthenticationResponseJSON, PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/types'; export * from './autogen/entities.js'; export * from './autogen/models.js'; @@ -153,6 +154,12 @@ export type ModerationLog = { type: 'resolveAbuseReport'; info: ModerationLogPayloads['resolveAbuseReport']; } | { + type: 'forwardAbuseReport'; + info: ModerationLogPayloads['forwardAbuseReport']; +} | { + type: 'updateAbuseReportNote'; + info: ModerationLogPayloads['updateAbuseReportNote']; +} | { type: 'unsetUserAvatar'; info: ModerationLogPayloads['unsetUserAvatar']; } | { @@ -250,6 +257,7 @@ export type SignupRequest = { 'hcaptcha-response'?: string | null; 'g-recaptcha-response'?: string | null; 'turnstile-response'?: string | null; + 'm-captcha-response'?: string | null; } export type SignupResponse = MeDetailed & { @@ -265,26 +273,42 @@ export type SignupPendingResponse = { i: string, }; -export type SigninRequest = { +export type SigninFlowRequest = { username: string; - password: string; + password?: string; token?: string; + credential?: AuthenticationResponseJSON; + 'hcaptcha-response'?: string | null; + 'g-recaptcha-response'?: string | null; + 'turnstile-response'?: string | null; + 'm-captcha-response'?: string | null; +}; + +export type SigninFlowResponse = { + finished: true; + id: User['id']; + i: string; +} | { + finished: false; + next: 'captcha' | 'password' | 'totp'; +} | { + finished: false; + next: 'passkey'; + authRequest: PublicKeyCredentialRequestOptionsJSON; }; export type SigninWithPasskeyRequest = { - credential?: object; + credential?: AuthenticationResponseJSON; context?: string; }; -export type SigninWithPasskeyResponse = { - option?: object; - context?: string; - signinResponse?: SigninResponse; +export type SigninWithPasskeyInitResponse = { + option: PublicKeyCredentialRequestOptionsJSON; + context: string; }; -export type SigninResponse = { - id: User['id'], - i: string, +export type SigninWithPasskeyResponse = { + signinResponse: SigninFlowResponse; }; type Values<T extends Record<PropertyKey, unknown>> = T[keyof T]; diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts index 2b7dfd4f2d..364328d4b0 100644 --- a/packages/sw/src/scripts/create-notification.ts +++ b/packages/sw/src/scripts/create-notification.ts @@ -210,6 +210,12 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif tag: `achievement:${data.body.achievement}`, }]; + case 'login': + return [i18n.ts._notification.login, { + badge: iconUrl('login-2'), + data, + }]; + case 'exportCompleted': { const entityName = { antenna: i18n.ts.antennas, diff --git a/packages/sw/src/types.ts b/packages/sw/src/types.ts index fac3e707d8..4f82779808 100644 --- a/packages/sw/src/types.ts +++ b/packages/sw/src/types.ts @@ -50,4 +50,5 @@ export type BadgeNames = | 'quote' | 'repeat' | 'user-plus' - | 'users'; + | 'users' + | 'login-2'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0822620bf3..1312e8c886 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,7 +52,7 @@ importers: devDependencies: '@misskey-dev/eslint-plugin': specifier: 2.0.3 - version: 2.0.3(@eslint/compat@1.1.1)(@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0)(typescript@5.6.2))(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0))(eslint@9.8.0)(globals@15.9.0) + version: 2.0.3(@eslint/compat@1.1.1)(@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0)(typescript@5.6.2))(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0))(eslint@9.8.0)(globals@15.9.0) '@types/node': specifier: 20.14.12 version: 20.14.12 @@ -102,29 +102,29 @@ importers: specifier: 15.1.0 version: 15.1.0 '@fastify/accepts': - specifier: 5.0.0 - version: 5.0.0 + specifier: 5.0.1 + version: 5.0.1 '@fastify/cookie': - specifier: 10.0.0 - version: 10.0.0 + specifier: 10.0.1 + version: 10.0.1 '@fastify/cors': - specifier: 10.0.0 - version: 10.0.0 + specifier: 10.0.1 + version: 10.0.1 '@fastify/express': - specifier: 4.0.0 - version: 4.0.0 + specifier: 4.0.1 + version: 4.0.1 '@fastify/http-proxy': specifier: 10.0.0 version: 10.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) '@fastify/multipart': - specifier: 9.0.0 - version: 9.0.0 + specifier: 9.0.1 + version: 9.0.1 '@fastify/static': - specifier: 8.0.0 - version: 8.0.0 + specifier: 8.0.1 + version: 8.0.1 '@fastify/view': - specifier: 10.0.0 - version: 10.0.0 + specifier: 10.0.1 + version: 10.0.1 '@misskey-dev/sharp-read-bmp': specifier: 1.2.0 version: 1.2.0 @@ -135,14 +135,14 @@ importers: specifier: 0.1.56 version: 0.1.56 '@nestjs/common': - specifier: 10.4.3 - version: 10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1) + specifier: 10.4.4 + version: 10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/core': - specifier: 10.4.3 - version: 10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + specifier: 10.4.4 + version: 10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/testing': - specifier: 10.4.3 - version: 10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.3)) + specifier: 10.4.4 + version: 10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)) '@peertube/http-signature': specifier: 1.7.0 version: 1.7.0 @@ -192,8 +192,8 @@ importers: specifier: 1.20.3 version: 1.20.3 bullmq: - specifier: 5.13.2 - version: 5.13.2 + specifier: 5.15.0 + version: 5.15.0 cacheable-lookup: specifier: 7.0.0 version: 7.0.0 @@ -336,8 +336,8 @@ importers: specifier: 0.0.14 version: 0.0.14 otpauth: - specifier: 9.3.2 - version: 9.3.2 + specifier: 9.3.4 + version: 9.3.4 parse5: specifier: 7.1.2 version: 7.1.2 @@ -387,8 +387,8 @@ importers: specifier: 7.8.1 version: 7.8.1 sanitize-html: - specifier: 2.13.0 - version: 2.13.0 + specifier: 2.13.1 + version: 2.13.1 secure-json-parse: specifier: 2.7.0 version: 2.7.0 @@ -533,8 +533,8 @@ importers: specifier: 29.7.0 version: 29.7.0 '@nestjs/platform-express': - specifier: 10.4.3 - version: 10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.3) + specifier: 10.4.4 + version: 10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4) '@simplewebauthn/types': specifier: 10.0.0 version: 10.0.0 @@ -554,8 +554,8 @@ importers: specifier: 1.19.5 version: 1.19.5 '@types/color-convert': - specifier: 2.0.3 - version: 2.0.3 + specifier: 2.0.4 + version: 2.0.4 '@types/content-disposition': specifier: 0.5.8 version: 0.5.8 @@ -723,10 +723,10 @@ importers: version: 15.1.1 '@vitejs/plugin-vue': specifier: 5.1.4 - version: 5.1.4(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.10(typescript@5.6.2)) + version: 5.1.4(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.11(typescript@5.6.2)) '@vue/compiler-sfc': - specifier: 3.5.10 - version: 3.5.10 + specifier: 3.5.11 + version: 3.5.11 aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.1.11 version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9 @@ -758,8 +758,8 @@ importers: specifier: 2.0.1 version: 2.0.1(chart.js@4.4.4) chromatic: - specifier: 11.10.4 - version: 11.10.4 + specifier: 11.11.0 + version: 11.11.0 compare-versions: specifier: 6.1.1 version: 6.1.1 @@ -815,14 +815,14 @@ importers: specifier: 4.22.5 version: 4.22.5 sanitize-html: - specifier: 2.13.0 - version: 2.13.0 + specifier: 2.13.1 + version: 2.13.1 sass: specifier: 1.79.3 version: 1.79.3 shiki: - specifier: 1.12.0 - version: 1.12.0 + specifier: 1.21.0 + version: 1.21.0 strict-event-emitter-types: specifier: 2.0.0 version: 2.0.0 @@ -852,77 +852,80 @@ importers: version: 10.0.0 v-code-diff: specifier: 1.13.1 - version: 1.13.1(vue@3.5.10(typescript@5.6.2)) + version: 1.13.1(vue@3.5.11(typescript@5.6.2)) vite: specifier: 5.4.8 version: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) vue: - specifier: 3.5.10 - version: 3.5.10(typescript@5.6.2) + specifier: 3.5.11 + version: 3.5.11(typescript@5.6.2) vuedraggable: specifier: next - version: 4.1.0(vue@3.5.10(typescript@5.6.2)) + version: 4.1.0(vue@3.5.11(typescript@5.6.2)) devDependencies: '@misskey-dev/summaly': specifier: 5.1.0 version: 5.1.0 '@storybook/addon-actions': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/addon-essentials': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/addon-interactions': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/addon-links': - specifier: 8.3.3 - version: 8.3.3(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/addon-mdx-gfm': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/addon-storysource': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/blocks': - specifier: 8.3.3 - version: 8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/components': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/core-events': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/manager-api': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/preview-api': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/react': - specifier: 8.3.3 - version: 8.3.3(@storybook/test@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2) + specifier: 8.3.4 + version: 8.3.4(@storybook/test@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2) '@storybook/react-vite': - specifier: 8.3.3 - version: 8.3.3(@storybook/test@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.5)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0)) + specifier: 8.3.4 + version: 8.3.4(@storybook/test@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.5)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0)) '@storybook/test': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/theming': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/types': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/vue3': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vue@3.5.10(typescript@5.6.2)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vue@3.5.11(typescript@5.6.2)) '@storybook/vue3-vite': - specifier: 8.3.3 - version: 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.10(typescript@5.6.2)) + specifier: 8.3.4 + version: 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.11(typescript@5.6.2)) '@testing-library/vue': specifier: 8.1.0 - version: 8.1.0(@vue/compiler-sfc@3.5.10)(@vue/server-renderer@3.5.10(vue@3.5.10(typescript@5.6.2)))(vue@3.5.10(typescript@5.6.2)) + version: 8.1.0(@vue/compiler-sfc@3.5.11)(@vue/server-renderer@3.5.11(vue@3.5.11(typescript@5.6.2)))(vue@3.5.11(typescript@5.6.2)) + '@types/canvas-confetti': + specifier: ^1.6.4 + version: 1.6.4 '@types/estree': specifier: 1.0.6 version: 1.0.6 @@ -966,8 +969,8 @@ importers: specifier: 1.6.0 version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.3)(terser@5.33.0)) '@vue/runtime-core': - specifier: 3.5.10 - version: 3.5.10 + specifier: 3.5.11 + version: 3.5.11 acorn: specifier: 8.12.1 version: 8.12.1 @@ -978,8 +981,8 @@ importers: specifier: 13.15.0 version: 13.15.0 eslint-plugin-import: - specifier: 2.30.0 - version: 2.30.0(@typescript-eslint/parser@7.17.0(eslint@9.11.0)(typescript@5.6.2))(eslint@9.11.0) + specifier: 2.31.0 + version: 2.31.0(@typescript-eslint/parser@7.17.0(eslint@9.11.0)(typescript@5.6.2))(eslint@9.11.0) eslint-plugin-vue: specifier: 9.28.0 version: 9.28.0(eslint@9.11.0) @@ -1020,11 +1023,11 @@ importers: specifier: 2.0.8 version: 2.0.8 storybook: - specifier: 8.3.3 - version: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + specifier: 8.3.4 + version: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/components@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/core-events@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/manager-api@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/preview-api@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/theming@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/types@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/components@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/core-events@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/manager-api@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/preview-api@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/theming@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/types@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 @@ -1066,10 +1069,10 @@ importers: version: 15.1.1 '@vitejs/plugin-vue': specifier: 5.1.4 - version: 5.1.4(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.10(typescript@5.6.2)) + version: 5.1.4(vite@5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0))(vue@3.5.11(typescript@5.6.2)) '@vue/compiler-sfc': - specifier: 3.5.10 - version: 3.5.10 + specifier: 3.5.11 + version: 3.5.11 astring: specifier: 1.9.0 version: 1.9.0 @@ -1098,11 +1101,11 @@ importers: specifier: 4.22.5 version: 4.22.5 sass: - specifier: 1.79.3 - version: 1.79.3 + specifier: 1.79.4 + version: 1.79.4 shiki: - specifier: 1.12.0 - version: 1.12.0 + specifier: 1.21.0 + version: 1.21.0 tinycolor2: specifier: 1.6.0 version: 1.6.0 @@ -1120,17 +1123,17 @@ importers: version: 10.0.0 vite: specifier: 5.4.8 - version: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) + version: 5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0) vue: - specifier: 3.5.10 - version: 3.5.10(typescript@5.6.2) + specifier: 3.5.11 + version: 3.5.11(typescript@5.6.2) devDependencies: '@misskey-dev/summaly': specifier: 5.1.0 version: 5.1.0 '@testing-library/vue': specifier: 8.1.0 - version: 8.1.0(@vue/compiler-sfc@3.5.10)(@vue/server-renderer@3.5.10(vue@3.5.10(typescript@5.6.2)))(vue@3.5.10(typescript@5.6.2)) + version: 8.1.0(@vue/compiler-sfc@3.5.11)(@vue/server-renderer@3.5.11(vue@3.5.11(typescript@5.6.2)))(vue@3.5.11(typescript@5.6.2)) '@types/estree': specifier: 1.0.6 version: 1.0.6 @@ -1160,10 +1163,10 @@ importers: version: 7.17.0(eslint@9.11.0)(typescript@5.6.2) '@vitest/coverage-v8': specifier: 1.6.0 - version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.3)(terser@5.33.0)) + version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0)) '@vue/runtime-core': - specifier: 3.5.10 - version: 3.5.10 + specifier: 3.5.11 + version: 3.5.11 acorn: specifier: 8.12.1 version: 8.12.1 @@ -1171,8 +1174,8 @@ importers: specifier: 7.0.3 version: 7.0.3 eslint-plugin-import: - specifier: 2.30.0 - version: 2.30.0(@typescript-eslint/parser@7.17.0(eslint@9.11.0)(typescript@5.6.2))(eslint@9.11.0) + specifier: 2.31.0 + version: 2.31.0(@typescript-eslint/parser@7.17.0(eslint@9.11.0)(typescript@5.6.2))(eslint@9.11.0) eslint-plugin-vue: specifier: 9.28.0 version: 9.28.0(eslint@9.11.0) @@ -1289,6 +1292,9 @@ importers: packages/misskey-js: dependencies: + '@simplewebauthn/types': + specifier: 10.0.0 + version: 10.0.0 eventemitter3: specifier: 5.0.1 version: 5.0.1 @@ -2710,8 +2716,8 @@ packages: '@fastify/accept-negotiator@2.0.0': resolution: {integrity: sha512-/Sce/kBzuTxIq5tJh85nVNOq9wKD8s+viIgX0fFMDBdw95gnpf53qmF1oBgJym3cPFliWUuSloVg/1w/rH0FcQ==} - '@fastify/accepts@5.0.0': - resolution: {integrity: sha512-5wpgycrn+DXPkATGqUbXY9tyqLNgxo9S8f0EHUyIWvUacor2cXa3liYZggsqoyMXgpIqUbGLPBl+dN2hRcU9jQ==} + '@fastify/accepts@5.0.1': + resolution: {integrity: sha512-8ji2MGTbceSnAXKYx/U9iWt6Fmf0zJovh0meO5rpwYS/vy0Z3QIR2J/hKmbcTpYfMu5NUliNpsAtMavmzBQhmA==} '@fastify/ajv-compiler@4.0.0': resolution: {integrity: sha512-dt0jyLAlay14LpIn4Fg1SY7V5NJ9KH0YFDpYVQY5cgIVBvdI8908AMx5zQ0bBYPGT6Wh+bM3f2caMmOXLP3QsQ==} @@ -2723,11 +2729,11 @@ packages: '@fastify/busboy@3.0.0': resolution: {integrity: sha512-83rnH2nCvclWaPQQKvkJ2pdOjG4TZyEVuFDnlOF6KP08lDaaceVyw/W63mDuafQT+MKHCvXIPpE5uYWeM0rT4w==} - '@fastify/cookie@10.0.0': - resolution: {integrity: sha512-S43spazwAfzm5nKlqq/spAGW+O6r+WQzg5vXXI1ArCXXFa8KBA/tiU3XRVQUehSNtbN5PA6+g183hzh5/dZ6Iw==} + '@fastify/cookie@10.0.1': + resolution: {integrity: sha512-NV/wbCUv4ETJ5KM1KMu0fLx0nSCm9idIxwg66NZnNbfPQH3rdbx6k0qRs5uy0y+MhBgvDudYRA30KlK659chyw==} - '@fastify/cors@10.0.0': - resolution: {integrity: sha512-kb9fkc/LVbLTQ3lhA+ZZjC/Styzysodo/MTCdVCvTtgHa/gBwxrEEkcp3fuoKIfAQt85wksrpXjUGbw5NQffEQ==} + '@fastify/cors@10.0.1': + resolution: {integrity: sha512-O8JIf6448uQbOgzSkCqhClw6gFTAqrdfeA6R3fc/3gwTJGUp7gl8/3tbNB+6INuu4RmgVOq99BmvdGbtu5pgOA==} '@fastify/deepmerge@2.0.0': resolution: {integrity: sha512-fsaybTGDyQ5KpPsplQqb9yKdCf2x/pbNpMNk8Tvp3rRz7lVcupKysH4b2ELMN2P4Hak1+UqTYdTj/u4FNV2p0g==} @@ -2735,8 +2741,8 @@ packages: '@fastify/error@4.0.0': resolution: {integrity: sha512-OO/SA8As24JtT1usTUTKgGH7uLvhfwZPwlptRi2Dp5P4KKmJI3gvsZ8MIHnNwDs4sLf/aai5LzTyl66xr7qMxA==} - '@fastify/express@4.0.0': - resolution: {integrity: sha512-e+IMKKV9+HRCVm7LVW8PaMrpEerHfqNLpRkbiVHYfVm0xeOphiwyNEoge4VA3Sh8gubtDfo9yKkpRzx6gx63kg==} + '@fastify/express@4.0.1': + resolution: {integrity: sha512-mEQ6pawaENeZ3swqVtkxdLi8NQC5eKBkclE+7ma1qQMuB+yI6WxDyEp55pdbqPIqBQTN/cGgHv84qxVS7NKC2Q==} '@fastify/fast-json-stringify-compiler@5.0.0': resolution: {integrity: sha512-tywfuZfXsyxLC5kEqrMubbFa9vpAxNtuPE7j9w5si1r+6p5b981pDfZ5Y8HBqmjDQl+PABT7cV5jZgXI2j+I5g==} @@ -2747,8 +2753,8 @@ packages: '@fastify/merge-json-schemas@0.1.1': resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} - '@fastify/multipart@9.0.0': - resolution: {integrity: sha512-B/rzOl1wmkj4LddH2i+zR8Gke8ZX1J8D7n4uJeis5VdIa7OR9Ys/TzUxI0/h1SF9ubHlNhBP+eO/FwnftarP9w==} + '@fastify/multipart@9.0.1': + resolution: {integrity: sha512-vt2gOCw/O4EwpN4KlLVJxth4iQlDf7T5ggw2Db2C+UbO2WJBG7y0jEBvu/HT6JIW/lBYaqrrUy9MmTpCKgXEpw==} '@fastify/reply-from@11.0.0': resolution: {integrity: sha512-dv3o8hyy4sxhg1RN9l6ueM+PMMaIPKLjtL2T99H5M7h1Xt8d1RX3r+xC+sL5AqJqLvReX4N+7mTq9QDeB8i6Lg==} @@ -2756,15 +2762,9 @@ packages: '@fastify/send@3.1.1': resolution: {integrity: sha512-LdiV2mle/2tH8vh6GwGl0ubfUAgvY+9yF9oGI1iiwVyNUVOQamvw5n+OFu6iCNNoyuCY80FFURBn4TZCbTe8LA==} - '@fastify/static@8.0.0': - resolution: {integrity: sha512-VKGn1PQslB2VqzspyMKPu9xasF9vj+YuyGhVLb1ih6V60VVcRvcf0fFRcl3opt6c6YWwhKKdTUTfVE6COnpw6A==} - '@fastify/static@8.0.1': resolution: {integrity: sha512-7idyhbcgf14v4bjWzUeHEFvnVxvNJ1n5cyGPgFtwTZjnjUQ1wgC7a2FQai7OGKqCKywDEjzbPhAZRW+uEK1LMg==} - '@fastify/view@10.0.0': - resolution: {integrity: sha512-2KnfgpSbAImKV5kKdNAkSyjV+9kYUYLvgDLx/wlzgqel92bN9Z520cwG3g3bAkr0yVnEJu62dIm2qAL9FASS1w==} - '@fastify/view@10.0.1': resolution: {integrity: sha512-rXtBN0oVDmoRZAS7lelrCIahf+qFtlMOOas8VPdA7JvrJ9ChcF7e36pIUPU0Vbs3KmHxESUb7XatavUZEe/k5Q==} @@ -3223,8 +3223,8 @@ packages: resolution: {integrity: sha512-SujSchzG6lLc/wT+Mwxam/w30Kk2sFTiU6bLFcidecKSmlhenAhGMQhZh2iGFfKoh2+8iit0jrt99n6TqReICQ==} engines: {node: '>= 10'} - '@nestjs/common@10.4.3': - resolution: {integrity: sha512-4hbLd3XIJubHSylYd/1WSi4VQvG68KM/ECYpMDqA3k3J1/T17SAg40sDoq3ZoO5OZgU0xuNyjuISdOTjs11qVg==} + '@nestjs/common@10.4.4': + resolution: {integrity: sha512-0j2/zqRw9nvHV1GKTktER8B/hIC/Z8CYFjN/ZqUuvwayCH+jZZBhCR2oRyuvLTXdnlSmtCAg2xvQ0ULqQvzqhA==} peerDependencies: class-transformer: '*' class-validator: '*' @@ -3236,8 +3236,8 @@ packages: class-validator: optional: true - '@nestjs/core@10.4.3': - resolution: {integrity: sha512-6OQz+5C8mT8yRtfvE5pPCq+p6w5jDot+oQku1KzQ24ABn+lay1KGuJwcKZhdVNuselx+8xhdMxknZTA8wrGLIg==} + '@nestjs/core@10.4.4': + resolution: {integrity: sha512-y9tjmAzU6LTh1cC/lWrRsCcOd80khSR0qAHAqwY2svbW+AhsR/XCzgpZrAAKJrm/dDfjLCZKyxJSayeirGcW5Q==} peerDependencies: '@nestjs/common': ^10.0.0 '@nestjs/microservices': ^10.0.0 @@ -3253,14 +3253,14 @@ packages: '@nestjs/websockets': optional: true - '@nestjs/platform-express@10.4.3': - resolution: {integrity: sha512-ss7gkofVm3eO+1P9iRhmGq6Xcjg+mIN3dWisKJZYelSV+msb0QpJmqChLvWjLkWtlqDnx915FKUk0IzCa0TVzw==} + '@nestjs/platform-express@10.4.4': + resolution: {integrity: sha512-y52q1MxhbHaT3vAgWd08RgiYon0lJgtTa8U6g6gV0KI0IygwZhDQFJVxnrRDUdxQGIP5CKHmfQu3sk9gTNFoEA==} peerDependencies: '@nestjs/common': ^10.0.0 '@nestjs/core': ^10.0.0 - '@nestjs/testing@10.4.3': - resolution: {integrity: sha512-SBNWrMU51YAlYmW86wyjlGZ2uLnASNiOPD0lBcNIlxxei0b05/aI3nh7OPuxbXQUdedUJfPq2d2jZj4TRG4S0w==} + '@nestjs/testing@10.4.4': + resolution: {integrity: sha512-qRGFj51A5RM7JqA8pcyEwSLA3Y0dle/PAZ8oxP0suimoCusRY3Tk7wYqutZdCNj1ATb678SDaUZDHk2pwSv9/g==} peerDependencies: '@nestjs/common': ^10.0.0 '@nestjs/core': ^10.0.0 @@ -3272,9 +3272,9 @@ packages: '@nestjs/platform-express': optional: true - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} + '@noble/hashes@1.5.0': + resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} + engines: {node: ^14.21.3 || >=16} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -3700,8 +3700,20 @@ packages: resolution: {integrity: sha512-+1I5H8dojURiEUGPliDwheQk8dhjp8uV1sMccR/W/zjFrt4wZyPs+Ttp/V7gzm9LDJoNek9tmELert/jQqWTgg==} engines: {node: '>=14.18'} - '@shikijs/core@1.12.0': - resolution: {integrity: sha512-mc1cLbm6UQ8RxLc0dZES7v5rkH+99LxQp/ZvTqV3NLyYsO/fD6JhEflP1H5b2SDq9gI0+0G36AVZWxvounfR9w==} + '@shikijs/core@1.21.0': + resolution: {integrity: sha512-zAPMJdiGuqXpZQ+pWNezQAk5xhzRXBNiECFPcJLtUdsFM3f//G95Z15EHTnHchYycU8kIIysqGgxp8OVSj1SPQ==} + + '@shikijs/engine-javascript@1.21.0': + resolution: {integrity: sha512-jxQHNtVP17edFW4/0vICqAVLDAxmyV31MQJL4U/Kg+heQALeKYVOWo0sMmEZ18FqBt+9UCdyqGKYE7bLRtk9mg==} + + '@shikijs/engine-oniguruma@1.21.0': + resolution: {integrity: sha512-AIZ76XocENCrtYzVU7S4GY/HL+tgHGbVU+qhiDyNw1qgCA5OSi4B4+HY4BtAoJSMGuD/L5hfTzoRVbzEm2WTvg==} + + '@shikijs/types@1.21.0': + resolution: {integrity: sha512-tzndANDhi5DUndBtpojEq/42+dpUF2wS7wdCDQaFtIXm3Rd1QkrcVgSSRLOvEwexekihOXfbYJINW37g96tJRw==} + + '@shikijs/vscode-textmate@9.2.2': + resolution: {integrity: sha512-TMp15K+GGYrWlZM8+Lnj9EaHEFmOen0WJBrfa17hF7taDOYthuPPV0GWzfd/9iMij0akS/8Yw2ikquH7uVi/fg==} '@sideway/address@4.1.4': resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} @@ -3989,97 +4001,97 @@ packages: '@sqltools/formatter@1.2.5': resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} - '@storybook/addon-actions@8.3.3': - resolution: {integrity: sha512-cbpksmld7iADwDGXgojZ4r8LGI3YA3NP68duAHg2n1dtnx1oUaFK5wd6dbNuz7GdjyhIOIy3OKU1dAuylYNGOQ==} + '@storybook/addon-actions@8.3.4': + resolution: {integrity: sha512-1y0yD3upKcyzNwwA6loAGW2cRDqExwl4oAT7GJQA4tmabI+fNwmANSgU/ezLvvSUf4Qo0eJHg2Zcn8y+Apq2eA==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-backgrounds@8.3.3': - resolution: {integrity: sha512-aX0OIrtjIB7UgSaiv20SFkfC1iWwJIGMPsPSJ5ZPhXIIOWIEBtSujh8YXwjDEXSC4DOHalmeT4bitRRe5KrVKA==} + '@storybook/addon-backgrounds@8.3.4': + resolution: {integrity: sha512-o3nl7cN3x8erJNxLEv8YptanEQAnbqnaseOAsvSC6/nnSAcRYBSs3BvekKvo4CcpS2mxn7F5NJTBFYnCXzy8EA==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-controls@8.3.3': - resolution: {integrity: sha512-78xRtVpY7eX/Lti00JLgwYCBRB6ZcvzY3SWk0uQjEqcTnQGoQkVg2L7oWFDlDoA1LBY18P5ei2vu8MYT9GXU4g==} + '@storybook/addon-controls@8.3.4': + resolution: {integrity: sha512-qQcaK6dczsb6wXkzGZKOjUYNA7FfKBewRv6NvoVKYY6LfhllGOkmUAtYpdtQG8adsZWTSoZaAOJS2vP2uM67lw==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-docs@8.3.3': - resolution: {integrity: sha512-REUandqq1RnMNOhsocRwx5q2fdlBAYPTDFlKASYfEn4Ln5NgbQRGxOAWl7yXAAFzbDmUDU7K20hkauecF0tyMw==} + '@storybook/addon-docs@8.3.4': + resolution: {integrity: sha512-TWauhqF/gJgfwPuWeM6KM3LwC+ErCOM+K2z16w3vgao9s67sij8lnrdAoQ0hjA+kw2/KAdCakFS6FyciG81qog==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-essentials@8.3.3': - resolution: {integrity: sha512-E/uXoUYcg8ulG3lVbsEKb4v5hnMeGkq9YJqiZYKgVK7iRFa6p4HeVB1wU1adnm7RgjWvh+p0vQRo4KL2CTNXqw==} + '@storybook/addon-essentials@8.3.4': + resolution: {integrity: sha512-C3+3hpmSn/8zdx5sXEP0eE6zMzxgRosHVZYfe9nBcMiEDp6UKVUyHVetWxEULOEgN46ysjcpllZ0bUkRYxi2IQ==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-highlight@8.3.3': - resolution: {integrity: sha512-MB084xJM66rLU+iFFk34kjLUiAWzDiy6Kz4uZRa1CnNqEK0sdI8HaoQGgOxTIa2xgJor05/8/mlYlMkP/0INsQ==} + '@storybook/addon-highlight@8.3.4': + resolution: {integrity: sha512-rxZTeuZyZ7RnU+xmRhS01COFLbGnVEmlUNxBw8ArsrTEZKW5PbKpIxNLTj9F0zdH8H0MfryJGP+Aadcm0oHWlw==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-interactions@8.3.3': - resolution: {integrity: sha512-3w5tpCGYdF33wF44xEhTS3Zmcwd6nITtwy5q+PJvHCJAm3fpjzL3xrjtlHKDvXNwYacJPRCbWKn2QwtxZIdN0g==} + '@storybook/addon-interactions@8.3.4': + resolution: {integrity: sha512-ORxqe35wUmF7EDHo45mdDHiju3Ryk2pZ1vO9PyvW6ZItNlHt/IxAr7T/TysGejZ/eTBg6tMZR3ExGky3lTg/CQ==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-links@8.3.3': - resolution: {integrity: sha512-rz4KEbzr1ca4zZEZwbOnhKiaEsokCl1KkngxT/C1YIkpW908j/kg2nnIb5MrtlAW1nirXguAR74t6CGntvdU9w==} + '@storybook/addon-links@8.3.4': + resolution: {integrity: sha512-R1DjARmxRIKJDGIG6uxmQ1yFNyoQbb+QIPUFjgWCak8+AdLJbC7W+Esvo9F5hQfh6czyy0piiM3qj5hpQJVh3A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.3.3 + storybook: ^8.3.4 peerDependenciesMeta: react: optional: true - '@storybook/addon-mdx-gfm@8.3.3': - resolution: {integrity: sha512-jdwVXoBSEdmuw8L4MxUeJ/qIInADfCwdtShnfTQIJBBRucOl8ykgfTKKNjllT79TFiK0gsWoiZmE05P4wuBofw==} + '@storybook/addon-mdx-gfm@8.3.4': + resolution: {integrity: sha512-O0sMP7VFo1fKsdViY+W6OMNYEXvB5FzEEsqgsydMcsJ0qOKR1li2l3cLCMLXdUKVZ+2uRbEhnm2RnB9RWF5O7g==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-measure@8.3.3': - resolution: {integrity: sha512-R20Z83gnxDRrocES344dw1Of/zDhe3XHSM6TLq80UQTJ9PhnMI+wYHQlK9DsdP3KiRkI+pQA6GCOp0s2ZRy5dg==} + '@storybook/addon-measure@8.3.4': + resolution: {integrity: sha512-IJ6WKEbqmG+r7sukFjo+bVmPB2Zry04sylGx/OGyOh7zIhhqAqpwOwMHP0uQrc3tLNnUM6qB/o83UyYX79ql+A==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-outline@8.3.3': - resolution: {integrity: sha512-OwqYfieNuqSqWNtUZLu3UmsfQNnwA2UaSMBZyeC2Dte9Jd59PPYggcWmH+b0S6OTbYXWNAUK5U6WdK+X9Ypzdw==} + '@storybook/addon-outline@8.3.4': + resolution: {integrity: sha512-kRRJTTLKM8gMfeh/e83djN5XLlc0hFtr9zKWxuZxaXt9Hmr+9tH/PRFtVK/S4SgqnBDoXk49Wgv6raiwj5/e3A==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-storysource@8.3.3': - resolution: {integrity: sha512-yPYQH9NepSNxoSsV9E7OV3/EVFrbU/r2B3E5WP/mCfqTXPg/5noce7iRi+rWqcVM1tsN1qPnSjfQQc7noF0h0Q==} + '@storybook/addon-storysource@8.3.4': + resolution: {integrity: sha512-uHTUiK7dzWRZAKpPafBH3U5PWAP7+J97lg66HDKAHpmmQdy7v3HfXaYNX1FoI+PeC5piUxFETXM0z+BNvJCknA==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-toolbars@8.3.3': - resolution: {integrity: sha512-4WyiVqDm4hlJdENIVQg9pLNLdfhnNKa+haerYYSzTVjzYrUx0X6Bxafshq+sud6aRtSYU14abwP56lfW8hgTlA==} + '@storybook/addon-toolbars@8.3.4': + resolution: {integrity: sha512-Km1YciVIxqluDbd1xmHjANNFyMonEOtnA6e4MrnBnC9XkPXSigeFlj0JvxyI/zjBsLBoFRmQiwq55W6l3hQ9sA==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/addon-viewport@8.3.3': - resolution: {integrity: sha512-2S+UpbKAL+z1ppzUCkixjaem2UDMkfmm/kyJ1wm3A/ofGLYi4fjMSKNRckk+7NdolXGQJjBo0RcaotUTxFIFwQ==} + '@storybook/addon-viewport@8.3.4': + resolution: {integrity: sha512-fU4LdXSSqIOLbCEh2leq/tZUYlFliXZBWr/+igQHdUoU7HY8RIImXqVUaR9wlCaTb48WezAWT60vJtwNijyIiQ==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/blocks@8.3.3': - resolution: {integrity: sha512-8Vsvxqstop3xfbsx3Dn1nEjyxvQUcOYd8vpxyp2YumxYO8FlXIRuYL6HAkYbcX8JexsKvCZYxor52D2vUGIKZg==} + '@storybook/blocks@8.3.4': + resolution: {integrity: sha512-1g4aCrd5CcN+pVhF2ATu9ZRVvAIgBMb2yF9KkCuTpdvqKDuDNK3sGb0CxjS7jp3LOvyjJr9laTOQsz8v8MQc5A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.3.3 + storybook: ^8.3.4 peerDependenciesMeta: react: optional: true react-dom: optional: true - '@storybook/builder-vite@8.3.3': - resolution: {integrity: sha512-3yTXCLaB6bzhoPH3PqtacKkcaC1uV4L+IHTf1Zypx1NO1pLZHyhYf0T7dIOxTh2JZfqu1Pm9hTvOmWfR12m+9w==} + '@storybook/builder-vite@8.3.4': + resolution: {integrity: sha512-Sa6SZ7LeHpkrnuvua8P8MR8e8a+MPKbyMmr9TqCCy8Ud/t4AM4kHY3JpJGtrgeK9l43fBnBwfdZYoRl5J6oWeA==} peerDependencies: '@preact/preset-vite': '*' - storybook: ^8.3.3 + storybook: ^8.3.4 typescript: '>= 4.3.x' vite: ^4.0.0 || ^5.0.0 vite-plugin-glimmerx: '*' @@ -4091,23 +4103,23 @@ packages: vite-plugin-glimmerx: optional: true - '@storybook/components@8.3.3': - resolution: {integrity: sha512-i2JYtesFGkdu+Hwuj+o9fLuO3yo+LPT1/8o5xBVYtEqsgDtEAyuRUWjSz8d8NPtzloGPOv5kvR6MokWDfbeMfw==} + '@storybook/components@8.3.4': + resolution: {integrity: sha512-iQzLJd87uGbFBbYNqlrN/ABrnx3dUrL0tjPCarzglzshZoPCNOsllJeJx5TJwB9kCxSZ8zB9TTOgr7NXl+oyVA==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/core-events@8.3.3': - resolution: {integrity: sha512-YL+gBuCS81qktzTkvw0MXUJW0bYAXfRzMoiLfDBTrEKZfcJOB4JAlMGmvRRar0+jygK3icD42Rl5BwWoZY6KFQ==} + '@storybook/core-events@8.3.4': + resolution: {integrity: sha512-3/5oJN2UnlmUILXCh7SXMTa2MYZOvrjeZCm3wFomoQASU2FFzS5AxBYYnwNdtrZmn4w32uw4T7qvA0+96Utwsg==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/core@8.3.3': - resolution: {integrity: sha512-pmf2bP3fzh45e56gqOuBT8sDX05hGdUKIZ/hcI84d5xmd6MeHiPW8th2v946wCHcxHzxib2/UU9vQUh+mB4VNw==} + '@storybook/core@8.3.4': + resolution: {integrity: sha512-4PZB91JJpuKfcjeOR2LXj3ABaPLLSd2P/SfYOKNCygrDstsQa/yay3/yN5Z9yi1cIG84KRr6/sUW+0x8HsGLPg==} - '@storybook/csf-plugin@8.3.3': - resolution: {integrity: sha512-7AD7ojpXr3THqpTcEI4K7oKUfSwt1hummgL/cASuQvEPOwAZCVZl2gpGtKxcXhtJXTkn3GMCAvlYMoe7O/1YWw==} + '@storybook/csf-plugin@8.3.4': + resolution: {integrity: sha512-ZMFWYxeTN4GxCn8dyIH4roECyLDy29yv/QKM+pHM3AC5Ny2HWI35SohWao4fGBAFxPQFbR5hPN8xa6ofHPSSTg==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 '@storybook/csf@0.1.11': resolution: {integrity: sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==} @@ -4122,45 +4134,45 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/instrumenter@8.3.3': - resolution: {integrity: sha512-ZiODB9EwCQkl4PBxGJjBHXRTLxcNs68ZZvR+xeMr0eMFzzlJG+trXoX5kK95oA4BFhGN+3uM0Zl3MoRjBtJTNA==} + '@storybook/instrumenter@8.3.4': + resolution: {integrity: sha512-jVhfNOPekOyJmta0BTkQl9Z6rgRbFHlc0eV4z1oSrzaawSlc9TFzAeDCtCP57vg3FuBX8ydDYAvyZ7s4xPpLyg==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/manager-api@8.3.3': - resolution: {integrity: sha512-Na4U+McOeVUJAR6qzJfQ6y2Qt0kUgEDUriNoAn+curpoKPTmIaZ79RAXBzIqBl31VyQKknKpZbozoRGf861YaQ==} + '@storybook/manager-api@8.3.4': + resolution: {integrity: sha512-tBx7MBfPUrKSlD666zmVjtIvoNArwCciZiW/UJ8IWmomrTJRfFBnVvPVM2gp1lkDIzRHYmz5x9BHbYaEDNcZWQ==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/preview-api@8.3.3': - resolution: {integrity: sha512-GP2QlaF3BBQGAyo248N7549YkTQjCentsc1hUvqPnFWU4xfjkejbnFk8yLaIw0VbYbL7jfd7npBtjZ+6AnphMQ==} + '@storybook/preview-api@8.3.4': + resolution: {integrity: sha512-/YKQ3QDVSHmtFXXCShf5w0XMlg8wkfTpdYxdGv1CKFV8DU24f3N7KWulAgeWWCWQwBzZClDa9kzxmroKlQqx3A==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/react-dom-shim@8.3.3': - resolution: {integrity: sha512-0dPC9K7+K5+X/bt3GwYmh+pCpisUyKVjWsI+PkzqGnWqaXFakzFakjswowIAIO1rf7wYZR591x3ehUAyL2bJiQ==} + '@storybook/react-dom-shim@8.3.4': + resolution: {integrity: sha512-L4llDvjaAzqPx6h4ddZMh36wPr75PrI2S8bXy+flLqAeVRYnRt4WNKGuxqH0t0U6MwId9+vlCZ13JBfFuY7eQQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/react-vite@8.3.3': - resolution: {integrity: sha512-vzOqVaA/rv+X5J17eWKxdZztMKEKfsCSP8pNNmrqXWxK3pSlW0fAPxtn1kw3UNxGtAv71pcqvaCUtTJKqI1PYA==} + '@storybook/react-vite@8.3.4': + resolution: {integrity: sha512-0Xm8eTH+jQ7SV4moLkPN4G6U2IDrqXPXUqsZdXaccepIMcD4G75foQFm2LOrFJuY+IMySPspKeTqf8OLskPppw==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.3.3 + storybook: ^8.3.4 vite: ^4.0.0 || ^5.0.0 - '@storybook/react@8.3.3': - resolution: {integrity: sha512-fHOW/mNqI+sZWttGOE32Q+rAIbN7/Oib091cmE8usOM0z0vPNpywUBtqC2cCQH39vp19bhTsQaSsTcoBSweAHw==} + '@storybook/react@8.3.4': + resolution: {integrity: sha512-PA7iQL4/9X2/iLrv+AUPNtlhTHJWhDao9gQIT1Hef39FtFk+TU9lZGbv+g29R1H9V3cHP5162nG2aTu395kmbA==} engines: {node: '>=18.0.0'} peerDependencies: - '@storybook/test': 8.3.3 + '@storybook/test': 8.3.4 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.3.3 + storybook: ^8.3.4 typescript: '>= 4.2.x' peerDependenciesMeta: '@storybook/test': @@ -4168,38 +4180,38 @@ packages: typescript: optional: true - '@storybook/source-loader@8.3.3': - resolution: {integrity: sha512-NeP7l53mvnnfwi+91vtRaibZer+UJi6gkoaGRCpphL3L+3qVIXN3p41uXhAy+TahdFI2dbrWvLSNgtsvdXVaFg==} + '@storybook/source-loader@8.3.4': + resolution: {integrity: sha512-wH//LuWfa2iOmjykSqsub8M8e0EdhEUZoHUFhwBeizfYQQHaMaSEBhhAQCaWWKmdGB9lnCe1cioQ32c2IWtBIw==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/test@8.3.3': - resolution: {integrity: sha512-uZ8nMIovfI2ry989K2+cYAeEVD/3dpjj2+Rbmy7DiZWWVhFALfmqaTRkzZfShLmlH0TFv+rfcBPihGccBtw0FQ==} + '@storybook/test@8.3.4': + resolution: {integrity: sha512-HRiUenitln8QPHu6DEWUg9s9cEoiGN79lMykzXzw9shaUvdEIhWCsh82YKtmB3GJPj6qcc6dZL/Aio8srxyGAg==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/theming@8.3.3': - resolution: {integrity: sha512-gWJKetI6XJQgkrvvry4ez10+jLaGNCQKi5ygRPM9N+qrjA3BB8F2LCuFUTBuisa4l64TILDNjfwP/YTWV5+u5A==} + '@storybook/theming@8.3.4': + resolution: {integrity: sha512-D4XVsQgTtpHEHLhwkx59aGy1GBwOedVr/mNns7hFrH8FjEpxrrWCuZQASq1ZpCl8LXlh7uvmT5sM2rOdQbGuGg==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/types@8.3.3': - resolution: {integrity: sha512-wV1kupG1tfTMOXaBrtVHXuqp19vURVDqWTQX6nqkoUFD7Xb1lz/YNVeGP1uT/zJdJy42/HIyoib9JPx9h0Vx9w==} + '@storybook/types@8.3.4': + resolution: {integrity: sha512-kIyb0g8C6EizI0Mv+l6L6yjCJe9/vW3UvgsZL5BXqs8THTAfs3/+A9Q9jDEMovSIVI3EgesO79+OCEazDUHmOA==} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 - '@storybook/vue3-vite@8.3.3': - resolution: {integrity: sha512-IFcoOGlUGuUkL3rpm9UFs8FK9JX1ZdfGpLXRObVOVRhW3t+MsNLpx4Fqp3a/re6WcCC3yvHzbLXgvGcjpapkbw==} + '@storybook/vue3-vite@8.3.4': + resolution: {integrity: sha512-0H1tLbRd8i6L3EW8QC9bDlgPIUM5i6b7onvyyQhyIxODWRfigHi6UP9sjHfrljdvnlOtYlZT2A5QbpkugzwLjg==} engines: {node: '>=18.0.0'} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 vite: ^4.0.0 || ^5.0.0 - '@storybook/vue3@8.3.3': - resolution: {integrity: sha512-peu8MFGwmhpXoD3n42qG6TxeVHRhfHZ0/HW4+A6FXSB1c9w0CC4AzHs5f1w3yUvshtexNN5bkw9Q4nSVKtfU7A==} + '@storybook/vue3@8.3.4': + resolution: {integrity: sha512-NNQXwidr+QjLndORWtPjXv/obsNNfJhP5Xj6vUZslrDpdIyTL3NEM+ktLK2EMw/a3zUbJMnMkyMgoWvioCNHxQ==} engines: {node: '>=18.0.0'} peerDependencies: - storybook: ^8.3.3 + storybook: ^8.3.4 vue: ^3.0.0 '@swc/cli@0.3.12': @@ -4579,8 +4591,11 @@ packages: '@types/cacheable-request@6.0.3': resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - '@types/color-convert@2.0.3': - resolution: {integrity: sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==} + '@types/canvas-confetti@1.6.4': + resolution: {integrity: sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==} + + '@types/color-convert@2.0.4': + resolution: {integrity: sha512-Ub1MmDdyZ7mX//g25uBAoH/mWGd9swVbt8BseymnaE18SU4po/PjmCrHxqIIRjBo3hV/vh1KGr0eMxUhp+t+dQ==} '@types/color-name@1.1.1': resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==} @@ -5094,8 +5109,8 @@ packages: '@vue/compiler-core@3.5.10': resolution: {integrity: sha512-iXWlk+Cg/ag7gLvY0SfVucU8Kh2CjysYZjhhP70w9qI4MvSox4frrP+vDGvtQuzIcgD8+sxM6lZvCtdxGunTAA==} - '@vue/compiler-core@3.5.7': - resolution: {integrity: sha512-A0gay3lK71MddsSnGlBxRPOugIVdACze9L/rCo5X5srCyjQfZOfYtSFMJc3aOZCM+xN55EQpb4R97rYn/iEbSw==} + '@vue/compiler-core@3.5.11': + resolution: {integrity: sha512-PwAdxs7/9Hc3ieBO12tXzmTD+Ln4qhT/56S+8DvrrZ4kLDn4Z/AMUr8tXJD0axiJBS0RKIoNaR0yMuQB9v9Udg==} '@vue/compiler-dom@3.4.37': resolution: {integrity: sha512-rIiSmL3YrntvgYV84rekAtU/xfogMUJIclUMeIKEtVBFngOL3IeZHhsH3UaFEgB5iFGpj6IW+8YuM/2Up+vVag==} @@ -5103,20 +5118,20 @@ packages: '@vue/compiler-dom@3.5.10': resolution: {integrity: sha512-DyxHC6qPcktwYGKOIy3XqnHRrrXyWR2u91AjP+nLkADko380srsC2DC3s7Y1Rk6YfOlxOlvEQKa9XXmLI+W4ZA==} - '@vue/compiler-dom@3.5.7': - resolution: {integrity: sha512-GYWl3+gO8/g0ZdYaJ18fYHdI/WVic2VuuUd1NsPp60DWXKy+XjdhFsDW7FbUto8siYYZcosBGn9yVBkjhq1M8Q==} + '@vue/compiler-dom@3.5.11': + resolution: {integrity: sha512-pyGf8zdbDDRkBrEzf8p7BQlMKNNF5Fk/Cf/fQ6PiUz9at4OaUfyXW0dGJTo2Vl1f5U9jSLCNf0EZJEogLXoeew==} '@vue/compiler-sfc@3.4.37': resolution: {integrity: sha512-vCfetdas40Wk9aK/WWf8XcVESffsbNkBQwS5t13Y/PcfqKfIwJX2gF+82th6dOpnpbptNMlMjAny80li7TaCIg==} - '@vue/compiler-sfc@3.5.10': - resolution: {integrity: sha512-to8E1BgpakV7224ZCm8gz1ZRSyjNCAWEplwFMWKlzCdP9DkMKhRRwt0WkCjY7jkzi/Vz3xgbpeig5Pnbly4Tow==} + '@vue/compiler-sfc@3.5.11': + resolution: {integrity: sha512-gsbBtT4N9ANXXepprle+X9YLg2htQk1sqH/qGJ/EApl+dgpUBdTv3yP7YlR535uHZY3n6XaR0/bKo0BgwwDniw==} '@vue/compiler-ssr@3.4.37': resolution: {integrity: sha512-TyAgYBWrHlFrt4qpdACh8e9Ms6C/AZQ6A6xLJaWrCL8GCX5DxMzxyeFAEMfU/VFr4tylHm+a2NpfJpcd7+20XA==} - '@vue/compiler-ssr@3.5.10': - resolution: {integrity: sha512-hxP4Y3KImqdtyUKXDRSxKSRkSm1H9fCvhojEYrnaoWhE4w/y8vwWhnosJoPPe2AXm5sU7CSbYYAgkt2ZPhDz+A==} + '@vue/compiler-ssr@3.5.11': + resolution: {integrity: sha512-P4+GPjOuC2aFTk1Z4WANvEhyOykcvEd5bIj2KVNGKGfM745LaXGr++5njpdBTzVz5pZifdlR1kpYSJJpIlSePA==} '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} @@ -5140,30 +5155,30 @@ packages: '@vue/reactivity@3.4.37': resolution: {integrity: sha512-UmdKXGx0BZ5kkxPqQr3PK3tElz6adTey4307NzZ3whZu19i5VavYal7u2FfOmAzlcDVgE8+X0HZ2LxLb/jgbYw==} - '@vue/reactivity@3.5.10': - resolution: {integrity: sha512-kW08v06F6xPSHhid9DJ9YjOGmwNDOsJJQk0ax21wKaUYzzuJGEuoKNU2Ujux8FLMrP7CFJJKsHhXN9l2WOVi2g==} + '@vue/reactivity@3.5.11': + resolution: {integrity: sha512-Nqo5VZEn8MJWlCce8XoyVqHZbd5P2NH+yuAaFzuNSR96I+y1cnuUiq7xfSG+kyvLSiWmaHTKP1r3OZY4mMD50w==} '@vue/runtime-core@3.4.37': resolution: {integrity: sha512-MNjrVoLV/sirHZoD7QAilU1Ifs7m/KJv4/84QVbE6nyAZGQNVOa1HGxaOzp9YqCG+GpLt1hNDC4RbH+KtanV7w==} - '@vue/runtime-core@3.5.10': - resolution: {integrity: sha512-9Q86I5Qq3swSkFfzrZ+iqEy7Vla325M7S7xc1NwKnRm/qoi1Dauz0rT6mTMmscqx4qz0EDJ1wjB+A36k7rl8mA==} + '@vue/runtime-core@3.5.11': + resolution: {integrity: sha512-7PsxFGqwfDhfhh0OcDWBG1DaIQIVOLgkwA5q6MtkPiDFjp5gohVnJEahSktwSFLq7R5PtxDKy6WKURVN1UDbzA==} '@vue/runtime-dom@3.4.37': resolution: {integrity: sha512-Mg2EwgGZqtwKrqdL/FKMF2NEaOHuH+Ks9TQn3DHKyX//hQTYOun+7Tqp1eo0P4Ds+SjltZshOSRq6VsU0baaNg==} - '@vue/runtime-dom@3.5.10': - resolution: {integrity: sha512-t3x7ht5qF8ZRi1H4fZqFzyY2j+GTMTDxRheT+i8M9Ph0oepUxoadmbwlFwMoW7RYCpNQLpP2Yx3feKs+fyBdpA==} + '@vue/runtime-dom@3.5.11': + resolution: {integrity: sha512-GNghjecT6IrGf0UhuYmpgaOlN7kxzQBhxWEn08c/SQDxv1yy4IXI1bn81JgEpQ4IXjRxWtPyI8x0/7TF5rPfYQ==} '@vue/server-renderer@3.4.37': resolution: {integrity: sha512-jZ5FAHDR2KBq2FsRUJW6GKDOAG9lUTX8aBEGq4Vf6B/35I9fPce66BornuwmqmKgfiSlecwuOb6oeoamYMohkg==} peerDependencies: vue: 3.4.37 - '@vue/server-renderer@3.5.10': - resolution: {integrity: sha512-IVE97tt2kGKwHNq9yVO0xdh1IvYfZCShvDSy46JIh5OQxP1/EXSpoDqetVmyIzL7CYOWnnmMkVqd7YK2QSWkdw==} + '@vue/server-renderer@3.5.11': + resolution: {integrity: sha512-cVOwYBxR7Wb1B1FoxYvtjJD8X/9E5nlH4VSkJy2uMA1MzYNdzAAB//l8nrmN9py/4aP+3NjWukf9PZ3TeWULaA==} peerDependencies: - vue: 3.5.10 + vue: 3.5.11 '@vue/shared@3.4.37': resolution: {integrity: sha512-nIh8P2fc3DflG8+5Uw8PT/1i17ccFn0xxN/5oE9RfV5SVnd7G0XEFRwakrnNFE/jlS95fpGXDVG5zDETS26nmg==} @@ -5171,8 +5186,8 @@ packages: '@vue/shared@3.5.10': resolution: {integrity: sha512-VkkBhU97Ki+XJ0xvl4C9YJsIZ2uIlQ7HqPpZOS3m9VCvmROPaChZU6DexdMJqvz9tbgG+4EtFVrSuailUq5KGQ==} - '@vue/shared@3.5.7': - resolution: {integrity: sha512-NBE1PBIvzIedxIc2RZiKXvGbJkrZ2/hLf3h8GlS4/sP9xcXEZMFWOazFkNd6aGeUCMaproe5MHVYB3/4AW9q9g==} + '@vue/shared@3.5.11': + resolution: {integrity: sha512-W8GgysJVnFo81FthhzurdRAWP/byq3q2qIw70e0JWblzVhjgOMiC2GyovXrZTFQJnFVryYaKGP3Tc9vYzYm6PQ==} '@vue/test-utils@2.4.1': resolution: {integrity: sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==} @@ -5580,10 +5595,6 @@ packages: bn.js@4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - body-parser@1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -5657,8 +5668,8 @@ packages: resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} engines: {node: '>=6.14.2'} - bullmq@5.13.2: - resolution: {integrity: sha512-McGE8k3mrCvdUHdU0sHkTKDS1xr4pff+hbEKBY51wk5S6Za0gkuejYA620VQTo3Zz37E/NVWMgumwiXPQ3yZcA==} + bullmq@5.15.0: + resolution: {integrity: sha512-h53shVjx8s6wxYGtUfzAfENpSP7N5T0D4PMTvbZncozLjb8yUKhopfpa7PmcpQfq7SSO9dm/OZ9XQuGOCSGNug==} buraha@0.0.1: resolution: {integrity: sha512-G563A0mTbzknm2jDaNxfZuNKIdeArs8T+XQN6t+KbmgnOoevXSXhKDkyf8Md/36Jrx99ikwbCag37VGe3myExQ==} @@ -5786,6 +5797,12 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} @@ -5850,8 +5867,8 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - chromatic@11.10.4: - resolution: {integrity: sha512-nfgDpW5gQ4FtgV1lZXXfqLjONKDCh2K4vwI3dbZrtU1ObOL9THyAzpIdnK9LRcNSeisDLX+XFCryfMg1Ql2U2g==} + chromatic@11.11.0: + resolution: {integrity: sha512-mwmYsNMsZlRLtlfFUEtac5zhoVRhc+O/lsuMdOpwkiDQiKX6WdSNIhic+dkLenfuzao2r18s50nphcOgFoatBg==} hasBin: true peerDependencies: '@chromatic-com/cypress': ^0.*.* || ^1.0.0 @@ -5964,6 +5981,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -6667,6 +6687,27 @@ packages: eslint-import-resolver-webpack: optional: true + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + eslint-plugin-import@2.30.0: resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} engines: {node: '>=4'} @@ -6677,6 +6718,16 @@ packages: '@typescript-eslint/parser': optional: true + eslint-plugin-import@2.31.0: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint-plugin-vue@9.27.0: resolution: {integrity: sha512-5Dw3yxEyuBSXTzT5/Ge1X5kIkRTQ3nvBn/VwPwInNiZBSJOO/timWMUaflONnFBzU6NhB68lxnCda7ULV5N7LA==} engines: {node: ^14.17.0 || >=16.0.0} @@ -6821,10 +6872,6 @@ packages: exponential-backoff@3.1.1: resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} - express@4.19.2: - resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} - engines: {node: '>= 0.10.0'} - express@4.21.0: resolution: {integrity: sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==} engines: {node: '>= 0.10.0'} @@ -6967,10 +7014,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.2.0: - resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} - engines: {node: '>= 0.8'} - finalhandler@1.3.1: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} @@ -7372,9 +7415,15 @@ packages: hast-util-is-element@3.0.0: resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + hast-util-to-html@9.0.3: + resolution: {integrity: sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==} + hast-util-to-string@3.0.0: resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==} + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -7414,6 +7463,9 @@ packages: resolution: {integrity: sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==} engines: {node: '>=8'} + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + htmlescape@1.1.1: resolution: {integrity: sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==} engines: {node: '>=0.10'} @@ -8437,6 +8489,9 @@ packages: mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + mdast-util-to-markdown@2.1.0: resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==} @@ -8466,9 +8521,6 @@ packages: resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==} engines: {node: '>=10'} - merge-descriptors@1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} - merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -9088,6 +9140,9 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + oniguruma-to-js@0.4.3: + resolution: {integrity: sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==} + open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -9119,8 +9174,8 @@ packages: ospath@1.2.2: resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} - otpauth@9.3.2: - resolution: {integrity: sha512-KixtXWN9RGdS8WHPfDo7qsOYiivCbl+VeLBT+7HBTtJebBO6aXr/bpZXr+TwY2COecdY82VeBghm31mLYQVZlQ==} + otpauth@9.3.4: + resolution: {integrity: sha512-qXv+lpsCUO9ewitLYfeDKbLYt7UUCivnU/fwGK2OqhgrCBsRkTUNKWsgKAhkXG3aistOY+jEeuL90JEBu6W3mQ==} outvariant@1.4.2: resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==} @@ -9260,9 +9315,6 @@ packages: path-to-regexp@0.1.10: resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} - path-to-regexp@0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - path-to-regexp@1.8.0: resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==} @@ -9600,10 +9652,6 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.40: - resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.4.47: resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} @@ -9719,6 +9767,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-information@6.5.0: + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -9811,10 +9862,6 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - qs@6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} - engines: {node: '>=0.6'} - qs@6.13.0: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} @@ -9986,6 +10033,9 @@ packages: regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + regex@4.3.3: + resolution: {integrity: sha512-r/AadFO7owAq1QJVeZ/nq9jNS1vyZt+6t1p/E59B56Rn2GCya+gr1KSyOzNL/er+r+B7phv5jG2xU2Nz1YkmJg==} + regexp.prototype.flags@1.5.0: resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} engines: {node: '>= 0.4'} @@ -10154,14 +10204,19 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sanitize-html@2.13.0: - resolution: {integrity: sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==} + sanitize-html@2.13.1: + resolution: {integrity: sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg==} sass@1.79.3: resolution: {integrity: sha512-m7dZxh0W9EZ3cw50Me5GOuYm/tVAJAn91SUnohLRo9cXBixGUOdvmryN+dXpwR831bhoY3Zv7rEFt85PUwTmzA==} engines: {node: '>=14.0.0'} hasBin: true + sass@1.79.4: + resolution: {integrity: sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==} + engines: {node: '>=14.0.0'} + hasBin: true + sax@1.2.4: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} @@ -10212,18 +10267,10 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.18.0: - resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} - engines: {node: '>= 0.8.0'} - send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} - serve-static@1.15.0: - resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} - engines: {node: '>= 0.8.0'} - serve-static@1.16.2: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} @@ -10272,8 +10319,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@1.12.0: - resolution: {integrity: sha512-BuAxWOm5JhRcbSOl7XCei8wGjgJJonnV0oipUupPY58iULxUGyHhW5CF+9FRMuM1pcJ5cGEJGll1LusX6FwpPA==} + shiki@1.21.0: + resolution: {integrity: sha512-apCH5BoWTrmHDPGgg3RF8+HAAbEL/CdbYr8rMw7eIrdhCkZHdVGat5mMNlRtd1erNG01VPMIKHNQ0Pj2HMAiog==} shimmer@1.2.1: resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} @@ -10542,8 +10589,8 @@ packages: react-dom: optional: true - storybook@8.3.3: - resolution: {integrity: sha512-FG2KAVQN54T9R6voudiEftehtkXtLO+YVGP2gBPfacEdDQjY++ld7kTbHzpTT/bpCDx7Yq3dqOegLm9arVJfYw==} + storybook@8.3.4: + resolution: {integrity: sha512-nzvuK5TsEgJwcWGLGgafabBOxKn37lfJVv7ZoUVPgJIjk2mNRyJDFwYRJzUZaD37eiR/c/lQ6MoaeqlGwiXoxw==} hasBin: true stream-browserify@3.0.0: @@ -10614,6 +10661,9 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + stringz@2.1.0: resolution: {integrity: sha512-KlywLT+MZ+v0IRepfMxRtnSvDCMc3nR1qqCs3m/qIbSOWkNZYT8XHQA31rS3TnKp0c5xjZu3M4GY/2aRKSi/6A==} @@ -10866,6 +10916,9 @@ packages: trace-redirect@1.0.6: resolution: {integrity: sha512-UUfa1DjjU5flcjMdaFIiIEGDTyu2y/IiMjOX4uGXa7meKBS4vD4f2Uy/tken9Qkd4Jsm4sRsfZcIIPqrRVF3Mg==} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} @@ -11146,6 +11199,9 @@ packages: unist-util-is@6.0.0: resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} @@ -11421,8 +11477,8 @@ packages: typescript: optional: true - vue@3.5.10: - resolution: {integrity: sha512-Vy2kmJwHPlouC/tSnIgXVg03SG+9wSqT1xu1Vehc+ChsXsRd7jLkKgMltVEFOzUdBr3uFwBCG+41LJtfAcBRng==} + vue@3.5.11: + resolution: {integrity: sha512-/8Wurrd9J3lb72FTQS7gRMNQD4nztTtKPmuDuPuhqXmmpD6+skVjAeahNpVzsuky6Sy9gy7wn8UadqPtt9SQIg==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -11693,13 +11749,13 @@ snapshots: dependencies: '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.609.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-crypto/crc32c@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.609.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-crypto/sha1-browser@5.2.0': dependencies: @@ -11708,7 +11764,7 @@ snapshots: '@aws-sdk/types': 3.609.0 '@aws-sdk/util-locate-window': 3.208.0 '@smithy/util-utf8': 2.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-crypto/sha256-browser@5.2.0': dependencies: @@ -11718,23 +11774,23 @@ snapshots: '@aws-sdk/types': 3.609.0 '@aws-sdk/util-locate-window': 3.208.0 '@smithy/util-utf8': 2.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-crypto/sha256-js@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.609.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-crypto/supports-web-crypto@5.2.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@aws-crypto/util@5.2.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/util-utf8': 2.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/client-s3@3.620.0': dependencies: @@ -11840,7 +11896,7 @@ snapshots: '@smithy/util-middleware': 3.0.3 '@smithy/util-retry': 3.0.3 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -11883,7 +11939,7 @@ snapshots: '@smithy/util-middleware': 3.0.3 '@smithy/util-retry': 3.0.3 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -11928,7 +11984,7 @@ snapshots: '@smithy/util-middleware': 3.0.3 '@smithy/util-retry': 3.0.3 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -11940,14 +11996,14 @@ snapshots: '@smithy/smithy-client': 3.1.11 '@smithy/types': 3.3.0 fast-xml-parser: 4.2.5 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/credential-provider-env@3.609.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/property-provider': 3.1.3 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/credential-provider-http@3.620.0': dependencies: @@ -11959,7 +12015,7 @@ snapshots: '@smithy/smithy-client': 3.1.11 '@smithy/types': 3.3.0 '@smithy/util-stream': 3.1.3 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/credential-provider-ini@3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))(@aws-sdk/client-sts@3.620.0)': dependencies: @@ -11974,7 +12030,7 @@ snapshots: '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -11992,7 +12048,7 @@ snapshots: '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - '@aws-sdk/client-sts' @@ -12004,7 +12060,7 @@ snapshots: '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/credential-provider-sso@3.620.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))': dependencies: @@ -12014,7 +12070,7 @@ snapshots: '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -12025,7 +12081,7 @@ snapshots: '@aws-sdk/types': 3.609.0 '@smithy/property-provider': 3.1.3 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/lib-storage@3.620.0(@aws-sdk/client-s3@3.620.0)': dependencies: @@ -12046,14 +12102,14 @@ snapshots: '@smithy/protocol-http': 4.1.0 '@smithy/types': 3.3.0 '@smithy/util-config-provider': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-expect-continue@3.620.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/protocol-http': 4.1.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-flexible-checksums@3.620.0': dependencies: @@ -12064,33 +12120,33 @@ snapshots: '@smithy/protocol-http': 4.1.0 '@smithy/types': 3.3.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-host-header@3.620.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/protocol-http': 4.1.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-location-constraint@3.609.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-logger@3.609.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-recursion-detection@3.620.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/protocol-http': 4.1.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-sdk-s3@3.620.0': dependencies: @@ -12104,7 +12160,7 @@ snapshots: '@smithy/util-config-provider': 3.0.0 '@smithy/util-stream': 3.1.3 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-signing@3.620.0': dependencies: @@ -12114,13 +12170,13 @@ snapshots: '@smithy/signature-v4': 4.1.0 '@smithy/types': 3.3.0 '@smithy/util-middleware': 3.0.3 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-ssec@3.609.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/middleware-user-agent@3.620.0': dependencies: @@ -12128,7 +12184,7 @@ snapshots: '@aws-sdk/util-endpoints': 3.614.0 '@smithy/protocol-http': 4.1.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/region-config-resolver@3.614.0': dependencies: @@ -12137,7 +12193,7 @@ snapshots: '@smithy/types': 3.3.0 '@smithy/util-config-provider': 3.0.0 '@smithy/util-middleware': 3.0.3 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/signature-v4-multi-region@3.620.0': dependencies: @@ -12146,7 +12202,7 @@ snapshots: '@smithy/protocol-http': 4.1.0 '@smithy/signature-v4': 4.1.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/token-providers@3.614.0(@aws-sdk/client-sso-oidc@3.620.0(@aws-sdk/client-sts@3.620.0))': dependencies: @@ -12155,46 +12211,46 @@ snapshots: '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/types@3.609.0': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/util-arn-parser@3.568.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/util-endpoints@3.614.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/types': 3.3.0 '@smithy/util-endpoints': 2.0.5 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/util-locate-window@3.208.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/util-user-agent-browser@3.609.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/types': 3.3.0 bowser: 2.11.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/util-user-agent-node@3.614.0': dependencies: '@aws-sdk/types': 3.609.0 '@smithy/node-config-provider': 3.1.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@aws-sdk/xml-builder@3.609.0': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@babel/code-frame@7.23.5': dependencies: @@ -12223,7 +12279,7 @@ snapshots: '@babel/traverse': 7.23.5 '@babel/types': 7.24.7 convert-source-map: 2.0.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -12243,7 +12299,7 @@ snapshots: '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 convert-source-map: 2.0.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -12477,7 +12533,7 @@ snapshots: '@babel/template@7.22.15': dependencies: '@babel/code-frame': 7.24.7 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.6 '@babel/types': 7.24.7 '@babel/template@7.24.0': @@ -12489,7 +12545,7 @@ snapshots: '@babel/template@7.24.7': dependencies: '@babel/code-frame': 7.24.7 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.6 '@babel/types': 7.24.7 '@babel/traverse@7.23.5': @@ -12500,9 +12556,9 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.6 '@babel/types': 7.24.7 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -12515,9 +12571,9 @@ snapshots: '@babel/helper-function-name': 7.24.7 '@babel/helper-hoist-variables': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.6 '@babel/types': 7.24.7 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -12684,7 +12740,7 @@ snapshots: '@emnapi/runtime@1.2.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 optional: true '@esbuild/aix-ppc64@0.19.11': @@ -13093,7 +13149,7 @@ snapshots: '@fastify/accept-negotiator@2.0.0': {} - '@fastify/accepts@5.0.0': + '@fastify/accepts@5.0.1': dependencies: accepts: 1.3.8 fastify-plugin: 5.0.0 @@ -13108,12 +13164,12 @@ snapshots: '@fastify/busboy@3.0.0': {} - '@fastify/cookie@10.0.0': + '@fastify/cookie@10.0.1': dependencies: cookie-signature: 1.2.1 fastify-plugin: 5.0.0 - '@fastify/cors@10.0.0': + '@fastify/cors@10.0.1': dependencies: fastify-plugin: 5.0.0 mnemonist: 0.39.8 @@ -13122,9 +13178,9 @@ snapshots: '@fastify/error@4.0.0': {} - '@fastify/express@4.0.0': + '@fastify/express@4.0.1': dependencies: - express: 4.19.2 + express: 4.21.0 fastify-plugin: 5.0.0 transitivePeerDependencies: - supports-color @@ -13147,7 +13203,7 @@ snapshots: dependencies: fast-deep-equal: 3.1.3 - '@fastify/multipart@9.0.0': + '@fastify/multipart@9.0.1': dependencies: '@fastify/busboy': 3.0.0 '@fastify/deepmerge': 2.0.0 @@ -13173,15 +13229,6 @@ snapshots: http-errors: 2.0.0 mime: 3.0.0 - '@fastify/static@8.0.0': - dependencies: - '@fastify/accept-negotiator': 2.0.0 - '@fastify/send': 3.1.1 - content-disposition: 0.5.4 - fastify-plugin: 5.0.0 - fastq: 1.17.1 - glob: 11.0.0 - '@fastify/static@8.0.1': dependencies: '@fastify/accept-negotiator': 2.0.0 @@ -13191,11 +13238,6 @@ snapshots: fastq: 1.17.1 glob: 11.0.0 - '@fastify/view@10.0.0': - dependencies: - fastify-plugin: 5.0.0 - toad-cache: 3.7.0 - '@fastify/view@10.0.1': dependencies: fastify-plugin: 5.0.0 @@ -13642,13 +13684,13 @@ snapshots: '@misskey-dev/browser-image-resizer@2024.1.0': {} - '@misskey-dev/eslint-plugin@2.0.3(@eslint/compat@1.1.1)(@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0)(typescript@5.6.2))(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0))(eslint@9.8.0)(globals@15.9.0)': + '@misskey-dev/eslint-plugin@2.0.3(@eslint/compat@1.1.1)(@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0)(typescript@5.6.2))(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0))(eslint@9.8.0)(globals@15.9.0)': dependencies: '@eslint/compat': 1.1.1 '@typescript-eslint/eslint-plugin': 7.17.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0)(typescript@5.6.2) '@typescript-eslint/parser': 7.17.0(eslint@9.8.0)(typescript@5.6.2) eslint: 9.8.0 - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0) globals: 15.9.0 '@misskey-dev/sharp-read-bmp@1.2.0': @@ -13754,7 +13796,7 @@ snapshots: '@napi-rs/canvas-linux-x64-musl': 0.1.56 '@napi-rs/canvas-win32-x64-msvc': 0.1.56 - '@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1)': + '@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1)': dependencies: iterare: 1.2.1 reflect-metadata: 0.2.2 @@ -13762,9 +13804,9 @@ snapshots: tslib: 2.7.0 uid: 2.0.2 - '@nestjs/core@10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + '@nestjs/core@10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)': dependencies: - '@nestjs/common': 10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2(encoding@0.1.13) fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -13774,14 +13816,14 @@ snapshots: tslib: 2.7.0 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.3) + '@nestjs/platform-express': 10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4) transitivePeerDependencies: - encoding - '@nestjs/platform-express@10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.3)': + '@nestjs/platform-express@10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)': dependencies: - '@nestjs/common': 10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) body-parser: 1.20.3 cors: 2.8.5 express: 4.21.0 @@ -13790,15 +13832,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/testing@10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.3))': + '@nestjs/testing@10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4))': dependencies: - '@nestjs/common': 10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) tslib: 2.7.0 optionalDependencies: - '@nestjs/platform-express': 10.4.3(@nestjs/common@10.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.3) + '@nestjs/platform-express': 10.4.4(@nestjs/common@10.4.4(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4) - '@noble/hashes@1.4.0': {} + '@noble/hashes@1.5.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -13824,7 +13866,7 @@ snapshots: '@npmcli/fs@3.1.0': dependencies: - semver: 7.6.0 + semver: 7.6.3 '@nsfw-filter/gif-frames@1.0.2': dependencies: @@ -14080,27 +14122,27 @@ snapshots: dependencies: '@peculiar/asn1-schema': 2.3.8 asn1js: 3.0.5 - tslib: 2.6.3 + tslib: 2.7.0 '@peculiar/asn1-ecc@2.3.8': dependencies: '@peculiar/asn1-schema': 2.3.8 '@peculiar/asn1-x509': 2.3.8 asn1js: 3.0.5 - tslib: 2.6.3 + tslib: 2.7.0 '@peculiar/asn1-rsa@2.3.8': dependencies: '@peculiar/asn1-schema': 2.3.8 '@peculiar/asn1-x509': 2.3.8 asn1js: 3.0.5 - tslib: 2.6.3 + tslib: 2.7.0 '@peculiar/asn1-schema@2.3.8': dependencies: asn1js: 3.0.5 pvtsutils: 1.3.5 - tslib: 2.6.3 + tslib: 2.7.0 '@peculiar/asn1-x509@2.3.8': dependencies: @@ -14108,7 +14150,7 @@ snapshots: asn1js: 3.0.5 ipaddr.js: 2.2.0 pvtsutils: 1.3.5 - tslib: 2.6.3 + tslib: 2.7.0 '@peertube/http-signature@1.7.0': dependencies: @@ -14334,9 +14376,32 @@ snapshots: dependencies: '@sentry/types': 8.20.0 - '@shikijs/core@1.12.0': + '@shikijs/core@1.21.0': dependencies: + '@shikijs/engine-javascript': 1.21.0 + '@shikijs/engine-oniguruma': 1.21.0 + '@shikijs/types': 1.21.0 + '@shikijs/vscode-textmate': 9.2.2 '@types/hast': 3.0.4 + hast-util-to-html: 9.0.3 + + '@shikijs/engine-javascript@1.21.0': + dependencies: + '@shikijs/types': 1.21.0 + '@shikijs/vscode-textmate': 9.2.2 + oniguruma-to-js: 0.4.3 + + '@shikijs/engine-oniguruma@1.21.0': + dependencies: + '@shikijs/types': 1.21.0 + '@shikijs/vscode-textmate': 9.2.2 + + '@shikijs/types@1.21.0': + dependencies: + '@shikijs/vscode-textmate': 9.2.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@9.2.2': {} '@sideway/address@4.1.4': dependencies: @@ -14403,21 +14468,21 @@ snapshots: '@smithy/abort-controller@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/abort-controller@3.1.1': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/chunked-blob-reader-native@3.0.0': dependencies: '@smithy/util-base64': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/chunked-blob-reader@3.0.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/config-resolver@3.0.5': dependencies: @@ -14425,7 +14490,7 @@ snapshots: '@smithy/types': 3.3.0 '@smithy/util-config-provider': 3.0.0 '@smithy/util-middleware': 3.0.3 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/core@2.3.1': dependencies: @@ -14436,7 +14501,7 @@ snapshots: '@smithy/smithy-client': 3.1.11 '@smithy/types': 3.3.0 '@smithy/util-middleware': 3.0.3 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/credential-provider-imds@3.2.0': dependencies: @@ -14444,37 +14509,37 @@ snapshots: '@smithy/property-provider': 3.1.3 '@smithy/types': 3.3.0 '@smithy/url-parser': 3.0.3 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/eventstream-codec@3.1.2': dependencies: '@aws-crypto/crc32': 5.2.0 '@smithy/types': 3.3.0 '@smithy/util-hex-encoding': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/eventstream-serde-browser@3.0.5': dependencies: '@smithy/eventstream-serde-universal': 3.0.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/eventstream-serde-config-resolver@3.0.3': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/eventstream-serde-node@3.0.4': dependencies: '@smithy/eventstream-serde-universal': 3.0.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/eventstream-serde-universal@3.0.4': dependencies: '@smithy/eventstream-codec': 3.1.2 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/fetch-http-handler@3.2.4': dependencies: @@ -14482,52 +14547,52 @@ snapshots: '@smithy/querystring-builder': 3.0.3 '@smithy/types': 3.3.0 '@smithy/util-base64': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/hash-blob-browser@3.1.2': dependencies: '@smithy/chunked-blob-reader': 3.0.0 '@smithy/chunked-blob-reader-native': 3.0.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/hash-node@3.0.3': dependencies: '@smithy/types': 3.3.0 '@smithy/util-buffer-from': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/hash-stream-node@3.1.2': dependencies: '@smithy/types': 3.3.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/invalid-dependency@3.0.3': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/is-array-buffer@2.0.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/is-array-buffer@3.0.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/md5-js@3.0.3': dependencies: '@smithy/types': 3.3.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/middleware-content-length@3.0.5': dependencies: '@smithy/protocol-http': 4.1.0 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/middleware-endpoint@3.1.0': dependencies: @@ -14537,7 +14602,7 @@ snapshots: '@smithy/types': 3.3.0 '@smithy/url-parser': 3.0.3 '@smithy/util-middleware': 3.0.3 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/middleware-retry@3.0.13': dependencies: @@ -14548,25 +14613,25 @@ snapshots: '@smithy/types': 3.3.0 '@smithy/util-middleware': 3.0.3 '@smithy/util-retry': 3.0.3 - tslib: 2.6.3 + tslib: 2.7.0 uuid: 9.0.1 '@smithy/middleware-serde@3.0.3': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/middleware-stack@3.0.3': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/node-config-provider@3.1.4': dependencies: '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/node-http-handler@2.5.0': dependencies: @@ -14582,39 +14647,39 @@ snapshots: '@smithy/protocol-http': 4.1.0 '@smithy/querystring-builder': 3.0.3 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/property-provider@3.1.3': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/protocol-http@3.3.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/protocol-http@4.1.0': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/querystring-builder@2.2.0': dependencies: '@smithy/types': 2.12.0 '@smithy/util-uri-escape': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/querystring-builder@3.0.3': dependencies: '@smithy/types': 3.3.0 '@smithy/util-uri-escape': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/querystring-parser@3.0.3': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/service-error-classification@3.0.3': dependencies: @@ -14623,7 +14688,7 @@ snapshots: '@smithy/shared-ini-file-loader@3.1.4': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/signature-v4@4.1.0': dependencies: @@ -14634,7 +14699,7 @@ snapshots: '@smithy/util-middleware': 3.0.3 '@smithy/util-uri-escape': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/smithy-client@3.1.11': dependencies: @@ -14643,49 +14708,49 @@ snapshots: '@smithy/protocol-http': 4.1.0 '@smithy/types': 3.3.0 '@smithy/util-stream': 3.1.3 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/types@2.12.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/types@3.3.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/url-parser@3.0.3': dependencies: '@smithy/querystring-parser': 3.0.3 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-base64@3.0.0': dependencies: '@smithy/util-buffer-from': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-body-length-browser@3.0.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-body-length-node@3.0.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-buffer-from@2.0.0': dependencies: '@smithy/is-array-buffer': 2.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-buffer-from@3.0.0': dependencies: '@smithy/is-array-buffer': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-config-provider@3.0.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-defaults-mode-browser@3.0.13': dependencies: @@ -14693,7 +14758,7 @@ snapshots: '@smithy/smithy-client': 3.1.11 '@smithy/types': 3.3.0 bowser: 2.11.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-defaults-mode-node@3.0.13': dependencies: @@ -14703,28 +14768,28 @@ snapshots: '@smithy/property-provider': 3.1.3 '@smithy/smithy-client': 3.1.11 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-endpoints@2.0.5': dependencies: '@smithy/node-config-provider': 3.1.4 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-hex-encoding@3.0.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-middleware@3.0.3': dependencies: '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-retry@3.0.3': dependencies: '@smithy/service-error-classification': 3.0.3 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-stream@3.1.3': dependencies: @@ -14735,148 +14800,148 @@ snapshots: '@smithy/util-buffer-from': 3.0.0 '@smithy/util-hex-encoding': 3.0.0 '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-uri-escape@2.2.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-uri-escape@3.0.0': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-utf8@2.0.0': dependencies: '@smithy/util-buffer-from': 2.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-utf8@3.0.0': dependencies: '@smithy/util-buffer-from': 3.0.0 - tslib: 2.6.3 + tslib: 2.7.0 '@smithy/util-waiter@3.1.2': dependencies: '@smithy/abort-controller': 3.1.1 '@smithy/types': 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 '@sqltools/formatter@1.2.5': {} - '@storybook/addon-actions@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-actions@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/global': 5.0.0 '@types/uuid': 9.0.8 dequal: 2.0.3 polished: 4.2.2 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) uuid: 9.0.1 - '@storybook/addon-backgrounds@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-backgrounds@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 - '@storybook/addon-controls@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-controls@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/global': 5.0.0 dequal: 2.0.3 lodash: 4.17.21 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 - '@storybook/addon-docs@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-docs@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@mdx-js/react': 3.0.1(@types/react@18.0.28)(react@18.3.1) - '@storybook/blocks': 8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/csf-plugin': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/blocks': 8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/csf-plugin': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/react-dom-shim': 8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@types/react': 18.0.28 fs-extra: 11.1.1 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) rehype-external-links: 3.0.0 rehype-slug: 6.0.0 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 - '@storybook/addon-essentials@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-essentials@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - '@storybook/addon-actions': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/addon-backgrounds': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/addon-controls': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/addon-docs': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/addon-highlight': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/addon-measure': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/addon-outline': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/addon-toolbars': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/addon-viewport': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@storybook/addon-actions': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/addon-backgrounds': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/addon-controls': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/addon-docs': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/addon-highlight': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/addon-measure': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/addon-outline': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/addon-toolbars': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/addon-viewport': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 - '@storybook/addon-highlight@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-highlight@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/addon-interactions@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-interactions@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/test': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/instrumenter': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/test': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) polished: 4.2.2 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 - '@storybook/addon-links@8.3.3(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-links@8.3.4(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/csf': 0.1.11 '@storybook/global': 5.0.0 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 optionalDependencies: react: 18.3.1 - '@storybook/addon-mdx-gfm@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-mdx-gfm@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: remark-gfm: 4.0.0 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - '@storybook/addon-measure@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-measure@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) tiny-invariant: 1.3.3 - '@storybook/addon-outline@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-outline@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 - '@storybook/addon-storysource@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-storysource@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - '@storybook/source-loader': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/source-loader': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) estraverse: 5.3.0 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) tiny-invariant: 1.3.3 - '@storybook/addon-toolbars@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-toolbars@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/addon-viewport@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/addon-viewport@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: memoizerific: 1.11.3 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/blocks@8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/blocks@8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/csf': 0.1.11 '@storybook/global': 5.0.0 @@ -14889,7 +14954,7 @@ snapshots: memoizerific: 1.11.3 polished: 4.2.2 react-colorful: 5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) telejson: 7.2.0 ts-dedent: 2.2.0 util-deprecate: 1.0.2 @@ -14897,9 +14962,9 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/builder-vite@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))': + '@storybook/builder-vite@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))': dependencies: - '@storybook/csf-plugin': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/csf-plugin': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@types/find-cache-dir': 3.2.1 browser-assert: 1.2.1 es-module-lexer: 1.5.4 @@ -14907,7 +14972,7 @@ snapshots: find-cache-dir: 3.3.2 fs-extra: 11.1.1 magic-string: 0.30.11 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 vite: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) optionalDependencies: @@ -14915,15 +14980,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/components@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/components@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/core-events@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/core-events@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/core@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)': + '@storybook/core@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)': dependencies: '@storybook/csf': 0.1.11 '@types/express': 4.17.21 @@ -14943,9 +15008,9 @@ snapshots: - supports-color - utf-8-validate - '@storybook/csf-plugin@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/csf-plugin@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) unplugin: 1.4.0 '@storybook/csf@0.1.11': @@ -14959,40 +15024,40 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/instrumenter@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/instrumenter@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/global': 5.0.0 '@vitest/utils': 2.1.1 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) util: 0.12.5 - '@storybook/manager-api@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/manager-api@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/preview-api@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/preview-api@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/react-dom-shim@8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/react-dom-shim@8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/react-vite@8.3.3(@storybook/test@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.5)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))': + '@storybook/react-vite@8.3.4(@storybook/test@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.5)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0)) '@rollup/pluginutils': 5.1.2(rollup@4.22.5) - '@storybook/builder-vite': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0)) - '@storybook/react': 8.3.3(@storybook/test@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2) + '@storybook/builder-vite': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0)) + '@storybook/react': 8.3.4(@storybook/test@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2) find-up: 5.0.0 magic-string: 0.30.11 react: 18.3.1 react-docgen: 7.0.1 react-dom: 18.3.1(react@18.3.1) resolve: 1.22.8 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) tsconfig-paths: 4.2.0 vite: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) transitivePeerDependencies: @@ -15003,14 +15068,14 @@ snapshots: - typescript - vite-plugin-glimmerx - '@storybook/react@8.3.3(@storybook/test@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)': + '@storybook/react@8.3.4(@storybook/test@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)': dependencies: - '@storybook/components': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/components': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/preview-api': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/react-dom-shim': 8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/theming': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/manager-api': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/preview-api': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/react-dom-shim': 8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/theming': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 '@types/node': 22.5.5 @@ -15024,72 +15089,72 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-element-to-jsx-string: 15.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) semver: 7.6.3 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 type-fest: 2.19.0 util-deprecate: 1.0.2 optionalDependencies: - '@storybook/test': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/test': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) typescript: 5.6.2 - '@storybook/source-loader@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/source-loader@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/csf': 0.1.11 estraverse: 5.3.0 lodash: 4.17.21 prettier: 3.3.3 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/test@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/test@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: '@storybook/csf': 0.1.11 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/instrumenter': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@testing-library/dom': 10.4.0 '@testing-library/jest-dom': 6.5.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) '@vitest/expect': 2.0.5 '@vitest/spy': 2.0.5 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) util: 0.12.5 - '@storybook/theming@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/theming@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/types@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@storybook/types@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@storybook/vue3-vite@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.10(typescript@5.6.2))': + '@storybook/vue3-vite@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.11(typescript@5.6.2))': dependencies: - '@storybook/builder-vite': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0)) - '@storybook/vue3': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vue@3.5.10(typescript@5.6.2)) + '@storybook/builder-vite': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(typescript@5.6.2)(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0)) + '@storybook/vue3': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vue@3.5.11(typescript@5.6.2)) find-package-json: 1.2.0 magic-string: 0.30.11 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) typescript: 5.6.2 vite: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) vue-component-meta: 2.0.16(typescript@5.6.2) - vue-docgen-api: 4.75.1(vue@3.5.10(typescript@5.6.2)) + vue-docgen-api: 4.75.1(vue@3.5.11(typescript@5.6.2)) transitivePeerDependencies: - '@preact/preset-vite' - supports-color - vite-plugin-glimmerx - vue - '@storybook/vue3@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vue@3.5.10(typescript@5.6.2))': + '@storybook/vue3@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4))(vue@3.5.11(typescript@5.6.2))': dependencies: - '@storybook/components': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/components': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/preview-api': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/theming': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@vue/compiler-core': 3.5.7 - storybook: 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@storybook/manager-api': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/preview-api': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/theming': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@vue/compiler-core': 3.5.10 + storybook: 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) ts-dedent: 2.2.0 type-fest: 2.19.0 - vue: 3.5.10(typescript@5.6.2) + vue: 3.5.11(typescript@5.6.2) vue-component-type-helpers: 2.1.6 '@swc/cli@0.3.12(@swc/core@1.6.6)(chokidar@3.5.3)': @@ -15397,14 +15462,14 @@ snapshots: dependencies: '@testing-library/dom': 10.4.0 - '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.5.10)(@vue/server-renderer@3.5.10(vue@3.5.10(typescript@5.6.2)))(vue@3.5.10(typescript@5.6.2))': + '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.5.11)(@vue/server-renderer@3.5.11(vue@3.5.11(typescript@5.6.2)))(vue@3.5.11(typescript@5.6.2))': dependencies: '@babel/runtime': 7.23.4 '@testing-library/dom': 9.3.4 - '@vue/test-utils': 2.4.1(@vue/server-renderer@3.5.10(vue@3.5.10(typescript@5.6.2)))(vue@3.5.10(typescript@5.6.2)) - vue: 3.5.10(typescript@5.6.2) + '@vue/test-utils': 2.4.1(@vue/server-renderer@3.5.11(vue@3.5.11(typescript@5.6.2)))(vue@3.5.11(typescript@5.6.2)) + vue: 3.5.11(typescript@5.6.2) optionalDependencies: - '@vue/compiler-sfc': 3.5.10 + '@vue/compiler-sfc': 3.5.11 transitivePeerDependencies: - '@vue/server-renderer' @@ -15469,7 +15534,9 @@ snapshots: '@types/node': 20.14.12 '@types/responselike': 1.0.0 - '@types/color-convert@2.0.3': + '@types/canvas-confetti@1.6.4': {} + + '@types/color-convert@2.0.4': dependencies: '@types/color-name': 1.1.1 @@ -15895,7 +15962,7 @@ snapshots: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) eslint: 9.11.0 optionalDependencies: typescript: 5.5.4 @@ -15908,7 +15975,7 @@ snapshots: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) eslint: 9.11.0 optionalDependencies: typescript: 5.6.2 @@ -15921,7 +15988,7 @@ snapshots: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) eslint: 9.8.0 optionalDependencies: typescript: 5.6.2 @@ -15942,7 +16009,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) '@typescript-eslint/utils': 7.1.0(eslint@9.11.0)(typescript@5.3.3) - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) eslint: 9.11.0 ts-api-utils: 1.0.1(typescript@5.3.3) optionalDependencies: @@ -15954,7 +16021,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4) '@typescript-eslint/utils': 7.17.0(eslint@9.11.0)(typescript@5.5.4) - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) eslint: 9.11.0 ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: @@ -15966,7 +16033,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/utils': 7.17.0(eslint@9.11.0)(typescript@5.6.2) - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) eslint: 9.11.0 ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: @@ -15978,7 +16045,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/utils': 7.17.0(eslint@9.8.0)(typescript@5.6.2) - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) eslint: 9.8.0 ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: @@ -15994,7 +16061,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -16009,7 +16076,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -16024,7 +16091,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -16094,16 +16161,21 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-vue@5.1.4(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.10(typescript@5.6.2))': + '@vitejs/plugin-vue@5.1.4(vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0))(vue@3.5.11(typescript@5.6.2))': dependencies: vite: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) - vue: 3.5.10(typescript@5.6.2) + vue: 3.5.11(typescript@5.6.2) + + '@vitejs/plugin-vue@5.1.4(vite@5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0))(vue@3.5.11(typescript@5.6.2))': + dependencies: + vite: 5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0) + vue: 3.5.11(typescript@5.6.2) '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.3)(terser@5.33.0))': dependencies: '@ampproject/remapping': 2.2.1 '@bcoe/v8-coverage': 0.2.3 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.4 @@ -16118,11 +16190,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.3)(terser@5.33.0))': + '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0))': dependencies: '@ampproject/remapping': 2.2.1 '@bcoe/v8-coverage': 0.2.3 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.4 @@ -16133,7 +16205,7 @@ snapshots: std-env: 3.7.0 strip-literal: 2.1.0 test-exclude: 6.0.0 - vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.3)(terser@5.33.0) + vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0) transitivePeerDependencies: - supports-color @@ -16239,10 +16311,10 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-core@3.5.7': + '@vue/compiler-core@3.5.11': dependencies: '@babel/parser': 7.25.6 - '@vue/shared': 3.5.7 + '@vue/shared': 3.5.11 entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.1 @@ -16257,10 +16329,10 @@ snapshots: '@vue/compiler-core': 3.5.10 '@vue/shared': 3.5.10 - '@vue/compiler-dom@3.5.7': + '@vue/compiler-dom@3.5.11': dependencies: - '@vue/compiler-core': 3.5.7 - '@vue/shared': 3.5.7 + '@vue/compiler-core': 3.5.11 + '@vue/shared': 3.5.11 '@vue/compiler-sfc@3.4.37': dependencies: @@ -16274,13 +16346,13 @@ snapshots: postcss: 8.4.47 source-map-js: 1.2.0 - '@vue/compiler-sfc@3.5.10': + '@vue/compiler-sfc@3.5.11': dependencies: '@babel/parser': 7.25.6 - '@vue/compiler-core': 3.5.10 - '@vue/compiler-dom': 3.5.10 - '@vue/compiler-ssr': 3.5.10 - '@vue/shared': 3.5.10 + '@vue/compiler-core': 3.5.11 + '@vue/compiler-dom': 3.5.11 + '@vue/compiler-ssr': 3.5.11 + '@vue/shared': 3.5.11 estree-walker: 2.0.2 magic-string: 0.30.11 postcss: 8.4.47 @@ -16291,10 +16363,10 @@ snapshots: '@vue/compiler-dom': 3.4.37 '@vue/shared': 3.4.37 - '@vue/compiler-ssr@3.5.10': + '@vue/compiler-ssr@3.5.11': dependencies: - '@vue/compiler-dom': 3.5.10 - '@vue/shared': 3.5.10 + '@vue/compiler-dom': 3.5.11 + '@vue/shared': 3.5.11 '@vue/compiler-vue2@2.7.16': dependencies: @@ -16304,8 +16376,8 @@ snapshots: '@vue/language-core@2.0.16(typescript@5.6.2)': dependencies: '@volar/language-core': 2.2.0 - '@vue/compiler-dom': 3.5.7 - '@vue/shared': 3.5.7 + '@vue/compiler-dom': 3.5.11 + '@vue/shared': 3.5.11 computeds: 0.0.1 minimatch: 9.0.4 path-browserify: 1.0.1 @@ -16318,7 +16390,7 @@ snapshots: '@volar/language-core': 2.4.5 '@vue/compiler-dom': 3.4.37 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.4.37 + '@vue/shared': 3.5.11 computeds: 0.0.1 minimatch: 9.0.4 muggle-string: 0.4.1 @@ -16330,19 +16402,19 @@ snapshots: dependencies: '@vue/shared': 3.4.37 - '@vue/reactivity@3.5.10': + '@vue/reactivity@3.5.11': dependencies: - '@vue/shared': 3.5.10 + '@vue/shared': 3.5.11 '@vue/runtime-core@3.4.37': dependencies: '@vue/reactivity': 3.4.37 '@vue/shared': 3.4.37 - '@vue/runtime-core@3.5.10': + '@vue/runtime-core@3.5.11': dependencies: - '@vue/reactivity': 3.5.10 - '@vue/shared': 3.5.10 + '@vue/reactivity': 3.5.11 + '@vue/shared': 3.5.11 '@vue/runtime-dom@3.4.37': dependencies: @@ -16351,11 +16423,11 @@ snapshots: '@vue/shared': 3.4.37 csstype: 3.1.3 - '@vue/runtime-dom@3.5.10': + '@vue/runtime-dom@3.5.11': dependencies: - '@vue/reactivity': 3.5.10 - '@vue/runtime-core': 3.5.10 - '@vue/shared': 3.5.10 + '@vue/reactivity': 3.5.11 + '@vue/runtime-core': 3.5.11 + '@vue/shared': 3.5.11 csstype: 3.1.3 '@vue/server-renderer@3.4.37(vue@3.4.37(typescript@5.5.4))': @@ -16364,25 +16436,25 @@ snapshots: '@vue/shared': 3.4.37 vue: 3.4.37(typescript@5.5.4) - '@vue/server-renderer@3.5.10(vue@3.5.10(typescript@5.6.2))': + '@vue/server-renderer@3.5.11(vue@3.5.11(typescript@5.6.2))': dependencies: - '@vue/compiler-ssr': 3.5.10 - '@vue/shared': 3.5.10 - vue: 3.5.10(typescript@5.6.2) + '@vue/compiler-ssr': 3.5.11 + '@vue/shared': 3.5.11 + vue: 3.5.11(typescript@5.6.2) '@vue/shared@3.4.37': {} '@vue/shared@3.5.10': {} - '@vue/shared@3.5.7': {} + '@vue/shared@3.5.11': {} - '@vue/test-utils@2.4.1(@vue/server-renderer@3.5.10(vue@3.5.10(typescript@5.6.2)))(vue@3.5.10(typescript@5.6.2))': + '@vue/test-utils@2.4.1(@vue/server-renderer@3.5.11(vue@3.5.11(typescript@5.6.2)))(vue@3.5.11(typescript@5.6.2))': dependencies: js-beautify: 1.14.9 - vue: 3.5.10(typescript@5.6.2) + vue: 3.5.11(typescript@5.6.2) vue-component-type-helpers: 1.8.4 optionalDependencies: - '@vue/server-renderer': 3.5.10(vue@3.5.10(typescript@5.6.2)) + '@vue/server-renderer': 3.5.11(vue@3.5.11(typescript@5.6.2)) '@webgpu/types@0.1.30': {} @@ -16436,14 +16508,14 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color optional: true agent-base@7.1.0: dependencies: - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -16671,7 +16743,7 @@ snapshots: dependencies: pvtsutils: 1.3.5 pvutils: 1.1.3 - tslib: 2.6.3 + tslib: 2.7.0 assert-never@1.2.1: {} @@ -16838,23 +16910,6 @@ snapshots: bn.js@4.12.0: {} - body-parser@1.20.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - body-parser@1.20.3: dependencies: bytes: 3.1.2 @@ -16953,14 +17008,14 @@ snapshots: node-gyp-build: 4.6.0 optional: true - bullmq@5.13.2: + bullmq@5.15.0: dependencies: cron-parser: 4.8.1 ioredis: 5.4.1 msgpackr: 1.10.1 node-abort-controller: 3.1.1 - semver: 7.6.0 - tslib: 2.6.3 + semver: 7.6.3 + tslib: 2.7.0 uuid: 9.0.1 transitivePeerDependencies: - supports-color @@ -17118,6 +17173,10 @@ snapshots: char-regex@1.0.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + character-entities@2.0.2: {} character-parser@2.2.0: @@ -17204,7 +17263,7 @@ snapshots: chownr@2.0.0: {} - chromatic@11.10.4: {} + chromatic@11.11.0: {} ci-info@3.7.1: {} @@ -17307,6 +17366,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} + commander@10.0.1: {} commander@12.1.0: {} @@ -17462,12 +17523,12 @@ snapshots: css-tree@2.2.1: dependencies: mdn-data: 2.0.28 - source-map-js: 1.2.0 + source-map-js: 1.2.1 css-tree@2.3.1: dependencies: mdn-data: 2.0.30 - source-map-js: 1.2.0 + source-map-js: 1.2.1 css-what@6.1.0: {} @@ -17901,7 +17962,7 @@ snapshots: '@one-ini/wasm': 0.1.1 commander: 10.0.1 minimatch: 9.0.1 - semver: 7.6.0 + semver: 7.6.3 ee-first@1.1.1: {} @@ -18295,7 +18356,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.11.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@9.8.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.17.0(eslint@9.11.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@9.11.0): + dependencies: + debug: 3.2.7(supports-color@8.1.1) + optionalDependencies: + '@typescript-eslint/parser': 7.17.0(eslint@9.11.0)(typescript@5.6.2) + eslint: 9.11.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@9.8.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: @@ -18333,7 +18404,36 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.17.0(eslint@9.11.0)(typescript@5.6.2))(eslint@9.11.0): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7(supports-color@8.1.1) + doctrine: 2.1.0 + eslint: 9.11.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.17.0(eslint@9.11.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@9.11.0) + hasown: 2.0.2 + is-core-module: 2.15.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 7.17.0(eslint@9.11.0)(typescript@5.6.2) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint@9.8.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -18344,7 +18444,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.8.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.11.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@9.8.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.17.0(eslint@9.8.0)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint@9.8.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -18353,6 +18453,7 @@ snapshots: object.groupby: 1.0.3 object.values: 1.2.0 semver: 6.3.1 + string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: '@typescript-eslint/parser': 7.17.0(eslint@9.8.0)(typescript@5.6.2) @@ -18626,42 +18727,6 @@ snapshots: exponential-backoff@3.1.1: {} - express@4.19.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.2 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.6.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.7 - qs: 6.11.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - express@4.21.0: dependencies: accepts: 1.3.8 @@ -18865,18 +18930,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.2.0: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - finalhandler@1.3.1: dependencies: debug: 2.6.9 @@ -19346,10 +19399,28 @@ snapshots: dependencies: '@types/hast': 3.0.4 + hast-util-to-html@9.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.2 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + hast-util-to-string@3.0.0: dependencies: '@types/hast': 3.0.4 + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + he@1.2.0: {} headers-polyfill@4.0.2: {} @@ -19376,6 +19447,8 @@ snapshots: html-tags@3.2.0: {} + html-void-elements@3.0.0: {} + htmlescape@1.1.1: {} htmlparser2@5.0.1: @@ -19414,7 +19487,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -19453,7 +19526,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) transitivePeerDependencies: - supports-color optional: true @@ -19461,14 +19534,14 @@ snapshots: https-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -19635,7 +19708,7 @@ snapshots: is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 has-tostringtag: 1.0.0 is-buffer@1.1.6: {} @@ -19783,7 +19856,7 @@ snapshots: is-weakset@2.0.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 get-intrinsic: 1.2.1 is-wsl@2.2.0: @@ -19820,7 +19893,7 @@ snapshots: '@babel/parser': 7.24.7 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - supports-color @@ -19832,7 +19905,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -19841,7 +19914,7 @@ snapshots: istanbul-lib-source-maps@5.0.4: dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -20242,35 +20315,6 @@ snapshots: jsdoc-type-pratt-parser@4.1.0: {} - jsdom@24.1.1: - dependencies: - cssstyle: 4.0.1 - data-urls: 5.0.0 - decimal.js: 10.4.3 - form-data: 4.0.0 - html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 - is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.12 - parse5: 7.1.2 - rrweb-cssom: 0.7.1 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 4.1.4 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 7.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 14.0.0 - ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - optional: true - jsdom@24.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3): dependencies: cssstyle: 4.0.1 @@ -20547,7 +20591,7 @@ snapshots: lru-cache@10.0.2: dependencies: - semver: 7.6.0 + semver: 7.6.3 lru-cache@10.2.2: {} @@ -20598,7 +20642,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.6.0 + semver: 7.6.3 make-fetch-happen@13.0.0: dependencies: @@ -20722,6 +20766,18 @@ snapshots: '@types/mdast': 4.0.3 unist-util-is: 6.0.0 + mdast-util-to-hast@13.2.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.3 + '@ungap/structured-clone': 1.2.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.0 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.1 + mdast-util-to-markdown@2.1.0: dependencies: '@types/mdast': 4.0.3 @@ -20770,8 +20826,6 @@ snapshots: type-fest: 0.18.1 yargs-parser: 20.2.9 - merge-descriptors@1.0.1: {} - merge-descriptors@1.0.3: {} merge-stream@2.0.0: {} @@ -21387,7 +21441,7 @@ snapshots: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.13.1 - semver: 7.6.0 + semver: 7.6.3 validate-npm-package-license: 3.0.4 normalize-path@3.0.0: {} @@ -21522,6 +21576,10 @@ snapshots: dependencies: mimic-fn: 4.0.0 + oniguruma-to-js@0.4.3: + dependencies: + regex: 4.3.3 + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -21565,9 +21623,9 @@ snapshots: ospath@1.2.2: {} - otpauth@9.3.2: + otpauth@9.3.4: dependencies: - '@noble/hashes': 1.4.0 + '@noble/hashes': 1.5.0 outvariant@1.4.2: {} @@ -21686,8 +21744,6 @@ snapshots: path-to-regexp@0.1.10: {} - path-to-regexp@0.1.7: {} - path-to-regexp@1.8.0: dependencies: isarray: 0.0.1 @@ -21996,12 +22052,6 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.4.40: - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - postcss@8.4.47: dependencies: nanoid: 3.3.7 @@ -22108,6 +22158,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + property-information@6.5.0: {} + proto-list@1.2.4: {} proxy-addr@2.0.7: @@ -22211,7 +22263,7 @@ snapshots: pvtsutils@1.3.5: dependencies: - tslib: 2.6.3 + tslib: 2.7.0 pvutils@1.1.3: {} @@ -22221,10 +22273,6 @@ snapshots: pngjs: 5.0.0 yargs: 15.4.1 - qs@6.11.0: - dependencies: - side-channel: 1.0.6 - qs@6.13.0: dependencies: side-channel: 1.0.6 @@ -22419,6 +22467,8 @@ snapshots: regenerator-runtime@0.14.0: {} + regex@4.3.3: {} + regexp.prototype.flags@1.5.0: dependencies: call-bind: 1.0.2 @@ -22654,14 +22704,14 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-html@2.13.0: + sanitize-html@2.13.1: dependencies: deepmerge: 4.2.2 escape-string-regexp: 4.0.0 htmlparser2: 8.0.1 is-plain-object: 5.0.0 parse-srcset: 1.0.2 - postcss: 8.4.40 + postcss: 8.4.47 sass@1.79.3: dependencies: @@ -22669,6 +22719,12 @@ snapshots: immutable: 4.2.2 source-map-js: 1.2.0 + sass@1.79.4: + dependencies: + chokidar: 3.5.3 + immutable: 4.2.2 + source-map-js: 1.2.1 + sax@1.2.4: {} saxes@6.0.0: @@ -22705,24 +22761,6 @@ snapshots: semver@7.6.3: {} - send@0.18.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - send@0.19.0: dependencies: debug: 2.6.9 @@ -22741,15 +22779,6 @@ snapshots: transitivePeerDependencies: - supports-color - serve-static@1.15.0: - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.18.0 - transitivePeerDependencies: - - supports-color - serve-static@1.16.2: dependencies: encodeurl: 2.0.0 @@ -22826,9 +22855,13 @@ snapshots: shebang-regex@3.0.0: {} - shiki@1.12.0: + shiki@1.21.0: dependencies: - '@shikijs/core': 1.12.0 + '@shikijs/core': 1.21.0 + '@shikijs/engine-javascript': 1.21.0 + '@shikijs/engine-oniguruma': 1.21.0 + '@shikijs/types': 1.21.0 + '@shikijs/vscode-textmate': 9.2.2 '@types/hast': 3.0.4 shimmer@1.2.1: {} @@ -22856,7 +22889,7 @@ snapshots: dependencies: '@hapi/hoek': 11.0.4 '@hapi/wreck': 18.0.1 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) joi: 17.11.0 transitivePeerDependencies: - supports-color @@ -22956,7 +22989,7 @@ snapshots: socks-proxy-agent@8.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) socks: 2.7.1 transitivePeerDependencies: - supports-color @@ -23081,22 +23114,22 @@ snapshots: dependencies: internal-slot: 1.0.5 - storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/components@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/core-events@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/manager-api@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/preview-api@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/theming@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/types@8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/components@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/core-events@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/manager-api@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/preview-api@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/theming@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(@storybook/types@8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@storybook/blocks': 8.3.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/components': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/core-events': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/manager-api': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/preview-api': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/theming': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@storybook/types': 8.3.3(storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/blocks': 8.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/components': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/core-events': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/manager-api': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/preview-api': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/theming': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@storybook/types': 8.3.4(storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)) optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook@8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4): + storybook@8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: - '@storybook/core': 8.3.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@storybook/core': 8.3.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - supports-color @@ -23194,6 +23227,11 @@ snapshots: dependencies: safe-buffer: 5.2.1 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + stringz@2.1.0: dependencies: char-regex: 1.0.2 @@ -23426,6 +23464,8 @@ snapshots: trace-redirect@1.0.6: {} + trim-lines@3.0.1: {} + trim-newlines@3.0.1: {} trim-repeated@2.0.0: @@ -23677,6 +23717,10 @@ snapshots: dependencies: '@types/unist': 3.0.2 + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.2 @@ -23762,13 +23806,13 @@ snapshots: uuid@9.0.1: {} - v-code-diff@1.13.1(vue@3.5.10(typescript@5.6.2)): + v-code-diff@1.13.1(vue@3.5.11(typescript@5.6.2)): dependencies: diff: 5.2.0 diff-match-patch: 1.0.5 highlight.js: 11.10.0 - vue: 3.5.10(typescript@5.6.2) - vue-demi: 0.14.7(vue@3.5.10(typescript@5.6.2)) + vue: 3.5.11(typescript@5.6.2) + vue-demi: 0.14.7(vue@3.5.11(typescript@5.6.2)) v8-to-istanbul@9.2.0: dependencies: @@ -23805,7 +23849,7 @@ snapshots: vite-node@1.6.0(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0): dependencies: cac: 6.7.14 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) pathe: 1.1.2 picocolors: 1.0.1 vite: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) @@ -23820,6 +23864,24 @@ snapshots: - supports-color - terser + vite-node@1.6.0(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0): + dependencies: + cac: 6.7.14 + debug: 4.3.5(supports-color@5.5.0) + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vite-plugin-turbosnap@1.0.3: {} vite@5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0): @@ -23833,6 +23895,17 @@ snapshots: sass: 1.79.3 terser: 5.33.0 + vite@5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.47 + rollup: 4.22.5 + optionalDependencies: + '@types/node': 20.14.12 + fsevents: 2.3.3 + sass: 1.79.4 + terser: 5.33.0 + vitest-fetch-mock@0.2.2(encoding@0.1.13)(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.3)(terser@5.33.0)): dependencies: cross-fetch: 3.1.6(encoding@0.1.13) @@ -23876,7 +23949,7 @@ snapshots: - supports-color - terser - vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.3)(terser@5.33.0): + vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 @@ -23895,13 +23968,13 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.6.0 tinypool: 0.8.4 - vite: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) - vite-node: 1.6.0(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) + vite: 5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0) + vite-node: 1.6.0(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0) why-is-node-running: 2.2.2 optionalDependencies: '@types/node': 20.14.12 happy-dom: 10.0.3 - jsdom: 24.1.1 + jsdom: 24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - less - lightningcss @@ -23919,7 +23992,7 @@ snapshots: vscode-languageclient@9.0.1: dependencies: minimatch: 5.1.2 - semver: 7.6.0 + semver: 7.6.3 vscode-languageserver-protocol: 3.17.5 vscode-languageserver-protocol@3.17.5: @@ -23952,28 +24025,28 @@ snapshots: vue-component-type-helpers@2.1.6: {} - vue-demi@0.14.7(vue@3.5.10(typescript@5.6.2)): + vue-demi@0.14.7(vue@3.5.11(typescript@5.6.2)): dependencies: - vue: 3.5.10(typescript@5.6.2) + vue: 3.5.11(typescript@5.6.2) - vue-docgen-api@4.75.1(vue@3.5.10(typescript@5.6.2)): + vue-docgen-api@4.75.1(vue@3.5.11(typescript@5.6.2)): dependencies: '@babel/parser': 7.25.6 '@babel/types': 7.25.6 - '@vue/compiler-dom': 3.5.7 - '@vue/compiler-sfc': 3.5.10 + '@vue/compiler-dom': 3.5.10 + '@vue/compiler-sfc': 3.5.11 ast-types: 0.16.1 hash-sum: 2.0.0 lru-cache: 8.0.4 pug: 3.0.3 recast: 0.23.6 ts-map: 1.0.3 - vue: 3.5.10(typescript@5.6.2) - vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.5.10(typescript@5.6.2)) + vue: 3.5.11(typescript@5.6.2) + vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.5.11(typescript@5.6.2)) vue-eslint-parser@9.4.3(eslint@9.11.0): dependencies: - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.5(supports-color@5.5.0) eslint: 9.11.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 @@ -23984,9 +24057,9 @@ snapshots: transitivePeerDependencies: - supports-color - vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.5.10(typescript@5.6.2)): + vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.5.11(typescript@5.6.2)): dependencies: - vue: 3.5.10(typescript@5.6.2) + vue: 3.5.11(typescript@5.6.2) vue-template-compiler@2.7.14: dependencies: @@ -24010,20 +24083,20 @@ snapshots: optionalDependencies: typescript: 5.5.4 - vue@3.5.10(typescript@5.6.2): + vue@3.5.11(typescript@5.6.2): dependencies: - '@vue/compiler-dom': 3.5.10 - '@vue/compiler-sfc': 3.5.10 - '@vue/runtime-dom': 3.5.10 - '@vue/server-renderer': 3.5.10(vue@3.5.10(typescript@5.6.2)) - '@vue/shared': 3.5.10 + '@vue/compiler-dom': 3.5.11 + '@vue/compiler-sfc': 3.5.11 + '@vue/runtime-dom': 3.5.11 + '@vue/server-renderer': 3.5.11(vue@3.5.11(typescript@5.6.2)) + '@vue/shared': 3.5.11 optionalDependencies: typescript: 5.6.2 - vuedraggable@4.1.0(vue@3.5.10(typescript@5.6.2)): + vuedraggable@4.1.0(vue@3.5.11(typescript@5.6.2)): dependencies: sortablejs: 1.14.0 - vue: 3.5.10(typescript@5.6.2) + vue: 3.5.11(typescript@5.6.2) w3c-xmlserializer@5.0.0: dependencies: |