diff --git a/.config/docker_example.env b/.config/docker_example.env index 2797c2f807..3774d86d1c 100644 --- a/.config/docker_example.env +++ b/.config/docker_example.env @@ -2,3 +2,4 @@ POSTGRES_PASSWORD=example-cherrypick-pass POSTGRES_USER=example-cherrypick-user POSTGRES_DB=cherrypick +DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}" diff --git a/.config/docker_example.yml b/.config/docker_example.yml index edb9070074..d492bee81d 100644 --- a/.config/docker_example.yml +++ b/.config/docker_example.yml @@ -106,7 +106,7 @@ redis: # ┌───────────────────────────┐ #───┘ MeiliSearch configuration └───────────────────────────── -# You can set scope to local (default value) or global +# You can set scope to local (default value) or global # (include notes from remote). #meilisearch: @@ -151,7 +151,7 @@ id: 'aidx' # Job rate limiter # deliverJobPerSec: 128 -# inboxJobPerSec: 16 +# inboxJobPerSec: 32 # Job attempts # deliverJobMaxAttempts: 12 @@ -194,7 +194,7 @@ proxyRemoteFiles: true signToActivityPubGet: true # For security reasons, uploading attachments from the intranet is prohibited, -# but exceptions can be made from the following settings. Default value is "undefined". +# but exceptions can be made from the following settings. Default value is "undefined". # Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)). #allowedPrivateNetworks: [ # '127.0.0.1/32' diff --git a/.config/example.yml b/.config/example.yml index de12f1ebd7..5ad6ae0fef 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -166,7 +166,7 @@ id: 'aidx' # Job rate limiter #deliverJobPerSec: 128 -#inboxJobPerSec: 16 +#inboxJobPerSec: 32 #relashionshipJobPerSec: 64 # Job attempts diff --git a/.devcontainer/devcontainer.yml b/.devcontainer/devcontainer.yml index 8353977816..a16537fb9f 100644 --- a/.devcontainer/devcontainer.yml +++ b/.devcontainer/devcontainer.yml @@ -147,7 +147,7 @@ id: 'aidx' # Job rate limiter # deliverJobPerSec: 128 -# inboxJobPerSec: 16 +# inboxJobPerSec: 32 # Job attempts # deliverJobMaxAttempts: 12 diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.yml b/.github/ISSUE_TEMPLATE/01_bug-report.yml index 03618103dc..96911bca86 100644 --- a/.github/ISSUE_TEMPLATE/01_bug-report.yml +++ b/.github/ISSUE_TEMPLATE/01_bug-report.yml @@ -89,3 +89,9 @@ body: render: markdown validations: required: false + + - type: checkboxes + attributes: + label: Do you want to address this bug yourself? + options: + - label: Yes, I will patch the bug myself and send a pull request diff --git a/.github/ISSUE_TEMPLATE/02_feature-request.yml b/.github/ISSUE_TEMPLATE/02_feature-request.yml index 8420475b3e..8d7b0b2539 100644 --- a/.github/ISSUE_TEMPLATE/02_feature-request.yml +++ b/.github/ISSUE_TEMPLATE/02_feature-request.yml @@ -14,4 +14,9 @@ body: label: Purpose description: Describe the specific problem or need you think this feature will solve, and who it will help. validations: - required: true \ No newline at end of file + required: true + - type: checkboxes + attributes: + label: Do you want to implement this feature yourself? + options: + - label: Yes, I will implement this by myself and send a pull request diff --git a/.github/PULL_REQUEST_TEMPLATE/01_bug.md b/.github/PULL_REQUEST_TEMPLATE/01_bug.md index 8c688b5e3c..b367e4a39f 100644 --- a/.github/PULL_REQUEST_TEMPLATE/01_bug.md +++ b/.github/PULL_REQUEST_TEMPLATE/01_bug.md @@ -23,5 +23,5 @@ https://github.com/kokonect-link/cherrypick/blob/develop/CONTRIBUTING.md ## Checklist - [ ] Read the [contribution guide](https://github.com/kokonect-link/cherrypick/blob/develop/CONTRIBUTING.md) - [ ] Test working in a local environment -- [ ] (If needed) Update CHANGELOG.md +- [ ] (If needed) Update CHANGELOG_CHERRYPICK.md - [ ] (If possible) Add tests diff --git a/.github/PULL_REQUEST_TEMPLATE/02_enhance.md b/.github/PULL_REQUEST_TEMPLATE/02_enhance.md index 8c688b5e3c..b367e4a39f 100644 --- a/.github/PULL_REQUEST_TEMPLATE/02_enhance.md +++ b/.github/PULL_REQUEST_TEMPLATE/02_enhance.md @@ -23,5 +23,5 @@ https://github.com/kokonect-link/cherrypick/blob/develop/CONTRIBUTING.md ## Checklist - [ ] Read the [contribution guide](https://github.com/kokonect-link/cherrypick/blob/develop/CONTRIBUTING.md) - [ ] Test working in a local environment -- [ ] (If needed) Update CHANGELOG.md +- [ ] (If needed) Update CHANGELOG_CHERRYPICK.md - [ ] (If possible) Add tests diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5955f6b5d9..d4678ec5e0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -17,16 +17,32 @@ updates: directory: "/" schedule: interval: daily - # PNPM has an issue with dependabot. See: - # https://github.com/dependabot/dependabot-core/issues/7258 - # https://github.com/pnpm/pnpm/issues/6530 - # TODO: Restore this when the issue is solved - open-pull-requests-limit: 0 + open-pull-requests-limit: 10 + # List dependencies required to be updated together, sharing the same version numbers. + # Those who simply have the common owner (e.g. @fastify) don't need to be listed. groups: - swc: + aws-sdk: patterns: - - "@swc/*" + - "@aws-sdk/*" + bull-board: + patterns: + - "@bull-board/*" + nestjs: + patterns: + - "@nestjs/*" + slacc: + patterns: + - "slacc-*" storybook: patterns: - "storybook*" - "@storybook/*" + swc-core: + patterns: + - "@swc/core*" + typescript-eslint: + patterns: + - "@typescript-eslint/*" + tensorflow: + patterns: + - "@tensorflow/*" diff --git a/.github/labeler.yml b/.github/labeler.yml index 5312f3e328..bd234333b2 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,21 +1,34 @@ 'packages/backend': -- packages/backend/**/* +- any: + - changed-files: + - any-glob-to-any-file: ['packages/backend/**/*'] 'packages/backend:test': -- packages/backend/test/**/* +- any: + - changed-files: + - any-glob-to-any-file: ['packages/backend/test/**/*'] 'packages/frontend': -- packages/frontend/**/* +- any: + - changed-files: + - any-glob-to-any-file: ['packages/frontend/**/*'] 'packages/frontend:test': -- cypress/**/* +- any: + - changed-files: + - any-glob-to-any-file: ['cypress/**/*'] 'packages/sw': -- packages/sw/**/* +- any: + - changed-files: + - any-glob-to-any-file: ['packages/sw/**/*'] 'packages/cherrypick-js': -- packages/cherrypick-js/**/* +- any: + - changed-files: + - any-glob-to-any-file: ['packages/cherrypick-js/**/*'] 'packages/cherrypick-js:test': -- packages/cherrypick-js/test/**/* -- packages/cherrypick-js/test-d/**/* +- any: + - changed-files: + - any-glob-to-any-file: ['packages/cherrypick-js/test/**/*', 'packages/cherrypick-js/test-d/**/*'] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8c688b5e3c..b367e4a39f 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -23,5 +23,5 @@ https://github.com/kokonect-link/cherrypick/blob/develop/CONTRIBUTING.md ## Checklist - [ ] Read the [contribution guide](https://github.com/kokonect-link/cherrypick/blob/develop/CONTRIBUTING.md) - [ ] Test working in a local environment -- [ ] (If needed) Update CHANGELOG.md +- [ ] (If needed) Update CHANGELOG_CHERRYPICK.md - [ ] (If possible) Add tests diff --git a/.github/workflows/api-cherrypick-js.yml b/.github/workflows/api-cherrypick-js.yml index 4a9cdd847f..1d7b01eca8 100644 --- a/.github/workflows/api-cherrypick-js.yml +++ b/.github/workflows/api-cherrypick-js.yml @@ -1,6 +1,12 @@ name: API report (cherrypick.js) -on: [push, pull_request] +on: + push: + paths: + - packages/cherrypick-js/** + pull_request: + paths: + - packages/cherrypick-js/** jobs: report: @@ -14,7 +20,7 @@ jobs: - run: corepack enable - name: Setup Node.js - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index 7c20eb7913..f16123ad79 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -37,7 +37,7 @@ jobs: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -54,9 +54,9 @@ jobs: - name: Copy API.json run: cp packages/backend/built/api.json ${{ matrix.api-json-name }} - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: api-artifact + name: api-artifact-${{ matrix.api-json-name }} path: ${{ matrix.api-json-name }} save-pr-number: @@ -67,7 +67,7 @@ jobs: PR_NUMBER: ${{ github.event.number }} run: | echo "$PR_NUMBER" > ./pr_number - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: - name: api-artifact + name: api-artifact-pr-number path: pr_number diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index fa4a58c3a9..88e2aceaed 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -11,6 +11,6 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v4 + - uses: actions/labeler@v5 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 534856004c..856217bce7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,7 +5,19 @@ on: branches: - master - develop + paths: + - packages/backend/** + - packages/frontend/** + - packages/sw/** + - packages/cherrypick-js/** + - packages/shared/.eslintrc.js pull_request: + paths: + - packages/backend/** + - packages/frontend/** + - packages/sw/** + - packages/cherrypick-js/** + - packages/shared/.eslintrc.js jobs: pnpm_install: @@ -19,7 +31,7 @@ jobs: with: version: 8 run_install: false - - uses: actions/setup-node@v4.0.0 + - uses: actions/setup-node@v4.0.1 with: node-version-file: '.node-version' cache: 'pnpm' @@ -46,7 +58,7 @@ jobs: with: version: 7 run_install: false - - uses: actions/setup-node@v4.0.0 + - uses: actions/setup-node@v4.0.1 with: node-version-file: '.node-version' cache: 'pnpm' @@ -72,10 +84,12 @@ jobs: with: version: 7 run_install: false - - uses: actions/setup-node@v4.0.0 + - uses: actions/setup-node@v4.0.1 with: node-version-file: '.node-version' cache: 'pnpm' - run: corepack enable - run: pnpm i --frozen-lockfile + - run: pnpm --filter cherrypick-js run build + if: ${{ matrix.workspace == 'backend' }} - run: pnpm --filter ${{ matrix.workspace }} run typecheck diff --git a/.github/workflows/report-api-diff.yml b/.github/workflows/report-api-diff.yml index 9923a686d1..2c7df3fc7b 100644 --- a/.github/workflows/report-api-diff.yml +++ b/.github/workflows/report-api-diff.yml @@ -19,24 +19,28 @@ jobs: uses: actions/github-script@v7 with: script: | + const fs = require('fs'); let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, run_id: context.payload.workflow_run.id, }); - let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - return artifact.name == "api-artifact" - })[0]; - let download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', + let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name.startsWith("api-artifact-") || artifact.name == "api-artifact" }); - let fs = require('fs'); - fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/api-artifact.zip`, Buffer.from(download.data)); - - name: Extract artifact - run: unzip api-artifact.zip -d artifacts + await Promise.all(matchArtifacts.map(async (artifact) => { + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: artifact.id, + archive_format: 'zip', + }); + await fs.promises.writeFile(`${process.env.GITHUB_WORKSPACE}/${artifact.name}.zip`, Buffer.from(download.data)); + })); + - name: Extract all artifacts + run: | + find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec unzip {} -d artifacts ';' + ls -la - name: Load PR Number id: load-pr-num run: echo "pr-number=$(cat artifacts/pr_number)" >> "$GITHUB_OUTPUT" @@ -56,7 +60,7 @@ jobs: - name: Echo full diff run: cat ./api-full.json.diff - name: Upload full diff to Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: api-artifact path: | @@ -83,3 +87,11 @@ jobs: pr_number: ${{ steps.load-pr-num.outputs.pr-number }} comment_tag: show_diff filePath: ./output.md + - name: Tell error to PR + uses: thollander/actions-comment-pull-request@v2 + if: failure() && steps.load-pr-num.outputs.pr-number + with: + pr_number: ${{ steps.load-pr-num.outputs.pr-number }} + comment_tag: show_diff_error + message: | + api.json 간 차이점을 생성하는 도중 오류가 발생했습니다. 자세한 내용은 [Workflow 로그](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})를 확인해 주세요. diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index 5760a5620d..fd73994fe8 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -5,10 +5,18 @@ on: branches: - master - develop + paths: + - packages/backend/** + # for permissions + - packages/cherrypick-js/** pull_request: + paths: + - packages/backend/** + # for permissions + - packages/cherrypick-js/** jobs: - jest: + unit: runs-on: ubuntu-latest strategy: @@ -17,7 +25,7 @@ jobs: services: postgres: - image: postgres:13 + image: postgres:15 ports: - 54312:5432 env: @@ -38,7 +46,7 @@ jobs: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -51,9 +59,59 @@ jobs: - name: Build run: pnpm build - name: Test - run: pnpm jest-and-coverage - - name: Upload Coverage + run: pnpm --filter backend test-and-coverage + - name: Upload to Codecov uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/backend/coverage/coverage-final.json + + e2e: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.10.0] + + services: + postgres: + image: postgres:15 + ports: + - 54312:5432 + env: + POSTGRES_DB: test-cherrypick + POSTGRES_HOST_AUTH_METHOD: trust + redis: + image: redis:7 + ports: + - 56312:6379 + + steps: + - uses: actions/checkout@v4.1.1 + with: + submodules: true + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + run_install: false + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4.0.1 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + - run: corepack enable + - run: pnpm i --frozen-lockfile + - name: Check pnpm-lock.yaml + run: git diff --exit-code pnpm-lock.yaml + - name: Copy Configure + run: cp .github/cherrypick/test.yml .config + - name: Build + run: pnpm build + - name: Test + run: pnpm --filter backend test-and-coverage:e2e + - name: Upload to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./packages/backend/coverage/coverage-final.json diff --git a/.github/workflows/test-cherrypick-js.yml b/.github/workflows/test-cherrypick-js.yml index 792358d943..84b40c5769 100644 --- a/.github/workflows/test-cherrypick-js.yml +++ b/.github/workflows/test-cherrypick-js.yml @@ -6,8 +6,12 @@ name: Test (cherrypick.js) on: push: branches: [ develop ] + paths: + - packages/cherrypick-js/** pull_request: branches: [ develop ] + paths: + - packages/cherrypick-js/** jobs: test: @@ -26,7 +30,7 @@ jobs: - run: corepack enable - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 7ba92eb714..c73bf87ded 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -5,7 +5,20 @@ on: branches: - master - develop + paths: + - packages/frontend/** + # for permissions + - packages/cherrypick-js/** + # for e2e + - packages/backend/** + pull_request: + paths: + - packages/frontend/** + # for permissions + - packages/cherrypick-js/** + # for e2e + - packages/backend/** jobs: vitest: @@ -25,7 +38,7 @@ jobs: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -56,7 +69,7 @@ jobs: services: postgres: - image: postgres:13 + image: postgres:15 ports: - 54312:5432 env: @@ -83,7 +96,7 @@ jobs: version: 7 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -108,12 +121,12 @@ jobs: wait-on: 'http://localhost:61812' headed: true browser: ${{ matrix.browser }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: failure() with: name: ${{ matrix.browser }}-cypress-screenshots path: cypress/screenshots - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() with: name: ${{ matrix.browser }}-cypress-videos diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index ccf851f557..91f348600b 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -28,7 +28,7 @@ jobs: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml new file mode 100644 index 0000000000..bc5ba20cb9 --- /dev/null +++ b/.github/workflows/validate-api-json.yml @@ -0,0 +1,47 @@ +name: Test (backend) + +on: + push: + branches: + - master + - develop + paths: + - packages/backend/** + pull_request: + paths: + - packages/backend/** + +jobs: + validate-api-json: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.10.0] + + steps: + - uses: actions/checkout@v4.1.1 + with: + submodules: true + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + run_install: false + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4.0.1 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + - name: Install swagger-cli + run: npm i -g swagger-cli + - run: corepack enable + - run: pnpm i --frozen-lockfile + - name: Check pnpm-lock.yaml + run: git diff --exit-code pnpm-lock.yaml + - name: Copy Configure + run: cp .config/example.yml .config/default.yml + - name: Build and generate + run: pnpm build && pnpm --filter backend generate-api-json + - name: Validation + run: swagger-cli validate ./packages/backend/built/api.json diff --git a/.gitignore b/.gitignore index 74a0bb3c04..e8c19a1367 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ docker-compose.yml # cherrypick /build built +built-test /data /.cache-loader /db diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..c42da845b4 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict = true diff --git a/.vscode/settings.json b/.vscode/settings.json index 71fb02a59d..e2a82b1ffe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,11 +1,15 @@ { - "search.exclude": { - "**/node_modules": true - }, - "typescript.tsdk": "node_modules/typescript/lib", - "files.associations": { - "*.test.ts": "typescript" - }, - "jest.jestCommandLine": "pnpm run jest", - "jest.autoRun": "off" -} \ No newline at end of file + "search.exclude": { + "**/node_modules": true + }, + "typescript.tsdk": "node_modules/typescript/lib", + "files.associations": { + "*.test.ts": "typescript" + }, + "jest.jestCommandLine": "pnpm run jest", + "jest.autoRun": "off", + "editor.codeActionsOnSave": { + "source.fixAll": "explicit" + }, + "editor.formatOnSave": false +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 538fdc4cb5..510732cfb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,26 +5,107 @@ - ### Client -- Fix: ページ一覧ページの表示がモバイル環境において崩れているのを修正 -- Fix: MFMでルビの中のテキストがnyaizeされない問題を修正 +- ### Server - --> -## 2023.x.x (unreleased) +## 202x.x.x (Unreleased) + +### General +- Feat: [mCaptcha](https://github.com/mCaptcha/mCaptcha)のサポートを追加 +- Fix: リストライムラインの「リノートを表示」が正しく機能しない問題を修正 + +### Client +- Feat: 新しいゲームを追加 +- Enhance: ハッシュタグ入力時に、本文の末尾の行に何も書かれていない場合は新たにスペースを追加しないように +- Enhance: チャンネルノートのピン留めをノートのメニューからできるように +- Enhance: 管理者の場合はAPI tokenの発行画面で管理機能に関する権限を付与できるように +- Enhance: AiScriptを0.17.0に更新 [CHANGELOG](https://github.com/aiscript-dev/aiscript/blob/bb89d132b633a622d3cb0eff0d0cc7e476c0cfdd/CHANGELOG.md) + - 配列の範囲外・非整数のインデックスへの代入が完全禁止になるので注意 +- Enhance: 絵文字ピッカー・オートコンプリートで、完全一致した絵文字を優先的に表示するように +- Fix: ネイティブモードの絵文字がモノクロにならないように +- Fix: v2023.12.0で追加された「モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能」が管理画面上で正しく表示されていない問題を修正 +- Fix: AiScriptの`readline`関数が不正な値を返すことがある問題のv2023.12.0時点での修正がPlay以外に適用されていないのを修正 +- Fix: v2023.12.1で追加された`$[clickable ...]`および`onClickEv`が正しく機能していないのを修正 + +### Server +- Enhance: 連合先のレートリミットに引っかかった際にリトライするようになりました +- Enhance: ActivityPub Deliver queueでBodyを事前処理するように (#12916) +- Enhance: クリップをエクスポートできるように +- Fix: `drive/files/update`でファイル名のバリデーションが機能していない問題を修正 + +## 2023.12.2 + +### General +- v2023.12.1でDockerを利用してサーバーを起動できない問題を修正 + +### Client +- Enhance: 検索画面においてEnterキー押下で検索できるように + +## 2023.12.1 + +### Note +- アクセストークンの権限が再整理されたため、一部のAPIが古いAPIトークンでは動作しなくなりました。\ + 権限不足になる場合には権限を再設定して再生成してください。 + +### General +- Enhance: ローカリゼーションの更新 +- Fix: 自分のdirect noteがuser list timelineに追加されない + +### Client +- Feat: AiScript専用のMFM構文`$[clickable.ev=EVENTNAME ...]`を追加。`Mk:C:mfm`のオプション`onClickEv`に関数を渡すと、クリック時に`EVENTNAME`を引数にして呼び出す +- Enhance: MFM入力補助ボタンを投稿フォームに表示できるように #12787 +- Fix: 一部のモデログ(logYellowでの表示対象)について、表示の色が変わらない問題を修正 +- Fix: `fg`/`bg`MFMに長い単語を指定すると、オーバーフローされずはみ出る問題を修正 + +### Server +- Enhance: センシティブワードの設定がハッシュタグトレンドにも適用されるようになりました +- Enhance: `oauth/token`エンドポイントのCORS対応 +- Fix: 1702718871541-ffVisibility.jsのdownが壊れている +- Fix:「非センシティブのみ(リモートはいいねのみ)」を設定していても、センシティブに設定されたカスタム絵文字をリアクションできる問題を修正 +- Fix: ロールアサイン時の通知で,ロールアイコンが縮小されずに表示される問題を修正 +- Fix: サードパーティアプリケーションがWebsocket APIに無条件にアクセスできる問題を修正 +- Fix: サードパーティアプリケーションがユーザーの許可なしに非公開の情報を見ることができる問題を修正 + +## 2023.12.0 + +### Note +- 依存関係の更新に伴い、Node.js 20.10.0が最小要件になりました +- 絵文字の追加辞書を既にインストールしている場合は、お手数ですが再インストールのほどお願いします +- 絵文字ピッカーにピン留め表示する絵文字設定が「リアクション用」と「絵文字入力用」に分かれました。以前の設定は「リアクション用」として使用されます。 + + **影響:** + それにより、投稿フォームから表示される絵文字ピッカーのピン留め絵文字がリセットされたように感じるかもしれません(新設された"ピン留め(全般)"の設定が使われるため)。 + 投稿用のピン留め絵文字をアップデート前の状態にするには、以下の手順で操作します。 + + 1. 「設定」メニューに移動し、「絵文字ピッカー」タブを選択します。 + 2. 「ピン留 (全般)」のタブを選択します。 + 3. 「リアクション設定から上書きする」ボタンを押すことで、アップデート前の状態に戻すことができます。 ### General - Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed) - Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83) - Feat: TL上からノートが見えなくなるワードミュートであるハードミュートを追加 +- Enhance: 指定したドメインのメールアドレスの登録を弾くことができるように +- Enhance: 公開ロールにアサインされたときに通知が作成されるように +- Enhance: アイコンデコレーションを複数設定できるように +- Enhance: アイコンデコレーションの位置を微調整できるように +- Enhance: つながりの公開範囲をフォロー/フォロワーで個別に設定可能に #12072 +- Enhance: ローカリゼーションの更新 +- Enhance: 依存関係の更新 - Fix: MFM `$[unixtime ]` に不正な値を入力した際に発生する各種エラーを修正 ### Client - Feat: 今日誕生日のフォロー中のユーザーを一覧表示できるウィジェットを追加 -- Feat: データセーバーでコードハイライトの読み込みを削減できるように -- Enhance: 投稿フォームの絵文字ピッカーをリアクション時に使用するものと同じのを使用するように #12336 +- Feat: 画面に雪を降らせられるように +- Enhance: MFMのアニメーション要素(`tada`, `jelly`, `twitch`, `shake`, `spin`, `jump`, `bounce`, `rainbow`)に `delay` オプションを追加 +- Enhance: センシティブと判断されたウェブサイトのサムネイルを非表示に + - ウェブサイトをセンシティブと判断する仕組みが動いていないため、summalyProxyを使用しないと機能しません。 +- Enhance: 投稿フォームの絵文字ピッカーをリアクション時に使用するものと同じのを使用するように #12336 #12560 +- Enhance: リアクション用ピン留め絵文字と投稿時の絵文字入力用ピン留め絵文字を分けて設定できるように #12560 - Enhance: 絵文字のオートコンプリート機能強化 #12364 - Enhance: ユーザーのRawデータを表示するページが復活 - Enhance: リアクション選択時に音を鳴らせるように @@ -33,22 +114,50 @@ - Enhance: Shareページで投稿を完了すると、親ウィンドウ(親フレーム)にpostMessageするように - Enhance: チャンネル、クリップ、ページ、Play、ギャラリーにURLのコピーボタンを設置 #11305 - Enhance: ノートプレビューに「内容を隠す」が反映されるように +- Enhance: データセーバーでコードハイライトの読み込みを削減できるように - Enhance: データセーバーの適用範囲を個別で設定できるように - 従来のデータセーバーの設定はリセットされます -- Feat: センシティブと判断されたウェブサイトのサムネイルをぼかすように - - ウェブサイトをセンシティブと判断する仕組みが動いていないため、summalyProxyを使用しないと機能しません。 -- fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 -- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 +- Enhance: タイムライン上のタブからリスト、アンテナ、チャンネルの管理ページにジャンプできるように +- Enhance: ユーザー名、プロフィール、お知らせ、ページの編集画面でMFMや絵文字のオートコンプリートが使用できるように +- Enhance: プロフィール、お知らせの編集画面でMFMのプレビューを表示できるように - Enhance: 絵文字の詳細ページに記載される情報を追加 +- Enhance: リアクションの表示幅制限を設定可能に +- Enhance: Unicode 15.0のサポート +- Enhance: コードブロックのハイライト機能を利用するには言語を明示的に指定させるように + - MFMでコードブロックを利用する際に意図しないハイライトが起こらないようになりました + - 逆に、MFMでコードハイライトを利用したい際は言語を明示的に指定する必要があります + (例: ` ```js ` → Javascript, ` ```ais ` → AiScript) +- Enhance: 絵文字などのオートコンプリートでShift+Tabを押すと前の候補を選択できるように +- Enhance: チャンネルに新規の投稿がある場合にバッジを表示させる +- Enhance: サウンド設定に「サウンドを出力しない」と「Misskeyがアクティブな時のみサウンドを出力する」を追加 +- Enhance: 設定したタグをトレンドに表示させないようにする項目を管理画面で設定できるように +- Enhance: 絵文字ピッカーのカテゴリに「/」を入れることでフォルダ分け表示できるように +- Fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 +- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 - Fix: コードエディタが正しく表示されない問題を修正 - Fix: プロフィールの「ファイル」にセンシティブな画像がある際のデザインを修正 - Fix: 一度に大量の通知が入った際に通知音が音割れする問題を修正 - Fix: 共有機能をサポートしていないブラウザの場合は共有ボタンを非表示にする #11305 - Fix: 通知のグルーピング設定を変更してもリロードされるまで表示が変わらない問題を修正 #12470 - Fix: 長い名前のチャンネルにおける投稿フォームの表示が崩れる問題を修正 +- Fix: セキュリティ向上のためAiScriptの`Mk:apiExternal`を無効化 +- Fix: ノート中の絵文字をタップして「リアクションする」からリアクションした際にリアクションサウンドが鳴らない不具合を修正 +- Fix: ノート中のリアクションの表示を微調整 #12650 +- Fix: AiScriptの`readline`が不正な値を返すことがある問題を修正 +- Fix: 投票のみ/画像のみの引用RNが、通知欄でただのRNとして判定されるバグを修正 +- Fix: CWをつけて引用RNしても、普通のRNとして扱われてしまうバグを修正しました。 +- Fix: 「画像が1枚のみのメディアリストの高さ」を「デフォルト」以外に設定していると、CWの中などに添付された画像が見られないバグを修正 +- Fix: DeepL TranslationのPro accountトグルスイッチが表示されていなかったのを修正 +- Fix: twitterの埋め込みカード内リンクからリンク先を開けない問題を修正 +- Fix: WebKitブラウザー上でも「デバイスの画面を常にオンにする」機能が効くように +- Fix: ページ一覧ページの表示がモバイル環境において崩れているのを修正 +- Fix: MFMでルビの中のテキストがnyaizeされない問題を修正 ### Server - Enhance: MFM `$[ruby ]` が他ソフトウェアと連合されるように +- Enhance: Meilisearchを有効にした検索で、ユーザーのミュートやブロックを考慮するように +- Enhance: カスタム絵文字のインポート時の動作を改善 +- Enhance: json-schema(OpenAPIの戻り値として使用されるスキーマ定義)を出来る限り最新化 #12311 - Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303 - Fix: ロールタイムラインが保存されない問題を修正 - Fix: api.jsonの生成ロジックを改善 #12402 @@ -61,6 +170,10 @@ - Fix: ユーザのノート一覧にてインスタンスミュートが効かない問題 - Fix: チャンネルのノート一覧にてインスタンスミュートが効かない問題 - Fix: 「みつける」が年越し時に壊れる問題を修正 +- Fix: アカウントをブロックした際に、自身のユーザーのページでノートが相手に表示される問題を修正 +- Fix: モデレーションログがモデレーターは閲覧できないように修正 +- Fix: ハッシュタグのトレンド除外設定が即時に効果を持つように修正 +- Fix: HTTP Digestヘッダのアルゴリズム部分に大文字の"SHA-256"しか使えない ## 2023.11.1 @@ -71,7 +184,6 @@ - Feat: 管理者がコントロールパネルからメールアドレスの照会を行えるようになりました - Enhance: ローカリゼーションの更新 - Enhance: 依存関係の更新 -- Enhance: json-schema(OpenAPIの戻り値として使用されるスキーマ定義)を出来る限り最新化 #12311 ### Client - Enhance: MFMでルビを振れるように @@ -80,7 +192,6 @@ - 例: `$[unixtime 1701356400]` - Enhance: プラグインでエラーが発生した場合のハンドリングを強化 - Enhance: 細かなUIのブラッシュアップ -- Enhance: サウンド設定に「サウンドを出力しない」と「Misskeyがアクティブな時のみサウンドを出力する」を追加 - Fix: 効果音が再生されるとデバイスで再生している動画や音声が停止する問題を修正 #12339 - Fix: デッキに表示されたチャンネルの表示先チャンネルを切り替えた際、即座に反映されない問題を修正 #12236 - Fix: プラグインでノートの表示を書き換えられない問題を修正 @@ -108,7 +219,7 @@ ### General - Feat: アイコンデコレーション機能 - サーバーで用意された画像をアイコンに重ねることができます - - 画像のテンプレートはこちらです: https://misskey-hub.net/avatar-decoration-template.png + - 画像のテンプレートはこちらです: https://misskey-hub.net/brand-assets/ - 最大でも黄色いエリア内にデコレーションを収めることを推奨します。 - 画像は512x512pxを推奨します。 - Feat: チャンネル設定にリノート/引用リノートの可否を設定できる項目を追加 @@ -125,7 +236,7 @@ ### Client - Feat: プラグイン・テーマを外部サイトから直接インストールできるようになりました - 外部サイトでの実装が必要です。詳細は Misskey Hub をご覧ください - https://misskey-hub.net/docs/advanced/publish-on-your-website.html + https://misskey-hub.net/docs/for-developers/publish-on-your-website/ - Feat: 通知をグルーピングして表示するオプション(オプトアウト) - Feat: Misskeyの基本的なチュートリアルを実装 - Feat: スワイプしてタイムラインを再読込できるように @@ -190,7 +301,6 @@ ### Client - Enhance: TLの返信表示オプションを記憶するように - Enhance: 投稿されてから時間が経過しているノートであることを視覚的に分かりやすく -- Feat: 絵文字ピッカーのカテゴリに「/」を入れることでフォルダ分け表示できるように ### Server - Enhance: タイムライン取得時のパフォーマンスを向上 diff --git a/CHANGELOG_CHERRYPICK.md b/CHANGELOG_CHERRYPICK.md index cd909cb46e..21eec20aa4 100644 --- a/CHANGELOG_CHERRYPICK.md +++ b/CHANGELOG_CHERRYPICK.md @@ -23,29 +23,42 @@ Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023xx](CHANGE # 릴리즈 노트 이 문서는 CherryPick의 변경 사항만 포함합니다. -> Misskey 또는 CherryPick v4.3.0 이전 버전에서 마이그레이션 하는 경우, 버전 관리 방식의 차이 때문에 기존 버전보다 낮은 것으로 인식되어 마이그레이션 이후 업데이트 관련 대화 상자가 표시되지 않을 수 있습니다. -> -> 또한, 일부 locale이 누락되거나 기능이 정상적으로 작동하지 않는 등의 문제가 발생할 수 있으나 이는 정상적인 동작으로, -> 문제가 발생하면 '설정 - 캐시 비우기'를 진행하거나, 브라우저 캐시를 삭제하십시오. - ## 4.x.x 출시일: unreleased
기반 Misskey 버전: 2023.x.x
Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023xx](CHANGELOG.md#2023xx) 문서를 참고하십시오. +### Client +- Enhance: 빌트인 테마를 설치하려고 할 때 오류 메시지 개선 +- Fix: 장식 추가로 일부 태그를 추가할 수 없음 +- Fix: 알림 위젯 필터링이 작동하지 않을 수 있음 #404 + +--- + +## 4.6.0 +출시일: 2024/1/08
+기반 Misskey 버전: 2023.12.2
+Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023122](CHANGELOG.md#2023122) 문서를 참고하십시오. + ### General - Change: 노트를 번역할 때 유저가 고양이로 설정되어 있으면 nyaize를 적용 +- Change: Misskey 또는 CherryPick v4.3.0 이전 버전에서 마이그레이션 시, 마이그레이션 관련 대화 상자가 표시됨 - Feat: 리모트 서버의 이모지를 즉시 가져올 수 있음 ([pikokr/cherrypicnic@03d536c0](https://github.com/pikokr/cherrypicnic/commit/03d536c00212f2dfbebecf75e5d58e0ddb749444), [pikokr/cherrypicnic@8a2d6f3b](https://github.com/pikokr/cherrypicnic/commit/8a2d6f3b518fc13a6c32364780fba3be5eea3e5d)) -- Feat: 아이콘 장식을 여러 개 겹칠 수 있음 ([Secineralyr/misskey.dream@d929c8bf](https://github.com/Secineralyr/misskey.dream/commit/d929c8bf97add7fac64c12e0bcdfaa164031f864)) + - 노트 본문 및 리액션 뷰어에서 사용 가능 - Feat: 아이콘 장식을 세부 조정할 수 있음 ([Secineralyr/misskey.dream@b3299181](https://github.com/Secineralyr/misskey.dream/commit/b329918194f1991c84633361d8a1319cf203641c), [Secineralyr/misskey.dream@1a9642bb](https://github.com/Secineralyr/misskey.dream/commit/1a9642bb9087a256522767e113c3bbfa87ec2e47)) - 위치, 크기, 불투명도를 추가로 조정할 수 있습니다. - Feat: 노트를 클릭하여 자세히 볼 수 있음 +- Feat: 텍스트 장식(MFM, HTML, Markdown)을 보다 편하게 추가할 수 있음 + - 노트 작성 폼에서 텍스트 장식 버튼을 눌러 사용할 수 있음 + - 텍스트를 선택한 상태에서도 적용 가능 +- Enhance: 다양한 자산의 출력 파일 이름에 CherryPick 버전을 포함하도록 설정 ([MisskeyIO/misskey@436ddb8f](https://github.com/MisskeyIO/misskey/commit/436ddb8fdb2e585987f403c1527915947c7aae7c)) - Revert: 사용자 통계 표시 기능 제거 ([MisskeyIO/misskey@114c7fe6](https://github.com/MisskeyIO/misskey/commit/114c7fe6b37dd6bddbcd9d92406f8b13bf688e8b)) ### Client - Feat: 데이터 절약 모드로 코드 하이라이트 로드를 줄일 수 있음 (misskey-dev/misskey#12526) - Feat: InstanceTicker를 클릭해 노트를 자세히 볼 수 있음 - 리모트에서 수신된 노트인 경우, '리모트에서 보기'로 작동함 +- Feat: 신규 도전 과제 추가 - Enhance: 사운드 설정을 기본값으로 복원하거나 저장할 때 확실하게 표시함 - Enhance: 리모트 서버와 동일한 이모지가 존재하지 않는 경우 '이모지 복사'를 비활성화함 - Enhance: 아이콘 장식을 바로 업로드 하거나 드라이브에서 불러올 수 있음 ([Secineralyr/misskey.dream@e358212d](https://github.com/Secineralyr/misskey.dream/commit/e358212da93256749e31d9e0ca9dd2ed37fd548e), [Secineralyr/misskey.dream@52592fea](https://github.com/Secineralyr/misskey.dream/commit/52592fea52684497ba7e07f173aac2b1083afcb1)) @@ -57,6 +70,21 @@ Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023xx](CHANGE - 기존 데이터 절약 모드 설정이 재설정됩니다. - Enhance: 컴포넌트만 새로 고쳐도 적용할 수 있는 설정은 페이지를 새로 고치지 않고 설정을 반영함 - 각 기능이 적용되는 컴포넌트(타임라인, 알림)에 따라 해당 컴포넌트만 새로 로드됩니다. +- Enhance: 페이지를 새로 불러오지 않고 알림 컴포넌트를 갱신할 수 있음 +- Enhance: 리노트 개선 #400 + - 리노트 시 공개 범위를 설정할 수 있음 +- Enhance: 사용자 팝업 개선 + - 자신의 프로필인 경우, 팔로우 버튼을 프로필 편집 버튼으로 표시함 +- Enhance: 노트 상세 페이지의 노트 작성 폼에서 노트를 게시했을 때 작성 폼을 다시 닫도록 변경함 +- Enhance: 액세스 토큰 개선 + - 토큰을 생성할 때 토큰을 복사할 필요없이 '확인' 버튼을 누르면 자동으로 클립보드에 토큰이 복사됨 + - 토큰을 삭제할 때 삭제 전 대화 상자가 표시됨 +- Enhance: 링크 또는 내용을 복사할 때 토스트 알림 표시 +- Enhance: HTML 태그 및 Markdown 태그가 자동 완성을 지원함 + - `<`를 입력하면 ``, ~~, , ,
, , `, ```, \(\), \(\\ \)`` 태그를 자동으로 입력할 수 있음 +- Enhance: 서버에서 푸시 알림을 사용할 수 있으면 푸시 알림을 활성화 하도록 대화 상자를 표시 +- Enhance: 리액션 뷰어에서 우클릭하면 리액션을 복사할 수 있음 +- Enhance: 대화 페이지를 새로 고치지 않아도 자동으로 갱신함 - Fix: '모달 배경색 제거' 옵션이 이모지 피커에 반영되지 않음 - Fix: 열람 주의로 설정된 노트의 리액션이 '더 보기'를 눌러야 표시됨 - Fix: 채널 이름이 긴 경우 게시 양식 표시가 깨지는 문제 (misskey-dev/misskey#12524) @@ -64,9 +92,37 @@ Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023xx](CHANGE - Fix: 모바일 환경에서 스크롤 시 헤더 위에 요소가 존재할 경우 헤더 디자인에 문제가 발생함 - Fix: '모든 미디어 노트 간략화하기' 옵션을 활성화하면 미디어가 없는 노트가 잘려서 표시될 수 있음 - Fix: 모바일 환경에서 헤더 타이틀 부분을 터치할 때 영역이 강조되어 표시될 수 있음 +- Fix: 서브 노트에서 액션 버튼의 클릭 가능 영역이 매우 작게 설정될 수 있음 +- Fix: 내 프로필에서 간헐적으로 헤더에 MkFollowButton 컴포넌트가 표시될 수 있음 +- Fix: 다이렉트 노트를 리노트 할 수 있음 +- Fix: 이모지를 변경할 때 이모지가 '❤️'로 고정될 수 있음 +- Fix: 일부 환경에서 특정 영역에 스크롤 바가 표시될 수 있음 +- Fix: 일부 검색 페이지에서 Enter 키를 눌러 검색할 수 없음 +- Fix: 서버 이름이 매우 긴 경우, 후원(MkDonation) 대화 상자의 디자인이 잘못 표시될 수 있음 +- Fix: 화면이 작은 기기에서 Play의 액션 버튼이 잘려서 보일 수 있음 +- Fix: 노트 상세 페이지에서 노트 작성 폼을 클릭했을 때, 노트 작성자가 자동으로 멘션에 포함되지 않을 수 있음 +- Fix: 링크를 인용해서 노트를 작성할 때 노트 작성 폼의 디자인이 올바르지 않게 표시됨 +- Fix: MFM 도움말의 수식(블록) 항목이 누락됨 +- Fix: Temml를 사용할 때 폰트가 올바르게 표시되지 않을 수 있음 +- Fix: 열람 주의로 설정된 미디어가 답글 또는 인용된 경우 '더 보기' 버튼을 누를 수 없음 +- Fix: 노트 공개 범위가 비공개인 노트를 편집하면 다른 사용자가 노트 편집 기록을 볼 수 있음 +- Fix: 대화 목록의 인디케이터가 중복 및 잘못된 위치에 표시될 수 있음 +- Fix: 노트 작성 폼에서 링크 프리뷰가 표시될 수 있음 ### Server +- Feat: Bearcaps URL 지원 (MisskeyIO/misskey#330) - Enhance: (dev) 개발 모드에서 locale 및 유형 정의가 자동으로 재생성됨 (misskey-dev/misskey#12481) +- Enhance: 푸시 알림 개선 + - 개인간 대화 알림을 받았을 때, 대화 내용을 푸시 알림에 표시 + - 그룹간 대화 알림을 받았을 때, 대화를 보낸 사용자와 내용을 표시 + - 팔로우 알림에 Acct 및 host 정보 표시 + - 리액션 알림 디자인 개선 +- Enhance: 사용자 반응 목록 API 성능 향상 (MisskeyIO/misskey#278) +- Fix: RedisKVCache에서 Redis에서 읽은 값을 MemoryKVCache에 다시 쓰기 (MisskeyIO/misskey#289) +- Fix: redisForJobQueue 연결 사용 (MisskeyIO/misskey#268) +- Fix: redisForJobQueue의 maxRetriesPerRequest를 null로 설정 (MisskeyIO/misskey#272) +- Fix: Inbox 또는 Deliver 큐에 data 필드가 비어 있는 작업이 등록되지 않도록 (MisskeyIO/misskey#307) +- Fix: Misskey에서 CherryPick으로 마이그레이션 하면 타임라인이 표시되지 않음 --- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 303fd9e495..2384ebc663 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,6 +117,10 @@ command. - Server-side source files and automatically builds them if they are modified. Automatically start the server process(es). - Vite HMR (just the `vite` command) is available. The behavior may be different from production. - Service Worker is watched by esbuild. +- The front end can be viewed by accessing `http://localhost:5173`. +- The backend listens on the port configured with `port` in .config/default.yml. +If you have not changed it from the default, it will be "http://localhost:3000". +If "port" in .config/default.yml is set to something other than 3000, you need to change the proxy settings in packages/frontend/vite.config.local-dev.ts. ### Dev Container Instead of running `pnpm` locally, you can use Dev Container to set up your development environment. diff --git a/COPYING b/COPYING index c218443d42..57ad466702 100644 --- a/COPYING +++ b/COPYING @@ -1,10 +1,10 @@ Unless otherwise stated this repository is -Copyright © 2014-2023 syuilo and contributers +Copyright © 2014-2024 syuilo and noridev and other misskey, cherrypick contributors And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE. -Misskey includes several third-party Open-Source softwares. +CherryPick includes several third-party Open-Source softwares. Emoji keywords for Unicode 11 and below by Mu-An Chiou License: MIT diff --git a/Dockerfile b/Dockerfile index 4ccd2d5c0d..75ff80d229 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,6 +51,7 @@ WORKDIR /cherrypick COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"] COPY --link ["scripts", "./scripts"] COPY --link ["packages/backend/package.json", "./packages/backend/"] +COPY --link ["packages/cherrypick-js/package.json", "./packages/cherrypick-js/"] RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ pnpm i --frozen-lockfile --aggregate-output @@ -77,7 +78,9 @@ WORKDIR /cherrypick COPY --chown=cherrypick:cherrypick --from=target-builder /cherrypick/node_modules ./node_modules COPY --chown=cherrypick:cherrypick --from=target-builder /cherrypick/packages/backend/node_modules ./packages/backend/node_modules +COPY --chown=cherrypick:cherrypick --from=target-builder /cherrypick/packages/cherrypick-js/node_modules ./packages/cherrypick-js/node_modules COPY --chown=cherrypick:cherrypick --from=native-builder /cherrypick/built ./built +COPY --chown=cherrypick:cherrypick --from=native-builder /cherrypick/packages/cherrypick-js/built ./packages/cherrypick-js/built COPY --chown=cherrypick:cherrypick --from=native-builder /cherrypick/packages/backend/built ./packages/backend/built COPY --chown=cherrypick:cherrypick --from=native-builder /cherrypick/fluent-emojis /cherrypick/fluent-emojis COPY --chown=cherrypick:cherrypick . ./ diff --git a/README.md b/README.md index 477a8522ab..839faf85b7 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ --- - + find an instance - + create an instance @@ -51,7 +51,7 @@ With CherryPick's built in drive, you get cloud storage right in your social med ## Documentation -CherryPick Documentation can be found at [Misskey Hub](https://misskey-hub.net/), some of the links and graphics above also lead to specific portions of it. +CherryPick Documentation can be found at [Misskey Hub](https://misskey-hub.net/docs/), some of the links and graphics above also lead to specific portions of it. ## Sponsors diff --git a/ROADMAP.md b/ROADMAP.md index 3077c41e73..509ecb9fe7 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -6,6 +6,7 @@ Also, the later tasks are more indefinite and are subject to change as developme This is the phase we are at now. We need to make a high-maintenance environment that can withstand future development. - ~~Make the number of type errors zero (backend)~~ → Done ✔️ +- Make the number of type errors zero (frontend) - Improve CI - ~~Fix tests~~ → Done ✔️ - Fix random test failures - https://github.com/misskey-dev/misskey/issues/7985 and https://github.com/misskey-dev/misskey/issues/7986 diff --git a/SECURITY.md b/SECURITY.md index 8f519510c6..7385d0a288 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,7 +1,6 @@ # Reporting Security Issues -If you discover a security issue in Misskey, please report it by sending an -email to [syuilotan@yahoo.co.jp](mailto:syuilotan@yahoo.co.jp). +If you discover a security issue in Misskey, please report it by **[this form](https://github.com/misskey-dev/misskey/security/advisories/new)**. This will allow us to assess the risk, and make a fix available before we add a bug report to the GitHub repository. diff --git a/chart/files/default.yml b/chart/files/default.yml index 128502312c..d8774b6ea7 100644 --- a/chart/files/default.yml +++ b/chart/files/default.yml @@ -167,7 +167,7 @@ id: "aidx" # Job rate limiter # deliverJobPerSec: 128 -# inboxJobPerSec: 16 +# inboxJobPerSec: 32 # Job attempts # deliverJobMaxAttempts: 12 diff --git a/chart/templates/Deployment.yml b/chart/templates/Deployment.yml index f470280799..af543bd7f5 100644 --- a/chart/templates/Deployment.yml +++ b/chart/templates/Deployment.yml @@ -27,7 +27,7 @@ spec: ports: - containerPort: 3000 - name: postgres - image: postgres:14-alpine + image: postgres:15-alpine env: - name: POSTGRES_USER value: "example-cherrypick-user" @@ -38,7 +38,7 @@ spec: ports: - containerPort: 5432 - name: redis - image: redis:alpine + image: redis:7-alpine ports: - containerPort: 6379 volumes: diff --git a/docker-compose.local-db.yml b/docker-compose.local-db.yml new file mode 100644 index 0000000000..16ba4b49e1 --- /dev/null +++ b/docker-compose.local-db.yml @@ -0,0 +1,42 @@ +version: "3" + +# このconfigは、 dockerでMisskey本体を起動せず、 redisとpostgresql などだけを起動します + +services: + redis: + restart: always + image: redis:7-alpine + ports: + - "6379:6379" + volumes: + - ./redis:/data + healthcheck: + test: "redis-cli ping" + interval: 5s + retries: 20 + + db: + restart: always + image: postgres:15-alpine + ports: + - "5432:5432" + env_file: + - .config/docker.env + volumes: + - ./db:/var/lib/postgresql/data + healthcheck: + test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB" + interval: 5s + retries: 20 + +# meilisearch: +# restart: always +# image: getmeili/meilisearch:v1.3.4 +# environment: +# - MEILI_NO_ANALYTICS=true +# - MEILI_ENV=production +# env_file: +# - .config/meilisearch.env +# volumes: +# - ./meili_data:/meili_data + diff --git a/docker-compose_example.yml b/docker-compose_example.yml index 1dc184ce0c..618fd12270 100644 --- a/docker-compose_example.yml +++ b/docker-compose_example.yml @@ -7,6 +7,7 @@ services: links: - db - redis +# - mcaptcha # - meilisearch depends_on: db: @@ -48,6 +49,36 @@ services: interval: 5s retries: 20 +# mcaptcha: +# restart: always +# image: mcaptcha/mcaptcha:latest +# networks: +# internal_network: +# external_network: +# aliases: +# - localhost +# ports: +# - 7493:7493 +# env_file: +# - .config/docker.env +# environment: +# PORT: 7493 +# MCAPTCHA_redis_URL: "redis://mcaptcha_redis/" +# depends_on: +# db: +# condition: service_healthy +# mcaptcha_redis: +# condition: service_healthy +# +# mcaptcha_redis: +# image: mcaptcha/cache:latest +# networks: +# - internal_network +# healthcheck: +# test: "redis-cli ping" +# interval: 5s +# retries: 20 + # meilisearch: # restart: always # image: getmeili/meilisearch:v1.3.4 diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 87a951ac80..84c6e99ca8 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -120,7 +120,6 @@ sensitive: "محتوى حساس" add: "إضافة" reaction: "التفاعلات" reactions: "التفاعلات" -reactionSetting: "التفاعلات المراد عرضها في منتقي التفاعلات." reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة." rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات" attachCancel: "أزل المرفق" @@ -418,7 +417,6 @@ share: "شارِك" notFound: "غير موجود" notFoundDescription: "تعذر العثور على صفحة يقود إليها هذا الرابط." uploadFolder: "المجلد الافتراضي للرفع" -cacheClear: "مسح ذاكرة التخزين المؤقت" markAsReadAllNotifications: "وضع جميع الإشعارات كأنها مقروءة" markAsReadAllUnreadNotes: "علّم جميع الملاحظات كمقروءة" markAsReadAllTalkMessages: "علّم جميع الرسائل كمقروءة" @@ -802,7 +800,7 @@ hashtags: "الوسوم" troubleshooting: "استكشاف الأخطاء وإصلاحها" useBlurEffect: "استخدم تأثير الطمس في الواجهة" learnMore: "راجع المزيد" -misskeyUpdated: "حُدث ميسكي!" +misskeyUpdated: "حُدث CherryPick!" whatIsNew: "اعرض التغييرات" translate: "ترجم" translatedFrom: "تُرجم من {x}" @@ -830,8 +828,6 @@ makeReactionsPublicDescription: "هذا سيجعل قائمة تفاعلاتك classic: "تقليدي" muteThread: "اكتم النقاش" unmuteThread: "ارفع الكتم عن النقاش" -ffVisibility: "مرئية المتابِعين/المتابَعين" -ffVisibilityDescription: "يسمح لك بتحديد من يمكنهم رؤية متابِعيك ومتابَعيك." continueThread: "اعرض بقية النقاش" deleteAccountConfirm: "سيحذف حسابك نهائيًا، أتريد المتابعة؟" incorrectPassword: "كلمة السر خاطئة." @@ -925,7 +921,7 @@ numberOfLikes: "الإعجابات" show: "المظهر" neverShow: "لا تظهره مجددًا" remindMeLater: "ربما لاحقا" -didYouLikeMisskey: "هل أعجبك ميسكي؟" +didYouLikeMisskey: "هل أعجبك CherryPick؟" pleaseDonate: "يستخدم {host} البرمجية الحرة ميسكي. نتمنى أن تتبرعوا للمشروع مما سيسمح لنا متابعة تطويره!" roles: "الأدوار" role: "الدور" @@ -962,9 +958,12 @@ rolesAssignedToMe: "الأدوار المسندة إلي" resetPasswordConfirm: "هل تريد إعادة تعيين كلمة السر؟" license: "الرخصة" unfavoriteConfirm: "أتريد إزالتها من المفضلة؟" +reactionsDisplaySize: "حجم التفاعلات" +limitWidthOfReaction: "تصغير حجم التفاعلات" noteIdOrUrl: "معرف الملاحظة أو رابطها" video: "فيديو" videos: "فيديوهات" +dataSaver: "موفر البيانات" accountMigration: "ترحيل الحساب" accountMoved: "نقل هذا المستخدم حسابه:" accountMovedShort: "رُحل هذا الحساب." @@ -972,6 +971,7 @@ operationForbidden: "عملية ممنوعة" forceShowAds: "أظهر الإعلانات التجارية دائما" reactionsList: "التفاعلات" renotesList: "إعادات النشر" +notificationDisplay: "إشعارات" leftTop: "أعلى اليسار" rightTop: "أعلى اليمين" leftBottom: "أسفل اليسار" @@ -994,6 +994,7 @@ thisChannelArchived: "أُرشفت هذه القناة." displayOfNote: "عرض الملاحظة" initialAccountSetting: "إعداد الملف الشخصي" youFollowing: "متابَع" +preventAiLearning: "منع استخدام البيانات في تعليم الآلة" options: "خيارات" specifyUser: "مستخدم محدد" failedToPreviewUrl: "تتعذر المعاينة" @@ -1004,10 +1005,19 @@ rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "يجب أن تكون ال cancelReactionConfirm: "أتريد حذف تفاعلك؟" changeReactionConfirm: "أتريد تعديل تفاعلك؟" later: "لاحقاً" -goToMisskey: "لميسكي" +goToMisskey: "لCherryPick" additionalEmojiDictionary: "قواميس إيموجي إضافية" installed: "مُثبت" +enableServerMachineStats: "نشر إحصائيات عتاد الخادم" +turnOffToImprovePerformance: "تفعيله قد يزيد الأداء." +createInviteCode: "ولِّد دعوة" +inviteCodeCreated: "ولِّدت دعوة" +inviteLimitExceeded: "وصلتَ لحد عدد الدعوات المسموح لك توليدها." +createLimitRemaining: "حد عدد الدعوات: {limit} دعوة" expirationDate: "تاريخ انتهاء الصلاحية" +noExpirationDate: "لا نهاية لصلاحيتها" +inviteCodeUsedAt: "اُستخدم رمز الدعوة في" +registeredUserUsingInviteCode: "اِستخدم رمز الدعوة" unused: "غير مستعمَل" expired: "منتهية صلاحيته" icon: "الصورة الرمزية" @@ -1517,8 +1527,6 @@ _notification: youGotReply: "ردّ عليك {name}" youGotQuote: "اقتبس {name} منشورك" youRenoted: "أعاد {name} نشر منشورك" - youGotMessagingMessageFromUser: "لقد تلقيت رسالة مِن {name}" - youGotMessagingMessageFromGroup: "لقد أرسِلَت رسالة إلى الفريق {name}" youWereFollowed: "يتابعك" youReceivedFollowRequest: "تلقيتَ طلب متابعة" yourFollowRequestAccepted: "قُبل طلب المتابعة" @@ -1570,3 +1578,4 @@ _webhookSettings: _moderationLogTypes: suspend: "علِق" resetPassword: "أعد تعيين كلمتك السرية" + createInvitation: "ولِّد دعوة" diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index f15aa16a70..85fa28a472 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -2,6 +2,7 @@ _lang_: "বাংলা" headlineMisskey: "নোট ব্যাবহার করে সংযুক্ত নেটওয়ার্ক" introMisskey: "স্বাগতম! মিসকি একটি ওপেন সোর্স, ডিসেন্ট্রালাইজড মাইক্রোব্লগিং পরিষেবা। \n\"নোট\" তৈরির মাধ্যমে যা ঘটছে তা সবার সাথে শেয়ার করুন 📡\n\"রিঅ্যাকশন\" গুলির মাধ্যমে যেকোনো নোট সম্পর্কে আপনার অনুভূতি ব্যাক্ত করতে পারেন 👍\nএকটি নতুন দুনিয়া ঘুরে দেখুন 🚀\n" +poweredByMisskeyDescription: "{name} হল ওপেন সোর্স প্ল্যাটফর্ম CherryPick-এর সার্ভারগুলির একটি৷" monthAndDay: "{day}/{month}" search: "খুঁজুন" notifications: "বিজ্ঞপ্তি" @@ -12,12 +13,14 @@ fetchingAsApObject: "ফেডিভার্স থেকে খবর আন ok: "ঠিক" gotIt: "বুঝেছি" cancel: "বাতিল" +noThankYou: "না, ধন্যবাদ" enterUsername: "ইউজারনেম লিখুন" renotedBy: "{user} রিনোট করেছেন" noNotes: "কোন নোট নেই" noNotifications: "কোনো বিজ্ঞপ্তি নেই" instance: "ইন্সট্যান্স" settings: "সেটিংস" +notificationSettings: "বিজ্ঞপ্তির সেটিংস" basicSettings: "সাধারণ সেটিংস" otherSettings: "অন্যান্য সেটিংস" openInWindow: "নতুন উইন্ডোতে খুলা" @@ -42,12 +45,20 @@ pin: "পিন করা" unpin: "পিন সরান" copyContent: "বিষয়বস্তু কপি করুন" copyLink: "লিঙ্ক কপি করুন" +copyLinkRenote: "রিনোট লিঙ্ক কপি করুন" delete: "মুছুন" deleteAndEdit: "মুছুন এবং সম্পাদনা করুন" deleteAndEditConfirm: "আপনি কি এই নোটটি মুছে এটি সম্পাদনা করার বিষয়ে নিশ্চিত? আপনি এটির সমস্ত রিঅ্যাকশন, রিনোট এবং জবাব হারাবেন।" addToList: "লিস্ট এ যোগ করুন" +addToAntenna: "অ্যান্টেনা এ যোগ করুন" sendMessage: "একটি বার্তা পাঠান" +copyRSS: "RSS কপি করুন" copyUsername: "ব্যবহারকারীর নাম কপি করুন" +copyUserId: "ব্যবহারকারীর ID কপি করুন" +copyNoteId: "নোটের ID কপি করুন" +copyFileId: "ফাইল ID কপি করুন" +copyFolderId: "ফোল্ডার ID কপি করুন" +copyProfileUrl: "প্রোফাইল URL কপি করুন" searchUser: "ব্যবহারকারী খুঁজুন..." reply: "জবাব" loadMore: "আরও দেখুন" @@ -100,6 +111,8 @@ renoted: "রিনোট করা হয়েছে" cantRenote: "এই নোটটি রিনোট করা যাবে না।" cantReRenote: "রিনোটকে রিনোট করা যাবে না।" quote: "উদ্ধৃতি" +inChannelRenote: "চ্যানেলে রিনোট" +inChannelQuote: "চ্যানেলে উদ্ধৃতি" pinnedNote: "পিন করা নোট" pinned: "পিন করা" you: "আপনি" @@ -108,7 +121,10 @@ sensitive: "সংবেদনশীল বিষয়বস্তু" add: "যুক্ত করুন" reaction: "প্রতিক্রিয়া" reactions: "প্রতিক্রিয়া" -reactionSetting: "রিঅ্যাকশন পিকারে যেসকল প্রতিক্রিয়া দেখানো হবে" +emojiPicker: "ইমোজি পিকার" +pinnedEmojisForReactionSettingDescription: "রিঅ্যাকশন দেয়ার সময় আপনি ইমোজিটিকে পিন করা এবং প্রদর্শিত হওয়ার জন্য সেট করতে পারেন।" +pinnedEmojisSettingDescription: "ইমোজি ইনপুট দেয়ার সময় আপনি ইমোজিটিকে পিন করা এবং প্রদর্শিত হওয়ার জন্য সেট করতে পারেন।" +emojiPickerDisplay: "পিকার ডিসপ্লে" reactionSettingDescription2: "পুনরায় সাজাতে টেনে আনুন, মুছতে ক্লিক করুন, যোগ করতে + টিপুন।" rememberNoteVisibility: "নোটের দৃশ্যমান্যতার সেটিংস মনে রাখুন" attachCancel: "অ্যাটাচমেন্ট সরান " @@ -393,7 +409,6 @@ share: "শেয়ার" notFound: "পাওয়া যায়নি" notFoundDescription: "এই URL-এর সাথে সম্পর্কিত কোনো পৃষ্ঠা নেই।" uploadFolder: "আপলোডের জন্য ডিফল্ট ফোল্ডার" -cacheClear: "ক্যাশ পরিষ্কার করুন" markAsReadAllNotifications: "সমস্ত বিজ্ঞপ্তিগুলি পঠিত হিসাবে চিহ্নিত করুন" markAsReadAllUnreadNotes: "সমস্ত নোটগুলি পঠিত হিসাবে চিহ্নিত করুন" markAsReadAllTalkMessages: "সমস্ত মেসেজ পঠিত হিসাবে চিহ্নিত করুন" @@ -806,8 +821,6 @@ makeReactionsPublicDescription: "আপনার পূর্ববর্তী classic: "ক্লাসিক" muteThread: "থ্রেড মিউট করুন" unmuteThread: "থ্রেড আনমিউট করুন" -ffVisibility: "অনুসরণ/অনুসরণকারীদের দৃশ্যমান্যতা" -ffVisibilityDescription: "আপনি কাকে অনুসরণ করেন এবং কে আপনাকে অনুসরণ করে, সেটা কারা দেখতে পাবে তা নির্ধারণ করে।" continueThread: "আরো থ্রেড দেখুন" deleteAccountConfirm: "আপনার অ্যাকাউন্ট মুছে ফেলা হবে। ঠিক আছে?" incorrectPassword: "আপনার দেওয়া পাসওয়ার্ডটি ভুল।" @@ -1140,6 +1153,7 @@ _2fa: step3: "অ্যাপে প্রদর্শিত টোকেনটি লিখুন এবং আপনার কাজ শেষ।" step4: "আপনাকে এখন থেকে লগ ইন করার সময়, এইভাবে টোকেন লিখতে হবে।" securityKeyInfo: "আপনি একটি হার্ডওয়্যার সিকিউরিটি কী ব্যবহার করে লগ ইন করতে পারেন যা FIDO2 বা ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সর বা পিন সমর্থন করে৷" + renewTOTPCancel: "না, ধন্যবাদ" _permissions: "read:account": "অ্যাকাউন্টের তথ্য দেখুন" "write:account": "অ্যাকাউন্টের তথ্য সম্পাদন করুন" @@ -1381,8 +1395,6 @@ _notification: youGotReply: "{name} আপনাকে জবাব দিয়েছে" youGotQuote: "{name} আপনাকে উদ্ধৃত করেছে" youRenoted: "{name} এর Renote" - youGotMessagingMessageFromUser: "{name} আপনাকে মেসেজ করেছে" - youGotMessagingMessageFromGroup: "{name} গ্রুপে একটি নতুন মেসেজ আছে" youWereFollowed: "আপনাকে অনুসরণ করছে" youReceivedFollowRequest: "অনুসরণ করার জন্য অনুরোধ পাওয়া গেছে" yourFollowRequestAccepted: "আপনার অনুসরণ করার অনুরোধ গৃহীত হয়েছে" diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 0132938e41..a06d1f2442 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -121,7 +121,12 @@ sensitive: "NSFW" add: "Afegir" reaction: "Reaccions" reactions: "Reaccions" -reactionSetting: "Reaccions a mostrar al selector de reaccions" +emojiPicker: "Selecció d'emojis" +pinnedEmojisForReactionSettingDescription: "Selecciona l'emoji amb el qual reaccionar" +pinnedEmojisSettingDescription: "Selecciona l'emoji amb el qual reaccionar" +emojiPickerDisplay: "Visualitza el selector d'emojis" +overwriteFromPinnedEmojisForReaction: "Reemplaça els emojis de la reacció" +overwriteFromPinnedEmojis: "Sobreescriu des dels emojis fixats" reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem \"+\" per afegir." rememberNoteVisibility: "Recorda la configuració de visibilitat de les notes" attachCancel: "Eliminar el fitxer adjunt" @@ -157,6 +162,9 @@ addEmoji: "Afegeix un emoji" settingGuide: "Configuració recomanada" cacheRemoteFiles: "Emmagatzemar fitxers remots" cacheRemoteFilesDescription: "Quan aquesta opció està desactivada, els fitxers remots es carreguen directament des del servidor remot. Si desactiveu això, es reduirà l'ús d'emmagatzematge, però augmentarà el trànsit, ja que no es generaran miniatures." +youCanCleanRemoteFilesCache: "Pots netejar la memòria cau fent clic al botó de la paperera🗑️ a l'administrador d'arxius." +cacheRemoteSensitiveFiles: "Posar a la memòria cau arxius remots sensibles" +cacheRemoteSensitiveFilesDescription: "Quan aquesta opció és desactiva, els arxius remots sensibles es carregant directament del servidor d'origen sense que es guardin a la memòria cau." flagAsBot: "Marca aquest compte com a bot" flagAsBotDescription: "Marca aquest compte com a bot" flagAsCat: "Marca aquest compte com a gat" @@ -165,6 +173,7 @@ flagShowTimelineReplies: "Mostra les respostes a la línia de temps" flagShowTimelineRepliesDescription: "Mostra les respostes a la línia de temps" autoAcceptFollowed: "Aprova automàticament les sol·licituds de seguiment dels usuaris que segueixes" addAccount: "Afegeix un compte" +reloadAccountsList: "Recarregar la llista de contactes" loginFailed: "S'ha produït un error al accedir." showOnRemote: "Navega més en el perfil original" general: "General" @@ -191,6 +200,7 @@ perHour: "Per hora" perDay: "Per dia" stopActivityDelivery: "Deixa d'enviar activitats" blockThisInstance: "Deixa d'enviar activitats" +silenceThisInstance: "Silencia aquesta instància " operations: "Accions" software: "Programari" version: "Versió" @@ -209,6 +219,9 @@ clearQueueConfirmText: "Les notes no lliurades que quedin a la cua no es federar clearCachedFiles: "Esborra la memòria cau" clearCachedFilesConfirm: "Segur que voleu eliminar tots els fitxers de la memòria cau?" blockedInstances: "Instàncies bloquejades" +blockedInstancesDescription: "Llista els enllaços d'amfitrió de les instàncies que vols bloquejar separades per un salt de pàgina. Les instàncies llistades no podran comunicar-se amb aquesta instància." +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." muteAndBlock: "Silencia i bloca" mutedUsers: "Usuaris silenciats" blockedUsers: "Usuaris bloquejats" @@ -223,9 +236,12 @@ preview: "Vista prèvia" default: "Per defecte" defaultValueIs: "Per defecte: {value}" noCustomEmojis: "Cap emoji personalitzat" +noJobs: "No hi ha feines" federating: "Federant" blocked: "Bloquejat" suspended: "Suspés" +all: "tot" +subscribing: "Subscrit a" publishing: "S'està publicant" notResponding: "Sense resposta" instanceFollowing: "Seguits del servidor" @@ -250,11 +266,31 @@ removed: "Eliminat" removeAreYouSure: "Segur que voleu retirar «{x}»?" deleteAreYouSure: "Segur que voleu retirar «{x}»?" resetAreYouSure: "Segur que voleu restablir-ho?" +areYouSure: "Està segur?" saved: "S'ha desat" messaging: "Xat" upload: "Puja" +keepOriginalUploading: "Guarda la imatge original" +keepOriginalUploadingDescription: "Guarda la imatge pujada com hi és. Si està apagat, una versió per a la visualització a la xarxa serà generada quan sigui pujada." +fromDrive: "Des de la unitat" +fromUrl: "Des d'un enllaç" +uploadFromUrl: "Carrega des d'un enllaç" +uploadFromUrlDescription: "Enllaç del fitxer que vols carregar" +uploadFromUrlRequested: "Càrrega sol·licitada" +uploadFromUrlMayTakeTime: "La càrrega des de l'enllaç pot prendre un temps" +explore: "Explora" +messageRead: "Vist" +noMoreHistory: "No hi resta més per veure" +startMessaging: "Començar a xatejar" +nUsersRead: "Vist per {n}" +agreeTo: "Accepto que {0}" +agree: "Hi estic d'acord" +agreeBelow: "Hi estic d'acord amb el següent" +basicNotesBeforeCreateAccount: "Notes importants" +termsOfService: "Condicions d'ús" start: "Comença" home: "Inici" +remoteUserCaution: "Ja que aquest usuari resideix a una instància remota, la informació mostrada es podria trobar incompleta." activity: "Activitat" images: "Imatges" image: "Imatges" @@ -270,16 +306,34 @@ dark: "Fosc" lightThemes: "Temes clars" darkThemes: "Temes foscos" syncDeviceDarkMode: "Sincronitza el mode fosc amb la configuració del dispositiu" +drive: "Unitat" +fileName: "Nom del Fitxer" +selectFile: "Selecciona fitxers" +selectFiles: "Selecciona fitxers" +selectFolder: "Selecció de carpeta" +selectFolders: "Selecció de carpeta" renameFile: "Canvia el nom del fitxer" folderName: "Nom de la carpeta" createFolder: "Crea una carpeta" renameFolder: "Canvia el nom de la carpeta" deleteFolder: "Elimina la carpeta" +folder: "Carpeta " addFile: "Afegeix un fitxer" +emptyDrive: "La teva unitat és buida" emptyFolder: "La carpeta està buida" unableToDelete: "No es pot eliminar" +inputNewFileName: "Introduïu el nom de fitxer nou" +inputNewDescription: "Inserta una nova llegenda" +inputNewFolderName: "Introduïu el nom de la carpeta nova" +circularReferenceFolder: "La carpeta destinatària és una subcarpeta de la carpeta a la qual la desitges moure" +hasChildFilesOrFolders: "No és possible esborrar aquesta carpeta ja que no és buida" copyUrl: "Copia l'URL" rename: "Canvia el nom" +avatar: "Icona" +banner: "Bàner" +displayOfSensitiveMedia: "Visualització de contingut sensible" +whenServerDisconnected: "Quan es perdi la connexió al servidor" +disconnectedFromServer: "Desconnectat pel servidor" reload: "Actualitza" doNothing: "Ignora" accept: "Accepta" @@ -349,33 +403,132 @@ notFound: "No s'ha trobat" markAsReadAllUnreadNotes: "Marca-ho tot com a llegit" help: "Ajuda" invites: "Convida" +title: "Títol" +text: "Text" +enable: "Habilita" next: "Següent" +retype: "Torneu a introduir-la" noteOf: "Publicació de: {user}" +quoteAttached: "Frase adjunta" +quoteQuestion: "Vols annexar-la com a cita?" +noMessagesYet: "Encara no hi ha missatges" +newMessageExists: "Has rebut un nou missatge" +onlyOneFileCanBeAttached: "Només pots adjuntar un fitxer a un missatge" +signinRequired: "Si us plau, Registra't o inicia la sessió abans de continuar" invitations: "Convida" +invitationCode: "Codi d'invitació" +checking: "Comprovació en curs..." +available: "Disponible" +unavailable: "No és disponible" +usernameInvalidFormat: "Pots fer servir lletres (majúscules i minúscules), números i barres baixes (\"_\")" +tooShort: "Massa curt" +tooLong: "Massa llarg" +weakPassword: "Contrasenya insegura" +normalPassword: "Bona contrasenya" +strongPassword: "Contrasenya segura" +passwordMatched: "Correcte!" +passwordNotMatched: "No coincideix" +signinWith: "Inicia sessió amb amb {x}" +signinFailed: "Autenticació sense èxit. Intenta-ho un altre cop utilitzant la contrasenya i el nom correctes." +or: "O" +language: "Idioma" +uiLanguage: "Idioma de l'interfície" +aboutX: "Respecte a {x}" +emojiStyle: "Estil d'emoji" +native: "Nadiu" +disableDrawer: "No mostrar els menús en calaixos" +showNoteActionsOnlyHover: "Només mostra accions de la nota en passar amb el cursor" +noHistory: "No hi ha un registre previ" +signinHistory: "Historial d'autenticacions" +enableAdvancedMfm: "Habilitar l'MFM avançat" +enableAnimatedMfm: "Habilitar l'MFM amb moviment" +doing: "Processant..." +category: "Categoria" tags: "Etiquetes" docSource: "Font del document" createAccount: "Crea un compte" existingAccount: "Compte existent" regenerate: "Regenera" fontSize: "Mida del text" +mediaListWithOneImageAppearance: "Altura de la llista de fitxers amb una única imatge" +limitTo: "Limita a {x}" noFollowRequests: "No tens sol·licituds de seguiment" +openImageInNewTab: "Obre imatges a una nova pestanya" dashboard: "Panell de control" local: "Local" remote: "Remot" total: "Total" +weekOverWeekChanges: "Canvis l'última setmana" +dayOverDayChanges: "Canvis ahir" appearance: "Aparença" clientSettings: "Configuració del client" accountSettings: "Configuració del compte" +promotion: "Promocionat" +promote: "Promoure" +numberOfDays: "Nombre de dies" hideThisNote: "Amaga la publicació" showFeaturedNotesInTimeline: "Mostra publicacions destacades en la línia de temps" +objectStorage: "Emmagatzematge d'objectes\n" +useObjectStorage: "Utilitzar l'emmagatzematge d'objectes" +objectStorageBaseUrl: "Base d'enllaç" +objectStorageBaseUrlDesc: "Prefix d'enllaç utilitzat per a fer referencia als fitxers. Especifica l'enllaç del teu CDN o Proxy si n'estàs utilitzant qualsevol, en cas contrari, especifica l'enllaç al que es pot accedir públicament segons la guia de servei que vosté utilitza.\nPer l'ús d'S3 utilitza 'https://.s3.amazonaws.com' I per a GCS o serveis equivalents utilitza 'https://storage.googleapis.com/'." newNoteRecived: "Hi ha publicacions noves" installedDate: "Data d'instal·lació" state: "Estat" sort: "Ordena" ascendingOrder: "Ascendent" descendingOrder: "Descendent" +removeAllFollowing: "Deixar de seguir tots els usuaris seguits" +removeAllFollowingDescription: "El fet d'executar això, et farà deixar de seguir a tots els usuaris de {host}. Si us plau, executa això si l'amfitrió, per exemple, ja no existeix." +userSuspended: "Aquest usuari ha sigut suspès" +userSilenced: "Aquest usuari està sent silenciat" +yourAccountSuspendedTitle: "Aquest compte és suspès" +yourAccountSuspendedDescription: "Aquest compte ha sigut suspès a causa de la violació de les condicions d'ús o similars. Contacta l'administrador si en vol saber més. Si us plau, no en faci un altre compte." +tokenRevoked: "Codi de seguretat no vàlid" +tokenRevokedDescription: "La petició més recent ha estat denegada perquè contenia un codi de seguretat no vàlid. Actualitza la pàgina i torna-ho a provar." +accountDeleted: "Compte eliminat amb èxit" +accountDeletedDescription: "Aquest compte ha sigut eliminat" +menu: "Menú" +divider: "Divisor" +addItem: "Afegir element" +rearrange: "Torna a ordenar" +relays: "Relés" +addRelay: "Afegeix relés" +inboxUrl: "Enllaç de la safata d'entrada" +addedRelays: "Relés afegits" +serviceworkerInfo: "És obligatòria l'activació per a obtenir notificacions push" deletedNote: "Publicacions eliminades" invisibleNote: "Publicacions amagades" +enableInfiniteScroll: "Carrega més automàticament\n" +visibility: "Visibilitat" +poll: "Enquesta" +useCw: "Amaga el contingut" +enablePlayer: "Obre el reproductor de vídeo" +disablePlayer: "Tanca el reproductor de vídeo" +expandTweet: "Expandir post" +themeEditor: "Editor de temes" +description: "Descripció" +describeFile: "Afegir subtitulació" +enterFileDescription: "Afegeix un títol" +author: "Autor" +leaveConfirm: "Hi ha canvis sense guardar. Els vols descartar?" +manage: "Administració" +plugins: "Extensions" +preferencesBackups: "Configuracions de les Còpies de seguretat" +deck: "Escriptori" +undeck: "Tanca l'escriptori" +useBlurEffectForModal: "Utilitzar l'efecte de difuminació a modals" +useFullReactionPicker: "Utilitza el cercador de reaccions d'escala sencera" +width: "Amplada" +height: "Alçària" +large: "Gran" +medium: "Mitjà" +small: "Petit" +generateAccessToken: "Genera codi d'accés" +permission: "Permisos" +enableAll: "Habilita tot" +disableAll: "Deshabilita tot" +tokenRequested: "Donar accés al compte" smtpHost: "Amfitrió" smtpUser: "Nom d'usuari" smtpPass: "Contrasenya" @@ -385,12 +538,17 @@ clearCache: "Esborra la memòria cau" showingPastTimeline: "Estàs veient una línia de temps antiga" info: "Informació" user: "Usuaris" +administration: "Administració" +middle: "Mitjà" global: "Global" searchByGoogle: "Cercar" file: "Fitxers" +icon: "Icona" replies: "Respondre" renotes: "Impulsa" _role: + _priority: + middle: "Mitjà" _options: antennaMax: "Nombre màxim d'antenes" _email: @@ -399,9 +557,11 @@ _email: _instanceMute: instanceMuteDescription: "Silencia tots els impulsos dels servidors seleccionats, també els usuaris que responen a altres d'un servidor silenciat." _theme: + description: "Descripció" keys: mention: "Menció" renote: "Renotar" + divider: "Divisor" _sfx: note: "Notes" notification: "Notificacions" @@ -444,6 +604,8 @@ _timelines: local: "Local" social: "Social" global: "Global" +_play: + summary: "Descripció" _pages: contents: "Contingut" blocks: diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index 18519bd2a4..55f4d19432 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -120,7 +120,6 @@ sensitive: "NSFW" add: "Přidat" reaction: "Reakce" reactions: "Reakce" -reactionSetting: "Reakce zobrazené ve výběru reakcí" reactionSettingDescription2: "Přetažením změníte pořadí, kliknutím smažete, zmáčkněte \"+\" k přidání" rememberNoteVisibility: "Zapamatovat nastavení zobrazení poznámky" attachCancel: "Odstranit přílohu" @@ -428,7 +427,6 @@ share: "Sdílet" notFound: "Nenalezeno" notFoundDescription: "Nebyla nalezená žádná stránka korespondující se zadanou URL." uploadFolder: "Výchozí lokace pro upload" -cacheClear: "Vymazat cache" markAsReadAllNotifications: "Označit všechna oznámení za přečtená" markAsReadAllUnreadNotes: "Označit všechny příspěvky za přečtené" markAsReadAllTalkMessages: "Označit všechny zprávy za přečtené" @@ -733,7 +731,7 @@ onlineUsersCount: "{n} uživatelů je online" nUsers: "{n} užívatelů" nNotes: "{n} poznámek" sendErrorReports: "Odesílat chybové záznamy" -sendErrorReportsDescription: "Pokud je tato funkce zapnutá, budou se při výskytu problému sdílet podrobné informace o chybách se službou Misskey, což pomůže zlepšit kvalitu služby Misskey. Tyto informace budou zahrnovat například verzi operačního systému, jaký prohlížeč používáte, vaši aktivitu v Misskey atd." +sendErrorReportsDescription: "Pokud je tato funkce zapnutá, budou se při výskytu problému sdílet podrobné informace o chybách se službou CherryPick, což pomůže zlepšit kvalitu služby CherryPick. Tyto informace budou zahrnovat například verzi operačního systému, jaký prohlížeč používáte, vaši aktivitu v CherryPick atd." myTheme: "Moje vzhledy" backgroundColor: "Pozadí" accentColor: "Akcent" @@ -827,7 +825,7 @@ hashtags: "Hashtagy" troubleshooting: "Poradce při potížích" useBlurEffect: "Použít efekt rozostření v UI" learnMore: "Zjistit více" -misskeyUpdated: "Misskey byl aktualizován!" +misskeyUpdated: "CherryPick byl aktualizován!" whatIsNew: "Zobrazit změny" translate: "Přeložit" translatedFrom: "Přeloženo z {x}" @@ -856,8 +854,6 @@ makeReactionsPublicDescription: "Tohle zviditelný seznam vašich předchozích classic: "Klasický" muteThread: "Ztlumit vlákno" unmuteThread: "Zrušit ztlumení vlákna" -ffVisibility: "Viditelnost Sledovaných/Sledujících" -ffVisibilityDescription: "Umožní vám nastavit kdo uvidí koho sledujete a kdo vás sleduje." continueThread: "Zobrazit pokračování vlákna" deleteAccountConfirm: "Tohle nenávratně smaže váš účet, chcete pokračovat?" incorrectPassword: "Nesprávné heslo." @@ -956,8 +952,8 @@ numberOfLikes: "Počet \"To se mi líbí\"" show: "Zobrazit" neverShow: "Znovu nezobrazovat" remindMeLater: "Možná později" -didYouLikeMisskey: "Oblíbili jste si Misskey?" -pleaseDonate: "{host} používá bezplatný software Misskey. Velmi bychom ocenili vaše dary, aby mohl vývoj Misskey pokračovat!" +didYouLikeMisskey: "Oblíbili jste si CherryPick?" +pleaseDonate: "{host} používá bezplatný software CherryPick. Velmi bychom ocenili vaše dary, aby mohl vývoj CherryPick pokračovat!" roles: "Role" role: "Role" noRole: "Role nenalezena" @@ -1066,7 +1062,7 @@ rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Role musí být veřejné. cancelReactionConfirm: "Opravdu chcete odstranit vaší reakci?" changeReactionConfirm: "Opravdu chcete změnit vaši reakci?" later: "Později" -goToMisskey: "Jít na Misskey" +goToMisskey: "Jít na CherryPick" additionalEmojiDictionary: "Další slovníky emoji" installed: "Nainstalováno" branding: "Značka" @@ -1123,7 +1119,7 @@ _accountMigration: moveTo: "Přesunout tenhle účet do jiného" moveToLabel: "Cílový účet pro přesunutí:" moveCannotBeUndone: "Migrace účtu nemůže být vrácena." - moveAccountDescription: "Tím dojde k migraci vašeho účtu na jiný účet.\n ・Sledovatelé z tohoto účtu budou automaticky převedeni na nový účet.\n ・Tento účet zruší sledování všech uživatelů, které aktuálně sleduje.\n ・Na tomto účtu nebude možné vytvářet nové poznámky atd.\n\nZatímco migrace sledovaných uživatelů probíhá automaticky, pro migraci seznamu sledovaných uživatelů je nutné připravit některé kroky ručně. Za tímto účelem proveďte export sledovaných, který později naimportujete na nový účet v nabídce nastavení. Stejný postup platí pro seznamy i pro ztlumené a zablokované uživatele.\n\n(Tento výklad platí pro Misskey v13.12.0 a novější. Jiný software ActivityPub, například Mastodon, může fungovat jinak.)" + moveAccountDescription: "Tím dojde k migraci vašeho účtu na jiný účet.\n ・Sledovatelé z tohoto účtu budou automaticky převedeni na nový účet.\n ・Tento účet zruší sledování všech uživatelů, které aktuálně sleduje.\n ・Na tomto účtu nebude možné vytvářet nové poznámky atd.\n\nZatímco migrace sledovaných uživatelů probíhá automaticky, pro migraci seznamu sledovaných uživatelů je nutné připravit některé kroky ručně. Za tímto účelem proveďte export sledovaných, který později naimportujete na nový účet v nabídce nastavení. Stejný postup platí pro seznamy i pro ztlumené a zablokované uživatele.\n\n(Tento výklad platí pro CherryPick v13.12.0 a novější. Jiný software ActivityPub, například Mastodon, může fungovat jinak.)" moveAccountHowTo: "Chcete-li migrovat, vytvořte nejprve alias tohoto účtu na účtu, na který chcete přejít.\nPo vytvoření aliasu zadejte účet, na který chcete přejít, v následujícím formátu: @username@server.example.com" startMigration: "Migrovat" migrationConfirm: "Opravdu chcete migrovat tento účet na {account}? Jednou zahájený proces nelze zastavit ani vrátit zpět a tento účet již nebudete moci používat v původním stavu." @@ -1134,9 +1130,9 @@ _achievements: earnedAt: "Odemčeno v" _types: _notes1: - title: "Dobrý den Misskey!" + title: "Dobrý den CherryPick!" description: "Zveřejněte vaší první poznámku" - flavor: "Užijte si to s Misskey!" + flavor: "Užijte si to s CherryPick!" _notes10: title: "Pár poznámek" description: "Zveřejněte 10 poznámek" @@ -1232,7 +1228,7 @@ _achievements: _login1000: title: "Mistr poznámek III" description: "Přihlaste se celkově za 1000 dní" - flavor: "Děkujeme, že používáte Misskey!" + flavor: "Děkujeme, že používáte CherryPick!" _noteClipped1: title: "Musím... připnout..." description: "Připněte si první poznámku" @@ -1292,18 +1288,18 @@ _achievements: title: "Máš rád úspěchy" description: "Koukejte na váš seznam úspěchů alespoň po dobu 3 minut" _iLoveMisskey: - title: "Miluju Misskey" - description: "Zveřejněte \" I ❤ #Misskey\"" - flavor: "Vývojový tým Misskey si velmi váží vaší podpory!" + title: "Miluju CherryPick" + description: "Zveřejněte \" I ❤ #CherryPick\"" + flavor: "Vývojový tým CherryPick si velmi váží vaší podpory!" _foundTreasure: title: "Hon za pokladem" description: "Našli jste schovaný poklad!" _client30min: title: "Krátká pauza" - description: "Mějte otevřený Misskey alespoň po dobu 30 minut" + description: "Mějte otevřený CherryPick alespoň po dobu 30 minut" _client60min: - title: "Žádný \"Miss\" v Misskey" - description: "Mějte otevřený Misskey alespoň po dobu 60 minut" + title: "Žádný \"Miss\" v CherryPick" + description: "Mějte otevřený CherryPick alespoň po dobu 60 minut" _noteDeletedWithin1min: title: "Ups, nevadí" description: "Vymažte poznámku během minuty co ji zveřejníte" @@ -1345,6 +1341,9 @@ _achievements: _setNameToSyuilo: title: "Boží komplex" description: "Nastavte si jméno na \"syuilo\"" + _setNameToNoriDev: + title: "Boží komplex (CherryPick)" + description: "Nastavte si jméno na \"noridev\"" _passedSinceAccountCreated1: title: "Roční výročí" description: "Od vytvoření vašeho účtu uplynul jeden rok" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 41497e4d1c..a50e399ffc 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -121,7 +121,6 @@ sensitive: "Sensibel" add: "Hinzufügen" reaction: "Reaktionen" reactions: "Reaktionen" -reactionSetting: "In der Reaktionsauswahl anzuzeigende Reaktionen" reactionSettingDescription2: "Ziehe um Anzuordnen, klicke um zu löschen, drücke „+“ um hinzuzufügen" rememberNoteVisibility: "Notizsichtbarkeit merken" attachCancel: "Anhang entfernen" @@ -311,6 +310,7 @@ folderName: "Ordnername" createFolder: "Ordner erstellen" renameFolder: "Ordner umbenennen" deleteFolder: "Ordner löschen" +folder: "Ordner" addFile: "Datei hinzufügen" emptyDrive: "Deine Drive ist leer" emptyFolder: "Dieser Ordner ist leer" @@ -437,7 +437,6 @@ share: "Teilen" notFound: "Nicht gefunden" notFoundDescription: "Es konnte keine Seite unter dieser URL gefunden werden." uploadFolder: "Standardordner für Uploads" -cacheClear: "Cache leeren" markAsReadAllNotifications: "Alle Benachrichtigungen als gelesen markieren" markAsReadAllUnreadNotes: "Alle Notizen als gelesen markieren" markAsReadAllTalkMessages: "Alle Chats als gelesen markieren" @@ -556,6 +555,8 @@ showInPage: "In einer Seite anzeigen" popout: "Pop-Up" volume: "Lautstärke" masterVolume: "Gesamtlautstärke" +notUseSound: "Gebe kein Ton aus" +useSoundOnlyWhenActive: "Gebe nur Ton aus, wenn CherryPick aktiv ist" details: "Details" chooseEmoji: "Emoji auswählen" unableToProcess: "Der Vorgang konnte nicht abgeschlossen werden" @@ -576,6 +577,10 @@ output: "Ausgabe" script: "Skript" disablePagesScript: "AiScript auf Seiten deaktivieren" updateRemoteUser: "Benutzerinformationen aktualisieren" +unsetUserAvatar: "Entferne Profilbild" +unsetUserAvatarConfirm: "Möchtest du dein Profilbild entfernen?" +unsetUserBanner: "Entferne Profilbanner" +unsetUserBannerConfirm: "Möchtest du dein Profilbanner entfernen?" deleteAllFiles: "Alle Dateien löschen" deleteAllFilesConfirm: "Möchtest du wirklich alle Dateien löschen?" removeAllFollowing: "Allen gefolgten Benutzern entfolgen" @@ -880,8 +885,6 @@ makeReactionsPublicDescription: "Jeder wird die Liste deiner gesendeten Reaktion classic: "Classic" muteThread: "Thread stummschalten" unmuteThread: "Threadstummschaltung aufheben" -ffVisibility: "Sichtbarkeit von Gefolgten/Followern" -ffVisibilityDescription: "Konfiguriere wer sehen kann, wem du folgst sowie wer dir folgt." continueThread: "Weiteren Threadverlauf anzeigen" deleteAccountConfirm: "Dein Benutzerkonto wird unwiderruflich gelöscht. Trotzdem fortfahren?" incorrectPassword: "Falsches Passwort." @@ -1034,6 +1037,8 @@ resetPasswordConfirm: "Wirklich Passwort zurücksetzen?" sensitiveWords: "Sensible Wörter" sensitiveWordsDescription: "Die Notizsichtbarkeit aller Notizen, die diese Wörter enthalten, wird automatisch auf \"Startseite\" gesetzt. Durch Zeilenumbrüche können mehrere konfiguriert werden." sensitiveWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden." +hiddenTags: "Ausgeblendete Hashtags" +hiddenTagsDescription: "Die hier eingestellten Tags werden nicht mehr in den Trends angezeigt. Mit der Umschalttaste können mehrere ausgewählt werden." notesSearchNotAvailable: "Die Notizsuche ist nicht verfügbar." license: "Lizenz" unfavoriteConfirm: "Wirklich aus Favoriten entfernen?" @@ -1046,6 +1051,7 @@ enableChartsForRemoteUser: "Diagramme für Nutzer fremder Instanzen erstellen" enableChartsForFederatedInstances: "Diagramme für fremde Instanzen erstellen" showClipButtonInNoteFooter: "\"Clip\" zum Notizmenu hinzufügen" reactionsDisplaySize: "Reaktionsanzeigegröße" +limitWidthOfReaction: "Begrenze die Breite der Reaktion und zeige sie verkleinert an" noteIdOrUrl: "Notiz-ID oder URL" video: "Video" videos: "Videos" @@ -1169,7 +1175,10 @@ refreshing: "Wird aktualisiert..." pullDownToRefresh: "Zum Aktualisieren ziehen" disableStreamingTimeline: "Echtzeitaktualisierung der Chronik deaktivieren" useGroupedNotifications: "Benachrichtigungen gruppieren" +signupPendingError: "Beim Überprüfen der Mailadresse ist etwas schiefgelaufen. Der Link könnte abgelaufen sein." cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden." +doReaction: "Reagieren" +code: "Code" _announcement: forExistingUsers: "Nur für existierende Nutzer" forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt." @@ -1179,6 +1188,9 @@ _announcement: tooManyActiveAnnouncementDescription: "Zu viele aktive Ankündigungen können die Benutzerfreundlichkeit verschlechtern. Es wird empfohlen, veraltete Ankündigungen zu archivieren." readConfirmTitle: "Als gelesen markieren?" readConfirmText: "Dies markiert den Inhalt von \"{title}\" als gelesen." + dialogAnnouncementUxWarn: "Bei der Verwendung von mehr als zwei Meldungen im Dialog-Format wird um Vorsicht geboten, da dies negative Auswirkungen auf die UX haben kann." + silence: "Keine Benachrichtigung" + silenceDescription: "Wenn aktiviert, gibt diese Meldung keine Nachricht aus und muss nicht als \"gelesen\" markiert werden." _initialAccountSetting: accountCreated: "Dein Konto wurde erfolgreich erstellt!" letsStartAccountSetup: "Lass uns nun dein Konto einrichten." @@ -1191,8 +1203,20 @@ _initialAccountSetting: pushNotificationDescription: "Durch die Aktivierung von Push-Benachrichtigungen kannst du von {name} Benachrichtigungen direkt auf dein Gerät erhalten." initialAccountSettingCompleted: "Kontoeinrichtung abgeschlossen!" haveFun: "Viel Spaß mit {name}!" + youCanContinueTutorial: "Du kannst mit dem Tutorial von {name}(CherryPick) fortfahren, oder auch abbrechen und gleich anfangen CherryPick zu benutzen." + startTutorial: "Fange mit dem Tutorial an" skipAreYouSure: "Die Kontoeinrichtung wirklich überspringen?" laterAreYouSure: "Die Kontoeinrichtung wirklich später erledigen?" +_initialTutorial: + launchTutorial: "Tutorial ansehen" + title: "Tutorial" + wellDone: "Gut gemacht!" + skipAreYouSure: "Möchtest du das Tutorial verlassen?" + _landing: + title: "Willkommen zum Tutorial" + description: "Hier kannst du sehen, wie CherryPick funktioniert" + _note: + title: "Was sind Notizen?" _serverRules: description: "Eine Reihe von Regeln, die vor der Registrierung angezeigt werden. Eine Zusammenfassung der Nutzungsbedingungen anzuzeigen ist empfohlen." _serverSettings: @@ -1435,6 +1459,9 @@ _achievements: _setNameToSyuilo: title: "Gottkomplex" description: "Setze deinen Namen auf \"syuilo\"" + _setNameToNoriDev: + title: "Gottkomplex (CherryPick)" + description: "Setze deinen Namen auf \"noridev\"" _passedSinceAccountCreated1: title: "Einjahresjubiläum" description: "Seit der Erstellung deines Kontos ist 1 Jahr vergangen" @@ -1458,7 +1485,7 @@ _achievements: _brainDiver: title: "Brain Diver" description: "Sende den Link zu Brain Diver" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "Testüberfluss" description: "Betätige den Benachrichtigungstest mehrfach innerhalb einer extrem kurzen Zeitspanne" @@ -2125,8 +2152,6 @@ _notification: youGotReply: "{name} hat dir geantwortet" youGotQuote: "{name} hat dich zitiert" youRenoted: "Renote deiner Notiz von {name}" - youGotMessagingMessageFromUser: "{name} hat dir eine Chatnachricht gesendet" - youGotMessagingMessageFromGroup: "In die Gruppe {name} wurde eine Chatnachricht gesendet" youWereFollowed: "ist dir gefolgt" youReceivedFollowRequest: "Du hast eine Follow-Anfrage erhalten" yourFollowRequestAccepted: "Deine Follow-Anfrage wurde akzeptiert" diff --git a/locales/el-GR.yml b/locales/el-GR.yml index e46efcec1f..6a285118de 100644 --- a/locales/el-GR.yml +++ b/locales/el-GR.yml @@ -104,7 +104,6 @@ clickToShow: "Κάντε κλικ για εμφάνιση" add: "Προσθέστε" reaction: "Αντιδράσεις" reactions: "Αντιδράσεις" -reactionSetting: "Αντιδράσεις για εμφάνιση στην επιλογή αντίδρασης" reactionSettingDescription2: "Σύρετε για να αλλάξετε τη σειρά, κάντε κλικ για να διαγράψετε, πατήστε \"+\" για να προσθέσετε." rememberNoteVisibility: "Θυμήσου τις ρυθμίσεις ορατότητας σημειώματος" attachCancel: "Διαγραφή αρχείου" @@ -228,7 +227,6 @@ userList: "Λίστες" about: "Πληροφορίες" moderator: "Συντονιστής" moderation: "Συντονισμός" -cacheClear: "Εκκαθάριση προσωρινής μνήμης" markAsReadAllNotifications: "Όλες οι ειδοποιήσεις διαβάστηκαν" members: "Μέλη" transfer: "Μεταφορά" diff --git a/locales/en-US.yml b/locales/en-US.yml index 30cefd9378..1746363f75 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1,10 +1,16 @@ --- _lang_: "English" +cherrypickLabs: "CherryPick Labs" +cherrypickLabsDescription: "Why not try some of the features that are still under development? Some features may not work properly." +copiedLink: "The link has been copied!" +copiedContent: "Contents copied!" +copied: "Copied!" +welcome: "Welcome!" +cherrypickMigrated: "The migration to CherryPick is complete!" +cherrypickMigratedCacheClearTitle: "The cache must be cleared." +cherrypickMigratedCacheClear: "This server was migrated from Misskey or CherryPick v4.3.0 or earlier.\nBecause of the different versioning, any leftover cache can cause problems, so you'll need to clear the cache on the first connection after the migration.\n\nThis will only happen the first time." +showRenoteVisibilitySelector: "Show renote visibility selector" cannotBeUsedFunc: "This feature is currently unavailable." -maxinumLayerError: "You cannot stack more than 6 layers. Please delete other layers." -layer: "Layer" -Xcoordinate: "X-Coordinate" -Ycoordinate: "Y-Coordinate" scale: "Scale" opacity: "Opacity" noteUpdatedAt: "Edited: {date} {time}" @@ -194,7 +200,8 @@ sensitive: "Sensitive" add: "Add" reaction: "Reactions" reactions: "Reactions" -reactionSetting: "Reactions to show in the reaction picker" +emojiPicker: "Emoji picker" +emojiPickerDisplay: "Emoji picker display" reactionSettingDescription2: "Drag to reorder, click to delete, press \"+\" to add." rememberNoteVisibility: "Remember note visibility settings" attachCancel: "Remove attachment" @@ -334,6 +341,7 @@ removed: "Successfully deleted" removeAreYouSure: "Are you sure that you want to remove \"{x}\"?" deleteAreYouSure: "Are you sure that you want to delete \"{x}\"?" resetAreYouSure: "Really reset?" +areYouSure: "Are you sure?" saved: "Saved" messaging: "Chat" upload: "Upload" @@ -637,6 +645,8 @@ showInPage: "Show in page" popout: "Pop-out" volume: "Volume" masterVolume: "Master volume" +notUseSound: "Disable sound" +useSoundOnlyWhenActive: "Output sounds only if CherryPick is active." details: "Details" chooseEmoji: "Select an emoji" unableToProcess: "The operation could not be completed" @@ -657,10 +667,10 @@ output: "Output" script: "Script" disablePagesScript: "Disable AiScript on Pages" updateRemoteUser: "Update remote user information" -unsetUserAvatar: "Delete user icon" -unsetUserAvatarConfirm: "Are you sure that you want to delete this user's icon?" -unsetUserBanner: "Delete user banner" -unsetUserBannerConfirm: "Are you sure that you want to delete this user's banner?" +unsetUserAvatar: "Unset avatar" +unsetUserAvatarConfirm: "Are you sure you want to unset the avatar?" +unsetUserBanner: "Unset banner" +unsetUserBannerConfirm: "Are you sure you want to unset the banner?" deleteAllFiles: "Delete all files" deleteAllFilesConfirm: "Are you sure that you want to delete all files?" removeAllFollowing: "Unfollow all followed users" @@ -732,6 +742,7 @@ smtpSecure: "Use implicit SSL/TLS for SMTP connections" smtpSecureInfo: "Turn this off when using STARTTLS" testEmail: "Test email delivery" wordMute: "Word mute" +hardWordMute: "Hard word mute" regexpError: "Regular Expression error" regexpErrorDescription: "An error occurred in the regular expression on line {line} of your {tab} word mutes:" instanceMute: "Instance Mutes" @@ -968,8 +979,8 @@ makeReactionsPublicDescription: "This will make the list of all your past reacti classic: "Classic" muteThread: "Mute thread" unmuteThread: "Unmute thread" -ffVisibility: "Follows/Followers Visibility" -ffVisibilityDescription: "Allows you to configure who can see who you follow and who follows you." +followingVisibility: "Visibility of follows" +followersVisibility: "Visibility of followers" continueThread: "View thread continuation" deleteAccountConfirm: "This will irreversibly delete your account. Proceed?" incorrectPassword: "Incorrect password." @@ -1123,6 +1134,8 @@ resetPasswordConfirm: "Really reset your password?" sensitiveWords: "Sensitive words" sensitiveWordsDescription: "The visibility of all notes containing any of the configured words will be set to \"Home\" automatically. You can list multiple by separating them via line breaks." sensitiveWordsDescription2: "Using spaces will create AND expressions and surrounding keywords with slashes will turn them into a regular expression." +hiddenTags: "Hidden hashtags" +hiddenTagsDescription: "Select tags which will not shown on trend list.\nMultiple tags could be registered by lines." notesSearchNotAvailable: "Note search is unavailable." license: "License" unfavoriteConfirm: "Really remove from favorites?" @@ -1135,6 +1148,7 @@ enableChartsForRemoteUser: "Generate remote user data charts" enableChartsForFederatedInstances: "Generate remote instance data charts" showClipButtonInNoteFooter: "Add \"Clip\" to note action menu" reactionsDisplaySize: "Reaction display size" +limitWidthOfReaction: "Limits the maximum width of reactions and display them in reduced size." noteIdOrUrl: "Note ID or URL" video: "Video" videos: "Videos" @@ -1268,7 +1282,8 @@ signupPendingError: "There was a problem verifying the email address. The link m cwNotationRequired: "If \"Hide content\" is enabled, a description must be provided." doReaction: "Add reaction" code: "Code" -tryReloadIfNotApplied: "If the settings are not reflected, please try refresh." +reloadRequiredToApplySettings: "Reloading is required to apply the settings." +decorate: "Decorate" showUnreadNotificationsCount: "Show the number of unread notifications" showCatOnly: "Show only cats" additionalPermissionsForFlash: "Allow to add permission to Play" @@ -1336,7 +1351,8 @@ _cherrypick: mobileHeaderChange: "Header design change in mobile environment" renameTheButtonInPostFormToNya: "Change the \"Note\" button on the note-posting form to \"Nyan!\"" renameTheButtonInPostFormToNyaDescription: "Outside of the note-posting form, they are still as \"Note\"." - enableLongPressOpenAccountMenu: "Press and hold to open the account menu." + enableLongPressOpenAccountMenu: "Press and hold to open the account menu" + enableLongPressOpenAccountMenuDescription: "It can be opened by long-pressing the Timeline tab at the bottom of the screen." friendlyShowAvatarDecorationsInNavBtn: "Show avatar decorations on floating buttons" _bannerDisplay: all: "All" @@ -1430,7 +1446,7 @@ _initialTutorial: sensitiveSucceeded: "When attaching files, please set sensitivities in accordance with the server guidelines." doItToContinue: "Mark the attachment file as sensitive to proceed." _done: - title: "The tutorial is complete! 🎉" + title: "You've completed the tutorial! 🎉" description: "The functions introduced here are just a small part. For a more detailed understanding of using CherryPick, please refer to {link}." _timelineDescription: home: "In the Home timeline, you can see notes from accounts you follow." @@ -1475,6 +1491,8 @@ _serverSettings: shortName: "Short name" shortNameDescription: "A shorthand for the instance's name that can be displayed if the full official name is long." 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." _accountMigration: moveFrom: "Migrate another account to this one" moveFromSub: "Create alias to another account" @@ -1705,6 +1723,9 @@ _achievements: _setNameToSyuilo: title: "God Complex" description: "Set your name to \"syuilo\"" + _setNameToNoriDev: + title: "God Complex (CherryPick)" + description: "Set your name to \"noridev\"" _passedSinceAccountCreated1: title: "One Year Anniversary" description: "One year has passed since your account was created" @@ -1728,7 +1749,7 @@ _achievements: _brainDiver: title: "Brain Diver" description: "Post the link to Brain Diver" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "Test overflow" description: "Trigger the notification test repeatedly within an extremely short time" @@ -1745,7 +1766,9 @@ _role: assignTarget: "Assignment type" descriptionOfAssignTarget: "Manual to manually change who is part of this role and who is not.\nConditional to have users be automatically assigned and removed from this role based on a condition." manual: "Manual" + manualRoles: "Manual roles" conditional: "Conditional" + conditionalRoles: "Conditional roles" condition: "Condition" isConditionalRole: "This is a conditional role." isPublic: "Public role" @@ -1895,7 +1918,7 @@ _registry: domain: "Domain" createKey: "Create key" _aboutMisskey: - about: "CherryPick is a customization client based on Misskey that has been in development since 2021." + about: "CherryPick is a customization open-source software based on Misskey that has been in development since 2021." contributors: "Main contributors" allContributors: "All contributors" source: "Source code" @@ -1908,7 +1931,6 @@ _aboutMisskey: serverStatus: "Server Status" donate: "Donate to Kokonect" _cherrypick: - about: "This Misskey was customized by NoriDev!" translation: "Translate CherryPick" donate: "Donate to CherryPick" relayServer: "Relay Server" @@ -2111,6 +2133,14 @@ _sfx: chatBg: "Chat (Background)" antenna: "Antennas" channel: "Channel notifications" + reaction: "On choosing a reaction" +_soundSettings: + driveFile: "Use an audio file in Drive." + driveFileWarn: "Select an audio file from Drive." + driveFileTypeWarn: "This file is not supported" + driveFileTypeWarnDescription: "Select an audio file" + driveFileDurationWarn: "The audio is too long." + driveFileDurationWarnDescription: "Long audio may disrupt using CherryPick. Still continue?" _ago: future: "Future" justNow: "Just now" @@ -2122,6 +2152,14 @@ _ago: monthsAgo: "{n}mo ago" yearsAgo: "{n}y ago" invalid: "None" +_timeIn: + seconds: "In {n}s" + minutes: "In {n}m" + hours: "In {n}h" + days: "In {n}d" + weeks: "In {n}w" + months: "In {n}mo" + years: "In {n}y" _time: second: "Second(s)" minute: "Minute(s)" @@ -2248,6 +2286,7 @@ _widgets: _userList: chooseList: "Select a list" clicker: "Clicker" + birthdayFollowings: "Users who celebrate their birthday today" _cw: hide: "Hide" show: "Show content" @@ -2425,9 +2464,8 @@ _notification: youGotMention: "{name} mentioned you" youGotReply: "{name} replied to you" youGotQuote: "{name} quoted you" + youGotReact: "{name} reacted to you" youRenoted: "Renote from {name}" - youGotMessagingMessageFromUser: "{name} sent you a chat message" - youGotMessagingMessageFromGroup: "A chat message was sent to the {name} group" youWereFollowed: "followed you" youReceivedFollowRequest: "You've received a follow request" yourFollowRequestAccepted: "Your follow request was accepted" @@ -2435,6 +2473,7 @@ _notification: pollEnded: "Poll results have become available" newNote: "New note" unreadAntennaNote: "Antenna {name}" + roleAssigned: "Role given" emptyPushNotificationMessage: "Push notifications have been updated" achievementEarned: "Achievement unlocked" testNotification: "Test notification" @@ -2457,6 +2496,7 @@ _notification: receiveFollowRequest: "Received follow requests" followRequestAccepted: "Accepted follow requests" groupInvited: "Group invitations" + roleAssigned: "Role given" achievementEarned: "Achievement unlocked" app: "Notifications from linked apps" _actions: @@ -2551,6 +2591,8 @@ _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" _fileViewer: title: "File details" type: "File type" @@ -2602,17 +2644,17 @@ _externalResourceInstaller: description: "A problem occurred during theme installation. Please try again. Error details can be viewed in the Javascript console." _dataSaver: _media: - title: "Load media" + title: "Loading Media" description: "Prevents images/videos from being loaded automatically. Hidden images/videos will be loaded when tapped." _avatar: - title: "User icon image" - description: "Animation of user's icon images stops. Since animated images can be larger in file size than normal images, data traffic can be further reduced." + title: "Avatar image" + description: "Stop avatar image animation. Animated images can be larger in file size than normal images, potentially leading to further reductions in data traffic." _urlPreview: - title: "URL preview thumbnail" + title: "URL preview thumbnails" description: "URL preview thumbnail images will no longer load." _code: - title: "Code Highlights" - description: "If code highlighting notation is used, such as MFM, it will not be loaded until tapped. Code highlighting requires loading the definition file for each language to be highlighted, but since these files are no longer loaded automatically, a reduction in communication volume can be expected." + title: "Code highlighting" + description: "If code highlighting notations are used in MFM, etc., they will not load until tapped. Syntax highlighting requires downloading the highlight definition files for each programming language. Therefore, disabling the automatic loading of these files is expected to reduce the amount of communication data." _abuse: _resolver: 1hour: "one hour" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 6ed9ee2bc8..6af5b58122 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -121,7 +121,12 @@ sensitive: "Marcado como sensible" add: "Agregar" reaction: "Reacción" reactions: "Reacción" -reactionSetting: "Reacciones para mostrar en el menú de reacciones" +emojiPicker: "Selector de emojis" +pinnedEmojisForReactionSettingDescription: "Puedes seleccionar reacciones para fijarlos en el selector" +pinnedEmojisSettingDescription: "Puedes seleccionar emojis para fijarlos en el selector" +emojiPickerDisplay: "Mostrar el selector de emojis" +overwriteFromPinnedEmojisForReaction: "Sobreescribir las reacciones fijadas" +overwriteFromPinnedEmojis: "Sobreescribir los emojis fijados" reactionSettingDescription2: "Arrastre para reordenar, click para borrar, apriete la tecla + para añadir." rememberNoteVisibility: "Recordar visibilidad" attachCancel: "Quitar adjunto" @@ -261,6 +266,7 @@ removed: "Borrado" removeAreYouSure: "¿Desea borrar \"{x}\"?" deleteAreYouSure: "¿Desea borrar \"{x}\"?" resetAreYouSure: "¿Desea reestablecer?" +areYouSure: "¿Estás conforme?" saved: "Guardado" messaging: "Chat" upload: "Subir" @@ -311,6 +317,7 @@ folderName: "Nombre de la carpeta" createFolder: "Crear carpeta" renameFolder: "Renombrar carpeta" deleteFolder: "Borrar carpeta" +folder: "Carpeta" addFile: "Agregar archivo" emptyDrive: "El drive está vacío" emptyFolder: "La carpeta está vacía" @@ -437,7 +444,6 @@ share: "Compartir" notFound: "No se encuentra" notFoundDescription: "No se encontró la página correspondiente a la URL elegida" uploadFolder: "Carpeta de subidas por defecto" -cacheClear: "Borrar caché" markAsReadAllNotifications: "Marcar todas las notificaciones como leídas" markAsReadAllUnreadNotes: "Marcar todas las notas como leídas" markAsReadAllTalkMessages: "Marcar todos los chats como leídos" @@ -556,6 +562,8 @@ showInPage: "Mostrar en la página" popout: "Popout" volume: "Volumen" masterVolume: "Volumen principal" +notUseSound: "Sin sonido" +useSoundOnlyWhenActive: "Sonar solo cuando CherryPick esté activo" details: "Detalles" chooseEmoji: "Elije un emoji" unableToProcess: "La operación no se puede llevar a cabo" @@ -576,6 +584,10 @@ output: "Salida" script: "Script" disablePagesScript: "Deshabilitar AiScript en Páginas" updateRemoteUser: "Actualizar información de usuario remoto" +unsetUserAvatar: "Quitar avatar" +unsetUserAvatarConfirm: "¿Confirmas que quieres quitar tu avatar?" +unsetUserBanner: "Quitar banner" +unsetUserBannerConfirm: "¿Confirmas que quieres quitar tu banner?" deleteAllFiles: "Borrar todos los archivos" deleteAllFilesConfirm: "¿Desea borrar todos los archivos?" removeAllFollowing: "Retener todos los siguientes" @@ -647,6 +659,7 @@ smtpSecure: "Usar SSL/TLS implícito en la conexión SMTP" smtpSecureInfo: "Apagar cuando se use STARTTLS" testEmail: "Prueba de envío" wordMute: "Silenciar palabras" +hardWordMute: "Filtro de palabra fuerte" regexpError: "Error de la expresión regular" regexpErrorDescription: "Ocurrió un error en la expresión regular en la linea {line} de las palabras muteadas {tab}" instanceMute: "Instancias silenciadas" @@ -880,8 +893,8 @@ makeReactionsPublicDescription: "Todas las reacciones que hayas hecho serán pú classic: "Clásico" muteThread: "Silenciar hilo" unmuteThread: "Mostrar hilo" -ffVisibility: "Visibilidad de seguidores y seguidos" -ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes te siguen" +followingVisibility: "Visibilidad de seguidos" +followersVisibility: "Visibilidad de seguidores" continueThread: "Ver la continuación del hilo" deleteAccountConfirm: "La cuenta será borrada. ¿Está seguro?" incorrectPassword: "La contraseña es incorrecta" @@ -993,6 +1006,7 @@ assign: "Asignar" unassign: "Quitar" color: "Color" manageCustomEmojis: "Administrar emojis personalizados" +manageAvatarDecorations: "Administrar decoraciones de avatar" youCannotCreateAnymore: "Has llegado al límite de creaciones." cannotPerformTemporary: "Temporalmente no disponible" cannotPerformTemporaryDescription: "Esta acción no se puede realizar porque se excedió el límite de ejecución. Espera un poco y prueba de nuevo." @@ -1033,6 +1047,8 @@ resetPasswordConfirm: "¿Realmente quieres cambiar la contraseña?" sensitiveWords: "Palabras sensibles" sensitiveWordsDescription: "La visibilidad de todas las notas que contienen cualquiera de las palabras configuradas serán puestas en \"Inicio\" automáticamente. Puedes enumerás varias separándolas con saltos de línea" sensitiveWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares." +hiddenTags: "Hashtags ocultos" +hiddenTagsDescription: "Selecciona las etiquetas que no se mostrarán en tendencias. Una etiqueta por línea." notesSearchNotAvailable: "No se puede buscar una nota" license: "Licencia" unfavoriteConfirm: "¿Desea quitar de favoritos?" @@ -1045,6 +1061,7 @@ enableChartsForRemoteUser: "Generar gráficas de usuarios remotos." enableChartsForFederatedInstances: "Generar gráficos de servidores remotos" showClipButtonInNoteFooter: "Añadir \"Clip\" al menú de notas" reactionsDisplaySize: "Tamaño de las reacciones" +limitWidthOfReaction: "Limitar ancho de las reacciones" noteIdOrUrl: "ID o URL de la nota" video: "Video" videos: "Video" @@ -1146,6 +1163,10 @@ mutualFollow: "Os seguís mutuamente" fileAttachedOnly: "Solo notas con archivos" showRepliesToOthersInTimeline: "Mostrar respuestas a otros en la línea de tiempo" hideRepliesToOthersInTimeline: "Ocultar respuestas a otros en la línea de tiempo" +showRepliesToOthersInTimelineAll: "Muestra tus respuestas a otros usuarios que sigues en la línea de tiempo" +hideRepliesToOthersInTimelineAll: "Ocultar tus respuestas a otros usuarios que sigues en la línea de tiempo" +confirmShowRepliesAll: "Esta operación es irreversible. ¿Confirmas que quieres mostrar tus respuestas a otros usuarios que sigues en tu línea de tiempo?" +confirmHideRepliesAll: "Esta operación es irreversible. ¿Confirmas que quieres ocultar tus respuestas a otros usuarios que sigues en tu línea de tiempo?" externalServices: "Servicios Externos" impressum: "Impressum" impressumUrl: "Impressum URL" @@ -1153,7 +1174,27 @@ impressumDescription: "En algunos países, como Alemania, la inclusión del oper privacyPolicy: "Política de Privacidad" privacyPolicyUrl: "URL de la Política de Privacidad" tosAndPrivacyPolicy: "Condiciones de Uso y Política de Privacidad" +avatarDecorations: "Decoraciones de avatar" +attach: "Acoplar" +detach: "Quitar" +detachAll: "Quitar todo" +angle: "Ángulo" flip: "Echar de un capirotazo" +showAvatarDecorations: "Mostrar decoraciones de avatar" +releaseToRefresh: "Soltar para recargar" +refreshing: "Recargando..." +pullDownToRefresh: "Tira hacia abajo para recargar" +disableStreamingTimeline: "Desactivar actualizaciones en tiempo real de la línea de tiempo" +useGroupedNotifications: "Mostrar notificaciones agrupadas" +signupPendingError: "Ha habido un problema al verificar tu dirección de correo electrónico. Es posible que el enlace haya caducado." +cwNotationRequired: "Si se ha activado \"ocultar contenido\", es necesario proporcionar una descripción." +doReaction: "Añadir reacción" +code: "Código" +reloadRequiredToApplySettings: "Es necesario recargar para que se aplique la configuración." +remainingN: "Faltan: {n}" +overwriteContentConfirm: "¿Quieres sustituir todo el contenido actual?" +seasonalScreenEffect: "Efectos de pantalla asociados a estaciones" +decorate: "Decorar" _announcement: forExistingUsers: "Solo para usuarios registrados" forExistingUsersDescription: "Este anuncio solo se mostrará a aquellos usuarios registrados en el momento de su publicación. Si se deshabilita esta opción, aquellos usuarios que se registren tras su publicación también lo verán." @@ -1163,6 +1204,10 @@ _announcement: tooManyActiveAnnouncementDescription: "Tener demasiados anuncios activos empeora la experiencia de usuario. Por favor, considera archivar aquellos anuncios que hayan quedado obsoletos." readConfirmTitle: "¿Marcar como leído?" readConfirmText: "Esto marcará el contenido de \"{title}\" como leído." + shouldNotBeUsedToPresentPermanentInfo: "Dado que puede impactar en la experiencia de usuario de forma significativa, es recomendable usar notificaciones en el flujo de información en vez de información persistente." + dialogAnnouncementUxWarn: "Mostrar dos o más notificaciones en formato diálogo a la vez puede impactar en la experiencia de usuario de forma significativa, úsalos con cuidado." + silence: "Silenciar notificaciones" + silenceDescription: "Si lo activas, no enviarás notificación sobre este anuncio y el usuario no tendrá que leerlo." _initialAccountSetting: accountCreated: "¡La cuenta ha sido creada!" letsStartAccountSetup: "Para empezar, creemos tu perfil." @@ -1175,8 +1220,77 @@ _initialAccountSetting: pushNotificationDescription: "Habilitar las notificaciones push te permitirá recibir notificaciones de {name} directamente en tu dispositivo." initialAccountSettingCompleted: "¡Configuración del perfil completada!" haveFun: "¡Disfruta de {name}!" + youCanContinueTutorial: "Puedes proceder a un tutorial sobre cómo usar {name} (CherryPick) o puedes terminar la instalación aquí y empezar a usarlo ya mismo." + startTutorial: "Comenzar tutorial" skipAreYouSure: "¿Realmente quieres saltarte la configuración del perfil?" laterAreYouSure: "¿Realmente quieres configurar tu perfil después?" +_initialTutorial: + launchTutorial: "Comenzar tutorial" + title: "Tutorial" + wellDone: "¡Bien hecho!" + skipAreYouSure: "¿Salir del tutorial?" + _landing: + title: "Bienvenid@ al tutorial" + description: "Aquí podrás aprender las nociones básicas sobre cómo usar CherryPick y sus funciones." + _note: + title: "¿Qué es una nota?" + description: "Las publicaciones en CherryPick se llaman 'Notas'. Las notas se ordenan de forma cronológica en la línea de tiempo y se actualizan en tiempo real." + reply: "Pulsa en este botón para contestar a un mensaje. También es posible contestar a otras contestaciones, continuando así la conversación como un hilo." + renote: "Puedes compartir esa nota en tu propia línea de tiempo. También puedes añadir una cita con tus comentarios." + reaction: "Puedes añadir reacciones a la Nota. Se explicarán más detalles en la siguiente página." + menu: "Puedes ver los detalles de la Nota, copiar enlaces, y realizar otras acciones." + _reaction: + title: "¿Qué son las reacciones?" + description: "Se puede reaccionar a las Notas con diferentes emojis. Las reacciones te permiten expresar matices que no se pueden transmitir con un simple 'me gusta'." + letsTryReacting: "Puedes añadir reacciones pulsando en el botón '+' de la nota. ¡Intenta reaccionar a esta nota de ejemplo!" + reactToContinue: "Añade una reacción para continuar." + reactNotification: "Recibirás notificaciones en tiempo real cuando alguien reaccione a tu nota." + reactDone: "Puedes deshacer una reacción pulsando en el botón '-'." + _timeline: + title: "El concepto de Línea de tiempo" + description1: "CherryPick proporciona múltiples líneas de tiempo basadas en su uso (algunas pueden no estar disponibles dependiendo de las políticas de la instancia)." + home: "Puedes ver los posts de las cuentas que sigues." + local: "Puedes ver los posts de todos los usuarios de este servidor." + social: "Se ven los posts de la línea de tiempo de inicio junto con los de la línea de tiempo local." + global: "Puedes ver notas de todos los servidores conectados." + description2: "Puedes cambiar la línea de tiempo en la parte superior de la pantalla cuando quieras." + description3: "Además, hay listas de líneas de tiempo y listas de canales. Para más detalle, por favor visita este enlace: {link}" + _postNote: + title: "Ajustes de publicación de nota" + description1: "Cuando publicas una nota en CherryPick, hay varias opciones disponibles. El formulario tiene este aspecto." + _visibility: + description: "Puedes limitar quién puede ver tu nota." + public: "Tu nota será visible para todos los usuarios." + home: "Publicar solo en la línea de tiempo de Inicio. La nota se verá en tu perfil, la verán tus seguidores y también cuando sea renotada." + followers: "Visible solo para seguidores. Sólo tus seguidores podrán ver la nota, y no podrá ser renotada por otras personas." + direct: "Visible sólo para usuarios específicos, y el destinatario será notificado. Puede usarse como alternativa a la mensajería directa." + doNotSendConfidencialOnDirect1: "¡Ten cuidado cuando vayas a enviar información sensible!" + doNotSendConfidencialOnDirect2: "Los administradores del servidor pueden leer lo que escribes. Ten cuidado cuando envíes información sensible en notas directas en servidores no confiables." + localOnly: "Publicando con esta opción seleccionada, la nota no se federará hacia otros servidores. Los usuarios de otros servidores no podrán ver estas notas directamente, sin importar los ajustes seleccionados más arriba." + _cw: + title: "Alerta de contenido (CW)" + description: "En lugar de mostrarse el contenido de la nota, se mostrará lo que escribas en el campo \"comentarios\". Pulsando en \"leer más\" desplegará el contenido de la nota." + _exampleNote: + cw: "¡Esto te hará tener hambre!" + note: "Acabo de comerme un donut de chocolate glaseado 🍩😋" + useCases: "Esto se usa cuando las normas del servidor lo requieren, o para ocultar spoilers o contenido sensible." + _howToMakeAttachmentsSensitive: + title: "¿Cómo puedo marcar adjuntos como contenido sensible?" + description: "Cuando las normas del servidor lo requieran, o el contenido lo requiera, marca la opción de \"contenido sensible\" para el adjunto." + tryThisFile: "¡Prueba a marcar la imagen adjunta como contenido sensible!" + _exampleNote: + note: "Ups, la he liado al abrir la tapa del natto..." + method: "Para marcar un adjunto como sensible, haz clic en la miniatura, abre el menú, y haz clic en \"Marcar como sensible\"." + sensitiveSucceeded: "Cuando adjuntes archivos, por favor, ten en cuenta las normas del servidor para marcarlos como contenido sensible." + doItToContinue: "Marca el archivo adjunto como sensible para continuar." + _done: + title: "¡Has completado el tutorial! 🎉" + description: "Las funciones que mostramos aquí son sólo una pequeña parte. Para más detalles sobre el funcionamiento de CherryPick, pulsa en este enlace: {link}" +_timelineDescription: + home: "En la línea de tiempo de Inicio puedes ver las notas de las cuentas a las que sigues." + local: "En la línea de tiempo Local puedes ver las notas de todos los usuarios del servidor." + social: "En la línea de tiempo Social verás las notas de Inicio y Local a la vez." + global: "En la línea de tiempo Global verás las notas de todos los servidores conectados." _serverRules: description: "Un conjunto de reglas que serán mostradas antes del registro. Configurar un sumario de términos de servicio es recomendado." _serverSettings: @@ -1188,6 +1302,9 @@ _serverSettings: manifestJsonOverride: "Sobreescribir manifest.json" shortName: "Nombre corto" shortNameDescription: "Forma corta del nombre de la instancia que puede mostrarse si el nombre completo es demasiado largo." + fanoutTimelineDescription: "Incrementa el rendimiento de forma significativa cuando se obtienen las líneas de tiempo y reduce la carga en la base de datos. A cambio, el uso de la memoria en Redis incrementará. Considera desactivar esta opción en caso de que tu servidor tenga poca memoria o detectes inestabilidad." + fanoutTimelineDbFallback: "Cargar desde la base de datos" + fanoutTimelineDbFallbackDescription: "Cuando esta opción está habilitada, la carga de peticiones adicionales de la línea de tiempo se hará desde la base de datos cuando éstas no se encuentren en la caché. Al deshabilitar esta opción se reduce la carga del servidor, pero limita el número de líneas de tiempo que pueden obtenerse." _accountMigration: moveFrom: "Trasladar de otra cuenta a ésta" moveFromSub: "Crear un alias para otra cuenta." @@ -1418,6 +1535,9 @@ _achievements: _setNameToSyuilo: title: "Complejo de superioridad" description: "Configurar el nombre como 'Syuilo'" + _setNameToNoriDev: + title: "Complejo de superioridad (CherryPick)" + description: "Configurar el nombre como 'NoriDev'" _passedSinceAccountCreated1: title: "Primer aniversario" description: "Pasó un año desde la creación de la cuenta" @@ -1441,10 +1561,13 @@ _achievements: _brainDiver: title: "Brain Diver" description: "Publicaste un vínculo a \"Brain Diver\"" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "Sobrecarga de pruebas" description: "Envía muchas notificaciones de prueba en un corto espacio de tiempo" + _tutorialCompleted: + title: "Diploma del Curso Básico de CherryPick" + description: "Tutorial completado" _role: new: "Crear rol" edit: "Editar rol" @@ -1455,7 +1578,9 @@ _role: assignTarget: "Asignar objetivo" descriptionOfAssignTarget: "Manual Para cambiar manualmente lo que se incluye en este rol.\nCondicional configura una condición, y los usuarios que cumplan la condición serán incluídos automáticamente." manual: "manual" + manualRoles: "Roles manuales" conditional: "condicional" + conditionalRoles: "Roles condicionales" condition: "condición" isConditionalRole: "Esto es un rol condicional" isPublic: "Publicar rol" @@ -1488,6 +1613,7 @@ _role: inviteLimitCycle: "Enfriamiento del límite de invitaciones" inviteExpirationTime: "Intervalo de caducidad de invitaciones" canManageCustomEmojis: "Administrar emojis personalizados" + canManageAvatarDecorations: "Administrar decoraciones de avatar" driveCapacity: "Capacidad del drive" alwaysMarkNsfw: "Siempre marcar archivos como NSFW" pinMax: "Máximo de notas fijadas" @@ -1503,6 +1629,7 @@ _role: canHideAds: "Puede ocultar anuncios" canSearchNotes: "Uso de la búsqueda de notas" canUseTranslator: "Uso de traductor" + avatarDecorationLimit: "Número máximo de decoraciones de avatar" _condition: isLocal: "Usuario local" isRemote: "Usuario remoto" @@ -1531,6 +1658,7 @@ _emailUnavailable: disposable: "No es un correo reutilizable" mx: "Servidor de correo inválido" smtp: "Servidor de correo no disponible" + banned: "Email no disponible" _ffVisibility: public: "Publicar" followers: "Visible solo para seguidores" @@ -1607,6 +1735,7 @@ _aboutMisskey: donate: "Donar a Misskey" morePatrons: "Muchas más personas nos apoyan. Muchas gracias🥰" patrons: "Patrocinadores" + projectMembers: "Miembros del proyecto" _displayOfSensitiveMedia: respect: "Esconder medios marcados como sensibles" ignore: "Mostrar medios marcados como sensibles" @@ -1697,6 +1826,7 @@ _channel: notesCount: "{n} notas" nameAndDescription: "Nombre y descripción" nameOnly: "Sólo nombre" + allowRenoteToExternal: "Permitir renotas y menciones fuera del canal" _menuDisplay: sideFull: "Horizontal" sideIcon: "Horizontal (ícono)" @@ -1790,6 +1920,14 @@ _sfx: chatBg: "Chat (Fondo)" antenna: "Antena receptora" channel: "Notificaciones del canal" + reaction: "Al seleccionar una reacción" +_soundSettings: + driveFile: "Usar un archivo de audio en Drive" + driveFileWarn: "Selecciona un archivo de audio en Drive." + driveFileTypeWarn: "Este archivo es incompatible" + driveFileTypeWarnDescription: "Selecciona un archivo de audio" + driveFileDurationWarn: "La duración del audio es demasiado larga." + driveFileDurationWarnDescription: "Usar un audio de larga duración puede llegar a molestar mientras usas CherryPick. ¿Quieres continuar?" _ago: future: "Futuro" justNow: "Justo ahora" @@ -1801,6 +1939,14 @@ _ago: monthsAgo: "Hace {n} meses" yearsAgo: "Hace {n} años" invalid: "No hay nada que ver aqui" +_timeIn: + seconds: "En {n} segundos" + minutes: "En {n}m" + hours: "En {n}h" + days: "En {n}d" + weeks: "En {n}sem." + months: "En {n}M" + years: "En {n} años" _time: second: "Segundos" minute: "Minutos" @@ -1927,6 +2073,7 @@ _widgets: _userList: chooseList: "Seleccione una lista" clicker: "Cliqueador" + birthdayFollowings: "Hoy cumplen años" _cw: hide: "Ocultar" show: "Ver más" @@ -1989,6 +2136,7 @@ _profile: changeAvatar: "Cambiar avatar" changeBanner: "Cambiar banner" verifiedLinkDescription: "Introduciendo una URL que contiene un enlace a tu perfil, se puede mostrar un icono de verificación de propiedad al lado del campo." + avatarDecorationMax: "Puedes añadir un máximo de {max} decoraciones de avatar." _exportOrImport: allNotes: "Todas las notas" favoritedNotes: "Notas favoritas" @@ -2105,8 +2253,6 @@ _notification: youGotReply: "Respuesta de {name}" youGotQuote: "Citado por {name}" youRenoted: "Renotado por {name}" - youGotMessagingMessageFromUser: "{name} comenzó un chat contigo" - youGotMessagingMessageFromGroup: "Tienes un chat de {name}" youWereFollowed: "te ha seguido" youReceivedFollowRequest: "Has mandado una solicitud de seguimiento" yourFollowRequestAccepted: "Tu solicitud de seguimiento fue aceptada" @@ -2114,12 +2260,16 @@ _notification: pollEnded: "Estan disponibles los resultados de la encuesta" newNote: "Nueva nota" unreadAntennaNote: "Antena {name}" + roleAssigned: "Rol asignado" emptyPushNotificationMessage: "Se han actualizado las notificaciones push" achievementEarned: "Logro desbloqueado" testNotification: "Notificación de prueba" checkNotificationBehavior: "Comprobar comportamiento de la notificación" sendTestNotification: "Enviar notificación de prueba" notificationWillBeDisplayedLikeThis: "Las notificaciones tendrán este aspecto" + reactedBySomeUsers: "{n} usuarios han reaccionado" + renotedBySomeUsers: "{n} usuarios han renotado" + followedBySomeUsers: "Seguido por {n} usuarios" _types: all: "Todo" note: "Nuevas notas" @@ -2133,6 +2283,7 @@ _notification: receiveFollowRequest: "Recibió una solicitud de seguimiento" followRequestAccepted: "El seguimiento fue aceptado" groupInvited: "Invitado al grupo" + roleAssigned: "Rol asignado" achievementEarned: "Logro desbloqueado" app: "Notificaciones desde aplicaciones" _actions: @@ -2224,6 +2375,11 @@ _moderationLogTypes: createAd: "Anuncio creado" deleteAd: "Anuncio eliminado" updateAd: "Anuncio actualizado" + createAvatarDecoration: "Decoración de avatar creada" + updateAvatarDecoration: "Decoración de avatar actualizada" + deleteAvatarDecoration: "Decoración de avatar eliminada" + unsetUserAvatar: "Quitar decoración de avatar de este usuario" + unsetUserBanner: "Quitar banner de este usuario" _fileViewer: title: "Detalles del archivo" type: "Tipo de archivo" @@ -2232,3 +2388,57 @@ _fileViewer: uploadedAt: "Subido el" attachedNotes: "Notas adjuntas" thisPageCanBeSeenFromTheAuthor: "Esta página solo puede ser vista por el autor." +_externalResourceInstaller: + title: "Instalar desde sitio externo" + checkVendorBeforeInstall: "Asegúrate de que el distribuidor de este recurso es de confianza antes de proceder a la instalación." + _plugin: + title: "¿Quieres instalar este plugin?" + metaTitle: "Información del plugin" + _theme: + title: "¿Quieres instalar este tema?" + metaTitle: "Información del tema" + _meta: + base: "Esquema de color base" + _vendorInfo: + title: "Información del distribuidor" + endpoint: "Terminal referenciada" + hashVerify: "Verificación de hash" + _errors: + _invalidParams: + title: "Parámetros inválidos" + description: "No hay información suficiente para cargar datos de un sitio externo. Por favor, confirma la URL introducida." + _resourceTypeNotSupported: + title: "Este recurso externo no es compatible" + description: "El tipo de este recurso externo no es compatible. Por favor, contacta con el administrador del sitio." + _failedToFetch: + title: "No se pudo obtener los datos" + fetchErrorDescription: "Ha ocurrido un error al comunicarse con el sitio externo. Si no se soluciona tras intentarlo otra vez, por favor, contacta con el administrador del sitio." + parseErrorDescription: "Ha ocurrido un error al procesar los datos obtenidos del sitio externo. Por favor, contacta con el administrador del sitio." + _hashUnmatched: + title: "Verificación de datos fallida" + description: "Ha ocurrido un error al verificar la integridad de los datos obtenidos. Por seguridad, la instalación no se puede realizar. Por favor, contacta con el administrador del sitio." + _pluginParseFailed: + title: "Error de AiScript" + description: "Los datos se han obtenido correctamente, pero ha ocurrido un error de AiScript al procesarlos. Por favor, contacta con el autor del plugin. Se pueden ver más detalles del error en la consola de Javascript." + _pluginInstallFailed: + title: "Instalación del plugin fallida." + description: "Ha ocurrido un problema al instalar el plugin. Por favor, inténtalo de nuevo. Se pueden ver más detalles del error en la consola de Javascript." + _themeParseFailed: + title: "Análisis del tema fallido" + description: "Los datos se han obtenido correctamente, pero ha ocurrido un error al analizar el tema. Por favor, contacta con el autor. Se pueden ver más detalles del error en la consola de Javascript." + _themeInstallFailed: + title: "Instalación de tema fallida" + description: "Ha ocurrido un problema al instalar el tema. Por favor, inténtalo de nuevo. Se pueden ver más detalles del error en la consola de Javascript." +_dataSaver: + _media: + title: "Cargando Multimedia" + description: "Desactiva la carga automática de imágenes y vídeos. Tendrás que tocar en las imágenes y vídeos ocultos para cargarlos." + _avatar: + title: "Avatares animados" + description: "Desactiva la animación de los avatares. Las imágenes animadas pueden llegar a ser de mayor tamaño que las normales, por lo que al desactivarlas puedes reducir el consumo de datos." + _urlPreview: + title: "Vista previa de URLs" + description: "Desactiva la carga de vistas previas de las URLs." + _code: + title: "Resaltar código" + description: "Si se usa resaltado de código en MFM, etc., no se cargará hasta pulsar en ello. El resaltado de sintaxis requiere la descarga de archivos de definición para cada lenguaje de programación. Debido a esto, al deshabilitar la carga automática de estos archivos reducirás el consumo de datos." diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 210ac171f7..e6d6ec506e 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -75,7 +75,7 @@ import: "Importer" export: "Exporter" files: "Fichiers" download: "Télécharger" -driveFileDeleteConfirm: "Êtes-vous sûr de vouloir supprimer le fichier \"{name}\" ? Les notes liées à ce fichier seront aussi supprimées." +driveFileDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer le fichier « {name} » ? Les notes avec ce fichier joint seront aussi supprimées." unfollowConfirm: "Désirez-vous vous désabonner de {name} ?" exportRequested: "Vous avez demandé une exportation. L’opération pourrait prendre un peu de temps. Une fois terminée, le fichier sera ajouté au Drive." importRequested: "Vous avez initié un import. Cela pourrait prendre un peu de temps." @@ -121,7 +121,12 @@ sensitive: "Contenu sensible" add: "Ajouter" reaction: "Réactions" reactions: "Réactions" -reactionSetting: "Réactions à afficher dans le sélecteur de réactions" +emojiPicker: "Sélecteur d’émojis" +pinnedEmojisForReactionSettingDescription: "Vous pouvez définir les émojis épinglés lors de la réaction" +pinnedEmojisSettingDescription: "Vous pouvez définir les émojis épinglés lors de la saisie de l'émoji" +emojiPickerDisplay: "Affichage du sélecteur d'émojis" +overwriteFromPinnedEmojisForReaction: "Remplacer par les émojis épinglés pour la réaction" +overwriteFromPinnedEmojis: "Remplacer par les émojis épinglés globalement" reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser « + » pour ajouter." rememberNoteVisibility: "Se souvenir de la visibilité des notes" attachCancel: "Supprimer le fichier attaché" @@ -157,6 +162,7 @@ addEmoji: "Ajouter un émoji" settingGuide: "Configuration proposée" cacheRemoteFiles: "Mise en cache des fichiers distants" cacheRemoteFilesDescription: "Lorsque cette option est désactivée, les fichiers distants sont chargés directement depuis l’instance distante. La désactiver diminuera certes l’utilisation de l’espace de stockage local mais augmentera le trafic réseau puisque les miniatures ne seront plus générées." +youCanCleanRemoteFilesCache: "Vous pouvez supprimer tous les caches en cliquant le bouton 🗑️ dans la gestion des fichiers." cacheRemoteSensitiveFiles: "Mettre en cache les fichiers distants sensibles" cacheRemoteSensitiveFilesDescription: "Si vous désactivez ce paramètre, les fichiers sensibles distants ne seront pas mis en cache et un lien direct sera utilisé à la place" flagAsBot: "Ce compte est un robot" @@ -258,14 +264,15 @@ imageUrl: "URL de l’image" remove: "Supprimer" removed: "Supprimé" removeAreYouSure: "Êtes-vous sûr·e de vouloir supprimer « {x} » ?" -deleteAreYouSure: "Êtes-vous sûr·e de vouloir supprimer「{x}」?" +deleteAreYouSure: "Êtes-vous sûr·e de vouloir supprimer « {x} » ?" resetAreYouSure: "Voulez-vous réinitialiser ?" +areYouSure: "Êtes-vous sûr·e ?" saved: "Enregistré" messaging: "Discuter" upload: "Téléverser" keepOriginalUploading: "Garder l’image d’origine" keepOriginalUploadingDescription: "Conserve la version originale lors du téléchargement d'images. S'il est désactivé, le navigateur génère l'image pour la publication web lors du téléchargement." -fromDrive: "Depuis le Drive" +fromDrive: "Depuis le Disque" fromUrl: "Depuis une URL" uploadFromUrl: "Téléverser via une URL" uploadFromUrlDescription: "URL du fichier que vous souhaitez téléverser" @@ -299,7 +306,7 @@ dark: "Sombre" lightThemes: "Thèmes clairs" darkThemes: "Thèmes sombres" syncDeviceDarkMode: "Utiliser le mode sombre de votre appareil" -drive: "Drive" +drive: "Disque" fileName: "Nom du fichier" selectFile: "Choisir le fichier" selectFiles: "Choisir les fichiers" @@ -310,8 +317,9 @@ folderName: "Nom du dossier" createFolder: "Créer un dossier" renameFolder: "Renommer le dossier" deleteFolder: "Supprimer le dossier" +folder: "Dossier" addFile: "Ajouter un fichier" -emptyDrive: "Le Drive est vide" +emptyDrive: "Le Disque est vide" emptyFolder: "Le dossier est vide" unableToDelete: "Suppression impossible" inputNewFileName: "Entrez un nouveau nom de fichier" @@ -355,8 +363,8 @@ disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur registration: "S’inscrire" enableRegistration: "Autoriser les nouvelles inscriptions" invite: "Inviter" -driveCapacityPerLocalAccount: "Volume du Drive par utilisateur local" -driveCapacityPerRemoteAccount: "Volume du Drive par utilisateur distant" +driveCapacityPerLocalAccount: "Capacité de stockage du Disque par utilisateur local" +driveCapacityPerRemoteAccount: "Capacité de stockage du Disque par utilisateur distant" inMb: "en mégaoctets" bannerUrl: "URL de l’image de la bannière" backgroundImageUrl: "URL de l'image d'arrière-plan" @@ -428,6 +436,7 @@ lastUsed: "Dernier utilisé" lastUsedAt: "Dernière utilisation : {t}" unregister: "Se désinscrire" passwordLessLogin: "Se connecter sans mot de passe" +passwordLessLoginDescription: "Se connecter uniquement avec une clé de sécurité ou une clé d'accès sans utiliser de mot de passe" resetPassword: "Réinitialiser le mot de passe" newPasswordIs: "Votre nouveau mot de passe est \"{password}\"" reduceUiAnimation: "Réduire les animations dans l’interface" @@ -435,7 +444,6 @@ share: "Partager" notFound: "Non trouvé" notFoundDescription: "Aucune page ne correspond à l’URL spécifiée." uploadFolder: "Emplacement de téléversement par défaut" -cacheClear: "Vider le cache" markAsReadAllNotifications: "Marquer toutes les notifications comme lues" markAsReadAllUnreadNotes: "Marquer toutes les notes comme lues" markAsReadAllTalkMessages: "Marquer toutes les discussions comme lues" @@ -495,6 +503,7 @@ showNoteActionsOnlyHover: "Afficher les actions de note uniquement au survol" noHistory: "Pas d'historique" signinHistory: "Historique de connexion" enableAdvancedMfm: "Activer la MFM avancée" +enableAnimatedMfm: "Activer le MFM animé" doing: "En cours..." category: "Catégorie" tags: "Étiquettes" @@ -503,6 +512,7 @@ createAccount: "Créer un compte" existingAccount: "Compte existant" regenerate: "Générer à nouveau" fontSize: "Taille de la police" +mediaListWithOneImageAppearance: "Hauteur des listes de médias n'ayant qu'une image " limitTo: "Limiter à {x}" noFollowRequests: "Vous n’avez aucune demande d’abonnement en attente" openImageInNewTab: "Ouvrir les images dans un nouvel onglet" @@ -540,6 +550,7 @@ objectStorageSetPublicRead: "Régler sur « public » lors de l'envoi" serverLogs: "Journal du serveur" deleteAll: "Supprimer tout" showFixedPostForm: "Afficher le formulaire de publication en haut du fil d'actualité" +showFixedPostFormInChannel: "Afficher le formulaire de publication en haut du fil (canaux)" withRepliesByDefaultForNewlyFollowed: "Afficher les réponses des nouvelles personnes que vous suivez dans le fil par défaut" newNoteRecived: "Voir les nouvelles notes" sounds: "Sons" @@ -550,6 +561,8 @@ showInPage: "Afficher dans la page" popout: "Fenêtre contextuelle" volume: "Volume" masterVolume: "Volume principal" +notUseSound: "Ne pas émettre de son" +useSoundOnlyWhenActive: "Émettre des sons uniquement quand CherryPick est active" details: "Détails" chooseEmoji: "Choisissez un émoji" unableToProcess: "L’opération n’a pas pu être complétée." @@ -570,9 +583,13 @@ output: "Sortie" script: "Script" disablePagesScript: "Désactiver AiScript sur les Pages" updateRemoteUser: "Mettre à jour les informations de l’utilisateur·rice distant·e" +unsetUserAvatar: "Supprimer l’avatar" +unsetUserAvatarConfirm: "Êtes-vous sûr·e de vouloir supprimer l'avatar ?" +unsetUserBanner: "Supprimer la bannière" +unsetUserBannerConfirm: "Êtes-vous sûr·e de vouloir supprimer la bannière ?" deleteAllFiles: "Supprimer tous les fichiers" deleteAllFilesConfirm: "Êtes-vous sûr·e de vouloir supprimer tous les fichiers ?" -removeAllFollowing: "Retenir tous les abonnements" +removeAllFollowing: "Se désabonner de tous les utilisateurs auxquels vous êtes abonné·e" removeAllFollowingDescription: "Se désabonner de tous les comptes de {host}. Veuillez lancer cette action dans les cas où l’instance n’existe plus, etc." userSuspended: "Cet·te utilisateur·rice a été suspendu·e." userSilenced: "Cette utilisateur·trice a été mis·e en sourdine." @@ -641,6 +658,7 @@ smtpSecure: "Utiliser SSL/TLS implicitement dans les connexions SMTP" smtpSecureInfo: "Désactiver cette option lorsque STARTTLS est utilisé" testEmail: "Tester la distribution de courriel" wordMute: "Filtre de mots" +hardWordMute: "Filtre de mots dur" regexpError: "Erreur d’expression régulière" regexpErrorDescription: "Une erreur s'est produite dans l'expression régulière sur la ligne {ligne} de votre mot muet {tab} :" instanceMute: "Instance en sourdine" @@ -713,14 +731,15 @@ pollVotesCount: "Nombre de votes envoyés" pollVotedCount: "Nombre de votes reçus" yes: "Oui" no: "Non" -driveFilesCount: "Nombre de fichiers dans le Drive" -driveUsage: "Utilisation du Drive" +driveFilesCount: "Nombre de fichiers sur le Disque" +driveUsage: "Utilisation du Disque" noCrawle: "Refuser l'indexation par les robots" noCrawleDescription: "Demandez aux moteurs de recherche de ne pas indexer votre page de profil, vos notes, vos pages, etc." lockedAccountInfo: "À moins que vous ne définissiez la visibilité de votre note sur \"Abonné-e-s\", vos notes sont visibles par tous, même si vous exigez que les demandes d'abonnement soient approuvées manuellement." alwaysMarkSensitive: "Marquer les médias comme contenu sensible par défaut" loadRawImages: "Affichage complet des images jointes au lieu des vignettes" disableShowingAnimatedImages: "Désactiver l'animation des images" +highlightSensitiveMedia: "Mettre en évidence les médias sensibles" verificationEmailSent: "Un e-mail de vérification a été envoyé. Veuillez accéder au lien pour compléter la vérification." notSet: "Non défini" emailVerified: "Votre adresse e-mail a été vérifiée." @@ -857,7 +876,7 @@ pubSub: "Comptes Pub/Sub" lastCommunication: "Dernière communication" resolved: "Résolu" unresolved: "En attente" -breakFollow: "Ne plus suivre" +breakFollow: "Supprimer l'abonné·e" breakFollowConfirm: "Êtes-vous sûr de vouloir vous désabonner ?" itsOn: "Activé" itsOff: "Désactivé" @@ -873,8 +892,8 @@ makeReactionsPublicDescription: "Ceci rendra la liste de toutes vos réactions d classic: "Classique" muteThread: "Masquer cette discussion" unmuteThread: "Ne plus masquer le fil" -ffVisibility: "Visibilité des abonnés/abonnements" -ffVisibilityDescription: "Permet de configurer qui peut voir les personnes que tu suis et les personnes qui te suivent." +followingVisibility: "Visibilité des abonnements" +followersVisibility: "Visibilité des abonnés" continueThread: "Afficher la suite du fil" deleteAccountConfirm: "Votre compte sera supprimé. Êtes vous certain ?" incorrectPassword: "Le mot de passe est incorrect." @@ -918,7 +937,7 @@ noEmailServerWarning: "Serveur de courrier non configuré." thereIsUnresolvedAbuseReportWarning: "Il n’y a aucun rapport non résolu." recommended: "Recommandé" check: "Vérifier" -driveCapOverrideLabel: "Modifier la capacité de stockage du drive de cet·te utilisateur·rice" +driveCapOverrideLabel: "Modifier la capacité de stockage du Disque de cet·te utilisateur·rice" driveCapOverrideCaption: "Si une valeur inférieure à 0 est spécifiée, elle est annulée." requireAdminForView: "Vous devez être connecté avec un compte administrateur pour les visualiser." isSystemAccount: "Ces comptes sont automatiquement créés et gérés par le système." @@ -976,6 +995,7 @@ show: "Affichage" neverShow: "Ne plus afficher" remindMeLater: "Peut-être plus tard" didYouLikeMisskey: "Avez-vous aimé CherryPick ?" +pleaseDonate: "CherryPick est le logiciel libre utilisé par {host}. Merci de faire un don pour que nous puissions continuer à le développer !" roles: "Rôles" role: "Rôles" noRole: "Aucun rôle" @@ -988,12 +1008,15 @@ manageCustomEmojis: "Gestion des émojis personnalisés" manageAvatarDecorations: "Gérer les décorations d'avatar" youCannotCreateAnymore: "Vous avez atteint la limite de création." cannotPerformTemporary: "Temporairement indisponible" +cannotPerformTemporaryDescription: "Temporairement indisponible puisque le nombre d'opérations dépasse la limite. Veuillez patienter un peu, puis réessayer." invalidParamError: "Paramètres invalides" permissionDeniedError: "Opération refusée" +permissionDeniedErrorDescription: "Ce compte n'a pas la permission d'effectuer cette opération." preset: "Préréglage" selectFromPresets: "Sélectionner à partir des préréglages" achievements: "Accomplissements" gotInvalidResponseError: "Réponse du serveur invalide" +gotInvalidResponseErrorDescription: "Il se peut que le serveur soit hors ligne ou en maintenance. Veuillez réessayer plus tard." thisPostMayBeAnnoying: "Cette note peut gêner d'autres personnes." thisPostMayBeAnnoyingHome: "Publier vers le fil principal" thisPostMayBeAnnoyingCancel: "Annuler" @@ -1003,16 +1026,34 @@ internalServerError: "Erreur interne du serveur" copyErrorInfo: "Copier les détails de l’erreur" joinThisServer: "S'inscrire à cette instance" exploreOtherServers: "Trouver une autre instance" +letsLookAtTimeline: "Jetez un coup d'œil au fil" +disableFederationConfirm: "Voulez-vous vraiment désactiver la fédération ?" +disableFederationConfirmWarn: "Même sans fédération, la note ne sera pas privée. Dans la plupart des cas, ce n'est pas nécessaire de désactiver la fédération." disableFederationOk: "Désactiver" +invitationRequiredToRegister: "Actuellement, cette instance est uniquement sur invitation. Seuls ceux qui ont un code d'invitation peuvent s'inscrire." +emailNotSupported: "Cette instance ne prend pas en charge l'envoi de courriels" postToTheChannel: "Publier au canal" +cannotBeChangedLater: "Cela ne peut pas être modifié plus tard." +reactionAcceptance: "Acceptation des réactions" likeOnly: "Les favoris uniquement" +likeOnlyForRemote: "Toutes (mentions j'aime seulement pour les instances distantes)" +nonSensitiveOnly: "Non sensibles seulement" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "Non sensibles seulement (mentions j'aime seulement pour les instances distantes)" +rolesAssignedToMe: "Rôles attribués à moi" +resetPasswordConfirm: "Souhaitez-vous réinitialiser votre mot de passe ?" sensitiveWords: "Mots sensibles" +hiddenTags: "Hashtags cachés" +hiddenTagsDescription: "Les hashtags définis ne s'afficheront pas dans les tendances. Vous pouvez définir plusieurs hashtags en faisant un saut de ligne." notesSearchNotAvailable: "La recherche de notes n'est pas disponible." license: "Licence" myClips: "Mes clips" +drivecleaner: "Nettoyeur du Disque" retryAllQueuesConfirmText: "Cela peut augmenter temporairement la charge du serveur." +enableChartsForRemoteUser: "Générer les graphiques pour les utilisateurs distants" +enableChartsForFederatedInstances: "Générer les graphiques pour les instances distantes" showClipButtonInNoteFooter: "Ajouter « Clip » au menu d'action de la note" reactionsDisplaySize: "Taille de l'affichage des réactions" +limitWidthOfReaction: "Limiter la largeur maximale des réactions et les afficher en taille réduite" noteIdOrUrl: "Identifiant de la note ou URL" video: "Vidéo" videos: "Vidéos" @@ -1023,6 +1064,7 @@ accountMovedShort: "Ce compte a migré" operationForbidden: "Opération non autorisée" forceShowAds: "Toujours afficher les publicités" addMemo: "Ajouter un mémo" +editMemo: "Éditer le mémo" reactionsList: "Réactions" renotesList: "Liste de renotes" notificationDisplay: "Style des notifications" @@ -1035,10 +1077,13 @@ vertical: "Vertical" horizontal: "Latéral" position: "Position" serverRules: "Règles du serveur" +pleaseConfirmBelowBeforeSignup: "Pour vous inscrire sur cette instance, vous devez confirmer et accepter le contenu suivant." pleaseAgreeAllToContinue: "Pour continuer, veuillez accepter tous les champs ci-dessus." continue: "Continuer" preservedUsernames: "Noms d'utilisateur·rice réservés" +createNoteFromTheFile: "Rédiger une note de ce fichier" archive: "Archive" +channelArchiveConfirmTitle: "Voulez-vous vraiment archiver {name} ?" thisChannelArchived: "Ce canal a été archivé." displayOfNote: "Affichage de la note" initialAccountSetting: "Configuration initiale du profil" @@ -1049,11 +1094,15 @@ options: "Options" specifyUser: "Spécifier l'utilisateur·rice" failedToPreviewUrl: "Aperçu d'URL échoué" update: "Mettre à jour" +rolesThatCanBeUsedThisEmojiAsReaction: "Rôles qui peuvent utiliser cet émoji comme réaction" later: "Plus tard" goToMisskey: "Retour vers CherryPick" +additionalEmojiDictionary: "Dictionnaires d'émojis additionnels" installed: "Installé" +branding: "Image de marque" expirationDate: "Date d’expiration" waitingForMailAuth: "En attente de la vérification de l'adresse courriel" +inviteCodeCreator: "Créateur·rice de ce code d'invitation" usedAt: "Utilisé le" unused: "Non-utilisé" used: "Utilisé" @@ -1094,6 +1143,7 @@ tosAndPrivacyPolicy: "Conditions d'utilisation et politique de confidentialité" avatarDecorations: "Décorations d'avatar" attach: "Mettre" detach: "Enlever" +detachAll: "Tout enlever" angle: "Angle" flip: "Inverser" showAvatarDecorations: "Afficher les décorations d'avatar" @@ -1105,6 +1155,12 @@ useGroupedNotifications: "Grouper les notifications" signupPendingError: "Un problème est survenu lors de la vérification de votre adresse e-mail. Le lien a peut-être expiré." cwNotationRequired: "Si « Masquer le contenu » est activé, une description doit être fournie." doReaction: "Réagir" +code: "Code" +reloadRequiredToApplySettings: "Le rafraîchissement est nécessaire pour que les paramètres prennent effet." +remainingN: "Restants : {n}" +overwriteContentConfirm: "Voulez-vous remplacer le contenu actuel ?" +seasonalScreenEffect: "Effet d'écran saisonnier" +decorate: "Décorer" _announcement: readConfirmTitle: "Marquer comme lu ?" shouldNotBeUsedToPresentPermanentInfo: "Puisque cela pourrait nuire considérablement à l'expérience utilisateur pour les nouveaux utilisateurs, il est recommandé d'utiliser les annonces pour afficher des informations temporaires plutôt que des informations persistantes." @@ -1174,7 +1230,7 @@ _initialTutorial: tryThisFile: "Essayez de marquer l'image jointe à ce formulaire de publication comme sensible !" _exampleNote: note: "Oups, j'ai échoué à ouvrir le couvercle du natto..." - method: "Pour marquer un fichier joint comme sensible, cliquez sur la vignette du fichier, ouvrez le menu et cliquez sur « marquer comme sensible » ." + method: "Pour marquer un fichier joint comme sensible, cliquez sur la vignette du fichier pour ouvrir le menu et cliquez sur « marquer comme sensible » ." sensitiveSucceeded: "Quand vous joignez des fichiers, veuillez indiquer la sensibilité selon les règles du serveur." doItToContinue: "Marquez le fichier joint comme sensible pour procéder." _done: @@ -1310,6 +1366,8 @@ _achievements: title: "Référence circulaire" _setNameToSyuilo: description: "Vous avez spécifié « syuilo » comme nom" + _setNameToNoriDev: + description: "Vous avez spécifié « noridev » comme nom" _passedSinceAccountCreated1: title: "Premier anniversaire" _passedSinceAccountCreated2: @@ -1324,7 +1382,7 @@ _achievements: _cookieClicked: flavor: "Attendez une minute, vous êtes sur le mauvais site web ?" _brainDiver: - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "Débordement de tests" description: "Détruire le bouton de test de notifications dans un intervalle extrêmement court" @@ -1338,6 +1396,8 @@ _role: description: "Description du rôle" permission: "Rôle et autorisations" assignTarget: "Attribuer" + manualRoles: "Rôles manuels" + conditionalRoles: "Rôles conditionnels" condition: "Condition" isPublic: "Rôle public" options: "Options" @@ -1355,8 +1415,10 @@ _role: _options: canManageCustomEmojis: "Gestion des émojis personnalisés" canManageAvatarDecorations: "Gestion des décorations d'avatar" + driveCapacity: "Capacité de stockage du Disque" wordMuteMax: "Nombre maximal de caractères dans le filtre de mots" canUseTranslator: "Usage de la fonctionnalité de traduction" + avatarDecorationLimit: "Nombre maximal de décorations d'avatar" _sensitiveMediaDetection: description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement." sensitivity: "Sensibilité de la détection" @@ -1424,7 +1486,7 @@ _preferencesBackups: nameAlreadyExists: "Le nom de sauvegarde \"{name}\" existe déjà. Veuillez spécifier un autre nom." applyConfirm: "Voulez-vous appliquer la sauvegarde '{name}' au dispositif actuel ? La configuration actuelle de l'appareil sera perdue." saveConfirm: "Voulez-vous écraser {name} ?" - deleteConfirm: "Voulez-vous supprimer {name} ?" + deleteConfirm: "Êtes-vous sûr·e de vouloir supprimer {name} ?" renameConfirm: "Voulez-vous remplacer \"{old}\" par \"{new}\" ?" noBackups: "Aucune sauvegarde n'est disponible. L'option \"Nouvelle sauvegarde\" vous permet de sauvegarder la configuration actuelle du client sur le serveur." createdAt: "Créé : {date} {time}" @@ -1629,6 +1691,14 @@ _sfx: chatBg: "Discussion (arrière-plan)" antenna: "Réception de l’antenne" channel: "Notifications de canal" + reaction: "Lors de la sélection de la réaction" +_soundSettings: + driveFile: "Utiliser un effet sonore sur le Disque" + driveFileWarn: "Veuillez sélectionner le fichier sur le Disque" + driveFileTypeWarn: "Ce fichier n'est pas pris en charge" + driveFileTypeWarnDescription: "Veuillez sélectionner un fichier audio" + driveFileDurationWarn: "L'effet sonore est trop long" + driveFileDurationWarnDescription: "Utiliser un effet sonore long peut affecter l'utilisation de CherryPick. Voulez-vous encore continuer ?" _ago: future: "Futur" justNow: "à l’instant" @@ -1640,6 +1710,14 @@ _ago: monthsAgo: "Il y a {n} mois" yearsAgo: "Il y a {n} ans" invalid: "Il n'y a rien à voir ici" +_timeIn: + seconds: "Dans {n}s" + minutes: "Dans {n}min" + hours: "Dans {n}h" + days: "Dans {n}j" + weeks: "Dans {n} sem." + months: "Dans {n} mois" + years: "Dans {n}a" _time: second: "s" minute: "min" @@ -1657,7 +1735,7 @@ _2fa: securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser davantage le processus de connexion grâce à une clé de sécurité matérielle qui prend en charge FIDO2, ou bien en configurant l'authentification par empreinte digitale ou par code PIN sur votre appareil." securityKeyName: "Nom de la clé" removeKey: "Supprimer la clé de sécurité" - removeKeyConfirm: "Voulez-vous supprimer {name} ?" + removeKeyConfirm: "Êtes-vous sûr·e de vouloir supprimer {name} ?" renewTOTPOk: "Reconfigurer" renewTOTPCancel: "Pas maintenant" backupCodes: "Codes de Secours" @@ -1666,8 +1744,8 @@ _permissions: "write:account": "Mettre à jour les informations de votre compte" "read:blocks": "Voir les comptes bloqués" "write:blocks": "Gérer les comptes bloqués" - "read:drive": "Parcourir le Drive" - "write:drive": "Écrire sur le Drive" + "read:drive": "Parcourir le Disque" + "write:drive": "Modifier le Disque" "read:favorites": "Afficher les favoris" "write:favorites": "Gérer les favoris" "read:following": "Voir les informations de vos abonnements" @@ -1687,7 +1765,7 @@ _permissions: "read:page-likes": "Voir les mentions « J'aime » des pages" "write:page-likes": "Gérer les mentions « J'aime » sur les pages" "read:user-groups": "Voir les groupes d'utilisateur·rice·s" - "write:user-groups": "Éditer les groupes des utilisateur·rice·s" + "write:user-groups": "Éditer les groupes d'utilisateur·rice·s" "read:channels": "Lire les canaux" "write:channels": "Gérer les canaux" "read:gallery": "Voir la galerie" @@ -1742,6 +1820,7 @@ _widgets: userList: "Liste utilisateur" _userList: chooseList: "Sélectionner une liste" + birthdayFollowings: "Utilisateurs qui fêtent l'anniversaire aujourd'hui" _cw: hide: "Masquer" show: "Afficher le contenu" @@ -1778,6 +1857,7 @@ _visibility: followersDescription: "Publier à vos abonné·e·s uniquement" specified: "Direct" specifiedDescription: "Publier uniquement aux utilisateur·rice·s mentionné·e·s" + disableFederation: "Défédérer" _postForm: replyPlaceholder: "Répondre à cette note ..." quotePlaceholder: "Citez cette note ..." @@ -1799,8 +1879,9 @@ _profile: metadataDescription: "Vous pouvez afficher jusqu'à quatre informations supplémentaires dans votre profil." metadataLabel: "Étiquette" metadataContent: "Contenu" - changeAvatar: "Changer l'image de profil" + changeAvatar: "Changer l'avatar" changeBanner: "Changer de bannière" + avatarDecorationMax: "Vous pouvez mettre au plus {max} décorations d'avatar." _exportOrImport: allNotes: "Toutes les notes" followingList: "Abonnements" @@ -1907,14 +1988,13 @@ _notification: youGotReply: "Réponse de {name}" youGotQuote: "Cité·e par {name}" youRenoted: "{name} vous a Renoté" - youGotMessagingMessageFromUser: "{name} vous envoyé un message" - youGotMessagingMessageFromGroup: "Un message a été envoyé au groupe {name}" youWereFollowed: "s'est abonné·e à vous" youReceivedFollowRequest: "Vous avez reçu une demande d’abonnement" yourFollowRequestAccepted: "Votre demande d’abonnement a été accepté" youWereInvitedToGroup: "Invité·e au groupe" pollEnded: "Les résultats du sondage sont disponibles" unreadAntennaNote: "Antenne {name}" + roleAssigned: "Rôle attribué" emptyPushNotificationMessage: "Les notifications push ont été mises à jour" achievementEarned: "Accomplissement" testNotification: "Tester la notification" @@ -1933,6 +2013,7 @@ _notification: receiveFollowRequest: "Demande d'abonnement reçue" followRequestAccepted: "Demande d'abonnement acceptée" groupInvited: "Invitation à un groupe" + roleAssigned: "Rôle reçu" achievementEarned: "Accomplissement" app: "Notifications provenant des apps" _actions: @@ -1966,6 +2047,9 @@ _deck: channel: "Canal" mentions: "Mentions" direct: "Direct" +_drivecleaner: + orderBySizeDesc: "Taille descendante" + orderByCreatedAtAsc: "Date d'ajout ascendante" _webhookSettings: name: "Nom" active: "Activé" @@ -2003,6 +2087,8 @@ _moderationLogTypes: createAvatarDecoration: "Décoration d'avatar créée" updateAvatarDecoration: "Décoration d'avatar mise à jour" deleteAvatarDecoration: "Décoration d'avatar supprimée" + unsetUserAvatar: "Supprimer l'avatar de l'utilisateur·rice" + unsetUserBanner: "Supprimer la bannière de l'utilisateur·rice" _fileViewer: title: "Détails du fichier" type: "Type du fichier" @@ -2052,3 +2138,16 @@ _externalResourceInstaller: _themeInstallFailed: title: "Échec d'installation du thème" description: "Il y a eu un problème lors de l'installation du thème. Veuillez réessayer. Pour plus de détails sur l'erreur, veuillez consulter la console JavaScript." +_dataSaver: + _media: + title: "Chargement des médias" + description: "Empêche le chargement automatique des images et des vidéos. Appuyez sur les images et les vidéos cachées pour les charger." + _avatar: + title: "Animation d'avatars" + description: "Arrête l'animation d'avatars. Comme les images animées peuvent être plus volumineuses que les images normales, cela permet de réduire davantage le trafic de données." + _urlPreview: + title: "Vignettes d'aperçu des URL" + description: "Les vignettes d'aperçu des URL ne seront plus chargées." + _code: + title: "Mise en évidence du code" + description: "Si la notation de mise en évidence du code est utilisée, par exemple dans la MFM, elle ne sera pas chargée tant qu'elle n'aura pas été tapée. La mise en évidence du code nécessite le chargement du fichier de définition de chaque langue à mettre en évidence, mais comme ces fichiers ne sont plus chargés automatiquement, on peut s'attendre à une réduction du trafic de données." diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 75b09bf880..da91c9cfd4 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -121,7 +121,10 @@ sensitive: "Konten sensitif" add: "Tambahkan" reaction: "Reaksi" reactions: "Reaksi" -reactionSetting: "Reaksi untuk dimunculkan di bilah reaksi" +emojiPicker: "Emoji Picker" +pinnedEmojisForReactionSettingDescription: "Atur sematan emoji pada reaksi" +pinnedEmojisSettingDescription: "Atur sematan emoji pada masukan emoji" +emojiPickerDisplay: "Tampilan Emoji Picker" reactionSettingDescription2: "Geser untuk memindah urutan emoji, klik untuk menghapus, tekan \"+\" untuk menambahkan" rememberNoteVisibility: "Ingat pengaturan visibilitas catatan" attachCancel: "Hapus lampiran" @@ -261,6 +264,7 @@ removed: "Telah dihapus" removeAreYouSure: "Apakah kamu yakin ingin menghapus \"{x}\"?" deleteAreYouSure: "Apakah kamu yakin ingin menghapus \"{x}\"?" resetAreYouSure: "Yakin mau atur ulang?" +areYouSure: "Apakah kamu yakin?" saved: "Telah disimpan" messaging: "Pesan" upload: "Unggah" @@ -311,6 +315,7 @@ folderName: "Nama folder" createFolder: "Buat folder" renameFolder: "Ubah nama folder" deleteFolder: "Hapus folder" +folder: "Folder" addFile: "Tambahkan berkas" emptyDrive: "Drive kosong" emptyFolder: "Folder kosong" @@ -437,7 +442,6 @@ share: "Bagikan" notFound: "Tidak dapat ditemukan" notFoundDescription: "Tidak ada halaman sesuai dengan URL yang ditentukan." uploadFolder: "Lokasi unggah folder bawaan" -cacheClear: "Bersihkan tembolok" markAsReadAllNotifications: "Tandai semua notifikasi telah dibaca" markAsReadAllUnreadNotes: "Tandai semua catatan telah dibaca" markAsReadAllTalkMessages: "Tandai semua pesan telah dibaca" @@ -556,6 +560,8 @@ showInPage: "Tampilkan di halaman" popout: "Pop-out" volume: "Volume" masterVolume: "Master volume" +notUseSound: "Tidak ada keluaran suara" +useSoundOnlyWhenActive: "Hanya keluarkan suara jika CherryPick sedang aktif" details: "Selengkapnya" chooseEmoji: "Pilih emoji" unableToProcess: "Operasi tersebut tidak dapat diselesaikan." @@ -576,6 +582,10 @@ output: "Keluaran" script: "Script" disablePagesScript: "Nonaktifkan script pada halaman" updateRemoteUser: "Perbaharui informasi pengguna instansi luar" +unsetUserAvatar: "Hapus avatar" +unsetUserAvatarConfirm: "Apakah kamu yakin ingin menghapus avatar?" +unsetUserBanner: "Hapus banner" +unsetUserBannerConfirm: "Apakah kamu yakin ingin menghapus banner?" deleteAllFiles: "Hapus semua berkas" deleteAllFilesConfirm: "Apakah kamu yakin ingin menghapus semua berkas?" removeAllFollowing: "Batalkan mengikuti semua pengguna" @@ -647,6 +657,7 @@ smtpSecure: "Gunakan SSL/TLS implisit untuk koneksi SMTP" smtpSecureInfo: "Matikan ini ketika menggunakan STARTTLS" testEmail: "Tes pengiriman surel" wordMute: "Bisukan kata" +hardWordMute: "Pembisuan kata keras" regexpError: "Kesalahan ekspresi reguler" regexpErrorDescription: "Galat terjadi pada baris {line} ekspresi reguler dari {tab} kata yang dibisukan:" instanceMute: "Bisukan instansi" @@ -880,8 +891,6 @@ makeReactionsPublicDescription: "Pengaturan ini akan membuat daftar dari semua r classic: "Klasik" muteThread: "Bisukan thread" unmuteThread: "Suarakan thread" -ffVisibility: "Visibilitas Mengikuti/Pengikut" -ffVisibilityDescription: "Mengatur siapa yang dapat melihat pengikutmu dan yang kamu ikuti." continueThread: "Lihat lanjutan thread" deleteAccountConfirm: "Akun akan dihapus. Apakah kamu yakin?" incorrectPassword: "Kata sandi salah." @@ -993,6 +1002,7 @@ assign: "Tetapkan\n" unassign: "Batalkan penetapan" color: "Warna" manageCustomEmojis: "Kelola Emoji Kustom" +manageAvatarDecorations: "Kelola dekorasi avatar" youCannotCreateAnymore: "Kamu melewati batas pembuatan." cannotPerformTemporary: "Sementara Tidak Tersedia" cannotPerformTemporaryDescription: "Aksi ini tidak dapat dilakukan sementara karena melewati batas eksekusi. Mohon tunggu sejenak dan coba lagi." @@ -1033,6 +1043,8 @@ resetPasswordConfirm: "Yakin untuk mereset kata sandimu?" sensitiveWords: "Kata sensitif" sensitiveWordsDescription: "Visibilitas dari semua catatan mengandung kata yang telah diatur akan dijadikan \"Beranda\" secara otomatis. Kamu dapat mendaftarkan kata tersebut lebih dari satu dengan menuliskannya di baris baru." sensitiveWordsDescription2: "Menggunakan spasi akan membuat ekspresi AND dan kata kunci disekitarnya dengan garis miring akan mengubahnya menjadi ekspresi reguler." +hiddenTags: "Tagar tersembunyi" +hiddenTagsDescription: "Pilih tanda yang mana akan tidak diperlihatkan dalam daftar tren.\nTanda lebih dari satu dapat didaftarkan dengan tiap baris." notesSearchNotAvailable: "Pencarian catatan tidak tersedia." license: "Lisensi" unfavoriteConfirm: "Yakin ingin menghapusnya dari favorit?" @@ -1045,6 +1057,7 @@ enableChartsForRemoteUser: "Buat bagan data pengguna instansi luar" enableChartsForFederatedInstances: "Buat bagan data peladen instansi luar" showClipButtonInNoteFooter: "Tambahkan \"Klip\" ke menu aksi catatan" reactionsDisplaySize: "Ukuran tampilan reaksi" +limitWidthOfReaction: "Batasi lebar maksimum reaksi dan tampilkan dalam ukuran terbatasi." noteIdOrUrl: "ID catatan atau URL" video: "Video" videos: "Video" @@ -1146,6 +1159,10 @@ mutualFollow: "Saling mengikuti" fileAttachedOnly: "Hanya catatan dengan berkas" showRepliesToOthersInTimeline: "Tampilkan balasan ke pengguna lain dalam lini masa" hideRepliesToOthersInTimeline: "Sembunyikan balasan ke orang lain dari lini masa" +showRepliesToOthersInTimelineAll: "Tampilkan balasan ke lainnya dari semua orang yang kamu ikuti di lini masa" +hideRepliesToOthersInTimelineAll: "Sembuyikan balasan ke lainnya dari semua orang yang kamu ikuti di lini masa" +confirmShowRepliesAll: "Operasi ini tidak dapat diubah. Apakah kamu yakin untuk menampilkan balasan ke lainnya dari semua orang yang kamu ikuti di lini masa?" +confirmHideRepliesAll: "Operasi ini tidak dapat diubah. Apakah kamu yakin untuk menyembunyikan balasan ke lainnya dari semua orang yang kamu ikuti di lini masa?" externalServices: "Layanan eksternal" impressum: "Impressum" impressumUrl: "Tautan Impressum" @@ -1153,7 +1170,25 @@ impressumDescription: "Pada beberapa negara seperti Jerman, inklusi dari informa privacyPolicy: "Kebijakan Privasi" privacyPolicyUrl: "Tautan Kebijakan Privasi" tosAndPrivacyPolicy: "Syarat dan Ketentuan serta Kebijakan Privasi" +avatarDecorations: "Dekorasi avatar" +attach: "Lampirkan" +detach: "Hapus" +detachAll: "Lepas Semua" +angle: "Sudut" flip: "Balik" +showAvatarDecorations: "Tampilkan dekorasi avatar" +releaseToRefresh: "Lepaskan untuk memuat ulang" +refreshing: "Sedang memuat ulang..." +pullDownToRefresh: "Tarik ke bawah untuk memuat ulang" +disableStreamingTimeline: "Nonaktifkan pembaharuan lini masa real-time" +useGroupedNotifications: "Tampilkan notifikasi secara dikelompokkan" +signupPendingError: "Terdapat masalah ketika memverifikasi alamat surel. Tautan kemungkinan telah kedaluwarsa." +cwNotationRequired: "Jika \"Sembunyikan konten\" diaktifkan, deskripsi harus disediakan." +doReaction: "Tambahkan reaksi" +code: "Kode" +reloadRequiredToApplySettings: "Muat ulang diperlukan untuk menerapkan pengaturan." +remainingN: "Sisa : {n}" +decorate: "Dekor" _announcement: forExistingUsers: "Hanya pengguna yang telah ada" forExistingUsersDescription: "Pengumuman ini akan dimunculkan ke pengguna yang sudah ada dari titik waktu publikasi jika dinyalakan. Apabila dimatikan, mereka yang baru mendaftar setelah publikasi ini akan juga melihatnya." @@ -1163,6 +1198,7 @@ _announcement: tooManyActiveAnnouncementDescription: "Terlalu banyak pengumuman dapat memperburuk pengalaman pengguna. Mohon pertimbangkan untuk mengarsipkan pengumuman yang sudah usang/tidak relevan." readConfirmTitle: "Tandai telah dibaca?" readConfirmText: "Aksi ini akan menandai konten dari \"{title}\" telah dibaca." + silence: "Tiada notifikasi" _initialAccountSetting: accountCreated: "Akun kamu telah sukses dibuat!" letsStartAccountSetup: "Untuk pemula, ayo atur profilmu dulu." @@ -1175,8 +1211,37 @@ _initialAccountSetting: pushNotificationDescription: "Menyalakan notifikasi dorong akan membuatmu menerima notifikasi dari {name} secara langsung ke perangkatmu." initialAccountSettingCompleted: "Pengaturan profil selesai!" haveFun: "Selamat menikmati, {name}!" + startTutorial: "Mulai Tutorial" skipAreYouSure: "Yakin melewati atur profil?" laterAreYouSure: "Yakin banget untuk atur profil nanti?" +_initialTutorial: + launchTutorial: "Lihat Tutorial" + title: "Tutorial" + wellDone: "Kerja bagus!" + skipAreYouSure: "Berhenti dari Tutorial?" + _landing: + title: "Selamat datang di Tutorial" + description: "Di sini kamu dapat mempelajari dasar-dasar dari penggunaan CherryPick dan fitur-fiturnya." + _note: + title: "Apa itu Catatan?" + _reaction: + title: "Apa itu Reaksi?" + _timeline: + title: "Konsep Lini Masa" + _postNote: + title: "Pengaturan posting Catatan" + _visibility: + public: "Perlihatkan catatan ke semua pengguna." + home: "Hanya publik ke lini masa Beranda. Pengguna yang mengunjungi profilmu melalui pengikut dan renote dapat melihatnya." + followers: "Perlihatkan ke pengikut saja. Hanya pengikut yang dapat melihat postinganmu dan tidak dapat direnote oleh siapapun." + direct: "Hanya perlihatkan ke pengguna spesifik dan penerima akan diberi tahu. Dapat juga digunakan sebagai alternatif dari pesan langsung." + _cw: + title: "Peringatan Konten (CW)" + _exampleNote: + cw: "Peringatan: Bikin Lapar!" + note: "Baru aja makan donat berlapis coklat 🍩😋" + _howToMakeAttachmentsSensitive: + title: "Bagaimana menandai lampiran sebagai sensitif?" _serverRules: description: "Daftar peraturan akan ditampilkan sebelum pendaftaran. Mengatur ringkasan dari Syarat dan Ketentuan sangat direkomendasikan." _serverSettings: @@ -1418,6 +1483,9 @@ _achievements: _setNameToSyuilo: title: "God Complex" description: "Atur namamu jadi \"syuilo\"" + _setNameToNoriDev: + title: "God Complex (CherryPick)" + description: "Atur namamu jadi \"noridev\"" _passedSinceAccountCreated1: title: "Perayaan Satu Tahun" description: "Satu tahun telah lewat sejak akunmu dibuat" @@ -1441,7 +1509,7 @@ _achievements: _brainDiver: title: "Brain Diver" description: "Posting tautan mengenai Brain Diver" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "Tes overflow" description: "Picu tes notifikasi secara berulang dalam waktu yang sangat pendek" @@ -1488,6 +1556,7 @@ _role: inviteLimitCycle: "Interval Penerbitan Kode Undangan" inviteExpirationTime: "Interval kedaluwarsa undangan" canManageCustomEmojis: "Dapat mengelola Emoji kustom" + canManageAvatarDecorations: "Kelola dekorasi avatar" driveCapacity: "Kapasitas Drive" alwaysMarkNsfw: "Selalu tandai berkas sebagai NSFW" pinMax: "Jumlah maksimal catatan yang disematkan" @@ -2103,8 +2172,6 @@ _notification: youGotReply: "{name} membalas kamu" youGotQuote: "{name} mengutip kamu" youRenoted: "{name} me-renote kamu" - youGotMessagingMessageFromUser: "{name} mengirimi kamu pesan" - youGotMessagingMessageFromGroup: "Sebuah pesan telah dikirim ke grup {name}" youWereFollowed: "Mengikuti kamu" youReceivedFollowRequest: "Kamu menerima permintaan mengikuti" yourFollowRequestAccepted: "Permintaan mengikuti kamu telah diterima" diff --git a/locales/index.d.ts b/locales/index.d.ts index 06f8422a59..b5471a017a 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -3,11 +3,17 @@ // Do not edit this file directly. export interface Locale { "_lang_": string; + "cherrypickLabs": string; + "cherrypickLabsDescription": string; + "copiedLink": string; + "copiedContent": string; + "copied": string; + "welcome": string; + "cherrypickMigrated": string; + "cherrypickMigratedCacheClearTitle": string; + "cherrypickMigratedCacheClear": string; + "showRenoteVisibilitySelector": string; "cannotBeUsedFunc": string; - "maxinumLayerError": string; - "layer": string; - "Xcoordinate": string; - "Ycoordinate": string; "scale": string; "opacity": string; "noteUpdatedAt": string; @@ -197,7 +203,12 @@ export interface Locale { "add": string; "reaction": string; "reactions": string; - "reactionSetting": string; + "emojiPicker": string; + "pinnedEmojisForReactionSettingDescription": string; + "pinnedEmojisSettingDescription": string; + "emojiPickerDisplay": string; + "overwriteFromPinnedEmojisForReaction": string; + "overwriteFromPinnedEmojis": string; "reactionSettingDescription2": string; "rememberNoteVisibility": string; "attachCancel": string; @@ -337,6 +348,7 @@ export interface Locale { "removeAreYouSure": string; "deleteAreYouSure": string; "resetAreYouSure": string; + "areYouSure": string; "saved": string; "messaging": string; "upload": string; @@ -450,6 +462,11 @@ export interface Locale { "enableHcaptcha": string; "hcaptchaSiteKey": string; "hcaptchaSecretKey": string; + "mcaptcha": string; + "enableMcaptcha": string; + "mcaptchaSiteKey": string; + "mcaptchaSecretKey": string; + "mcaptchaInstanceUrl": string; "recaptcha": string; "enableRecaptcha": string; "recaptchaSiteKey": string; @@ -716,6 +733,7 @@ export interface Locale { "small": string; "generateAccessToken": string; "permission": string; + "adminPermission": string; "enableAll": string; "disableAll": string; "tokenRequested": string; @@ -759,6 +777,7 @@ export interface Locale { "other": string; "regenerateLoginToken": string; "regenerateLoginTokenDescription": string; + "theKeywordWhenSearchingForCustomEmoji": string; "setMultipleBySeparatingWithSpace": string; "fileIdOrUrl": string; "behavior": string; @@ -974,8 +993,8 @@ export interface Locale { "classic": string; "muteThread": string; "unmuteThread": string; - "ffVisibility": string; - "ffVisibilityDescription": string; + "followingVisibility": string; + "followersVisibility": string; "continueThread": string; "deleteAccountConfirm": string; "incorrectPassword": string; @@ -1265,6 +1284,7 @@ export interface Locale { "avatarDecorations": string; "attach": string; "detach": string; + "detachAll": string; "angle": string; "flip": string; "showAvatarDecorations": string; @@ -1278,6 +1298,18 @@ export interface Locale { "doReaction": string; "code": string; "reloadRequiredToApplySettings": string; + "remainingN": string; + "overwriteContentConfirm": string; + "seasonalScreenEffect": string; + "decorate": string; + "addMfmFunction": string; + "enableQuickAddMfmFunction": string; + "bubbleGame": string; + "sfx": string; + "soundWillBePlayed": string; + "showReplay": string; + "replay": string; + "replaying": string; "showUnreadNotificationsCount": string; "showCatOnly": string; "additionalPermissionsForFlash": string; @@ -1304,6 +1336,14 @@ export interface Locale { "_messaging": { "direct": string; }; + "_bubbleGame": { + "howToPlay": string; + "_howToPlay": { + "section1": string; + "section2": string; + "section3": string; + }; + }; "_announcement": { "forExistingUsers": string; "forExistingUsersDescription": string; @@ -1353,6 +1393,7 @@ export interface Locale { "renameTheButtonInPostFormToNya": string; "renameTheButtonInPostFormToNyaDescription": string; "enableLongPressOpenAccountMenu": string; + "enableLongPressOpenAccountMenuDescription": string; "friendlyShowAvatarDecorationsInNavBtn": string; }; "_bannerDisplay": { @@ -1811,6 +1852,10 @@ export interface Locale { "title": string; "description": string; }; + "_setNameToNoriDev": { + "title": string; + "description": string; + }; "_passedSinceAccountCreated1": { "title": string; "description": string; @@ -1850,6 +1895,15 @@ export interface Locale { "title": string; "description": string; }; + "_bubbleGameExplodingHead": { + "title": string; + "description": string; + }; + "_bubbleGameDoubleExplodingHead": { + "title": string; + "description": string; + "flavor": string; + }; }; }; "_role": { @@ -1915,6 +1969,7 @@ export interface Locale { "canHideAds": string; "canSearchNotes": string; "canUseTranslator": string; + "avatarDecorationLimit": string; }; "_condition": { "isLocal": string; @@ -1952,6 +2007,7 @@ export interface Locale { "disposable": string; "mx": string; "smtp": string; + "banned": string; }; "_ffVisibility": { "public": string; @@ -2047,7 +2103,6 @@ export interface Locale { "donate": string; }; "_cherrypick": { - "about": string; "translation": string; "donate": string; "relayServer": string; @@ -2366,6 +2421,55 @@ export interface Locale { "write:flash": string; "read:flash-likes": string; "write:flash-likes": string; + "read:admin:abuse-user-reports": string; + "write:admin:delete-account": string; + "write:admin:delete-all-files-of-a-user": string; + "read:admin:index-stats": string; + "read:admin:table-stats": string; + "read:admin:user-ips": string; + "read:admin:meta": string; + "write:admin:reset-password": string; + "write:admin:resolve-abuse-user-report": string; + "write:admin:send-email": string; + "read:admin:server-info": string; + "read:admin:show-moderation-log": string; + "read:admin:show-user": string; + "read:admin:show-users": string; + "write:admin:suspend-user": string; + "write:admin:unset-user-avatar": string; + "write:admin:unset-user-banner": string; + "write:admin:unsuspend-user": string; + "write:admin:meta": string; + "write:admin:user-note": string; + "write:admin:roles": string; + "read:admin:roles": string; + "write:admin:relays": string; + "read:admin:relays": string; + "write:admin:invite-codes": string; + "read:admin:invite-codes": string; + "write:admin:announcements": string; + "read:admin:announcements": string; + "write:admin:avatar-decorations": string; + "read:admin:avatar-decorations": string; + "write:admin:federation": string; + "write:admin:account": string; + "read:admin:account": string; + "write:admin:emoji": string; + "read:admin:emoji": string; + "write:admin:queue": string; + "read:admin:queue": string; + "write:admin:promo": string; + "write:admin:drive": string; + "read:admin:drive": string; + "read:admin:stream": string; + "write:admin:ad": string; + "read:admin:ad": string; + "write:invite-codes": string; + "read:invite-codes": string; + "write:clip-favorite": string; + "read:clip-favorite": string; + "read:federation": string; + "write:report-abuse": string; }; "_auth": { "shareAccessTitle": string; @@ -2496,10 +2600,12 @@ export interface Locale { "changeAvatar": string; "changeBanner": string; "verifiedLinkDescription": string; + "avatarDecorationMax": string; }; "_exportOrImport": { "allNotes": string; "favoritedNotes": string; + "clips": string; "followingList": string; "muteList": string; "blockingList": string; @@ -2620,9 +2726,8 @@ export interface Locale { "youGotMention": string; "youGotReply": string; "youGotQuote": string; + "youGotReact": string; "youRenoted": string; - "youGotMessagingMessageFromUser": string; - "youGotMessagingMessageFromGroup": string; "youWereFollowed": string; "youReceivedFollowRequest": string; "yourFollowRequestAccepted": string; @@ -2630,6 +2735,7 @@ export interface Locale { "pollEnded": string; "newNote": string; "unreadAntennaNote": string; + "roleAssigned": string; "emptyPushNotificationMessage": string; "achievementEarned": string; "testNotification": string; @@ -2652,6 +2758,7 @@ export interface Locale { "receiveFollowRequest": string; "followRequestAccepted": string; "groupInvited": string; + "roleAssigned": string; "achievementEarned": string; "app": string; }; diff --git a/locales/it-IT.yml b/locales/it-IT.yml index f7b4fa6671..8e7afc891c 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -15,7 +15,7 @@ gotIt: "ok!" cancel: "Annulla" noThankYou: "No grazie" enterUsername: "Inserisci un nome utente" -renotedBy: "Rinotato da {user}" +renotedBy: "Rinotata da {user}" noNotes: "Nessuna nota!" noNotifications: "Nessuna notifica" instance: "Istanza" @@ -102,12 +102,12 @@ defaultNoteVisibility: "Privacy predefinita delle note" follow: "Segui" followRequest: "Richiesta di follow" followRequests: "Richieste di follow" -unfollow: "Non seguire" +unfollow: "Interrompi following" followRequestPending: "Richiesta in approvazione" enterEmoji: "Inserisci emoji" renote: "Rinota" unrenote: "Elimina la Rinota" -renoted: "Rinotato!" +renoted: "Rinotata!" cantRenote: "È impossibile rinotare questa nota." cantReRenote: "È impossibile rinotare una Rinota." quote: "Citazione" @@ -121,7 +121,12 @@ sensitive: "Allegato esplicito" add: "Aggiungi" reaction: "Reazioni" reactions: "Reazioni" -reactionSetting: "Reazioni visualizzate sul pannello" +emojiPicker: "Selettore emoji" +pinnedEmojisForReactionSettingDescription: "Scegli quale sia l'emoji in cima, quando reagisci" +pinnedEmojisSettingDescription: "Scegli quale sia l'emoji in cima, quando reagisci" +emojiPickerDisplay: "Visualizza selettore" +overwriteFromPinnedEmojisForReaction: "Sovrascrivi con le impostazioni reazioni" +overwriteFromPinnedEmojis: "Sovrascrivi con le impostazioni globali" reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere." rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note" attachCancel: "Rimuovi allegato" @@ -261,6 +266,7 @@ removed: "Eliminato con successo" removeAreYouSure: "Vuoi davvero eliminare \"{x}\"?" deleteAreYouSure: "Vuoi davvero eliminare \"{x}\"?" resetAreYouSure: "Ripristinare?" +areYouSure: "Confermi?" saved: "Salvato" messaging: "Messaggi" upload: "Carica" @@ -311,6 +317,7 @@ folderName: "Nome della cartella" createFolder: "Nuova cartella" renameFolder: "Rinomina cartella" deleteFolder: "Elimina cartella" +folder: "Cartella" addFile: "Allega" emptyDrive: "Il Drive è vuoto" emptyFolder: "La cartella è vuota" @@ -437,7 +444,6 @@ share: "Condividi" notFound: "Non trovato" notFoundDescription: "Nessuna pagina corrisponde all'URL indicata." uploadFolder: "Destinazione caricamento predefinita" -cacheClear: "Svuota cache" markAsReadAllNotifications: "Segna tutte le notifiche come lette" markAsReadAllUnreadNotes: "Segna tutte le note come lette" markAsReadAllTalkMessages: "Segna tutte le chat come lette" @@ -556,6 +562,8 @@ showInPage: "Visualizza in pagina" popout: "Finestra pop-out" volume: "Volume" masterVolume: "Volume principale" +notUseSound: "Non emettere suoni" +useSoundOnlyWhenActive: "Emetti suoni solo quando CherryPick è in attività" details: "Dettagli" chooseEmoji: "Scegli emoji" unableToProcess: "Impossibile compiere l'operazione" @@ -576,6 +584,10 @@ output: "Uscita" script: "Script" disablePagesScript: "Disabilita AiScript nelle pagine" updateRemoteUser: "Aggiorna le informazioni dal profilo remoto" +unsetUserAvatar: "Rimozione foto profilo" +unsetUserAvatarConfirm: "Vuoi davvero rimuovere la foto profilo?" +unsetUserBanner: "Rimuovi intestazione profilo" +unsetUserBannerConfirm: "Vuoi davvero rimuovere l'intestazione dal profilo?" deleteAllFiles: "Elimina tutti i file" deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?" removeAllFollowing: "Annulla tutti i follow" @@ -647,6 +659,7 @@ smtpSecure: "Usare SSL/TLS implicito per le connessioni SMTP" smtpSecureInfo: "Disabilitare quando è attivo STARTTLS." testEmail: "Verifica il funzionamento" wordMute: "Filtri parole" +hardWordMute: "Filtro parole forte" regexpError: "errore regex" regexpErrorDescription: "Si è verificato un errore nell'espressione regolare alla riga {line} della parola muta {tab}:" instanceMute: "Silenzia l'istanza" @@ -826,7 +839,7 @@ configure: "Imposta" postToGallery: "Pubblicare nella galleria" postToHashtag: "Pubblica a questo hashtag" gallery: "Galleria" -recentPosts: "Le più recenti" +recentPosts: "Pubblicazioni recenti" popularPosts: "Le più visualizzate" shareWithNote: "Condividere in nota" ads: "Banner" @@ -864,7 +877,7 @@ pubSub: "Publish/Subscribe del profilo" lastCommunication: "La comunicazione più recente" resolved: "Risolto" unresolved: "Non risolto" -breakFollow: "Non farti più seguire" +breakFollow: "Interrompi follow" breakFollowConfirm: "Vuoi davvero che questo profilo smetta di seguirti?" itsOn: "Abilitato" itsOff: "Disabilitato" @@ -880,8 +893,6 @@ makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a di classic: "Classico" muteThread: "Silenzia conversazione" unmuteThread: "Riattiva la conversazione" -ffVisibility: "Visibilità delle connessioni" -ffVisibilityDescription: "Puoi scegliere a chi mostrare le tue relazioni con altri profili nel fediverso." continueThread: "Altre conversazioni" deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?" incorrectPassword: "La password è errata." @@ -1034,6 +1045,8 @@ resetPasswordConfirm: "Vuoi davvero ripristinare la password?" sensitiveWords: "Parole esplicite" sensitiveWordsDescription: "Imposta automaticamente \"Home\" alla visibilità delle Note che contengono una qualsiasi parola tra queste configurate. Puoi separarle per riga." sensitiveWordsDescription2: "Gli spazi creano la relazione \"E\" tra parole (questo E quello). Racchiudere una parola nelle slash \"/\" la trasforma in Espressione Regolare." +hiddenTags: "Hashtag nascosti" +hiddenTagsDescription: "Impedire la visualizzazione del tag impostato nei trend. Puoi impostare più valori, uno per riga." notesSearchNotAvailable: "Non è possibile cercare tra le Note." license: "Licenza" unfavoriteConfirm: "Vuoi davvero rimuovere la preferenza?" @@ -1046,6 +1059,7 @@ enableChartsForRemoteUser: "Abilita i grafici per i profili remoti" enableChartsForFederatedInstances: "Abilita i grafici per le istanze federate" showClipButtonInNoteFooter: "Aggiungi il bottone Clip tra le azioni delle Note" reactionsDisplaySize: "Grandezza delle reazioni" +limitWidthOfReaction: "Limita la larghezza delle reazioni e ridimensionale" noteIdOrUrl: "ID della Nota o URL" video: "Video" videos: "Video" @@ -1128,7 +1142,7 @@ currentAnnouncements: "Annunci attuali" pastAnnouncements: "Annunci precedenti" youHaveUnreadAnnouncements: "Ci sono Annunci non letti" useSecurityKey: "Per utilizzare la chiave di sicurezza o la passkey, segui le indicazioni del dispositivo" -replies: "Rispondi" +replies: "Risposte" renotes: "Rinota" loadReplies: "Leggi le risposte" loadConversation: "Leggi la conversazione" @@ -1161,6 +1175,7 @@ tosAndPrivacyPolicy: "Condizioni d'uso e informativa privacy" avatarDecorations: "Decorazioni foto profilo" attach: "Applica" detach: "Rimuovi" +detachAll: "Togli tutto" angle: "Angolo" flip: "Inverti" showAvatarDecorations: "Mostra decorazione della foto profilo" @@ -1172,6 +1187,12 @@ useGroupedNotifications: "Mostra le notifiche raggruppate" signupPendingError: "Si è verificato un problema durante la verifica del tuo indirizzo email. Potrebbe essere scaduto il collegamento temporaneo." cwNotationRequired: "Devi indicare perché il contenuto è indicato come esplicito." doReaction: "Reagisci" +code: "Codice" +reloadRequiredToApplySettings: "Per applicare le impostazioni, occorre ricaricare." +remainingN: "Rimangono: {n}" +overwriteContentConfirm: "Vuoi davvero sostituire l'attuale contenuto?" +seasonalScreenEffect: "Schermate in base alla stagione" +decorate: "Decora" _announcement: forExistingUsers: "Solo ai profili attuali" forExistingUsersDescription: "L'annuncio sarà visibile solo ai profili esistenti in questo momento. Se disabilitato, sarà visibile anche ai profili che verranno creati dopo la pubblicazione di questo annuncio." @@ -1280,6 +1301,8 @@ _serverSettings: shortName: "Abbreviazione" shortNameDescription: "Un'abbreviazione o un nome comune che può essere visualizzato al posto del nome ufficiale lungo del server." fanoutTimelineDescription: "Attivando questa funzionalità migliori notevolmente la capacità delle Timeline di collezionare Note, riducendo il carico sul database. Tuttavia, aumenterà l'impiego di memoria RAM per Redis. Disattiva se il tuo server ha poca RAM o la funzionalità è irregolare." + fanoutTimelineDbFallback: "Elaborazione dati alternativa" + fanoutTimelineDbFallbackDescription: "Attivando l'elaborazione alternativa, verrà interrogato ulteriormente il database se la timeline non è nella cache. \nDisattivando, si può ridurre ulteriormente il carico del server, evitando l'elaborazione alternativa, ma limitando l'intervallo recuperabile delle timeline." _accountMigration: moveFrom: "Migra un altro profilo dentro a questo" moveFromSub: "Crea un alias verso un altro profilo remoto" @@ -1510,6 +1533,9 @@ _achievements: _setNameToSyuilo: title: "Complesso divino" description: "Hai impostati il tuo nome in «syuilo»" + _setNameToNoriDev: + title: "Complesso divino (CherryPick)" + description: "Hai impostati il tuo nome in «noridev»" _passedSinceAccountCreated1: title: "Primo Anniversario" description: "È passato un anno da quando hai creato il profilo" @@ -1550,7 +1576,9 @@ _role: assignTarget: "Modalità di assegnazione del ruolo" descriptionOfAssignTarget: "Manuale: per assegnare manualmente questo ruolo ai profili.\nCondizionale: per assegnare o rimuovere automaticamente questo ruolo ai profili, a precise condizioni." manual: "Manuale" + manualRoles: "Ruoli assegnati manualmente" conditional: "Condizionale" + conditionalRoles: "Ruoli condizionati" condition: "Condizioni" isConditionalRole: "Questo è un ruolo condizionato" isPublic: "Ruolo pubblico" @@ -1599,6 +1627,7 @@ _role: canHideAds: "Nascondere i banner" canSearchNotes: "Ricercare nelle Note" canUseTranslator: "Tradurre le Note" + avatarDecorationLimit: "Numero massimo di decorazioni foto profilo installabili" _condition: isLocal: "Profilo locale" isRemote: "Profilo remoto" @@ -1674,7 +1703,7 @@ _preferencesBackups: list: "Elenco di impostazioni salvate in precedenza" saveNew: "Nuovo salvataggio" loadFile: "Carica da file" - apply: "Applicabile a questo dispositivo" + apply: "Applica a questo dispositivo" save: "Sovrascrivi il backup" inputName: "Inserire il nome del backup." cannotSave: "Impossibile salvare." @@ -1888,6 +1917,14 @@ _sfx: chatBg: "Chat (sfondo)" antenna: "Ricezione dell'antenna" channel: "Notifiche di canale" + reaction: "Quando seleziono una reazione" +_soundSettings: + driveFile: "Suoni del Drive" + driveFileWarn: "Seleziona file dal dispositivo" + driveFileTypeWarn: "Formato file non supportato" + driveFileTypeWarnDescription: "Per favore, scegli un file di tipo audio" + driveFileDurationWarn: "La durata dell'audio è troppo lunga" + driveFileDurationWarnDescription: "Scegliere un audio lungo potrebbe interferire con l'uso di CherryPick. Vuoi continuare lo stesso?" _ago: future: "Futuro" justNow: "Adesso" @@ -1899,6 +1936,14 @@ _ago: monthsAgo: "{n} mesi fa" yearsAgo: "{n} anni fa" invalid: "Niente da visualizzare" +_timeIn: + seconds: "Dopo {n} secondi" + minutes: "Dopo {n} minuti" + hours: "Dopo {n} ore" + days: "Dopo {n} giorni" + weeks: "Dopo {n} settimane" + months: "Dopo {n} mesi" + years: "Dopo {n} anni" _time: second: "s" minute: "min" @@ -1943,7 +1988,7 @@ _permissions: "read:favorites": "Visualizza i tuoi preferiti" "write:favorites": "Gestisci i tuoi preferiti" "read:following": "Vedi le informazioni di follow" - "write:following": "Seguire / Non seguire altri profili" + "write:following": "Following di altri profili" "read:messaging": "Visualizzare la chat" "write:messaging": "Gestire la chat" "read:mutes": "Vedi i profili silenziati" @@ -2025,6 +2070,7 @@ _widgets: _userList: chooseList: "Seleziona una lista" clicker: "Cliccaggio" + birthdayFollowings: "Chi nacque oggi" _cw: hide: "Nascondere" show: "Continua la lettura..." @@ -2087,6 +2133,7 @@ _profile: changeAvatar: "Modifica immagine profilo" 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." _exportOrImport: allNotes: "Tutte le note" favoritedNotes: "Note preferite" @@ -2203,8 +2250,6 @@ _notification: youGotReply: "{name} ti ha risposto" youGotQuote: "{name} ha citato la tua Nota e ha detto" youRenoted: "{name} ha rinotato" - youGotMessagingMessageFromUser: "{name} ti ha mandato un messaggio" - youGotMessagingMessageFromGroup: "{name} ti ha mandato un messaggio nella chat" youWereFollowed: "Adesso ti segue" youReceivedFollowRequest: "Hai ricevuto una richiesta di follow" yourFollowRequestAccepted: "La tua richiesta di follow è stata accettata" @@ -2328,6 +2373,8 @@ _moderationLogTypes: createAvatarDecoration: "Creazione decorazione della foto profilo" updateAvatarDecoration: "Aggiornamento decorazione foto profilo" deleteAvatarDecoration: "Eliminazione decorazione della foto profilo" + unsetUserAvatar: "Rimossa foto profilo" + unsetUserBanner: "Rimossa intestazione profilo" _fileViewer: title: "Dettagli del file" type: "Tipo di file" @@ -2377,3 +2424,16 @@ _externalResourceInstaller: _themeInstallFailed: title: "Impossibile installare la variazione grafica" description: "Si è verificato un impedimento durante l'installazione della variazione grafica. Per favore riprova e consulta la console di Javascript per ottenere dettagli aggiuntivi." +_dataSaver: + _media: + title: "Caricamento dei media" + description: "Impedire il caricamento automatico di immagini e video. Devi toccare le immagini o i video nascosti per caricarli." + _avatar: + title: "Immagine del profilo" + description: "Impedire l'animazione per l'immagine del profilo. Le immagini animate possono avere dimensioni file maggiori rispetto a quelle normali, puoi ridurre ulteriormente l'utilizzo dei dati." + _urlPreview: + title: "Anteprime delle URL" + description: "Impedire il caricamento delle anteprime URL." + _code: + title: "Codice evidenziato" + description: "Impedire che il codice sorgente sia automaticamente evidenziato. Evidenziare il codice richiede il caricamento di un file per ogni linguaggio. Puoi evidenziare soltanto il codice che intendi leggere e ridurre il traffico inutilizzato." diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4e1954b684..2feb52c5c6 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1,10 +1,16 @@ _lang_: "日本語" +cherrypickLabs: "CherryPick研究室" +cherrypickLabsDescription: "まだ開発中の機能を試してみませんか。一部の機能はちゃんと動かないかもしれません。" +copiedLink: "リンクをコピーしました!" +copiedContent: "内容をコピーしました!" +copied: "コピーしました!" +welcome: "ようこそ!" +cherrypickMigrated: "CherryPickへの移行が完了しました!" +cherrypickMigratedCacheClearTitle: "キャッシュクリアのご案内" +cherrypickMigratedCacheClear: "このサーバーはMisskeyまたはCherryPick v4.3.0以前のバージョンから移行されました。\nバージョン管理方式が異なり、残っているキャッシュが問題を引き起こす可能性があるため、移行後、最初の接続時にキャッシュを削除する作業を行う必要があります。\n\nこの作業は最初一度だけ行われます。" +showRenoteVisibilitySelector: "リノートの公開範囲オプションを表示" cannotBeUsedFunc: "この機能は現在使用できません。" -maxinumLayerError: "6枚以上重ねることはできません。他のレイヤーを削除してください。" -layer: "レイヤー" -Xcoordinate: "X座標" -Ycoordinate: "Y座標" scale: "大きさ" opacity: "不透明度" noteUpdatedAt: "編集済み: {date} {time}" @@ -194,7 +200,12 @@ sensitive: "センシティブ" add: "追加" reaction: "リアクション" reactions: "リアクション" -reactionSetting: "ピッカーに表示するリアクション" +emojiPicker: "絵文字ピッカー" +pinnedEmojisForReactionSettingDescription: "リアクション時にピン留め表示する絵文字を設定できます" +pinnedEmojisSettingDescription: "絵文字入力時にピン留め表示する絵文字を設定できます" +emojiPickerDisplay: "ピッカーの表示" +overwriteFromPinnedEmojisForReaction: "リアクション設定から上書きする" +overwriteFromPinnedEmojis: "全般設定から上書きする" reactionSettingDescription2: "ドラッグして並び替え、クリックして削除、+を押して追加します。" rememberNoteVisibility: "公開範囲を記憶する" attachCancel: "添付取り消し" @@ -334,6 +345,7 @@ removed: "削除しました" removeAreYouSure: "「{x}」を削除しますか?" deleteAreYouSure: "「{x}」を削除しますか?" resetAreYouSure: "リセットしますか?" +areYouSure: "よろしいですか?" saved: "保存しました" messaging: "チャット" upload: "アップロード" @@ -447,6 +459,11 @@ hcaptcha: "hCaptcha" enableHcaptcha: "hCaptchaを有効にする" hcaptchaSiteKey: "サイトキー" hcaptchaSecretKey: "シークレットキー" +mcaptcha: "mCaptcha" +enableMcaptcha: "mCaptchaを有効にする" +mcaptchaSiteKey: "サイトキー" +mcaptchaSecretKey: "シークレットキー" +mcaptchaInstanceUrl: "mCaptchaのインスタンスのURL" recaptcha: "reCAPTCHA" enableRecaptcha: "reCAPTCHAを有効にする" recaptchaSiteKey: "サイトキー" @@ -713,6 +730,7 @@ medium: "中" small: "小" generateAccessToken: "アクセストークンの発行" permission: "権限" +adminPermission: "管理者権限" enableAll: "全て有効にする" disableAll: "全て無効にする" tokenRequested: "アカウントへのアクセス許可" @@ -756,6 +774,7 @@ useGlobalSettingDesc: "オンにすると、アカウントの通知設定が使 other: "その他" regenerateLoginToken: "ログイントークンを再生成" regenerateLoginTokenDescription: "ログインに使用される内部トークンを再生成します。通常この操作を行う必要はありません。再生成すると、全てのデバイスでログアウトされます。" +theKeywordWhenSearchingForCustomEmoji: "カスタム絵文字を検索する時のキーワードになります。" setMultipleBySeparatingWithSpace: "スペースで区切って複数設定できます。" fileIdOrUrl: "ファイルIDまたはURL" behavior: "動作" @@ -971,8 +990,8 @@ makeReactionsPublicDescription: "あなたがしたリアクション一覧を classic: "クラシック" muteThread: "スレッドをミュート" unmuteThread: "スレッドのミュートを解除" -ffVisibility: "つながりの公開範囲" -ffVisibilityDescription: "自分のフォロー/フォロワー情報の公開範囲を設定できます。" +followingVisibility: "フォローの公開範囲" +followersVisibility: "フォロワーの公開範囲" continueThread: "さらにスレッドを見る" deleteAccountConfirm: "アカウントが削除されます。よろしいですか?" incorrectPassword: "パスワードが間違っています。" @@ -1262,6 +1281,7 @@ tosAndPrivacyPolicy: "利用規約・プライバシーポリシー" avatarDecorations: "アイコンデコレーション" attach: "付ける" detach: "外す" +detachAll: "全て外す" angle: "角度" flip: "反転" showAvatarDecorations: "アイコンのデコレーションを表示" @@ -1275,6 +1295,18 @@ cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述 doReaction: "リアクションする" code: "コード" reloadRequiredToApplySettings: "設定の反映にはリロードが必要です。" +remainingN: "残り: {n}" +overwriteContentConfirm: "現在の内容に上書きされますがよろしいですか?" +seasonalScreenEffect: "季節に応じた画面の演出" +decorate: "デコる" +addMfmFunction: "装飾を追加" +enableQuickAddMfmFunction: "高度なMFMのピッカーを表示する" +bubbleGame: "バブルゲーム" +sfx: "効果音" +soundWillBePlayed: "サウンドが再生されます" +showReplay: "リプレイを見る" +replay: "リプレイ" +replaying: "リプレイ中" showUnreadNotificationsCount: "未読の通知の数を表示する" showCatOnly: "キャット付きのみ" additionalPermissionsForFlash: "Playへの追加許可" @@ -1302,6 +1334,13 @@ _showingAnimatedImages: _messaging: direct: "ダイレクトメッセージ" +_bubbleGame: + howToPlay: "遊び方" + _howToPlay: + section1: "位置を調整してハコにモノを落とします。" + section2: "同じ種類のモノがくっつくと別のモノに変化して、スコアが得られます。" + section3: "モノがハコからあふれるとゲームオーバーです。ハコからあふれないようにしつつモノを融合させてハイスコアを目指そう!" + _announcement: forExistingUsers: "既存ユーザーのみ" forExistingUsersDescription: "有効にすると、このお知らせ作成時点で存在するユーザーにのみお知らせが表示されます。無効にすると、このお知らせ作成後にアカウントを作成したユーザーにもお知らせが表示されます。" @@ -1350,6 +1389,7 @@ _cherrypick: renameTheButtonInPostFormToNya: "ノート作成画面の「ノート」ボタンを「にゃ!」に変更する" renameTheButtonInPostFormToNyaDescription: "にゃあにゃんにゃんにゃんにゃにゃん?" enableLongPressOpenAccountMenu: "長押しでアカウントメニューを開く" + enableLongPressOpenAccountMenuDescription: "画面下部のタイムラインタブを長押しして開くことができます。" friendlyShowAvatarDecorationsInNavBtn: "フローティングボタンにアイコンのデコレーションを表示" _bannerDisplay: @@ -1730,6 +1770,9 @@ _achievements: _setNameToSyuilo: title: "神様コンプレックス" description: "名前を syuilo に設定した" + _setNameToNoriDev: + title: "神様コンプレックス(CherryPick)" + description: "名前を noridev に設定した" _passedSinceAccountCreated1: title: "一周年" description: "アカウント作成から1年経過した" @@ -1753,13 +1796,20 @@ _achievements: _brainDiver: title: "Brain Diver" description: "Brain Diverへのリンクを投稿した" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "テスト過剰" description: "通知のテストをごく短時間のうちに連続して行った" _tutorialCompleted: title: "CherryPick初心者講座 修了証" description: "チュートリアルを完了した" + _bubbleGameExplodingHead: + title: "🤯" + description: "バブルゲームで最も大きいモノを出した" + _bubbleGameDoubleExplodingHead: + title: "ダブル🤯" + description: "バブルゲームで最も大きいモノを2つ同時に出した" + flavor: "これくらいの おべんとばこに 🤯 🤯 ちょっとつめて" _role: new: "ロールの作成" @@ -1823,6 +1873,7 @@ _role: canHideAds: "広告の非表示" canSearchNotes: "ノート検索の利用" canUseTranslator: "翻訳機能の利用" + avatarDecorationLimit: "アイコンデコレーションの最大取付個数" _condition: isLocal: "ローカルユーザー" isRemote: "リモートユーザー" @@ -1858,6 +1909,7 @@ _emailUnavailable: disposable: "恒久的に使用可能なアドレスではありません" mx: "正しいメールサーバーではありません" smtp: "メールサーバーが応答しません" + banned: "このメールアドレスでは登録できません" _ffVisibility: public: "公開" @@ -1937,7 +1989,7 @@ _registry: createKey: "キーを作成" _aboutMisskey: - about: "CherryPickは、Misskeyをベースに2021年から開発中のカスタマイズクライアントです。" + about: "CherryPickは、Misskeyをベースに2021年から開発中のカスタマイズオープンソースのソフトウェアです。" contributors: "コントリビューター" allContributors: "全てのコントリビューター" source: "ソースコード" @@ -1950,7 +2002,6 @@ _aboutMisskey: serverStatus: "サーバ状態" donate: "ココネクトに寄付" _cherrypick: - about: "このMisskeyはNoriDevによってカスタムされました!" translation: "CherryPickを翻訳" donate: "CherryPickに寄付" relayServer: "リレーサーバー" @@ -2268,6 +2319,55 @@ _permissions: "write:flash": "Playを操作する" "read:flash-likes": "Playのいいねを見る" "write:flash-likes": "Playのいいねを操作する" + "read:admin:abuse-user-reports": "ユーザーからの通報を見る" + "write:admin:delete-account": "ユーザーアカウントを削除する" + "write:admin:delete-all-files-of-a-user": "ユーザーのすべてのファイルを削除する" + "read:admin:index-stats": "データベースインデックスに関する情報を見る" + "read:admin:table-stats": "データベーステーブルに関する情報を見る" + "read:admin:user-ips": "ユーザーのIPアドレスを見る" + "read:admin:meta": "インスタンスのメタデータを見る" + "write:admin:reset-password": "ユーザーのパスワードをリセットする" + "write:admin:resolve-abuse-user-report": "ユーザーからの通報を解決する" + "write:admin:send-email": "メールを送る" + "read:admin:server-info": "サーバーの情報を見る" + "read:admin:show-moderation-log": "モデレーションログを見る" + "read:admin:show-user": "ユーザーのプライベートな情報を見る" + "read:admin:show-users": "ユーザーのプライベートな情報を見る" + "write:admin:suspend-user": "ユーザーを凍結する" + "write:admin:unset-user-avatar": "ユーザーのアバターを削除する" + "write:admin:unset-user-banner": "ユーザーのバーナーを削除する" + "write:admin:unsuspend-user": "ユーザーの凍結を解除する" + "write:admin:meta": "インスタンスのメタデータを操作する" + "write:admin:user-note": "モデレーションノートを操作する" + "write:admin:roles": "ロールを操作する" + "read:admin:roles": "ロールを見る" + "write:admin:relays": "リレーを操作する" + "read:admin:relays": "リレーを見る" + "write:admin:invite-codes": "招待コードを操作する" + "read:admin:invite-codes": "招待コードを見る" + "write:admin:announcements": "お知らせを操作する" + "read:admin:announcements": "お知らせを見る" + "write:admin:avatar-decorations": "アバターデコレーションを操作する" + "read:admin:avatar-decorations": "アバターデコレーションを見る" + "write:admin:federation": "連合に関する情報を操作する" + "write:admin:account": "ユーザーアカウントを操作する" + "read:admin:account": "ユーザーに関する情報を見る" + "write:admin:emoji": "絵文字を操作する" + "read:admin:emoji": "絵文字を見る" + "write:admin:queue": "ジョブキューを操作する" + "read:admin:queue": "ジョブキューに関する情報を見る" + "write:admin:promo": "プロモーションノートを操作する" + "write:admin:drive": "ユーザーのドライブを操作する" + "read:admin:drive": "ユーザーのドライブの関する情報を見る" + "read:admin:stream": "管理者用のWebsocket APIを使う" + "write:admin:ad": "広告を操作する" + "read:admin:ad": "広告を見る" + "write:invite-codes": "招待コードを作成する" + "read:invite-codes": "招待コードを取得する" + "write:clip-favorite": "クリップのいいねを操作する" + "read:clip-favorite": "クリップのいいねを見る" + "read:federation": "連合に関する情報を取得する" + "write:report-abuse": "違反を報告する" _auth: shareAccessTitle: "アプリへのアクセス許可" @@ -2396,10 +2496,12 @@ _profile: changeAvatar: "アイコン画像を変更" changeBanner: "バナー画像を変更" verifiedLinkDescription: "内容にURLを設定すると、リンク先のWebサイトに自分のプロフィールへのリンクが含まれている場合に所有者確認済みアイコンを表示させることができます。" + avatarDecorationMax: "最大{max}つまでデコレーションを付けられます。" _exportOrImport: allNotes: "全てのノート" favoritedNotes: "お気に入りにしたノート" + clips: "クリップ" followingList: "フォロー" muteList: "ミュート" blockingList: "ブロック" @@ -2519,9 +2621,8 @@ _notification: youGotMention: "{name}からのメンション" youGotReply: "{name}からのリプライ" youGotQuote: "{name}による引用" + youGotReact: "{name}が反応しました" youRenoted: "{name}がRenoteしました" - youGotMessagingMessageFromUser: "{name}からのチャットがあります" - youGotMessagingMessageFromGroup: "{name}のチャットがあります" youWereFollowed: "フォローされました" youReceivedFollowRequest: "フォローリクエストが来ました" yourFollowRequestAccepted: "フォローリクエストが承認されました" @@ -2529,6 +2630,7 @@ _notification: pollEnded: "アンケートの結果が出ました" newNote: "新しい投稿" unreadAntennaNote: "アンテナ {name}" + roleAssigned: "ロールが付与されました" emptyPushNotificationMessage: "プッシュ通知の更新をしました" achievementEarned: "実績を獲得" testNotification: "通知テスト" @@ -2552,6 +2654,7 @@ _notification: receiveFollowRequest: "フォロー申請を受け取った" followRequestAccepted: "フォローが受理された" groupInvited: "グループに招待された" + roleAssigned: "ロールが付与された" achievementEarned: "実績の獲得" app: "連携アプリからの通知" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index c9a2a9e25f..990c1bfba0 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -1,7 +1,5 @@ --- _lang_: "日本語 (関西弁)" -maxinumLayerError: "6枚以上重ねられんで。他のレイヤーを削除してなー" -layer: "レイヤー" headlineMisskey: "ノートでつながるネットワーク" introMisskey: "ようお越し!CherryPickは、オープンソースの分散型マイクロブログサービスやねん。\n「ノート」を作って、いま起こっとることを共有したり、あんたについて皆に発信しよう📡\n「ツッコミ」機能で、皆のノートに素早く反応を追加したりもできるで✌\nほな、新しい世界を探検しよか🚀" poweredByMisskeyDescription: "{name}は、オープンソースのプラットフォームCherryPickのサーバーのひとつなんやで。" @@ -17,7 +15,7 @@ gotIt: "ほい" cancel: "やめとく" noThankYou: "やめとく" enterUsername: "ユーザー名を入れてや" -renotedBy: "{user}がRenoteしたで" +renotedBy: "{user}がリノートしたで" noNotes: "ノートはあらへん" noNotifications: "通知はあらへん" instance: "サーバー" @@ -40,7 +38,7 @@ addUser: "ユーザーを追加や" favorite: "お気に入り" favorites: "お気に入り" unfavorite: "やっぱ気に入らん" -favorited: "お気に入りに入れたで" +favorited: "お気に入りに入れたで。" alreadyFavorited: "もうお気に入りに入れとるがな。" cantFavorite: "アカン、お気に入りに入れれんかったわ。" pin: "ピン留めしとく" @@ -50,9 +48,9 @@ copyLink: "リンクをコピー" copyLinkRenote: "リノートのリンクをコピーするで?" delete: "ほかす" deleteAndEdit: "ほかして直す" -deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのツッコミ、Renote、返信も全部消えるんやけどそれでもええん?" +deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのツッコミ、リノート、返信も全部消えるんやけどそれでもええん?" addToList: "リストに入れたる" -addToAntenna: "アンテナに追加" +addToAntenna: "アンテナに入れる" sendMessage: "メッセージを送る" copyRSS: "RSSをコピー" copyUsername: "ユーザー名をコピー" @@ -61,7 +59,7 @@ copyNoteId: "ノートIDをコピー" copyFileId: "ファイルIDをコピー" copyFolderId: "フォルダーIDをコピー" copyProfileUrl: "プロフィールURLをコピー" -searchUser: "ユーザーを検索" +searchUser: "ユーザーを探す" reply: "返事" loadMore: "まだまだあるで!" showMore: "まだまだあるで!" @@ -70,7 +68,7 @@ youGotNewFollower: "フォローされたで" receiveFollowRequest: "フォローリクエストされたで" followRequestAccepted: "フォローが承認されたで" mention: "メンション" -mentions: "自分宛て" +mentions: "あんた宛て" directNotes: "ダイレクト投稿" importAndExport: "インポートとエクスポート" import: "インポート" @@ -90,7 +88,7 @@ followers: "フォロワー" followsYou: "フォローされとるで" createList: "リスト作る" manageLists: "リストの管理" -error: "エラー" +error: "おかしなったで" somethingHappened: "なんかあかんわ" retry: "もっぺんやる?" pageLoadError: "ページが読み込めんかったわ。" @@ -107,13 +105,13 @@ followRequests: "フォロー申請" unfollow: "フォローやめる" followRequestPending: "フォロー許してくれるん待っとる" enterEmoji: "絵文字を入れてや" -renote: "Renote" -unrenote: "Renoteやめる" -renoted: "Renoteしたで。" -cantRenote: "この投稿はRenoteできへんらしい。" -cantReRenote: "Renote自体はRenoteできへんで。" +renote: "リノート" +unrenote: "リノートやめる" +renoted: "リノートしたで。" +cantRenote: "この投稿はリノートできへんっぽい。" +cantReRenote: "リノート自体はリノートできへんで。" quote: "引用" -inChannelRenote: "チャンネル内Renote" +inChannelRenote: "チャンネルの中でリノート" inChannelQuote: "チャンネル内引用" pinnedNote: "ピン留めされとるノート" pinned: "ピン留めしとく" @@ -123,7 +121,12 @@ sensitive: "気いつけて見いや" add: "増やす" reaction: "ツッコミ" reactions: "ツッコミ" -reactionSetting: "ピッカーに出しとくツッコミ" +emojiPicker: "絵文字ピッカー" +pinnedEmojisForReactionSettingDescription: "リアクションしたときにピンで留めてる表示をする絵文字を設定するで" +pinnedEmojisSettingDescription: "絵文字打ったときにピン留め表示する絵文字設定できるで" +emojiPickerDisplay: "ピッカーの表示" +overwriteFromPinnedEmojisForReaction: "リアクション設定から上書きする" +overwriteFromPinnedEmojis: "全般設定から上書きする" reactionSettingDescription2: "ドラッグで並び替え、クリックで削除、+を押して追加やで。" rememberNoteVisibility: "公開範囲覚えといて" attachCancel: "のっけるのやめる" @@ -132,8 +135,8 @@ unmarkAsSensitive: "そこまでアカンことないやろ" enterFileName: "ファイル名を入れてや" mute: "ミュート" unmute: "ミュートやめたる" -renoteMute: "Renoteは見いひん" -renoteUnmute: "Renoteもやっぱ見るわ" +renoteMute: "リノートは見いひん" +renoteUnmute: "リノートもやっぱ見るわ" block: "ブロック" unblock: "ブロックやめたる" suspend: "凍結" @@ -143,13 +146,13 @@ unblockConfirm: "ブロックやめたるってほんまか?" suspendConfirm: "凍結してしもうてええか?" unsuspendConfirm: "解凍するけどええか?" selectList: "リストを選ぶ" -editList: "リスト直すで" +editList: "リストいじる" selectChannel: "チャンネルを選ぶ" selectAntenna: "アンテナを選ぶ" -editAntenna: "アンテナを編集" +editAntenna: "アンテナいじる" selectWidget: "ウィジェットを選ぶ" editWidgets: "ウィジェットをいじる" -editWidgetsExit: "編集終ったで" +editWidgetsExit: "いじるのをやめる" customEmojis: "カスタム絵文字" emoji: "絵文字" emojis: "絵文字" @@ -158,14 +161,14 @@ emojiUrl: "絵文字画像URL" addEmoji: "絵文字を追加" settingGuide: "ええ感じの設定" cacheRemoteFiles: "リモートのファイルをキャッシュする" -cacheRemoteFilesDescription: "この設定を切っとったら、リモートファイルをキャッシュせんと直リンクするようになるで。サーバーの容量は節約できるけど、サムネイルを作らんなるから通信量が増えるで。" +cacheRemoteFilesDescription: "この設定を入れとったら、リモートのファイルを端から端までこのサーバーのキャッシュん中突っ込むようになるで。画像映し出すんがめっちゃ速うなるけど、サーバーの容量をやたらと食うようになるで。リモートの人がどんだけ長くキャッシュを持っとくかはドライブ容量の制限で決めとくで。制限を超えたら古いのから順々に消してって、かわりにリンクになるで。この設定を切ったら、リモートのファイルは最初っからリンクとして扱うことにするけど、画像のサムネ作るのとかみんなのプライバシー守るために、default.ymlのproxyRemoteFilesをtrueにしといたほうがええよ。" youCanCleanRemoteFilesCache: "ファイル管理にある🗑️ボタンでキャッシュ全部ほかすで。" -cacheRemoteSensitiveFiles: "リモートのセンシティブなファイルをキャッシュする" -cacheRemoteSensitiveFilesDescription: "この設定を無効にすると、リモートのセンシティブなファイルはキャッシュせず直リンクするようになるで。" +cacheRemoteSensitiveFiles: "リモートのきわどいファイルをキャッシュに突っ込む" +cacheRemoteSensitiveFilesDescription: "この設定を切ると、リモートのきわどいファイルはキャッシュせず直でリンクするようになるで。" flagAsBot: "Botにするで" flagAsBotDescription: "もしこのアカウントをプログラム使うて運用するんやったら、このフラグをオンにしてや。オンにすれば、反応がバーッて連鎖せんように開発者が使うたり、CherryPickのシステム上での扱いがBotに合ったもんになるからな。" -flagAsCat: "Catやで" -flagAsCatDescription: "ワレ、猫ちゃんならこのフラグをつけてみ?" +flagAsCat: "猫や。かわええな。" +flagAsCatDescription: "ネコになりたいんならこれつけとき。" flagShowTimelineReplies: "タイムラインにノートへの返信を表示するで" flagShowTimelineRepliesDescription: "オンにしたら、タイムラインにユーザーのノートの他にもそのユーザーの他のノートへの返信を表示するで。" autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストを勝手に許可しとく" @@ -216,12 +219,12 @@ clearQueueConfirmText: "未配達の投稿は配送されんなるで。ふつ clearCachedFiles: "キャッシュをほかす" clearCachedFilesConfirm: "キャッシュされとるリモートファイルをみんなほかしてええか?" blockedInstances: "ブロックしたサーバー" -blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定してな。ブロックされてもうたサーバーとはもう金輪際やり取りできひんくなるで。ついでにそのサブドメインもブロックするで。" +blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定してな。ブロックされてもうたサーバーとはもう金輪際やり取りできひんくなるで。" silencedInstances: "サーバーサイレンスされてんねん" silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定すんで。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなんねん。ブロックしたインスタンスには影響せーへんで。" muteAndBlock: "ミュートとブロック" -mutedUsers: "ミュートしたユーザー" -blockedUsers: "ブロックしたユーザー" +mutedUsers: "ミュートしとるユーザー" +blockedUsers: "ブロックしとるユーザー" noUsers: "ユーザーはおらん" editProfile: "プロフィールをいじる" noteDeleteConfirm: "このノートをほかしてええか?" @@ -248,7 +251,7 @@ changePassword: "パスワードをいじる" security: "セキュリティ" retypedNotMatch: "入れたやつ合うてへんわ。" currentPassword: "今のパスワード" -newPassword: "次のパスワード" +newPassword: "今度のパスワード" newPasswordRetype: "今度のパスワード(もっぺん入れて)" attachFile: "ファイルのっける" more: "他のん" @@ -263,6 +266,7 @@ removed: "ほかしたで!" removeAreYouSure: "「{x}」はほかしてええか?" deleteAreYouSure: "「{x}」はほかしてええか?" resetAreYouSure: "リセットしてええん?" +areYouSure: "いいん?" saved: "保存したで!" messaging: "チャット" upload: "アップロード" @@ -313,6 +317,7 @@ folderName: "フォルダー名" createFolder: "フォルダー作る" renameFolder: "フォルダー名を変える" deleteFolder: "フォルダーをほかす" +folder: "フォルダー" addFile: "ファイルを追加" emptyDrive: "ドライブは空っぽや" emptyFolder: "このフォルダーは空や" @@ -326,7 +331,7 @@ copyUrl: "URLをコピー" rename: "名前を変えるで" avatar: "アイコン" banner: "バナー" -displayOfSensitiveMedia: "センシティブなメディアの表示" +displayOfSensitiveMedia: "きわどいやつの表示" whenServerDisconnected: "サーバーとの接続が失くなってしもうたとき" disconnectedFromServer: "サーバーが機嫌悪いねん" reload: "リロード" @@ -414,7 +419,7 @@ userList: "リスト" about: "情報" aboutMisskey: "CherryPickってなんや?" administrator: "管理者" -token: "トークン" +token: "確認コード" 2fa: "二要素認証" setupOf2fa: "二要素認証のセットアップ" totp: "認証アプリ" @@ -427,7 +432,7 @@ moderationLogs: "モデログ" nUsersMentioned: "{n}人が投稿" securityKeyAndPasskey: "セキュリティキー・パスキー" securityKey: "セキュリティキー" -lastUsed: "最後につこうた日" +lastUsed: "最後に使うた日" lastUsedAt: "最後に使うたんは: {t}" unregister: "登録やめる" passwordLessLogin: "パスワード無くてもログインできるようにする" @@ -439,7 +444,6 @@ share: "わけわけ" notFound: "見つからへんね" notFoundDescription: "言われたURLにはまるページはなかったで。" uploadFolder: "とりあえずアップロードしたやつ置いとく所" -cacheClear: "キャッシュをほかす" markAsReadAllNotifications: "通知はもう全て読んだわっ" markAsReadAllUnreadNotes: "投稿は全て読んだわっ" markAsReadAllTalkMessages: "チャットはもうぜんぶ読んだわっ" @@ -482,7 +486,7 @@ weakPassword: "へぼいパスワード" normalPassword: "ぼちぼちのパスワード" strongPassword: "ええ感じのパスワード" passwordMatched: "よし!一致や!" -passwordNotMatched: "一致しとらんで?" +passwordNotMatched: "ちゃうで?" signinWith: "{x}でログイン" signinFailed: "ログインできんかったで。もっかいユーザー名とパスワードを確認してみてや。" or: "それか" @@ -539,7 +543,7 @@ objectStorageEndpointDesc: "S3のときは空、それ以外は各サービス objectStorageRegion: "Region" objectStorageRegionDesc: "'xx-east-1'みたいなregionを指定したってやー。使ってるサービスにregionの概念がないときは、空か'us-east-1'にするんやで。" objectStorageUseSSL: "SSLを使う" -objectStorageUseSSLDesc: "API接続にhttpsを使わん場合はオフにするんやで" +objectStorageUseSSLDesc: "API接続にhttpsを使わんのやったら消しといて" objectStorageUseProxy: "Proxyを使う" objectStorageUseProxyDesc: "API接続にproxy使わんのやったら切ってくれへん?" objectStorageSetPublicRead: "アップロードした時に'public-read'を設定してや" @@ -550,14 +554,16 @@ showFixedPostForm: "タイムラインの上の方で投稿できるようにや showFixedPostFormInChannel: "タイムラインの上の方で投稿できるようにするわ(チャンネル)" withRepliesByDefaultForNewlyFollowed: "フォローする時、デフォルトで返信をタイムラインに含むようにしよか" newNoteRecived: "新しいノートがあるで" -sounds: "サウンド" -sound: "サウンド" +sounds: "音" +sound: "音" listen: "聴く" none: "なし" showInPage: "ページで表示" popout: "ポップアウト" volume: "やかましさ" masterVolume: "全体のやかましさ" +notUseSound: "音出さへん" +useSoundOnlyWhenActive: "CherryPickがアクティブなときだけ音出す" details: "もっと" chooseEmoji: "絵文字を選ぶ" unableToProcess: "なんか奥の方で詰まってもうた" @@ -578,6 +584,10 @@ output: "出力" script: "スクリプト" disablePagesScript: "Pagesのスクリプトを無効にしてや" updateRemoteUser: "リモートユーザー情報の更新してくれん?" +unsetUserAvatar: "アイコン戻す" +unsetUserAvatarConfirm: "アイコンを元に戻すで?" +unsetUserBanner: "バナー戻す" +unsetUserBannerConfirm: "バナー元に戻すで?" deleteAllFiles: "ファイルを全部ほかす" deleteAllFilesConfirm: "ホンマにファイル全部ほかすんか?消したもんはもう戻ってこんのやで?" removeAllFollowing: "フォローを全解除" @@ -589,7 +599,7 @@ yourAccountSuspendedDescription: "あんたのアカウントは、サーバー tokenRevoked: "トークンが無効やで" tokenRevokedDescription: "ログイントークンが失効しとるで。もっかいログインしてもろてもええか?" accountDeleted: "アカウントは削除されとるで" -accountDeletedDescription: "このアカウントは削除されとるで。" +accountDeletedDescription: "このアカウントはもう消えとる。" menu: "メニュー" divider: "分割線" addItem: "項目を追加" @@ -605,9 +615,9 @@ enableInfiniteScroll: "自動でもっと見る" visibility: "公開範囲" poll: "アンケート" useCw: "内容を隠す" -enablePlayer: "プレイヤーを開く" -disablePlayer: "プレイヤーを閉じる" -expandTweet: "ポストを展開する" +enablePlayer: "プレイヤー開く" +disablePlayer: "プレイヤー閉じる" +expandTweet: "ポスト展開しとく" themeEditor: "テーマエディター" description: "説明" describeFile: "キャプションを付ける" @@ -620,7 +630,7 @@ preferencesBackups: "設定のバックアップ" deck: "デッキ" undeck: "デッキ解除" useBlurEffectForModal: "モーダルにぼかし効果を使用" -useFullReactionPicker: "フル機能の突っ込みピッカーを使用" +useFullReactionPicker: "フルフルのツッコミピッカーを使う" width: "幅" height: "高さ" large: "大" @@ -649,6 +659,7 @@ smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する" smtpSecureInfo: "STARTTLS使っとる時はオフにしてや。" testEmail: "配信テスト" wordMute: "ワードミュート" +hardWordMute: "ハードワードミュート" regexpError: "正規表現エラー" regexpErrorDescription: "{tab}ワードミュートの{line}行目の正規表現にエラーが出てきたで:" instanceMute: "サーバーミュート" @@ -664,7 +675,7 @@ database: "データベース" channel: "チャンネル" create: "作成" notificationSetting: "通知設定" -notificationSettingDesc: "表示する通知の種類えらんでや。" +notificationSettingDesc: "出す通知の種類えらんでや。" useGlobalSetting: "グローバル設定を使ってや" useGlobalSettingDesc: "オンにすると、アカウントの通知設定が使われるで。オフにすると、別々に設定できるようになるで。" other: "その他" @@ -701,18 +712,18 @@ clip: "クリップ" createNew: "新しく作るで" optional: "任意" createNewClip: "新しいクリップを作るで" -unclip: "クリップ解除するで" -confirmToUnclipAlreadyClippedNote: "このノートはすでにクリップ「{name}」に含まれとるで。ノートをこのクリップから除外しよか?" +unclip: "クリップやめとく" +confirmToUnclipAlreadyClippedNote: "このノートはもう「{name}」に含まれとるで。ノート、このクリップから外そか?" public: "パブリック" private: "非公開" -i18nInfo: "CherryPickは有志によっていろんな言語に翻訳されとるで。{link}で翻訳に協力したってやー。" +i18nInfo: "CherryPickは有志がいろんな言語に訳しとるで。{link}で翻訳に協力したってやー。" manageAccessTokens: "アクセストークンの管理" accountInfo: "アカウント情報" notesCount: "ノートの数やで" repliesCount: "返信した数やで" -renotesCount: "Renoteした数やで" +renotesCount: "リノートした数やで" repliedCount: "返信された数やで" -renotedCount: "Renoteされた数やで" +renotedCount: "リノートされた数やで" followingCount: "フォロー数やで" followersCount: "フォロワー数やで" sentReactionsCount: "ツッコんだ数" @@ -729,7 +740,7 @@ lockedAccountInfo: "フォローを承認制にしとっても、ノートの公 alwaysMarkSensitive: "デフォルトでメディアを閲覧注意にするで" loadRawImages: "添付画像のサムネイルをオリジナル画質にするで" disableShowingAnimatedImages: "アニメーション画像を再生せんとくで" -highlightSensitiveMedia: "メディアがセンシティブなことをめっっちゃわかりやすく表紙" +highlightSensitiveMedia: "きわどいことをめっっちゃわかりやすくする" verificationEmailSent: "無事確認のメールを送れたで。メールに書いてあるリンクにアクセスして、設定を完了してなー。" notSet: "未設定" emailVerified: "メールアドレスは確認されたで" @@ -741,7 +752,7 @@ useSystemFont: "システムのデフォルトのフォントを使うで" clips: "クリップ" experimentalFeatures: "おためし機能やで" experimental: "実験的" -thisIsExperimentalFeature: "これは実験的な機能やで。仕様が変更になったりちゃんと動かなかったりするかもやで。" +thisIsExperimentalFeature: "これは実験的な機能やから、仕様が変わったりちゃんと動かんかったりするかもしれん。" developer: "開発者やで" makeExplorable: "アカウントを見つけやすくするで" makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らんくなるで。" @@ -759,7 +770,7 @@ onlineUsersCount: "{n}人が起きとるで" nUsers: "{n}ユーザー" nNotes: "{n}ノート" sendErrorReports: "エラーリポートを送る" -sendErrorReportsDescription: "オンにしたら、変なことが起きたときにエラーの詳細がCherryPickに送られて、ソフトウェアの品質向上に使えるようになるで。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴なんかが含まれるで。" +sendErrorReportsDescription: "オンにしたら、なんか変なことが起きたとき、詳しいのが全部CherryPickに送られて、ソフトウェアをもっと良うするで。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴なんかが含まれるな。" myTheme: "マイテーマ" backgroundColor: "背景" accentColor: "アクセント" @@ -775,8 +786,8 @@ deleteConfirm: "ホンマにほかすで?" invalidValue: "有効な値じゃないみたいやで。" registry: "レジストリ" closeAccount: "アカウントを閉鎖する" -currentVersion: "現在のバージョン" -latestVersion: "最新のバージョン" +currentVersion: "今のやつ" +latestVersion: "いっちゃん新しいやつ" youAreRunningUpToDateClient: "今使ってるクライアントが最新やで!" newVersionOfClientAvailable: "新しいバージョンのクライアントが使えるで。" usageAmount: "使用量" @@ -798,9 +809,9 @@ goBack: "戻る" unlikeConfirm: "いいね解除するんか?" fullView: "フルビュー" quitFullView: "フルビュー解除" -addDescription: "説明を追加するで" -userPagePinTip: "個々のノートのメニューから「ピン留め」を選んどくと、ここにノートを表示しておけるで。" -notSpecifiedMentionWarning: "宛先に含まれてへんメンションがあるで" +addDescription: "説明を入れるで" +userPagePinTip: "ノートのメニューから「ピン留め」を選んどいたら、ここにノートを置いとけるで。" +notSpecifiedMentionWarning: "宛先にないメンションがあるで" info: "情報" userInfo: "ユーザー情報やで" unknown: "不明" @@ -812,7 +823,7 @@ active: "アクティブ" offline: "オフライン" notRecommended: "あんま推奨しやんで" botProtection: "Botプロテクション" -instanceBlocking: "サーバーブロック" +instanceBlocking: "サーバーブロック・サイレンス" selectAccount: "アカウントを選んでなー" switchAccount: "アカウントを変えるで" enabled: "有効" @@ -872,7 +883,7 @@ itsOn: "オンになっとるよ" itsOff: "オフになってるで" on: "オン" off: "オフ" -emailRequiredForSignup: "アカウント登録にメールアドレスを必須にするで" +emailRequiredForSignup: "アカウント作るのにメールアドレスを必須にするで" unread: "未読" filter: "フィルタ" controlPanel: "コントロールパネル" @@ -882,11 +893,9 @@ makeReactionsPublicDescription: "あんたがしたツッコミ一覧を誰で classic: "クラシック" muteThread: "スレッドをミュート" unmuteThread: "スレッドのミュートを解除" -ffVisibility: "つながりの公開範囲" -ffVisibilityDescription: "あんたのフォロー/フォロワー情報の公開範囲を設定できるで。" continueThread: "さらにスレッドを見るで" deleteAccountConfirm: "アカウントを消すで?ええんか?" -incorrectPassword: "パスワードがちゃうで。" +incorrectPassword: "パスワードがちゃうわ。" voteConfirm: "「{choice}」に投票するんか?" hide: "隠す" leaveGroup: "グループから抜けるで" @@ -916,8 +925,8 @@ oneMonth: "1ヶ月" reflectMayTakeTime: "反映されるまで時間がかかることがあるで" failedToFetchAccountInformation: "アカウントの取得に失敗したみたいや…" rateLimitExceeded: "レート制限が超えたみたいやで" -cropImage: "画像のクロップ" -cropImageAsk: "画像をクロップしてもええか?" +cropImage: "画像切り取り" +cropImageAsk: "画像を切り取ってもええか?" cropYes: "切り抜いたる" cropNo: "切り抜かへん" file: "ファイル" @@ -928,18 +937,18 @@ thereIsUnresolvedAbuseReportWarning: "未対応の通報があるみたいやで recommended: "推奨" check: "チェック" driveCapOverrideLabel: "このユーザーのドライブ容量上限を変更するで" -driveCapOverrideCaption: "0以下を指定すると解除されるで。" -requireAdminForView: "これを見るには管理者アカウントでログインしとらなあかんで。" +driveCapOverrideCaption: "0以下にしたら解除されるで。" +requireAdminForView: "これ見たいんなら管理者じゃないとアカンわ。" isSystemAccount: "システムが自動で作成・管理しとるアカウントやで。" -typeToConfirm: "この操作をやるんなら {x} と入力してなー" +typeToConfirm: "これやるんなら {x} って入力してなー" deleteAccount: "アカウント削除するで" document: "ドキュメント" numberOfPageCache: "ページ、どんだけキャッシュすんの?" -numberOfPageCacheDescription: "増やすと使いやすくなる、負荷とメモリ使用量が増えてくで。一長一短やな。" +numberOfPageCacheDescription: "増やすと使いやすくなるけど、負荷とメモリ使用量が増えてくで。一長一短やな。" logoutConfirm: "ログアウトしまっか?" lastActiveDate: "最後に使った日時" statusbar: "ステータスバー" -pleaseSelect: "選択したってやー" +pleaseSelect: "選んだってやー" reverse: "反転" colored: "色付き" refreshInterval: "更新間隔" @@ -948,28 +957,28 @@ type: "タイプ" speed: "速度" slow: "遅い" fast: "速い" -sensitiveMediaDetection: "センシティブなメディアの検出" -localOnly: "ローカルのみ" -remoteOnly: "リモートのみ" +sensitiveMediaDetection: "きわどいやつの検出" +localOnly: "ローカルだけ" +remoteOnly: "リモートだけ" failedToUpload: "アップロードに失敗してもうたわ…" -cannotUploadBecauseInappropriate: "不適切な内容を含むかもしれへんって判定されたからアップロードできへんわ。" -cannotUploadBecauseNoFreeSpace: "ドライブの空き容量が無いからアップロードできへんわ。" +cannotUploadBecauseInappropriate: "きわどい内容を含むかもしれへんって言われたからアップロードできへんわ。" +cannotUploadBecauseNoFreeSpace: "ドライブがもうパンパンやからアップロードできへんわ。" cannotUploadBecauseExceedsFileSizeLimit: "ファイルが思うたよりも大きいさかいアップロードできへんでこれ。" beta: "ベータ" -enableAutoSensitive: "自動NSFW判定" +enableAutoSensitive: "自動できわどいか判断する" enableAutoSensitiveDescription: "使える時は、機械学習を使って自動でメディアにNSFWフラグを設定するで。この機能をオフにしても、サーバーによっては自動で設定されることがあるで。" -activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかとかを判定して積極的に行うで。オフにすると単に文字列として正しいかどうかだけチェックするで。" +activeEmailValidationDescription: "ユーザーのメアドのバリデーションを、捨てアドかどうかとか、ちゃんと通信できるかとかを見るで。切ったら単に文字列として合っとるかどうかだけ見るわ。" navbar: "ナビゲーションバー" shuffle: "シャッフルするで" account: "アカウント" -move: "移動するで" +move: "移すで" pushNotification: "プッシュ通知" subscribePushNotification: "プッシュ通知をオンにするで" unsubscribePushNotification: "プッシュ通知を止めるで" pushNotificationAlreadySubscribed: "プッシュ通知はオンになってるで" pushNotificationNotSupported: "ブラウザかサーバーがプッシュ通知に対応してないみたいやで。" sendPushNotificationReadMessage: "通知やメッセージが既読になったらプッシュ通知を消すで" -sendPushNotificationReadMessageCaption: "「{emptyPushNotificationMessage}」っていう表示が一瞬表示されるようになるで。端末の電池使用量が増える可能性があるで。" +sendPushNotificationReadMessageCaption: "あんたの端末の電池使う量が増えるかもしれん。" windowMaximize: "最大化" windowMinimize: "最小化" windowRestore: "元に戻す" @@ -979,30 +988,30 @@ tools: "ツール" cannotLoad: "読み込めへんで" numberOfProfileView: "プロフィール表示回数" like: "ええやん!" -unlike: "いいねを解除" +unlike: "いいねやめる" numberOfLikes: "いいね数" show: "表示" neverShow: "今後表示しない" remindMeLater: "また後で" didYouLikeMisskey: "CherryPick気に入ってくれた?" -pleaseDonate: "CherryPickは{host}が使用している無料のソフトウェアやで。これからも開発を続けれるように、寄付したってな~。" +pleaseDonate: "CherryPickは{host}が使うとる無料のソフトウェアやで。これからも開発を続けれるように、寄付したってな~。" roles: "ロール" role: "ロール" noRole: "ロールはありまへん" normalUser: "一般ユーザー" undefined: "未定義" assign: "アサイン" -unassign: "アサインを解除" +unassign: "アサインやめる" color: "色" manageCustomEmojis: "カスタム絵文字の管理" manageAvatarDecorations: "アバターを飾るモンの管理" youCannotCreateAnymore: "これ以上作れなさそうやわ" -cannotPerformTemporary: "一時的に利用できへんで" -cannotPerformTemporaryDescription: "操作回数が制限を超えたから一時的に利用できへんくなったで。ちょっと時間置いてからもう一回やってやー。" +cannotPerformTemporary: "ちょっといまは使えへんで" +cannotPerformTemporaryDescription: "操作し過ぎてちょっと今は使えへんくしとるで。ちょっと待ってからもっかいやってや。" invalidParamError: "パラメータがエラー言うとりますわ" -invalidParamErrorDescription: "リクエストパラメータに問題があんねん。普通はバグやねんけど、もしかすると入力した文字数が多すぎるとかの可能性もあるから確認してや〜" +invalidParamErrorDescription: "リクエストパラメータが変やわ。だいたいはバグやねんけど、もしかしたら入れた文字が多すぎるとかかもしれんから確認してや〜" permissionDeniedError: "操作が拒否されてもうた。" -permissionDeniedErrorDescription: "自分のアカウントにはこの操作を行う権限があらへんねん" +permissionDeniedErrorDescription: "このアカウントはこれやったらアカンって。" preset: "プリセット" selectFromPresets: "プリセットから選ぶ" achievements: "実績" @@ -1012,15 +1021,15 @@ thisPostMayBeAnnoying: "この投稿は迷惑かもしらんで。" thisPostMayBeAnnoyingHome: "ホームに投稿" thisPostMayBeAnnoyingCancel: "やめとく" thisPostMayBeAnnoyingIgnore: "このまま投稿" -collapseRenotes: "見たことあるRenoteは飛ばして表示するで" +collapseRenotes: "見たことあるリノートは飛ばして表示するで" internalServerError: "サーバー内部エラー" -internalServerErrorDescription: "サーバー内部でよう分からんエラーやわ" -copyErrorInfo: "エラー情報をコピー" +internalServerErrorDescription: "サーバーでなんか変なこと起こっとるわ。" +copyErrorInfo: "エラー情報をコピるで" joinThisServer: "このサーバーに登録するわ" exploreOtherServers: "他のサーバー見てみる" letsLookAtTimeline: "タイムライン見てみーや" disableFederationConfirm: "連合なしにしとくか?" -disableFederationConfirmWarn: "連合なしにしても投稿は非公開にはならへんで。大体の場合は連合なしにする必要はないで。" +disableFederationConfirmWarn: "連合なしにしても投稿が非公開になるわけちゃうで。大体の場合は連合なしにする必要はないで。" disableFederationOk: "連合なしにしとく" invitationRequiredToRegister: "今このサーバー招待制になってもうてんねん。招待コードを持っとるんやったら登録できるで。" emailNotSupported: "このサーバーはメール配信がサポートされてへんみたいやわ" @@ -1029,14 +1038,16 @@ cannotBeChangedLater: "後からは変えられへんで。" reactionAcceptance: "ツッコミの受け入れ" likeOnly: "いいねだけ" likeOnlyForRemote: "リモートからはいいねだけな" -nonSensitiveOnly: "センシティブじゃないやつだけ" -nonSensitiveOnlyForLocalLikeOnlyForRemote: "センシティブじゃないやつだけ (リモートはいいねだけ)" +nonSensitiveOnly: "いつ見ても大丈夫なやつだけ" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "いつ見ても大丈夫なやつだけ (リモートはいいねだけ)" rolesAssignedToMe: "自分に割り当てられたロール" resetPasswordConfirm: "パスワード作り直すんでええな?" sensitiveWords: "けったいな単語" sensitiveWordsDescription: "設定した単語が入っとるノートの公開範囲をホームにしたるわ。改行で区切ったら複数設定できるで。" sensitiveWordsDescription2: "スペースで区切るとAND指定、キーワードをスラッシュで囲んだら正規表現や。" -notesSearchNotAvailable: "ノート検索は使われへんで。" +hiddenTags: "見えてへんハッシュタグ" +hiddenTagsDescription: "設定したタグを最近流行りのとこに見えんようにすんで。複数設定するときは改行で区切ってな。" +notesSearchNotAvailable: "なんかノート探せへん。" license: "ライセンス" unfavoriteConfirm: "ほんまに気に入らんの?" myClips: "自分のクリップ" @@ -1047,20 +1058,21 @@ retryAllQueuesConfirmText: "一時的にサーバー重なるかもしれへん enableChartsForRemoteUser: "リモートユーザーのチャートを作る" enableChartsForFederatedInstances: "リモートサーバーのチャートを作る" showClipButtonInNoteFooter: "ノートのアクションにクリップを追加" -reactionsDisplaySize: "リアクションの表示のでかさ" +reactionsDisplaySize: "ツッコミの表示のでかさ" +limitWidthOfReaction: "ツッコミの最大横幅を制限して、ちっさく表示するで" noteIdOrUrl: "ノートIDかURL" video: "動画" videos: "動画" dataSaver: "データケチケチ" accountMigration: "アカウントのお引っ越し" accountMoved: "このユーザーはさらのアカウントに引っ越したで:" -accountMovedShort: "このアカウントは移行されとるで" +accountMovedShort: "このアカウントは引っ越し済みや" operationForbidden: "この操作はできまへん" -forceShowAds: "常に広告を表示しとく" +forceShowAds: "いっつも広告を映す" addMemo: "メモを足す" editMemo: "メモをいらう" reactionsList: "ツッコミ一覧" -renotesList: "Renote一覧" +renotesList: "リノート一覧" notificationDisplay: "通知見せる" leftTop: "左上" rightTop: "右上" @@ -1072,7 +1084,7 @@ horizontal: "横" position: "位置" serverRules: "サーバールール" pleaseConfirmBelowBeforeSignup: "このサーバーに登録する前に、下に書いてること確認してな。" -pleaseAgreeAllToContinue: "続けるんやったら、全ての「せやな」にチェック入れてる必要があるで。" +pleaseAgreeAllToContinue: "続けるんやったら、全部にチェック入れとかなアカンで。" continue: "続けるで" preservedUsernames: "予約ユーザー名" preservedUsernamesDescription: "予約しとくユーザー名を行ごとに挙げるで。ここで指定されたユーザー名はアカウント作るときに使えへんくなるけど、管理者は例外や。あと、もうあるアカウントも例外やな。" @@ -1098,29 +1110,29 @@ changeReactionConfirm: "ツッコミを別のに変えるか?" later: "あとで" goToMisskey: "CherryPickへ" additionalEmojiDictionary: "絵文字の追加辞書" -installed: "インストール済み" +installed: "インストールしとる" branding: "ブランディング" enableServerMachineStats: "サーバーのマシン情報見せびらかすで" enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする" turnOffToImprovePerformance: "オフにしたらえらい軽うなるで。" -createInviteCode: "招待コードを作成" -createWithOptions: "オプションを指定して作成" -createCount: "作成数" +createInviteCode: "招待コード作る" +createWithOptions: "オプション決めて作る" +createCount: "作った数" inviteCodeCreated: "招待コード作ったで" inviteLimitExceeded: "招待コード作りすぎやで。" -createLimitRemaining: "作成できる招待コード: 残り {limit} 個やで" -inviteLimitResetCycle: "{time}で最大 {limit} 個の招待コードを作成できるで。" +createLimitRemaining: "作れる招待コードは残り {limit} 個や" +inviteLimitResetCycle: "{time}で最大 {limit} 個の招待コードを作れるで。" expirationDate: "有効期限" -noExpirationDate: "有効期限を設けへん" -inviteCodeUsedAt: "招待コードが使用された日時" -registeredUserUsingInviteCode: "招待コードを使用したユーザー" +noExpirationDate: "期限なし" +inviteCodeUsedAt: "招待コードが使われた時" +registeredUserUsingInviteCode: "招待コードを使うた人" waitingForMailAuth: "メール認証待ち" -inviteCodeCreator: "招待コードを作成したユーザー" -usedAt: "使用日時" +inviteCodeCreator: "招待コードを作った人" +usedAt: "使った時" unused: "つこてへん" used: "もうつこてる" expired: "期限切れ" -doYouAgree: "同意するんか?" +doYouAgree: "ええんか?" beSureToReadThisAsItIsImportant: "重要やから絶対読んでや。" iHaveReadXCarefullyAndAgree: "「{x}」の内容をよう読んで、同意するで。" dialog: "ダイアログ" @@ -1131,119 +1143,181 @@ pastAnnouncements: "過去のお知らせやで" youHaveUnreadAnnouncements: "あんたまだこのお知らせ読んどらんやろ。" useSecurityKey: "ブラウザまたはデバイスの言う通りに、セキュリティキーまたはパスキーを使ってや。" replies: "返事" -renotes: "Renote" +renotes: "リノート" loadReplies: "返信を見るで" loadConversation: "会話を見るで" pinnedList: "ピン留めしはったリスト" keepScreenOn: "デバイスの画面を常にオンにすんで" -verifiedLink: "このリンク先の所有者であることが確認されたで。" +verifiedLink: "このリンク先の所有者ってわかったわ。" notifyNotes: "投稿を通知" -unnotifyNotes: "投稿の通知を解除すんで" +unnotifyNotes: "投稿の通知やめる" authentication: "認証" -authenticationRequiredToContinue: "続けるには認証をやってや。" +authenticationRequiredToContinue: "続けるんなら認証してや。" dateAndTime: "日時" -showRenotes: "リノートを表示" -edited: "編集し終わってる" -notificationRecieveConfig: "通知を受け取るかの設定" +showRenotes: "リノート出す" +edited: "いじったやつ" +notificationRecieveConfig: "通知もらうかの設定" mutualFollow: "お互いフォローしてんで" -fileAttachedOnly: "ファイル付きのみ" -showRepliesToOthersInTimeline: "タイムラインに他の人への返信とかも含めんで" -hideRepliesToOthersInTimeline: "タイムラインに他の人への返信とかは見ーへんで" -showRepliesToOthersInTimelineAll: "" -hideRepliesToOthersInTimelineAll: "" -confirmShowRepliesAll: "" -confirmHideRepliesAll: "" +fileAttachedOnly: "ファイルのっけてあるやつだけ" +showRepliesToOthersInTimeline: "タイムラインに他の人への返信とかも入れるで" +hideRepliesToOthersInTimeline: "タイムラインに他の人への返信とかは入れへん" +showRepliesToOthersInTimelineAll: "タイムラインに今フォローしとる人全員の返信入れるで" +hideRepliesToOthersInTimelineAll: "タイムラインに今フォローしとる人の返信入れへん" +confirmShowRepliesAll: "これは元に戻せへんから慎重に決めてや。本当にタイムラインに今フォローしとる全員の返信を入れるか?" +confirmHideRepliesAll: "これは元に戻せへんから慎重に決めてや。本当にタイムラインに今フォローしとる全員の返信を入れへんのか?" externalServices: "他のサイトのサービス" impressum: "運営者の情報" impressumUrl: "運営者の情報URL" -impressumDescription: "ドイツなどのほんま1部の国と地域ではな、表示が義務付けられててん。(Impressum)" +impressumDescription: "ドイツとかの一部んところではな、表示が義務付けられてんねん(Impressum)。" privacyPolicy: "プライバシーポリシー" privacyPolicyUrl: "プライバシーポリシーURL" tosAndPrivacyPolicy: "利用規約・プライバシーポリシー" avatarDecorations: "アイコンデコレーション" -attach: "" -detach: "" -angle: "" +attach: "のっける" +detach: "取る" +detachAll: "全部とる" +angle: "角度" flip: "反転" -showAvatarDecorations: "" -releaseToRefresh: "離してリロード" -refreshing: "リロード中" +showAvatarDecorations: "アイコンのデコレーション映す" +releaseToRefresh: "離したらリロード" +refreshing: "リロードしとる" pullDownToRefresh: "引っ張ってリロードするで" disableStreamingTimeline: "タイムラインのリアルタイム更新をやめるで" -useGroupedNotifications: "通知をグルーピングしてだすで" -signupPendingError: "メールアドレスの確認中に問題が起こってえらいこっちゃ。リンクの有効期限が切れてるかもやで" -cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要やで。" -doReaction: "ツッコミすんで" +useGroupedNotifications: "通知をグループ分けして出すで" +signupPendingError: "メアド確認してたらなんか変なことなったわ。リンクの期限切れてるかもしれん。" +cwNotationRequired: "「内容を隠す」んやったら注釈書かなアカンで。" +doReaction: "ツッコむで" +code: "コード" +reloadRequiredToApplySettings: "設定を見るんにはリロードが必要やで。" +remainingN: "残り:{n}" +overwriteContentConfirm: "今の内容に上書きされるけどいい?" +seasonalScreenEffect: "季節にあった画面の動き" +decorate: "デコる" _announcement: forExistingUsers: "もうおるユーザーのみ" - forExistingUsersDescription: "有効にすると、このお知らせ作成時点でおるユーザーにのみお知らせが表示されます。無効にすると、このお知らせ作成後にアカウントを作成したユーザーにもお知らせが表示されます。" - needConfirmationToRead: "既読にするのに確認が必要やで" - needConfirmationToReadDescription: "有効にすると、このお知らせを既読にする際に確認ダイアログが表示されます。また、一括既読操作の対象にもなりません。" - end: "お知らせを終了" - tooManyActiveAnnouncementDescription: "アクティブなお知らせが多いため、UXが低下する可能性があります。終了したお知らせはアーカイブすることを検討した方がええよ。" + forExistingUsersDescription: "オンにしたらこのお知らせができた時点でおる人らにだけお知らせが行くで。切ったらこの知らせが行ったあとにアカウント作った人にもちゃんとお知らせが行くで。" + needConfirmationToRead: "既読にするんやったら確認してや" + needConfirmationToReadDescription: "オンにしたら、このお知らせを既読にする時に確認するで。ついでに、一括既読しても既読扱いにならへんで。" + end: "お知らせやめる" + tooManyActiveAnnouncementDescription: "お知らせが多すぎてUXが落ちそうや。終わったお知らせはアーカイブに突っ込んだほうがええかも。" readConfirmTitle: "既読にしてええんやな?" - readConfirmText: "「{title}」の内容を読み、既読にします。" + readConfirmText: "「{title}」はもう読んだから既読にするで。" shouldNotBeUsedToPresentPermanentInfo: "新規ユーザーのUXを損ねやすいから、お知らせはストック情報やのうてフロー情報の掲示に使った方がええで。" - dialogAnnouncementUxWarn: "ダイアログ形式のお知らせが同時に2つ以上ある場合、UXに悪影響を及ぼす可能性が高くなるから、使用は慎重にすんのがおすすめやで。" + dialogAnnouncementUxWarn: "ダイアログ形式のお知らせがいっぺんに2コ以上ある場合、UXに良うないことが多いから、使うんは慎重にすんのがおすすめやで。" silence: "通知せんで" - silenceDescription: "オンにすると、このお知らせは通知されないで、既読にする必要もなくなるで。" + silenceDescription: "オンにすると、このお知らせは通知されへんし、既読にする必要もなくなるで。" _initialAccountSetting: accountCreated: "アカウント作り終わったで。" letsStartAccountSetup: "アカウントの初期設定をしよか。" - letsFillYourProfile: "最初はあんたのプロフィールを設定しよか。" + letsFillYourProfile: "最初はあんたのプロフィールを設定するで。" profileSetting: "プロフィール設定" privacySetting: "プライバシー設定" theseSettingsCanEditLater: "この設定はあとから変えれるで。" youCanEditMoreSettingsInSettingsPageLater: "これ以外にもいろんな設定を「設定」ページからできるで。後で確認してみてな。" followUsers: "タイムラインを構築するために、気になるユーザーをフォローしてみ。" pushNotificationDescription: "プッシュ通知を有効にすると{name}の通知をあんたのデバイスで受け取れるで。" - initialAccountSettingCompleted: "初期設定が終わったで。" + initialAccountSettingCompleted: "初期設定終わりや!" haveFun: "{name}、楽しんでな~" - youCanContinueTutorial: "このまま{name}(Misskey)の使い方のチュートリアルに進めるけど、ここで中断してすぐに使い始めることもできるで。" - startTutorial: "チュートリアルを開始するで" + youCanContinueTutorial: "こんまま{name}(CherryPick)の使い方のチュートリアルにも行けるけど、ここでやめてすぐに使い始めてもええで。" + startTutorial: "チュートリアルはじめる" skipAreYouSure: "初期設定飛ばすか?" laterAreYouSure: "初期設定あとでやり直すん?" _initialTutorial: - launchTutorial: "チュートリアルを見るで" + launchTutorial: "チュートリアル見るで" title: "チュートリアルやで" wellDone: "やるやん" - skipAreYouSure: "チュートリアルをやめるか?" + skipAreYouSure: "チュートリアルやめるか?" _landing: title: "チュートリアルによう来たな" - description: "ここでは、Misskeyの基本的な使い方や機能を確認できるで。" + description: "ここでは、CherryPickのカンタンな使い方とか機能を確かめれんで。" _note: title: "ノートってなんや?" - description: "Misskeyでの投稿は「ノート」って呼ばれてるで。ノートはタイムラインに時系列で並んでいて、リアルタイムで更新されてるで。" - reply: "返信することもできるで。返信に対しての返信も可能で、スレッドのように会話を続けることもできるで。" - renote: "そのノートを自分のタイムラインに流して共有することもできるで。テキストを追加して引用することもできるで。" - reaction: "ツッコミをつけることもできるで。細かいことは次のページで解説するで。" + description: "CherryPickでの投稿は「ノート」って呼ばれてんで。ノートは順々にタイムラインに載ってて、リアルタイムで新しくなってってんで。" + reply: "返信もできるで。返信の返信もできるから、スレッドっぽく会話をそのまま続けれもするで。" + renote: "そのノートを自分のタイムラインに流して共有できるで。テキスト入れて引用してもええな。" + reaction: "ツッコミをつけることもできるで。細かいことは次のページや。" + menu: "ノートの詳細を出したり、リンクをコピーしたり、いろいろできんねん。" + _reaction: + title: "ツッコミってなんや?" + description: "ノートには「ツッコミ」できんねん。「いいね」とか何言っとるかわからんし、簡単に表現できるのはええことやん?" + letsTryReacting: "ノートの「+」ボタンでツッコめるわ。試しに下のノートにツッコんでみ。" + reactToContinue: "ツッコんだら進めるようになるで。" + reactNotification: "あんたのノートが誰かにツッコまれたら、すぐ通知するで。" + reactDone: "「ー」ボタンでツッコミやめれるで。" + _timeline: + title: "タイムラインのしくみ" + description1: "CherryPickには、いろいろタイムラインがあんで(ただ、サーバーによっては無効化されてるところもあるな)。" + home: "あんたがフォローしてるアカウントの投稿が見れんねん。" + local: "このサーバーの中におる全員の投稿が見れるで。" + social: "ホームタイムラインの投稿もローカルタイムラインのも一緒に見れるで。" + global: "繋がってる他の全サーバーからの投稿が見れるで。" + description2: "それぞれのタイムラインは、いつでも画面上で切り替えられんねん。覚えとき。" + description3: "その他にも、リストタイムラインとかチャンネルタイムラインとかがあんねん。詳しいのは{link}を見とき。" + _postNote: + title: "ノートの投稿設定" + description1: "CherryPickにノートを投稿するとき、いろんなオプションが付けれるで。投稿画面はこんな感じや。" + _visibility: + description: "ノートを見れる相手を制限できるわ。" + public: "みんなに見せるで。" + home: "ホームタイムラインにだけ見せるで。フォロワーとか、プロフィールを見に来た人、リノートからも見れるから、実質は全員見れるけどな。あんまし広がりにくいってことや。" + followers: "フォロワーにだけ見せるで。自分以外はリノートできへんし、フォロワー以外は絶対に見れへん。" + direct: "指定した人にだけ公開されて、ついでに通知も送るで。ダイレクトメールの代わりとして使ってな。" + doNotSendConfidencialOnDirect1: "機密情報を送るときは十分注意せえよ。" + doNotSendConfidencialOnDirect2: "送信先のサーバーの管理者は投稿内容が見れるから、信用できへんサーバーのひとにダイレクト投稿するときには、めっちゃ用心しとくんやで。" + localOnly: "他のサーバーに投稿せえへんくなるで。他の公開範囲とか一切無視して、他のサーバーの人らはこの設定がされたノートは絶対に見れへん。" + _cw: + title: "内容隠し(CW)" + description: "本文のかわりに「注釈」に書いた内容だけ見せるで。「続き見して!」を押すと本文も見れんねん。" + _exampleNote: + cw: "飯テロ注意" + note: "チョコドーナツめっちゃ美味かったわ🍩😋" + useCases: "サーバーのガイドラインに決められとるノートに使うたり、ネタバレとかきわどい内容を自分で隠したりするとき用やな。" + _howToMakeAttachmentsSensitive: + title: "のっけたファイルをセンシティブにするんは?" + description: "サーバーのガイドラインに書いてあったり、そのままおっぴろげとくのはあんま良うないファイルには「センシティブ」っちゅう設定をつけるんや。" + tryThisFile: "試しに、これにのっけてある画像をセンシティブにしてみいや!" + _exampleNote: + note: "納豆のフタ開けるときにやらかしてもうた…" + method: "のっけたファイルをセンシティブにするときは、そのファイルを押してメニュー開けて、「ちょっとこれはアカン」を押すんよ。" + sensitiveSucceeded: "ファイルをのっけるときは、サーバーの言うこと聞いてちゃんと設定するんやで。" + doItToContinue: "画像をちゃんと設定したら先に進めるで。" + _done: + title: "チュートリアル終わり!おつかれさん🎉" + description: "ここで紹介したのは全部の中のちょび~っとだけや。もっと使い方知りたいんやったら、{link}を見ときや。" +_timelineDescription: + home: "ホームタイムラインは、あんたがフォローしとるアカウントの投稿だけ見れるで。" + local: "ローカルタイムラインは、このサーバーにおる全員の投稿を見れるで。" + social: "ソーシャルタイムラインは、ホームタイムラインの投稿もローカルタイムラインのも一緒に見れるで。" + global: "グローバルタイムラインは、繋がっとる他のサーバーの投稿、全部ひっくるめて見れんで。" _serverRules: - description: "新規登録前に見せる、サーバーの簡潔なルールを設定すんで。内容は使うための決め事の要約とすることを推奨するわ。" + description: "新規登録前に見せる、サーバーのカンタンなルールを決めるで。内容は使うための決め事の要約がええと思うわ。" _serverSettings: iconUrl: "アイコン画像のURL" appIconDescription: "{host}がアプリとして表示してるんやつをアイコンを指定すんで。" - appIconUsageExample: "PWAや、スマートフォンのホーム画面にブックマークとして追加された時など" - appIconStyleRecommendation: "円形もしくは角丸にクロップされる場合があるさかいに、塗り潰された余白のある背景があるものが推奨されるで。" - appIconResolutionMustBe: "解像度は必ず{resolution}である必要があるで。" + appIconUsageExample: "例えば、PWAとか、スマホのホームにブックマークしたときとか" + appIconStyleRecommendation: "円か角丸に切り取られることがあるさかい、塗り潰した余白のある背景があるものがおすすめや。" + appIconResolutionMustBe: "解像度は絶対{resolution}じゃないとアカン。" manifestJsonOverride: "manifest.jsonのオーバーライド" shortName: "略称" - shortNameDescription: "サーバーの名前が長い時に、代わりに表示することのできるあだ名。" - fanoutTimelineDescription: "" + shortNameDescription: "サーバーの名前が長ったらしい時に、代わりに出すあだ名。" + fanoutTimelineDescription: "入れると、おのおのタイムラインを取得するときにめちゃめちゃ動きが良うなって、データベースが軽くなるわ。でも、Redisのメモリ使う量が増えるから注意な。サーバーのメモリが足りんときとか、動きが変なときは切れるで。" + fanoutTimelineDbFallback: "データベースにフォールバックする" + fanoutTimelineDbFallbackDescription: "有効にしたら、タイムラインがキャッシュん中に入ってないときにDBにもっかい問い合わせるフォールバック処理ってのをやっとくで。切ったらフォールバック処理をやらんからサーバーはもっと軽くなんねんけど、タイムラインの取得範囲がちょっと減るで。" _accountMigration: moveFrom: "別のアカウントからこのアカウントに引っ越す" moveFromSub: "別のアカウントへエイリアスを作る" - moveFromLabel: "引っ越し元のアカウント:" - moveFromDescription: "別のアカウントからこのアカウントにフォロワーを引き継いで引っ越したかったら、ここでエイリアスを作っとく必要があるで。必ずお引っ越しを実行する前に作っとかなあかんで!引っ越し元のアカウントをこんな風に入力してくれへんか?:@person@instance.com" + moveFromLabel: "引っ越しする前のアカウント #{n}" + moveFromDescription: "別のアカウントからこのアカウントにフォロワーを引っ越ししたいんなら、ここでエイリアスを作っとかなアカンで。\n引っ越す前のアカウントをこんな感じに入力してや: @username@server.example.com\n入力欄空っぽやったら消しとくで(おすすめはせえへん)。" moveTo: "このアカウントをさらのアカウントに引っ越すで" - moveToLabel: "引っ越し先のアカウント:" - moveCannotBeUndone: "アカウントを移行すると、取り消すことはできへんくなります。" + moveToLabel: "引っ越し先のアカウント:" + moveCannotBeUndone: "アカウント引っ越したらもう戻せへん。" moveAccountDescription: "おニューのアカウントに移行すんで。\n ・フォロワーがおニューの方を勝手にフォローすんで。\n ・このアカウントからのフォローはまるまる全部解除されんで。\n ・このアカウントでノート作れへんようになるで。\n\nフォロワーの移行は勝手にこっちでやっとくけど、フォローの移行は自分でしてや。移行前にこのアカウントでフォローエクスポートして、移行したあとすぐにおニューのところでインポートしてくれな。\nリストとかミュート、あとブロックもおんなじや。自分で移行してな。\n\n(この説明はこのサーバー、つまりCherryPick v13.12.0から後の仕様や。Mastodonとか他のActivityPubソフトやとちょっと挙動が違うこともあんで。)" - moveAccountHowTo: "アカウントの引っ越しには、まず引っ越し先のアカウントで自分のアカウントに対しエイリアスを作成しなはれや。\nエイリアス作成した後、引っ越し先のアカウントを次のように入力してくれへんか?:@username@server.example.com" - startMigration: "引っ越しする" + moveAccountHowTo: "アカウントの引っ越しには、まず引っ越し先のアカウントで自分のアカウントに対しエイリアスを作ってな。\nエイリアス作ったら、引っ越し先のアカウントをこんな感じに入れてや: @username@server.example.com" + startMigration: "引っ越す" migrationConfirm: "ほんまにこのアカウントを {account} に引っ越すんか?一回引っ越してもうたら取り消されへんし、二度とこのアカウントを元に戻されへんくなるで。\nそれと、引っ越し先のアカウントでエイリアスが作れたかちゃ~んと確認しーや?" - movedAndCannotBeUndone: "\nアカウントはもう引っ越されてます。\n引っ越しを取り消すことはできまへん。" + movedAndCannotBeUndone: "\nアカウントはもう引っ越し済みや。\nこれはもう戻せへん。" postMigrationNote: "このアカウントからのフォロー解除は移行操作から丸一日経ったら実行されんで。\nこのアカウントのフォロー・フォロワー数はどっちも0や。フォローの解除はされへんから、あんたのフォロワーはこのアカウントのフォロワー向けの投稿をこの後も見れるで。" - movedTo: "引っ越し先のアカウント:" + movedTo: "引っ越し先のアカウント:" _achievements: earnedAt: "貰った日ぃ" _types: @@ -1267,10 +1341,10 @@ _achievements: title: "箕面の滝からノート" description: "ノートを5,000回投稿した" _notes10000: - title: "スーパーノート" + title: "えげつないノート" description: "ノートを10,000回投稿した" _notes20000: - title: "ニードモアノート" + title: "もっとノートよこせ!" description: "ノートを20,000回投稿した" _notes30000: title: "ノートノートノート" @@ -1367,7 +1441,7 @@ _achievements: title: "はじめてのフォロー" description: "初めてフォローした" _following10: - title: "ついてく、ついてく" + title: "すたこらさっさ" description: "フォローが10人超えた" _following50: title: "友達ぎょうさん" @@ -1420,10 +1494,10 @@ _achievements: description: "クライアント付けてから1時間経ってもうたで。" _noteDeletedWithin1min: title: "*おおっと*" - description: "投稿してから1分以内にその投稿を消した" + description: "投稿してから1分以内にその投稿をほかした" _postedAtLateNight: title: "夜行性" - description: "深夜にノートを投稿した" + description: "真夜中にノートを投稿した" flavor: "そろそろ寝よか" _postedAt0min0sec: title: "時報" @@ -1440,7 +1514,7 @@ _achievements: description: "サーバーのチャートを表示した" _outputHelloWorldOnScratchpad: title: "Hello, world!" - description: "スクラッチパッドで hello worldを出力した" + description: "スクラッチパッドで hello world を出力した" _open3windows: title: "マド開けすぎ" description: "ウィンドウを3つ以上開いた状態にした" @@ -1449,7 +1523,7 @@ _achievements: description: "ドライブのフォルダを再帰的な入れ子にしようとした" _reactWithoutRead: title: "ちゃんと読んだんか?" - description: "100文字以上のテキストを含むノートに投稿されてから3秒以内にツッコんだ" + description: "100文字以上のノートに投稿3秒以内にツッコんだ" _clickedClickHere: title: "ここをクリック" description: "ここをクリックした" @@ -1458,7 +1532,10 @@ _achievements: description: "10秒ごとに0.005%の確率で獲得" _setNameToSyuilo: title: "神様コンプレックス" - description: "名前を syuilo に設定した" + description: "名前を syuilo にした" + _setNameToNoriDev: + title: "神様コンプレックス(CherryPick)" + description: "名前を noridev にした" _passedSinceAccountCreated1: title: "一周年" description: "アカウント作成から1年経過した" @@ -1482,10 +1559,13 @@ _achievements: _brainDiver: title: "Brain Diver" description: "Brain Diverへのリンクを投稿したった" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: - title: "テスト過剰" - description: "通知テストをごく短時間のうちに連続して行ったねん" + title: "心配性" + description: "通知のテストしすぎやって" + _tutorialCompleted: + title: "CherryPickひよっこ講座 修了証" + description: "チュートリアル全部やった" _role: new: "ロールの作成" edit: "ロールの編集" @@ -1496,60 +1576,63 @@ _role: assignTarget: "アサイン" descriptionOfAssignTarget: "マニュアルは誰がこのロールに含まれてるかを手動で管理するで。\nコンディショナルは条件を設定して、それに合うユーザーが自動で含まれるようになるで。" manual: "マニュアル" + manualRoles: "マニュアルロール" conditional: "コンディショナル" + conditionalRoles: "コンディショナルロール" condition: "条件" isConditionalRole: "これはコンディショナルロールやで" isPublic: "ロールを公開" - descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができるで。そんで、ユーザーのプロフィールでこのロールが表示されるで。" + descriptionOfIsPublic: "プロフィールでこのロールが出されるで。" options: "オプション" policies: "ポリシー" baseRole: "ベースロール" - useBaseValue: "ベースロールの値を使用" - chooseRoleToAssign: "アサインするロールを選択" + useBaseValue: "ベースロールの値使う" + chooseRoleToAssign: "アサインするロール選ぶ" iconUrl: "アイコン画像のURL" asBadge: "バッジとして見せる" descriptionOfAsBadge: "オンにすると、ユーザー名の横んとこにロールのアイコンが表示されるで。" - isExplorable: "ロールタイムラインを公開するで〜" - descriptionOfIsExplorable: "オンにしたらロールのタイムラインを公開するで〜。でもロールの公開をオフにしたら公開されへんよ。" + isExplorable: "ユーザーを見つけやすくしたる" + descriptionOfIsExplorable: "オンにしたらロールの面子一覧が「みつける」で公開されるし、ロールのタイムラインが使えるようになるで。" displayOrder: "表示順" descriptionOfDisplayOrder: "数がでかいほど、UI上で先に表示されるで。" - canEditMembersByModerator: "モデレーターのメンバー編集を許可" - descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになるで。オフにすると管理者のみが行えるで。" + canEditMembersByModerator: "モデレーターがメンバーいじるのを許す" + descriptionOfCanEditMembersByModerator: "オンにすると、管理者だけやなくてモデレーターもこのロールにユーザーを入れたり抜いたりできるで。オフにすると管理者だけしかやれへんくなるで。" priority: "優先度" _priority: low: "低い" - middle: "中" + middle: "中くらい" high: "高い" _options: - gtlAvailable: "グローバルタイムラインの閲覧" - ltlAvailable: "ローカルタイムラインの閲覧" - canPublicNote: "パブリック投稿の許可" - canInvite: "サーバー招待コードの発行" - inviteLimit: "招待コードの作成可能数" - inviteLimitCycle: "招待コードの発行間隔" - inviteExpirationTime: "招待コードの有効期限" + gtlAvailable: "グローバルタイムライン見る" + ltlAvailable: "ローカルタイムライン見る" + canPublicNote: "パブリック投稿できるか" + canInvite: "サーバー招待コード作る" + inviteLimit: "招待コード作れる数" + inviteLimitCycle: "招待コードの作れる間隔" + inviteExpirationTime: "招待コードの期限" canManageCustomEmojis: "カスタム絵文字の管理" canManageAvatarDecorations: "アバターを飾るモンの管理" driveCapacity: "ドライブ容量" alwaysMarkNsfw: "勝手にファイルにNSFWをくっつける" - pinMax: "ノートのピン留めの最大数" - antennaMax: "アンテナの作成可能数" + pinMax: "ノートピン留めできる数" + antennaMax: "アンテナ作れる数" wordMuteMax: "ワードミュートの最大文字数" - webhookMax: "Webhockの作成可能数" - clipMax: "クリップの作成可能数" - noteEachClipsMax: "クリップ内のノートの最大数" - userListMax: "ユーザーリストの作成可能数" + webhookMax: "Webhook作れる数" + clipMax: "クリップ作れる数" + noteEachClipsMax: "クリップの中にノート作れる数" + userListMax: "ユーザーリスト作れる数" userEachUserListsMax: "ユーザーリスト内のユーザーの最大数" rateLimitFactor: "レートリミット" descriptionOfRateLimitFactor: "ちっちゃいほど制限が緩なって、大きいほど制限されるで。" - canHideAds: "広告を表示させへん" - canSearchNotes: "ノート検索を使わすかどうか" - canUseTranslator: "翻訳機能の利用" + canHideAds: "広告映さへん" + canSearchNotes: "ノート探せるかどうか" + canUseTranslator: "翻訳使えるかどうか" + avatarDecorationLimit: "アイコンデコのいっちばんつけれる数" _condition: isLocal: "ローカルユーザー" isRemote: "リモートユーザー" - createdLessThan: "アカウント作成から~以内" - createdMoreThan: "アカウント作成から~経過" + createdLessThan: "アカウント作ってから~以内" + createdMoreThan: "アカウント作ってから~経過" followersLessThanOrEq: "フォロワー数が~以下" followersMoreThanOrEq: "フォロワー数が~以上" followingLessThanOrEq: "フォロー数が~以下" @@ -1558,45 +1641,45 @@ _role: notesMoreThanOrEq: "投稿を~以上しとる" and: "~かつ~" or: "~または~" - not: "~ではない" + not: "~じゃない" _sensitiveMediaDetection: - description: "機械学習を使って自動でセンシティブなメディアを検出して、モデレーションに役立てることができるで。サーバーの負荷が少し増えてまうなあ。" + description: "機械学習で自動できわどいメディアを検出して、運営しやすくするで。でもサーバーが少し重くなってまうわ。" sensitivity: "検出感度やで" sensitivityDescription: "感度を低くすると、誤検知(偽陽性)が減るで。感度を高くすると、検知漏れ(偽陰性)が減るで。" - setSensitiveFlagAutomatically: "NSFWフラグを設定するで" - setSensitiveFlagAutomaticallyDescription: "この設定をオフにしても内部的に判定結果は保持されるで。" + setSensitiveFlagAutomatically: "センシティブフラグを設定するで" + setSensitiveFlagAutomaticallyDescription: "この設定切っても内部的には判定結果はそのままや。" analyzeVideos: "動画の解析をオンにするで" - analyzeVideosDescription: "画像に加えて動画も解析するようにするで。鯖の負荷が少し増えるで。" + analyzeVideosDescription: "画像だけじゃなくて動画も解析するようにするで。サーバーがちょっと重くなるで。" _emailUnavailable: - used: "もう使われとるで" + used: "もう使われとるわ" format: "形式がおかしいで" - disposable: "永久に使えるアドレスじゃないみたいやで" - mx: "正しいメールサーバーじゃない見たいやで" - smtp: "メールサーバーが応答してないみたいや" + disposable: "ずーっと使えるアドレスじゃないみたいや" + mx: "正しいメールサーバーじゃないっぽいわ" + smtp: "メールサーバーがうんともすんとも言わへん" _ffVisibility: public: "公開" followers: "フォロワーだけに公開" private: "非公開" _signup: - almostThere: "ほぼ完了やで" + almostThere: "ほぼ終わったようなもんや" emailAddressInfo: "あんたが使っとるメアドを入力してなー。入れたメアドが公開されることはないで。" - emailSent: "さっき入れたメールアドレス({email})宛に確認のメールが送られたで。メールに書かれたリンクにアクセスすれば、アカウントの作成が完了や!" + emailSent: "さっき入れたメアド({email})宛に確認メールを送ったで。メールに書かれたリンク押してアカウント作るの終わらしてな。\nメールの認証リンクの期限は30分や。" _accountDelete: accountDelete: "アカウントの削除" - mayTakeTime: "アカウントの削除は負荷がかかる処理やねんて。やから作ったコンテンツの数や上げたファイルの数が多いと削除が終わるまでに時間がかかることがあるんやって。" - sendEmail: "アカウントの削除が終わるときは、登録してたメールアドレス宛に通知を送るで。" - requestAccountDelete: "アカウント削除をリクエスト" + mayTakeTime: "アカウント消すんはサーバーが重いんやって。やから作ったコンテンツとか上げたファイルの数が多いと消し終わるまでに時間がかかるかもしれへん。" + sendEmail: "アカウントの消し終わるときは、登録してたメアドに通知するで。" + requestAccountDelete: "アカウント削除頼む" started: "削除処理が始まったで。" - inProgress: "削除が進んでるで" + inProgress: "今消しよるで" _ad: back: "戻る" - reduceFrequencyOfThisAd: "この広告の表示頻度を下げるで" + reduceFrequencyOfThisAd: "この広告ちょっとうざったらしいわ" hide: "表示せん" - timezoneinfo: "曜日はサーバーのタイムゾーンを元に指定されるで。" + timezoneinfo: "曜日はサーバーのタイムゾーンを元に決めるで。" adsSettings: "広告配信設定" notesPerOneAd: "リアタイ更新中に広告を出す間隔(ノートの個数な)" setZeroToDisable: "0でリアタイ更新時の広告配信を無効にすんで" - adsTooClose: "広告を出す間隔がめっちゃ短いから、ユーザー体験が著しく損なわれる可能性があんで。" + adsTooClose: "広告を出す間隔がめっちゃ短いから、ユーザー体験がめちゃめちゃ悪くなるかもしれへん。" _forgotPassword: enterEmail: "アカウントに登録したメールアドレスをここに入力してや。そのアドレス宛に、パスワードリセット用のリンクが送られるから待っててな~。" ifNoEmail: "メールアドレスを登録してへんのやったら、管理者まで教えてな~。" @@ -1615,7 +1698,7 @@ _plugin: install: "プラグインのインストール" installWarn: "信頼できへんプラグインはインストールせんとってな" manage: "プラグインの管理" - viewSource: "ソースを表示" + viewSource: "ソース見る" _preferencesBackups: list: "作ったバックアップ" saveNew: "新しく保存" @@ -1722,24 +1805,25 @@ _mfm: plainDescription: "内側の構文を全部無効にするで" _instanceTicker: none: "表示せん" - remote: "リモートユーザーに表示" - always: "常に表示" + remote: "リモートユーザーに見せる" + always: "いつでも見せる" _serverDisconnectedBehavior: reload: "自動でリロード" dialog: "ダイアログで警告" quiet: "控えめに警告" _channel: - create: "チャンネルを作る" - edit: "チャンネルを編集" + create: "チャンネル作る" + edit: "チャンネルいじる" setBanner: "バナーを設定" removeBanner: "バナーを削除" featured: "トレンド" - owned: "管理中" + owned: "管理しとる" following: "フォロー中やで" - usersCount: "{n}人が参加中やで" + usersCount: "{n}人が参加しとる" notesCount: "{n}こ投稿があるで" nameAndDescription: "名前と説明" nameOnly: "名前だけ" + allowRenoteToExternal: "チャンネルの外にリノートできるようにする" _menuDisplay: sideFull: "横" sideIcon: "横(アイコン)" @@ -1765,7 +1849,7 @@ _theme: builtinThemes: "標準のテーマ" alreadyInstalled: "そのテーマはもうインストールされとるで?" invalid: "テーマの形式が間違ってるみたいや" - make: "テーマを作る" + make: "テーマ作る" base: "ベース" addConstant: "定数を追加" constant: "定数" @@ -1833,6 +1917,14 @@ _sfx: chatBg: "チャット(バックグラウンド)" antenna: "アンテナ受信" channel: "チャンネル通知" + reaction: "ツッコミ選んどるとき" +_soundSettings: + driveFile: "ドライブん中の音使う" + driveFileWarn: "ドライブん中のファイル選びや" + driveFileTypeWarn: "このファイルは対応しとらへん" + driveFileTypeWarnDescription: "音声ファイルを選びや" + driveFileDurationWarn: "音が長すぎるわ" + driveFileDurationWarnDescription: "長い音使うたらCherryPick使うのに良うないかもしれへんで。それでもええか?" _ago: future: "未来" justNow: "ついさっき" @@ -1844,6 +1936,14 @@ _ago: monthsAgo: "{n}ヶ月前" yearsAgo: "{n}年前" invalid: "あらへん" +_timeIn: + seconds: "{n}秒後" + minutes: "{n}分後" + hours: "{n}時間後" + days: "{n}日後" + weeks: "{n}週間後" + months: "{n}ヶ月後" + years: "{n}年後" _time: second: "秒" minute: "分" @@ -1854,12 +1954,12 @@ _2fa: registerTOTP: "認証アプリの設定はじめる" step1: "ほんなら、{a}や{b}とかの認証アプリを使っとるデバイスにインストールしてな。" step2: "次に、ここにあるQRコードをアプリでスキャンしてな~。" - step2Click: "QRコードをクリックすると、今使とる端末に入っとる認証アプリとかキーリングに登録できるで。" + step2Click: "QRコード押したら、今使とる端末に入っとる認証アプリとかキーリングに登録できるで。" step2Uri: "デスクトップアプリを使う時は次のURIを入れるで" step3Title: "確認コードを入れてーや" - step3: "アプリに表示されているトークンを入力して終わりや。" - setupCompleted: "設定が完了したで。" - step4: "これからログインするときも、同じようにトークンを入力するんやで" + step3: "アプリに映っとる確認コード(トークン)を入れて終わりや。" + setupCompleted: "設定が終わったで。" + step4: "これからログインするときも、同じようにコードを入れるんや。" securityKeyNotSupported: "今使とるブラウザはセキュリティキーに対応してへんのやってさ。" registerTOTPBeforeKey: "セキュリティキー・パスキーを登録するんやったら、まず認証アプリを設定してーな。" securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキーか端末の指紋認証やPINを使ってログインするように設定できるで。" @@ -1970,6 +2070,7 @@ _widgets: _userList: chooseList: "リストを選ぶ" clicker: "クリッカー" + birthdayFollowings: "今日誕生日のツレ" _cw: hide: "隠す" show: "続き見して!" @@ -2032,6 +2133,7 @@ _profile: changeAvatar: "アバター画像を変更するで" changeBanner: "バナー画像を変更するで" verifiedLinkDescription: "内容をURLに設定すると、リンク先のwebサイトに自分のプロフのリンクが含まれてる場合に所有者確認済みアイコンを表示させることができるで。" + avatarDecorationMax: "最大{max}つまでデコつけれんで" _exportOrImport: allNotes: "全てのノート" favoritedNotes: "お気に入りにしたノート" @@ -2147,9 +2249,7 @@ _notification: youGotMention: "{name}からのメンション" youGotReply: "{name}からのリプライ" youGotQuote: "{name}による引用" - youRenoted: "{name}がRenoteしたみたいやで" - youGotMessagingMessageFromUser: "{name}からのチャットがあるで" - youGotMessagingMessageFromGroup: "{name}のチャットがあるで" + youRenoted: "{name}がリノートしたみたいやで" youWereFollowed: "フォローされたで" youReceivedFollowRequest: "フォロー許可してほしいみたいやな" yourFollowRequestAccepted: "フォローさせてもろたで" @@ -2163,6 +2263,9 @@ _notification: checkNotificationBehavior: "通知の表示を確かめるで" sendTestNotification: "テスト通知を送信するで" notificationWillBeDisplayedLikeThis: "通知はこのように表示されるで" + reactedBySomeUsers: "{n}人がツッコんだで" + renotedBySomeUsers: "{n}人がリノートしたで" + followedBySomeUsers: "{n}人にフォローされたで" _types: all: "すべて" note: "あんたらの新規投稿" @@ -2233,8 +2336,8 @@ _webhookSettings: followed: "フォローもらったとき~!" note: "ノートを投稿したとき~!" reply: "返信があるとき~!" - renote: "Renoteされるとき~!" - reaction: "ツッコミがあるとき~!" + renote: "リノートされるとき~!" + reaction: "ツッコまれたとき~!" mention: "メンションがあるとき~!" _moderationLogTypes: createRole: "ロールを追加すんで" @@ -2263,13 +2366,15 @@ _moderationLogTypes: markSensitiveDriveFile: "ファイルをセンシティブ付与" unmarkSensitiveDriveFile: "ファイルをセンシティブ解除" resolveAbuseReport: "苦情を解決" - createInvitation: "招待コードを作成" + createInvitation: "招待コード作る" createAd: "広告を作んで" deleteAd: "広告ほかす" updateAd: "広告を更新" createAvatarDecoration: "アイコンデコレーションを作成" updateAvatarDecoration: "アイコンデコレーションを更新" deleteAvatarDecoration: "アイコンデコレーションを削除" + unsetUserAvatar: "この子のアイコン元に戻す" + unsetUserBanner: "この子のバナー元に戻す" _fileViewer: title: "ファイルの詳しい情報" type: "ファイルの種類" @@ -2302,6 +2407,11 @@ _externalResourceInstaller: description: "" _failedToFetch: title: "" + fetchErrorDescription: "他のサイトに繋がらんかったわ。もっかいやってもダメやったら、サイトの管理してる人に言っといて。" + parseErrorDescription: "他のサイトから持ってきたデータ、よう分からんかったわ。サイトの管理してる人に言っといて。" + _hashUnmatched: + title: "ちゃんとしたデータが持ってこれんかったわ" + description: "もらったデータがなんかおかしいっぽいわ。ちょっと危ないからインストールはできへん。サイト管理してる人に言っといてな。" _pluginParseFailed: title: "AiScriptエラー起こしてもうたねん" description: "データは取得できたものの、AiScript解析時にエラーがあったから読み込めへんかってん。すまんが、プラグインを作った人に問い合わせてくれへん?ごめんな。エラーの詳細はJavaScriptコンソール読んでな。" @@ -2310,7 +2420,20 @@ _externalResourceInstaller: description: "プラグインのインストール中に問題発生してもた、もう1度試してな。エラーの詳細はJavaScriptのコンソール見てや。" _themeParseFailed: title: "テーマ解析エラー" - description: "データは取得できたものの、テーマファイル解析時にエラーがあったから読み込めへんかってん。すまんが、テーマ作った人に問い合わせてくれへん?ごめんな。エラーの詳細はJavaScriptコンソール読んでな。" + description: "データは取れたんやが、テーマファイル読み込んどる時にエラーがあったから読み込めへんかったわ。すまんけど、テーマ作った人に言うてくれへん?ごめんな。エラーの詳細はJavaScriptコンソール読んでな。" _themeInstallFailed: title: "テーマインストールに失敗してもた" - description: "テーマのインストール中に問題発生してもた、もう1度試してな。エラーの詳細はJavaScriptのコンソール見てや。" + description: "なんかテーマインストールできんかったわ。もう一回試してな。細かいのはJavaScriptのコンソール見てや。" +_dataSaver: + _media: + title: "メディアの読み込み" + description: "絵・動画が自動で読まれるのをふせぐわ。隠れてる絵・動画はタップするとひょっこりはんしてくれんで。" + _avatar: + title: "アイコンの絵" + description: "アイコン画像のアニメが止まるで。普通の画像よりもデータ量がでかいから、もっと通信量を節約できるねん。" + _urlPreview: + title: "URLプレビューのサムネイル画像" + description: "URLプレビューのサムネイル画像が読み込まへんなるで。" + _code: + title: "コードハイライト" + description: "MFMとかでコードハイライト記法が使われてるとき、タップするまで読み込まれへんくなるで。コードハイライトではハイライトする言語ごとにその決めてるファイルを読む必要はあんねんな。けどな、それは自動で読み込まれなくなるから、通信量を少なくできることができるねん。" diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml new file mode 100644 index 0000000000..114fe50c05 --- /dev/null +++ b/locales/ko-GS.yml @@ -0,0 +1,723 @@ +--- +_lang_: "한국어(경상)" +headlineMisskey: "노트로 이언 네트워크" +introMisskey: "어서 오이소! CherryPick언 오픈소스 분산헹 마이크로 블로그 서비스입니다.\n‘노트’럴 맨걸어서 지검 일나넌 일얼 노누던가 내 이바구럴 남한데 서 보이소.📡\n‘리액션’ 기넝서 남으 노트에 억수로 빠리게 답할 수 잇십니다.👍\n새롭운 세게럴 탐험해 보입시다.🚀" +poweredByMisskeyDescription: "{name} 서버넌 오픈소스 플랫폼 CherryPick으 서버 가운데 하나입니다." +monthAndDay: "{month}월 {day}일" +search: "찾기" +notifications: "알림" +username: "사용자 이럼" +password: "비밀번호" +forgotPassword: "비밀번호럴 잊엇뿟십니꺼?" +fetchingAsApObject: "연합서 찾아보고 잇어예" +ok: "예" +gotIt: "알것어예" +cancel: "아이예" +noThankYou: "뎃어예" +enterUsername: "사용자 이럼 서기" +renotedBy: "{user}님이 리노트햇어예" +noNotes: "노트가 없십니다" +noNotifications: "알림이 없십니다" +instance: "서버" +settings: "설정" +notificationSettings: "알림 설정" +basicSettings: "기본 설정" +otherSettings: "다린 설정" +openInWindow: "창서 옐기" +profile: "프로필" +timeline: "타임라인" +noAccountDescription: "자기소개가 없십니다" +login: "로그인" +loggingIn: "로그인하고 잇어예" +logout: "로그아웃" +signup: "가입하기" +uploading: "올리고 잇어예" +save: "저장하기" +users: "사용자" +addUser: "사용자 옇기" +favorite: "질겨찾기" +favorites: "질겨찾기" +unfavorite: "질겨찾기서 어ᇝ애기" +favorited: "질겨찾기에 담앗십니다." +alreadyFavorited: "벌시로 질겨찾기에 담기 잇십니다." +cantFavorite: "질겨찾기에 몬 담았십니다." +pin: "프로필에 붙이기" +unpin: "프로필서 띠기" +copyContent: "내용 복사하기" +copyLink: "링크 복사하기" +copyLinkRenote: "리노트 링크 복사" +delete: "내삐리기" +deleteAndEdit: "내삐리고 새로 적기" +deleteAndEditConfirm: "요 노트럴 뭉캐고 새로 적십니꺼? 요 노트서 리액션하고 리노트, 답하기도 말캉 뭉캐집니다." +addToList: "리스트에 옇기" +addToAntenna: "안테나에 옇기" +sendMessage: "메시지 보내기" +copyRSS: "알에스에스 복사하기" +copyUsername: "사용자 이럼 복사하기" +copyUserId: "사용자 아이디 복사하기" +copyNoteId: "노트 아이디 복사하기" +copyFileId: "파일 아이디 복사하기" +copyFolderId: "폴더 아이디 복사하기" +copyProfileUrl: "프로필 주소 복사하기" +searchUser: "사용자 찾기" +reply: "답하기" +loadMore: "더 볼래예" +showMore: "더 볼래예" +showLess: "꺼기" +youGotNewFollower: "새 팔로워가 잇십니다" +receiveFollowRequest: "팔로잉 요청이 잇십니다" +followRequestAccepted: "팔로잉이 받아딜이젓십니다" +mention: "멘션" +mentions: "받언 멘션" +directNotes: "쪽지 서기" +importAndExport: "가오기하고 내가기" +import: "가오기" +export: "내가기" +files: "파일" +download: "내리받기" +driveFileDeleteConfirm: "‘{name}’ 파일얼 뭉캡니꺼? 요 파일얼 서넌 콘텐츠도 뭉캐집니다." +unfollowConfirm: "{name}님얼 고마 팔로잉합니꺼?" +exportRequested: "내가기 요청얼 햇십니다. 시간이 쪼매 걸릴 깁니다. 요청이 껕나모 ‘드라이브’에 옇십니다." +importRequested: "가오기 요청얼 햇십니다. 시간이 쪼매 걸릴 깁니다." +lists: "리스트" +noLists: "리스트가 없십니다" +note: "노트" +notes: "노트" +following: "팔로잉" +followers: "팔로워" +followsYou: "내럴 팔로잉합니다" +createList: "리스트 맨걸기" +manageLists: "리스트 간리하기" +error: "우짭니꺼" +somethingHappened: "먼가 일낫십니다" +retry: "다시 하기" +pageLoadError: "하멘 부리오기가 아이뎁니다." +pageLoadErrorDescription: "네트워크나 브라우저 캐시 때문일 깁니다. 캐시럴 뭉캐던가 쪼매 잇다 새로 해 주이소." +serverIsDead: "서버가 대답얼 아이합니다. 쪼매 잇다 새로 해 주이소." +youShouldUpgradeClient: "요 하멘얼 볼라먼 새로 곤치던가 새 버전으 클라이언트럴 받아 서 보이소." +enterListName: "리스트 이럼 서기" +privacy: "개인 정보" +makeFollowManuallyApprove: "팔로잉얼 하나석 받아딜이기" +defaultNoteVisibility: "기본 공개 범위" +follow: "팔로우" +followRequest: "팔로우 요청하기" +followRequests: "팔로우 요청" +unfollow: "팔로우 무루기" +followRequestPending: "팔로우 수락 지둘림" +enterEmoji: "이모지 서기" +renote: "리노트" +unrenote: "리노트 무루기" +renoted: "리노트럴 햇십니다." +cantRenote: "요 걸언 리노트럴 몬 합니다." +cantReRenote: "리노트넌 지럴 리노트 몬 합니다." +quote: "따오기" +inChannelRenote: "채널 안 리노트" +inChannelQuote: "채널 안 따오기" +pinnedNote: "붙인 노트" +pinned: "프로필에 붙이기" +you: "나" +clickToShow: "누질라서 보기" +sensitive: "수ᇚ힛섭니다" +add: "옇기" +reaction: "반엉" +reactions: "반엉" +reactionSettingDescription2: "꺼시서 두고, 누질라서 뭉캐고, ‘+’럴 누질라서 옇십니다." +rememberNoteVisibility: "공개 범위럴 기억하기" +attachCancel: "붙임 빼기" +markAsSensitive: "수ᇚ힘 설정" +unmarkAsSensitive: "수ᇚ힘 무루기" +enterFileName: "파일 이럼 서기" +mute: "수ᇚ후기" +unmute: "수ᇚ훈 거 무루기" +renoteMute: "리노트 수ᇚ후기" +renoteUnmute: "리노트 수ᇚ훈 거 무루기" +block: "차단하기" +unblock: "차단 무루기" +suspend: "얼우기" +unsuspend: "얼우기 풀기" +blockConfirm: "차단합니꺼?" +unblockConfirm: "차단얼 무룹니꺼?" +suspendConfirm: "얼웁니꺼?" +unsuspendConfirm: "얼운 거 풉니꺼?" +selectList: "리스트 개리기" +editList: "리스트 적기" +selectChannel: "채널 개리기" +selectAntenna: "안테나 개리기" +editAntenna: "안테나 적기" +selectWidget: "위젯 개리기" +editWidgets: "위젯 적기" +editWidgetsExit: "고마 적기" +customEmojis: "사용자 지정 이모지" +emoji: "이모지" +emojis: "이모지" +emojiName: "이모지 이럼" +emojiUrl: "이모지 주소" +addEmoji: "이모지 옇기" +settingGuide: "개않언 설정" +cacheRemoteFiles: "웬겍 파일 캐시하기" +cacheRemoteFilesDescription: "요 설정얼 키모 웬겍 파일얼 요 서버으 스토리지에 캐시합니다. 미디어가 사게 비이지먼 서버으 스토리지럴 마이 섭니다. 웬겍 사용자가 얼매나 캐시럴 둘 긴가넌 고 옉할으 드라이브 크기 제한마중 다립니다. 요 제한얼 넘구모 엣날 파일버터 캐시서 뭉캐지서 링크가 뎁니다. 요 설정얼 꺼모 웬겍 파일언 첨버터 링크가 뎁니다. 이미지으 섬네일얼 맨걸던 사용자으 개인 정보럴 징키던 할라먼 default.yml서 proxyRemoteFiles럴 ture로 하입시다." +youCanCleanRemoteFilesCache: "파일 간리으 🗑️ 모냥얼 누질리모 캐시럴 말캉 뭉캘 수 잇십니다." +cacheRemoteSensitiveFiles: "웬겍으 수ᇚ힌 파일얼 캐시하기" +cacheRemoteSensitiveFilesDescription: "요 설정얼 꺼모 웬겍 수ᇚ힌 파일이 캐시하지 아이하고 바리 링크합니다." +flagAsBot: "자동 게정입니다" +flagAsBotDescription: "요 게정얼 프로그램서 설라먼 키야 합니다. 키모 다런 개발자가 반엉얼 끋없이 데풀이하지 몬 하게 도아 줄 수 잇고 CherryPick으 시스템서 자동 게정이 뎁니다." +flagAsCat: "애웅애웅애웅애웅!" +flagAsCatDescription: "애옹?" +flagShowTimelineReplies: "타임라인서 노트으 답하기 보기" +flagShowTimelineRepliesDescription: "키모 타임라인서 다런 사용자덜으 답하기도 봅니다." +autoAcceptFollowed: "팔로잉하넌 사용자으 팔로잉 요청 바리 받아딜이기" +addAccount: "게정 옇기" +reloadAccountsList: "게정 리스트으 정보 새로 바꾸기" +loginFailed: "로그인이 아이뎁니다." +showOnRemote: "웬겍서 보기" +general: "일반" +wallpaper: "벡지" +setWallpaper: "벡지 설정" +removeWallpaper: "벡지 뭉캐기" +searchWith: "찾기: {q}" +youHaveNoLists: "리스트가 없십니다" +followConfirm: "{name}님얼 팔로잉합니꺼?" +proxyAccount: "프락시 게정" +proxyAccountDescription: "프락시 게정언 턱벨한 조겐서 웬겍 팔로잉얼 하넌 게정입니다. 사용자가 웬겍 사용자럴 리스트에 옇얼 때 리스트에 옇언 사용자럴 누도 팔로잉 아이하모 할동이 서버로 아이 오니께 요 게정이 아인 프락시 게정얼 팔로잉하게 합니다." +host: "호스트 이럼" +selectUser: "사용자 개리기" +recipient: "받넌 사람" +annotation: "주석" +federation: "옌합" +instances: "서버" +registeredAt: "첫 발겐" +latestRequestReceivedAt: "막죽에 받언 요청" +latestStatus: "막죽 상태" +storageUsage: "스토리지 사용량" +charts: "차트" +perHour: "한 시간마중" +perDay: "하리마중" +stopActivityDelivery: "할동 고마 보내기" +blockThisInstance: "요 서버 차단하기" +silenceThisInstance: "서버 수ᇚ후기" +operations: "동작" +software: "소프트웨어" +version: "버전" +metadata: "메타데이터" +withNFiles: "파일 {n}개" +monitor: "모니터" +jobQueue: "작업 대기옐" +cpuAndMemory: "시피유하고 메모리" +network: "네트워크" +disk: "디스크" +instanceInfo: "서버 정보" +statistics: "통게" +clearQueue: "대기옐 비우기" +clearQueueConfirmTitle: "대기옐얼 비웁니꺼?" +clearQueueConfirmText: "대기옐에 잇넌 걸얼 아이 보냅니다. 흐이 요 동작언 할 필요가 없십니다." +clearCachedFiles: "캐시 비우기" +clearCachedFilesConfirm: "캐시한 웬겍 파일얼 말캉 뭉캡니꺼?" +blockedInstances: "차단한 서버" +blockedInstancesDescription: "차단할라넌 서버으 호스트럴 줄 바꿈해서로 비이 줍니다. 차단한 서버넌 요 서버하고 교류 몬 합니다." +silencedInstances: "수ᇚ훈 서버" +silencedInstancesDescription: "수ᇚ훌라넌 서버으 호스트럴 줄 바꿈해서로 비이 줍니다. 수ᇚ훈 서버으 게정언 말캉 ‘수ᇚ후기’가 데서 팔로잉 요청만 데고 팔로워가 아인 로컬 게정서 멘션얼 몬 합니다. 차단한 서버넌 상간 없십니다." +muteAndBlock: "수ᇚ훔하고 차단" +mutedUsers: "수ᇚ훈 사용자" +blockedUsers: "차단한 사용자" +noUsers: "사용자가 없십니다" +editProfile: "프로필 적기" +noteDeleteConfirm: "요 노트럴 뭉캡니꺼?" +pinLimitExceeded: "더 몬 붙입니다" +intro: "CherryPick럴 다 깔앗십니다! 간리자 게정얼 맨걸어 보입시다." +done: "햇어예" +processing: "처리하고 잇어예" +preview: "미리보기" +default: "기본값" +defaultValueIs: "기본값: {value}" +noCustomEmojis: "이모지가 없십니다" +noJobs: "작업이 없십니다" +federating: "옌합하고 잇어예" +blocked: "차단햇어예" +suspended: "고만 보내예" +all: "말캉" +subscribing: "구독하고 잇어예" +publishing: "보내고 잇어예" +notResponding: "답이 없어예" +instanceFollowing: "서버으 팔로잉" +instanceFollowers: "서버으 팔로워" +instanceUsers: "서버으 사용자" +changePassword: "비밀번호 바꾸기" +security: "보안" +retypedNotMatch: "선 거가 안 맞십니다." +currentPassword: "지검 비밀번호" +newPassword: "새 비밀번호" +newPasswordRetype: "새 비밀번호 다시 서기" +attachFile: "파일 붙이기" +more: "더 볼래예!" +featured: "인기" +usernameOrUserId: "사용자 이럼이나 사용자 아이디" +noSuchUser: "사용자럴 몬 찾앗십니다" +lookup: "찾아보기" +announcements: "공지 걸" +imageUrl: "이미지 주소" +remove: "내삐리기" +removed: "뭉캣십니다" +removeAreYouSure: "‘{x}’(얼)럴 뭉캡니꺼?" +deleteAreYouSure: "‘{x}’(얼)럴 뭉캡니꺼?" +resetAreYouSure: "아시로 데돌립니꺼?" +areYouSure: "갠찮십니꺼?" +saved: "저장햇십니다" +messaging: "대화" +upload: "올리기" +keepOriginalUploading: "온본 두기" +keepOriginalUploadingDescription: "이미지럴 올릴 때 온본얼 고대로 둡니다. 꺼모 올릴 때 브라우저서 웹 공개 이미지럴 맨겁니다." +fromDrive: "드라이브서" +fromUrl: "주소서" +uploadFromUrl: "주소 올리기" +uploadFromUrlDescription: "올리기할라넌 파일으 주소" +uploadFromUrlRequested: "올리기럴 요청햇십니다" +uploadFromUrlMayTakeTime: "올리기가 껕날라먼 시간이 쪼매 걸릴 깁니다." +explore: "살펴보기" +messageRead: "이럿어예" +noMoreHistory: "요카마 엣날 기록이 없십니다" +startMessaging: "대화하기" +nUsersRead: "{n}멩이 이럿십니다" +agreeTo: "{0}에 동이하기" +agree: "동이합니다" +agreeBelow: "밑으 내용에 동이합니다" +basicNotesBeforeCreateAccount: "주이할 내용" +termsOfService: "이용 약간" +start: "시작하기" +home: "덜머리" +remoteUserCaution: "웬겍 사용자넌 정보가 학실하지 아이할 수 잇십니다." +activity: "할동" +images: "이미지" +image: "이미지" +birthday: "생일" +yearsOld: "{age}살" +registeredDate: "맨건 날" +location: "장소" +theme: "테마" +themeForLightMode: "볽엄 모드서 설 테마" +themeForDarkMode: "어덥엄 모드서 설 테마" +light: "볽엄" +dark: "어덥엄" +lightThemes: "볽언 테마" +darkThemes: "어덥언 테마" +syncDeviceDarkMode: "디바이스 쪽 어덥엄 모드하고 같구로 마추기" +drive: "드라이브" +fileName: "파일 이럼" +selectFile: "파일 개리기" +selectFiles: "파일 개리기" +selectFolder: "폴더 개리기" +selectFolders: "폴더 개리기" +renameFile: "파일 이럼 바꾸기" +folderName: "폴더 이럼" +createFolder: "폴더 맨걸기" +renameFolder: "폴더 이럼 바꾸기" +deleteFolder: "폴더 뭉캐기" +folder: "폴더" +addFile: "파일 옇기" +emptyDrive: "드라이브가 비잇십니다" +emptyFolder: "폴더가 비잇십니다" +unableToDelete: "몬 뭉캡니다" +inputNewFileName: "새 파일 이럼얼 서 보이소" +inputNewDescription: "새 설멩얼 서 보이소" +inputNewFolderName: "새 폴더 이럼얼 서 보이소" +circularReferenceFolder: "엚길 폴더으 아래 폴더입니다." +hasChildFilesOrFolders: "요 폴더넌 아이 비잇어니께 몬 뭉캡니다." +copyUrl: "주소 복사하기" +rename: "이럼 바꾸기" +avatar: "아바타" +banner: "배너" +displayOfSensitiveMedia: "수ᇚ힌 옝상물 보기" +whenServerDisconnected: "서버하고 옌겔이 껂기모" +disconnectedFromServer: "서버하고 옌겔이 껂깃십니다" +reload: "새로곤침" +doNothing: "무시하기" +reloadConfirm: "새로곤침합니꺼?" +watch: "간심 갖기" +unwatch: "간심 고마 갖기" +accept: "받기" +reject: "아이 받기" +normal: "일반" +instanceName: "서버 이럼" +instanceDescription: "서버 소개" +maintainerName: "간리자 이럼" +maintainerEmail: "간리자 전자우펜" +tosUrl: "이용 약간 주소" +thisYear: "올개" +thisMonth: "요달" +today: "오올" +dayX: "{day}일" +monthX: "{month}월" +yearX: "{year}년" +pages: "바닥" +integration: "옌겔" +connectService: "옌겔하기" +disconnectService: "껂기" +enableLocalTimeline: "로컬 타임라인 키기" +enableGlobalTimeline: "글로벌 타임라인 키기" +disablingTimelinesInfo: "요 타임라인얼 꺼도 간리자하고 중재자넌 고대로 설 수 잇십니다." +registration: "맨걸기" +enableRegistration: "누라도 새로 맨걸 수 잇거로 하기" +invite: "초대하기" +driveCapacityPerLocalAccount: "로컬 사용자 하나마중 드라이브 커기" +driveCapacityPerRemoteAccount: "웬겍 사용자 하나마중 드라이브 커기" +inMb: "메가바이트 단이" +bannerUrl: "배너 이미지 주소" +backgroundImageUrl: "배겡 이미지 주소" +basicInfo: "기본 정보" +pinnedUsers: "붙인 사용자" +pinnedUsersDescription: "‘살펴보기’서 붙일라넌 사용자럴 줄 바꿈해서로 적십니다." +pinnedPages: "붙인 바닥" +pinnedPagesDescription: "서버으 대문서 붙일라넌 바닥으 겡로럴 줄 바꿈해서로 적십니다." +pinnedClipId: "붙일 클립으 아이디" +pinnedNotes: "붙인 노트" +hcaptcha: "에이치캡차" +enableHcaptcha: "에이치캡차 키기" +hcaptchaSiteKey: "사이트키" +hcaptchaSecretKey: "시크릿키" +recaptcha: "리캡차" +enableRecaptcha: "리캡차 키기" +recaptchaSiteKey: "사이트키" +recaptchaSecretKey: "시크릿키" +turnstile: "턴스타일" +enableTurnstile: "턴스타일 키기" +turnstileSiteKey: "사이트키" +turnstileSecretKey: "시크릿키" +avoidMultiCaptchaConfirm: "오만 캡차럴 서모 간섭이 잇얼 깁니다. 다린 캡차를 껍니꺼? ‘아이예’럴 누질리모 오만 캡차럴 키 둘 수도 잇십니다." +antennas: "안테나" +manageAntennas: "안테나 간리" +name: "이럼" +antennaSource: "받얼 소스" +antennaKeywords: "받얼 검색어" +antennaExcludeKeywords: "수ᇚ훌 검색어" +antennaKeywordsDescription: "띠어서기럴 하모 ‘거라고’가 데고 줄 바꿈얼 하모 ‘아이먼’이 뎁니다" +notifyAntenna: "새 노트럴 알리기" +withFileAntenna: "파일이 붙언 노트마" +enableServiceworker: "브라우저서 알림 포시럴 키기" +antennaUsersDescription: "사용자 이럼얼 줄 바꿈해서로 섭니다" +caseSensitive: "대소문자럴 구벨하기" +withReplies: "답하기도 옇기" +connectedTo: "요 게정하고 옌겔데어 잇십니다" +notesAndReplies: "걸하고 답걸" +withFiles: "파일에 붙이기" +silence: "수ᇚ후기" +silenceConfirm: "수ᇚ훕니꺼?" +unsilence: "수ᇚ후기 어ᇝ애기" +unsilenceConfirm: "수ᇚ후기럴 어ᇝ앱니꺼?" +popularUsers: "소문난 사용자" +recentlyUpdatedUsers: "얼마 전에 걸 선 사용자" +recentlyRegisteredUsers: "얼마 전에 맨건 사용자" +recentlyDiscoveredUsers: "얼마 전에 찾언 사용자" +exploreUsersCount: "사용자 {count}멩이 잇십니다." +exploreFediverse: "옌합우주 탐험하기" +popularTags: "소문난 태그" +userList: "리스트" +about: "정보" +aboutMisskey: "CherryPick넌예" +administrator: "간리자" +token: "학인 기호" +2fa: "두 단게 정멩" +setupOf2fa: "두 단게 정멩 설정" +totp: "정멩 앱" +totpDescription: "정멩 앱서 단헤용 비밀번호 서기" +moderator: "중재자" +moderation: "중재" +moderationNote: "중재 노트" +addModerationNote: "중재 노트 옇기" +moderationLogs: "중재 일지" +nUsersMentioned: "{n}멩이 이바구하고 잇어예" +securityKeyAndPasskey: "보안키·패스키" +securityKey: "보안키" +lastUsed: "마지막 쓰임" +lastUsedAt: "마지막 쓰임: {t}" +unregister: "맨걸기 무루기" +passwordLessLogin: "비밀번호 없시 로그인" +passwordLessLoginDescription: "비밀번호 말고 보안키나 패스키 같은 것만 써 가 로그인합니다." +resetPassword: "비밀번호 재설정" +newPasswordIs: "새 비밀번호는 \"{password}\" 입니다" +reduceUiAnimation: "화면 움직임 효과들을 수ᇚ후기" +share: "노누기" +notFound: "몬 찾앗십니다" +notFoundDescription: "고런 주소로 들어가는 하멘은 없십니다." +uploadFolder: "기본 업로드 위치" +markAsReadAllNotifications: "모든 알림 이럿다고 표시" +markAsReadAllUnreadNotes: "모든 글 이럿다고 표시" +markAsReadAllTalkMessages: "모든 대화 이럿다고 표시" +help: "도움말" +inputMessageHere: "여따가 메시지를 입력해주이소" +close: "닫기" +invites: "초대하기" +members: "멤버" +transfer: "양도" +title: "제목" +text: "글" +enable: "키기" +next: "다음" +retype: "다시 서기" +noteOf: "{user}님으 노트" +quoteAttached: "따옴" +quoteQuestion: "따와가 작성하겠십니까?" +noMessagesYet: "아직 대화가 없십니다" +newMessageExists: "새 메시지가 있십니다" +onlyOneFileCanBeAttached: "메시지엔 파일 하나까제밖에 몬 넣십니다" +invitations: "초대하기" +invitationCode: "초대장" +checking: "학인하고 잇십니다" +passwordMatched: "맞십니다" +passwordNotMatched: "안 맞십니다" +signinFailed: "로그인 몬 했십니다. 고 이름이랑 비밀번호 제대로 썼는가 확인해 주이소." +or: "아니면" +language: "언어" +uiLanguage: "UI 표시 언어" +aboutX: "{x}에 대해서" +emojiStyle: "이모지 모양" +native: "기본" +disableDrawer: "드로어 메뉴 쓰지 않기" +showNoteActionsOnlyHover: "마우스 올맀을 때만 노트 액션 버턴 보이기" +noHistory: "기록이 없십니다" +signinHistory: "로그인 기록" +enableAdvancedMfm: "복잡한 MFM 키기" +enableAnimatedMfm: "정신사나운 MFM 키기" +doing: "잠만예" +category: "카테고리" +tags: "태그" +docSource: "요 문서의 원본" +createAccount: "게정 맨걸기" +existingAccount: "원래 게정" +regenerate: "엎고 다시 맨걸기" +fontSize: "글자 크기" +mediaListWithOneImageAppearance: "사진 하나짜리 미디어 목록의 높이" +limitTo: "{x}로 제한" +noFollowRequests: "지둘리는 팔로우 요청이 없십니다" +openImageInNewTab: "새 탭서 사진 열기" +dashboard: "대시보드" +local: "로컬" +remote: "웬겍" +total: "합계" +weekOverWeekChanges: "저번주보다" +dayOverDayChanges: "어제보다" +appearance: "모냥" +clientSettings: "클라이언트 설정" +accountSettings: "게정 설정" +promotion: "선전" +promote: "선전하기" +numberOfDays: "며칠동안" +hideThisNote: "요 노트를 수ᇚ후기" +showFeaturedNotesInTimeline: "타임라인에다 추천 노트 보이기" +objectStorage: "오브젝트 스토리지" +useObjectStorage: "오브젝트 스토리지 키기" +objectStorageBaseUrl: "Base URL" +objectStorageBaseUrlDesc: "오브젝트 (미디어) 참조 링크 만들 때 쓰는 URL임다. CDN 내지 프락시를 쓴다 카멘은 그 URL을 갖다 늫고, 아이면 써먹을 서비스네 가이드를 봐봐가 공개적으로 접근할 수 있는 주소를 여 넣어 주이소. 그니께, 내가 AWS S3을 쓴다 카면은 'https://.s3.amazonaws.com', GCS를 쓴다 카면 'https://storage.googleapis.com/' 처럼 쓰믄 되입니더." +objectStorageBucket: "Bucket" +objectStorageBucketDesc: "써먹을 서비스의 바께쓰 이름을 여 써 주이소." +objectStoragePrefix: "Prefix" +objectStoragePrefixDesc: "요 Prefix 디렉토리 안에다가 파일이 들어감다." +objectStorageEndpoint: "Endpoint" +objectStorageEndpointDesc: "AWS S3을 쓸라멘 요는 비워두고, 아이멘은 그 서비스 가이드에 맞게 endpoint를 넣어 주이소. '' 내지 ':'처럼 넣십니다." +objectStorageRegion: "Region" +objectStorageRegionDesc: "'xx-east-1' 같은 region 이름을 옇어 주이소. 써먹을 서비스에 region 개념 같은 게 읎다! 카면은 대신에 'us-east-1'을 옇어 놓으이소. AWS 설정 파일이나 환경 변수를 갖다 끌어다 쓸 거면은 요는 비워 두이소." +objectStorageUseSSL: "SSL 쓰기" +objectStorageUseSSLDesc: "API 호출할 때 HTTPS 안 쓸거면은 꺼 두이소" +objectStorageUseProxy: "연결에 프락시 사용" +objectStorageUseProxyDesc: "오브젝트 스토리지 API 호출에 프락시 안 쓸 거면 꺼 두이소" +objectStorageSetPublicRead: "업로드할 때 'public-read' 설정하기" +s3ForcePathStyleDesc: "s3ForcePathStyle을 키면, 바께쓰 이름을 URL의 호스트명 말고 경로의 일부로써 취급합니다. 셀프 호스트 Minio 같은 걸 굴릴라믄 켜놔야 될 수도 있십니다." +serverLogs: "서버 로그" +deleteAll: "말캉 뭉캐기" +showFixedPostForm: "타임라인 우에 글 작성 칸 박기" +showFixedPostFormInChannel: "채널 타임라인 우에 글 작성 칸 박기" +withRepliesByDefaultForNewlyFollowed: "팔로우 할 때 기본적으로 답걸도 타임라인에 나오게 하기" +newNoteRecived: "새 노트 있어예" +sounds: "소리" +sound: "소리" +listen: "듣기" +none: "없음" +showInPage: "바닥서 보기" +popout: "새 창 열기" +volume: "음량" +masterVolume: "대빵 음량" +notUseSound: "음소거하기" +useSoundOnlyWhenActive: "CherryPick가 활성화되어 있을 때만 소리 내기" +details: "좀 더" +chooseEmoji: "이모지 선택" +unableToProcess: "작업 다 몬 했십니다" +recentUsed: "최근 쓴 놈" +install: "설치" +uninstall: "삭제" +installedApps: "설치된 애플리케이션" +nothing: "뭣도 없어예" +installedDate: "설치한 날" +lastUsedDate: "마지막 사용" +state: "상태" +sort: "정렬하기" +ascendingOrder: "작은 순" +descendingOrder: "큰 순" +scratchpad: "스크래치 패드" +scratchpadDescription: "스크래치 패드는 AiScript를 끼적거리는 창입니더. CherryPick랑 갖다 이리저리 상호작용하는 코드를 서가 굴리멘은 그 결과도 바로 확인할 수 있십니다." +output: "출력" +script: "스크립트" +disablePagesScript: "온갖 바닥서 AiScript를 쓰지 않음" +updateRemoteUser: "원겍 사용자 근황 알아오기" +unsetUserAvatar: "아바타 치우기" +unsetUserAvatarConfirm: "아바타 갖다 치울까예?" +unsetUserBanner: "배너 치우기" +unsetUserBannerConfirm: "배너 갖다 치울까예?" +deleteAllFiles: "파일 말캉 뭉캐기" +deleteAllFilesConfirm: "파일을 싸그리 다 뭉캐삐릴까예?" +removeAllFollowing: "팔로잉 말캉 무루기" +removeAllFollowingDescription: "{host} 서버랑 걸어놓은 모든 팔로잉을 무룹니다. 고 서버가 아예 없어지삐맀든가, 그런 경우에 하이소." +userSuspended: "요 게정은... 얼어 있십니다." +userSilenced: "요 게정은... 수ᇚ혀 있십니다." +relays: "릴레이" +addRelay: "릴레이 옇기" +addedRelays: "옇은 릴레이" +enableInfiniteScroll: "알아서 더 보기" +author: "맨던 사람" +manage: "간리" +emailServer: "전자우펜 서버" +email: "전자우펜" +emailAddress: "전자우펜 주소" +smtpHost: "호스트 이럼" +smtpPort: "포트" +smtpUser: "사용자 이럼" +smtpPass: "비밀번호" +display: "보기" +create: "맨걸기" +abuseReports: "신고하기" +reportAbuse: "신고하기" +reportAbuseRenote: "리노트 신고하기" +reportAbuseOf: "{name}님얼 신고하기" +reporter: "신고한 사람" +reporteeOrigin: "신고덴 사람" +reporterOrigin: "신고한 곳" +forwardReport: "웬겍 서버에 신고 보내기" +random: "무작이" +system: "시스템" +clip: "클립 맨걸기" +createNew: "새로 맨걸기" +notesCount: "노트 수" +renotesCount: "리노트한 수" +renotedCount: "리노트덴 수" +followingCount: "팔로우 수" +followersCount: "팔로워 수" +clips: "클립 맨걸기" +clearCache: "캐시 비우기" +unlikeConfirm: "좋네예럴 무룹니꺼?" +info: "정보" +user: "사용자" +administration: "간리" +on: "킴" +off: "껌" +clickToFinishEmailVerification: "[{ok}]럴 누질라서 전자우펜 정멩얼 껕내이소." +searchByGoogle: "찾기" +tenMinutes: "십 분" +oneHour: "한 시간" +oneDay: "하리" +oneWeek: "한 주" +oneMonth: "한 달" +file: "파일" +tools: "도구" +like: "좋네예!" +unlike: "좋네예 무루기" +numberOfLikes: "좋네예 수" +show: "보기" +roles: "옉할" +role: "옉할" +noRole: "옉할이 없십니다" +thisPostMayBeAnnoyingCancel: "아이예" +likeOnly: "좋네예마" +icon: "아바타" +replies: "답하기" +renotes: "리노트" +_initialAccountSetting: + startTutorial: "길라잡이 하기" +_initialTutorial: + launchTutorial: "길라잡이 보기" + title: "길라잡이" + skipAreYouSure: "길라잡이럴 껕냅니까?" + _landing: + title: "길라잡이에 어서 오이소" + _done: + title: "길라잡이가 껕낫십니다!🎉" +_achievements: + _types: + _tutorialCompleted: + description: "길라잡이럴 껕냇십니다" +_gallery: + liked: "좋네예한 걸" + like: "좋네예!" + unlike: "좋네예 무루기" +_email: + _follow: + title: "새 팔로워가 잇십니다" +_serverDisconnectedBehavior: + reload: "알아서 새로곤침" +_channel: + removeBanner: "배너 뭉캐기" +_theme: + keys: + mention: "멘션" +_sfx: + note: "새 노트" + notification: "알림" +_2fa: + step3Title: "학인 기호럴 서기" + renewTOTPCancel: "뎃어예" +_widgets: + profile: "프로필" + instanceInfo: "서버 정보" + notifications: "알림" + timeline: "타임라인" + activity: "할동" + federation: "옌합" + jobQueue: "작업 대기옐" + _userList: + chooseList: "리스트 개리기" +_cw: + show: "더 볼래예" +_visibility: + home: "덜머리" + followers: "팔로워" +_profile: + name: "이럼" + username: "사용자 이럼" +_exportOrImport: + followingList: "팔로잉" + muteList: "수ᇚ후기" + blockingList: "차단하기" + userLists: "리스트" +_charts: + federation: "옌합" +_timelines: + home: "덜머리" +_play: + script: "스크립트" +_pages: + like: "좋네예" + unlike: "좋네예 무루기" + blocks: + image: "이미지" + _note: + id: "노트 아이디" +_notification: + youWereFollowed: "새 팔로워가 잇십니다" + _types: + follow: "팔로잉" + mention: "멘션" + quote: "따오기" + reaction: "반엉" + _actions: + reply: "답하기" +_deck: + _columns: + notifications: "알림" + tl: "타임라인" + antenna: "안테나" + list: "리스트" + mentions: "받언 멘션" +_webhookSettings: + name: "이럼" +_moderationLogTypes: + suspend: "얼우기" + deleteNote: "노트 뭉캐기" + deleteUserAnnouncement: "사용자 공지 걸 뭉캐기" + resetPassword: "비밀번호 재설정" + resolveAbuseReport: "신고 해겔하기" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index da5901d640..a4faf8b383 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1,10 +1,16 @@ --- _lang_: "한국어" +cherrypickLabs: "CherryPick 실험실" +cherrypickLabsDescription: "개발 중인 기능을 사용해 보시겠어요? 아직 개발 중인 기능이므로 제대로 작동하지 않을 수 있어요." +copiedLink: "링크를 복사했어요!" +copiedContent: "내용을 복사했어요!" +copied: "복사했어요!" +welcome: "환영합니다!" +cherrypickMigrated: "CherryPick으로 마이그레이션이 완료되었어요!" +cherrypickMigratedCacheClearTitle: "캐시 삭제 안내" +cherrypickMigratedCacheClear: "이 서버는 Misskey 또는 CherryPick v4.3.0 이전 버전에서 마이그레이션 되었어요.\n버전 관리 방식이 다르기 때문에 남아있는 캐시가 문제를 일으킬 수 있으므로, 마이그레이션 이후 첫 접속 시 캐시를 삭제하는 작업을 진행해야 해요.\n\n이 작업은 처음 한 번만 진행돼요." +showRenoteVisibilitySelector: "리노트 공개 범위 옵션 표시" cannotBeUsedFunc: "이 기능은 현재 사용할 수 없어요." -maxinumLayerError: "레이어는 6장 이상 겹칠 수 없어요. 다른 레이어를 삭제해 주세요." -layer: "레이어" -Xcoordinate: "X 좌표" -Ycoordinate: "Y 좌표" scale: "크기" opacity: "불투명도" noteUpdatedAt: "편집됨: {date} {time}" @@ -68,11 +74,11 @@ cherrypickUpdatedCacheClear: "테마 및 색상, 로케일 등의 변경 사항 cherrypickUpdatedCacheClearLater: "나중에 캐시를 지우려면 설정 - 캐시 지우기에서 할 수 있어요!" headlineMisskey: "노트로 연결되는 네트워크" introMisskey: "어서오세요! CherryPick은 오픈 소스 분산형 마이크로 블로그 서비스에요.\n'노트'를 작성해서 지금 일어나고 있는 일을 공유하거나, 나만의 이야기를 모두에게 발신할 수 있어요.📡\n'리액션' 기능으로 친구의 노트에 총알같이 반응을 추가할 수도 있답니다!👍\n새로운 세계를 탐험해 보세요!🚀" -poweredByMisskeyDescription: "{name}은(는) 오픈소스 플랫폼 CherryPick을 사용한 서버 중 하나예요." +poweredByMisskeyDescription: "{name}은(는) 오픈소스 플랫폼 CherryPick의 서버 중 하나예요." monthAndDay: "{month}월 {day}일" search: "검색" notifications: "알림" -username: "유저명" +username: "사용자 이름" password: "비밀번호" forgotPassword: "비밀번호를 잊었어요!" fetchingAsApObject: "연합에서 조회 중" @@ -80,7 +86,7 @@ ok: "확인" gotIt: "알겠어요" cancel: "취소" noThankYou: "나중에" -enterUsername: "유저명 입력" +enterUsername: "사용자 이름 입력" renotedBy: "{user}님이 리노트 했어요" noNotes: "노트가 없어요" noNotifications: "표시할 알림이 없어요" @@ -101,8 +107,8 @@ logoutAllConfirm: "이 기기에 추가한 계정을 전부 로그아웃 할까 signup: "회원 가입" uploading: "업로드하고 있어요!" save: "저장" -users: "유저" -addUser: "유저 추가" +users: "사용자" +addUser: "사용자 추가" favorite: "즐겨찾기" favorites: "즐겨찾기" unfavorite: "즐겨찾기에서 제거" @@ -123,8 +129,8 @@ addToList: "리스트에 추가" addToAntenna: "안테나에 추가" sendMessage: "메시지 보내기" copyRSS: "RSS 복사" -copyUsername: "유저명 복사" -copyUserId: "유저 ID 복사" +copyUsername: "사용자 이름 복사" +copyUserId: "사용자 ID 복사" copyNoteId: "노트 ID 복사" copyFileId: "파일 ID 복사" copyFolderId: "폴더 ID 복사" @@ -145,7 +151,7 @@ import: "가져오기" export: "내보내기" files: "파일" download: "다운로드" -driveFileDeleteConfirm: "파일 \"{name}\" 을 삭제할까요? 노트는 삭제되지 않지만, 이 파일을 사용한 일부 콘텐츠가 삭제될 수 있어요." +driveFileDeleteConfirm: "'{name}' 파일을 삭제할까요? 노트는 삭제되지 않지만, 이 파일을 사용한 일부 콘텐츠가 삭제될 수 있어요." unfollowConfirm: "{name}님을 언팔로우 할까요?" exportRequested: "내보내기를 요청했어요! 이 작업은 약간의 시간이 필요할 수 있어요. 내보내기가 완료되면 \"드라이브\"에 추가돼요." importRequested: "가져오기를 요청했어요! 이 작업에는 약간의 시간이 필요할 수 있어요." @@ -194,7 +200,12 @@ sensitive: "열람 주의" add: "추가" reaction: "리액션" reactions: "리액션" -reactionSetting: "선택기에 표시할 리액션" +emojiPicker: "이모지 선택기" +pinnedEmojisForReactionSettingDescription: "리액션을 할 때 프로필에 고정해서 표시할 이모지를 설정할 수 있어요" +pinnedEmojisSettingDescription: "이모지를 입력할 때 프로필에 고정해서 표시할 이모지를 설정할 수 있어요" +emojiPickerDisplay: "선택기 표시" +overwriteFromPinnedEmojisForReaction: "리액션 설정 덮어쓰기" +overwriteFromPinnedEmojis: "일반 설정 덮어쓰기" reactionSettingDescription2: "끌어서 순서 변경, 클릭해서 삭제, +를 눌러서 추가할 수 있어요." rememberNoteVisibility: "공개 범위 기억하기" attachCancel: "첨부 취소" @@ -203,7 +214,7 @@ unmarkAsSensitive: "열람 주의 해제" enterFileName: "파일명 입력" mute: "뮤트" unmute: "뮤트 해제" -renoteMute: "리노트 뮤트" +renoteMute: "리노트 뮤트하기" renoteUnmute: "리노트 뮤트 해제" block: "차단" unblock: "차단 해제" @@ -229,7 +240,7 @@ emojiUrl: "이모지 URL" addEmoji: "이모지 추가" settingGuide: "추천 설정" cacheRemoteFiles: "리모트 파일을 캐시" -cacheRemoteFilesDescription: "이 설정을 활성화하면 리모트 파일을 이 서버의 저장소에 캐시해요. 그에 따라 미디어가 표시되는 속도가 증가하지만, 서버의 저장 공간을 많이 사용할 수도 있어요. 리모트 유저의 미디어를 얼마나 보관할 지는 '역할'의 '드라이브 용량 제한'에 따라 결정되며, 정해진 용량을 초과할 경우, 오래된 파일부터 차례대로 삭제하고 링크로 전환돼요. \n비활성화하면 리모트 파일을 직접 링크하며, 이미지 썸네일 생성 및 유저 프라이버시 보호를 위해 default.yml에서 proxyRemoteFiles를 true로 설정하는 것을 권장해요." +cacheRemoteFilesDescription: "이 설정을 활성화하면 리모트 파일을 이 서버의 저장소에 캐시해요. 그에 따라 미디어가 표시되는 속도가 증가하지만, 서버의 저장 공간을 많이 사용할 수도 있어요. 리모트 사용자의 미디어를 얼마나 보관할 지는 '역할'의 '드라이브 용량 제한'에 따라 결정되며, 정해진 용량을 초과할 경우, 오래된 파일부터 차례대로 삭제하고 링크로 전환돼요. \n비활성화하면 리모트 파일을 직접 링크하며, 이미지 썸네일 생성 및 사용자 프라이버시 보호를 위해 default.yml에서 proxyRemoteFiles를 true로 설정하는 것을 권장해요." youCanCleanRemoteFilesCache: "파일 관리 화면의 🗑️ 버튼을 눌러 모든 캐시를 삭제할 수 있어요." cacheRemoteSensitiveFiles: "리모트의 민감한 파일을 캐시" cacheRemoteSensitiveFilesDescription: "이 설정을 비활성화하면 리모트의 민감한 파일은 캐시하지 않고 리모트에서 직접 가져오도록 설정해요." @@ -238,8 +249,8 @@ flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우 flagAsCat: "나는 고양이다냥" flagAsCatDescription: "이 계정이 고양이라면 활성화해 달라냥" flagShowTimelineReplies: "타임라인에 노트의 답글을 표시하기" -flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 유저 간의 답글을 표시해요." -autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락" +flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 사용자 간의 답글을 표시해요." +autoAcceptFollowed: "팔로우 중인 사용자로부터의 팔로우 요청을 자동 수락" addAccount: "계정 추가" reloadAccountsList: "계정 리스트 정보 갱신" loginFailed: "로그인에 실패했어요.." @@ -252,9 +263,9 @@ searchWith: "검색: {q}" youHaveNoLists: "리스트가 없어요" followConfirm: "{name}님을 팔로우 하시겠어요?" proxyAccount: "프록시 계정" -proxyAccountDescription: "프록시 계정은 유저의 리모트 팔로우를 대행하는 계정이에요. 예를 들면, 리모트 유저를 리스트에 넣었을 때, 리스트에 들어간 유저를 아무도 팔로우한 적이 없다면 액티비티가 서버로 배달되지 않기 때문에 대신 프록시 계정이 해당 유저를 팔로우해서 문제를 해결해요." +proxyAccountDescription: "프록시 계정은 사용자의 리모트 팔로우를 대행하는 계정이에요. 예를 들면, 리모트 사용자를 리스트에 넣었을 때, 리스트에 들어간 사용자를 아무도 팔로우한 적이 없다면 액티비티가 서버로 배달되지 않기 때문에 대신 프록시 계정이 해당 사용자를 팔로우해서 문제를 해결해요." host: "호스트" -selectUser: "유저 선택" +selectUser: "사용자 선택" recipient: "수신인" annotation: "내용에 대한 주석" federation: "연합" @@ -289,10 +300,10 @@ clearCachedFilesConfirm: "캐시된 리모트 파일을 모두 삭제할까요?" blockedInstances: "차단된 서버" blockedInstancesDescription: "차단하려는 서버의 호스트 이름을 줄바꿈으로 구분하여 설정해요. 차단된 인스턴스는 이 인스턴스와 통신할 수 없게 돼요." silencedInstances: "사일런스한 서버" -silencedInstancesDescription: "사일런스하려는 서버의 호스트명을 한 줄에 하나씩 입력해 주세요. 사일런스된 서버에 소속된 유저는 모두 '사일런스'된 상태로 취급되며, 이 서버로부터의 팔로우가 프로필 설정과 무관하게 승인제로 변경되고, 팔로워가 아닌 로컬 유저에게는 멘션할 수 없게 돼요. 정지된 서버에는 적용되지 않아요." +silencedInstancesDescription: "사일런스하려는 서버의 호스트명을 한 줄에 하나씩 입력해 주세요. 사일런스된 서버에 소속된 사용자는 모두 '사일런스'된 상태로 취급되며, 이 서버로부터의 팔로우가 프로필 설정과 무관하게 승인제로 변경되고, 팔로워가 아닌 로컬 사용자에게는 멘션할 수 없게 돼요. 정지된 서버에는 적용되지 않아요." muteAndBlock: "뮤트 및 차단" -mutedUsers: "뮤트한 유저" -blockedUsers: "차단한 유저" +mutedUsers: "뮤트한 사용자" +blockedUsers: "차단한 사용자" noUsers: "아무도 없어요" editProfile: "프로필 수정" noteDeleteConfirm: "이 노트를 삭제할까요?" @@ -314,17 +325,17 @@ publishing: "배포 중" notResponding: "응답 없음" instanceFollowing: "서버의 팔로잉" instanceFollowers: "서버의 팔로워" -instanceUsers: "서버의 유저" +instanceUsers: "서버의 사용자" changePassword: "비밀번호 변경" security: "보안" retypedNotMatch: "비밀번호가 일치하지 않아요." currentPassword: "현재 비밀번호" newPassword: "새 비밀번호" -newPasswordRetype: "새 비밀번호 (재입력)" +newPasswordRetype: "새 비밀번호(재입력)" attachFile: "파일 첨부" more: "더 보기!" featured: "하이라이트" -usernameOrUserId: "유저명이나 ID" +usernameOrUserId: "사용자 이름이나 ID" noSuchUser: "연합우주 어디에서도 찾을 수 없었어요.." lookup: "조회" announcements: "공지사항" @@ -334,6 +345,7 @@ removed: "삭제했어요!" removeAreYouSure: "\"{x}\" 을(를) 삭제할까요?" deleteAreYouSure: "\"{x}\" 을(를) 삭제할까요?" resetAreYouSure: "정말 초기화를 진행할까요?" +areYouSure: "계속 진행할까요?" saved: "저장됨!" messaging: "대화" upload: "업로드" @@ -358,7 +370,7 @@ basicNotesBeforeCreateAccount: "기본적인 주의사항" termsOfService: "이용 약관" start: "시작하기" home: "홈" -remoteUserCaution: "리모트 유저에요! 인스턴스와 정보가 일치하지 않을 수 있어요." +remoteUserCaution: "리모트 사용자에요! 인스턴스와 정보가 일치하지 않을 수 있어요." activity: "활동" images: "이미지" image: "이미지" @@ -381,7 +393,7 @@ selectFiles: "파일 선택" selectFolder: "폴더 선택" selectFolders: "폴더 선택" renameFile: "파일 이름 변경" -folderName: "폴더명" +folderName: "폴더 이름" createFolder: "폴더 만들기" renameFolder: "폴더 이름 바꾸기" deleteFolder: "폴더 삭제" @@ -405,8 +417,8 @@ disconnectedFromServer: "접속이 끊어졌어요!" reload: "새로고침" doNothing: "무시하기" reloadConfirm: "페이지를 다시 불러올까요?" -watch: "지켜보기" -unwatch: "지켜보기 해제" +watch: "구독" +unwatch: "구독 해제" accept: "허가" reject: "거부" normal: "일반" @@ -416,7 +428,7 @@ maintainerName: "관리자 이름" maintainerEmail: "관리자 이메일" tosUrl: "이용약관 URL" thisYear: "올해" -thisMonth: "이번 달" +thisMonth: "이달" today: "오늘" dayX: "{day}일" monthX: "{month}월" @@ -431,14 +443,14 @@ disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리 registration: "등록" enableRegistration: "신규 회원가입 활성화" invite: "초대" -driveCapacityPerLocalAccount: "로컬 유저 한 명당 드라이브 용량" -driveCapacityPerRemoteAccount: "리모트 유저 한 명당 드라이브 용량" +driveCapacityPerLocalAccount: "로컬 사용자 한 명당 드라이브 용량" +driveCapacityPerRemoteAccount: "리모트 사용자 한 명당 드라이브 용량" inMb: "메가바이트 단위" bannerUrl: "배너 이미지 URL" backgroundImageUrl: "배경 이미지 URL" basicInfo: "기본 정보" -pinnedUsers: "고정된 유저" -pinnedUsersDescription: "\"발견하기\" 페이지 등에 고정하고 싶은 유저를 한 줄에 한 명씩 적어주세요." +pinnedUsers: "고정된 사용자" +pinnedUsersDescription: "\"발견하기\" 페이지 등에 고정하고 싶은 사용자를 한 줄에 한 명씩 적어주세요." pinnedPages: "고정한 페이지" pinnedPagesDescription: "서버의 대문에 고정하고 싶은 페이지의 경로를 한 줄에 하나씩 적어주세요." pinnedClipId: "고정할 클립의 ID" @@ -466,7 +478,7 @@ antennaKeywordsDescription: "공백으로 구분하는 경우 AND, 줄바꿈으 notifyAntenna: "새로운 노트를 알림" withFileAntenna: "파일이 첨부된 노트만" enableServiceworker: "ServiceWorker 사용" -antennaUsersDescription: "유저명을 한 줄에 한 명씩 적어주세요" +antennaUsersDescription: "사용자 이름을 한 줄에 한 명씩 적어주세요" caseSensitive: "대소문자를 구분" withReplies: "답글 포함" connectedTo: "이 계정에 연결되어 있어요" @@ -476,11 +488,11 @@ silence: "사일런스" silenceConfirm: "이 계정을 사일런스로 설정할까요?" unsilence: "사일런스 해제" unsilenceConfirm: "이 계정의 사일런스를 해제할까요?" -popularUsers: "인기 유저" -recentlyUpdatedUsers: "최근 활동한 유저" -recentlyRegisteredUsers: "최근 가입한 유저" -recentlyDiscoveredUsers: "최근 발견한 유저" -exploreUsersCount: "{count}명의 유저가 있어요" +popularUsers: "인기 사용자" +recentlyUpdatedUsers: "최근 활동한 사용자" +recentlyRegisteredUsers: "최근 가입한 사용자" +recentlyDiscoveredUsers: "최근 발견한 사용자" +exploreUsersCount: "{count}명의 사용자가 있어요" exploreFediverse: "연합우주 탐색" popularTags: "인기 태그" userList: "리스트" @@ -527,7 +539,7 @@ invites: "초대" groupName: "그룹명" members: "멤버" transfer: "양도" -messagingWithUser: "유저와 대화하기" +messagingWithUser: "사용자와 대화하기" messagingWithGroup: "그룹끼리 대화하기" title: "제목" text: "텍스트" @@ -556,7 +568,7 @@ strongPassword: "강한 비밀번호" passwordMatched: "똑같아요!" passwordNotMatched: "어라? 비밀번호가 다른 것 같아요" signinWith: "{x}로 로그인" -signinFailed: "로그인할 수 없었어요. 사용자명과 비밀번호를 다시 확인해 주세요." +signinFailed: "로그인할 수 없었어요. 사용자 이름과 비밀번호를 다시 확인해 주세요." or: "혹은" language: "언어" uiLanguage: "UI 표시 언어" @@ -637,6 +649,8 @@ showInPage: "페이지로 보기" popout: "새 창으로 열기" volume: "음량" masterVolume: "마스터 볼륨" +notUseSound: "사운드 출력 비활성화" +useSoundOnlyWhenActive: "CherryPick이 활성화된 경우에만 사운드 출력" details: "자세히" chooseEmoji: "이모지 선택" unableToProcess: "작업을 완료할 수 없었어요.." @@ -656,7 +670,11 @@ scratchpadDescription: "스크래치 패드는 AiScript 의 테스트 환경을 output: "출력" script: "스크립트" disablePagesScript: "Pages 에서 AiScript 를 사용하지 않음" -updateRemoteUser: "리모트 유저 정보 갱신" +updateRemoteUser: "리모트 사용자 정보 갱신" +unsetUserAvatar: "아바타 제거" +unsetUserAvatarConfirm: "아바타를 제거할까요?" +unsetUserBanner: "배너 제거" +unsetUserBannerConfirm: "배너를 제거할까요?" deleteAllFiles: "모든 파일 삭제" deleteAllFilesConfirm: "모든 파일을 삭제할까요?" removeAllFollowing: "모든 팔로잉 해제" @@ -721,13 +739,14 @@ emailAddress: "메일 주소" smtpConfig: "SMTP 서버 설정" smtpHost: "호스트" smtpPort: "포트" -smtpUser: "유저명" +smtpUser: "사용자 이름" smtpPass: "비밀번호" emptyToDisableSmtpAuth: "SMTP 인증을 사용하지 않으려면 공란으로 비워주세요." smtpSecure: "SMTP 연결에 Implicit SSL/TTS 사용" smtpSecureInfo: "STARTTLS 사용 시에는 해제해야 해요." testEmail: "이메일 전송 테스트" wordMute: "단어 뮤트" +hardWordMute: "단어 뮤트(하드)" regexpError: "정규 표현식 오류" regexpErrorDescription: "{tab}단어 뮤트 {line}행의 정규 표현식에 오류가 발생했어요:" instanceMute: "서버 뮤트" @@ -755,7 +774,7 @@ behavior: "동작" sample: "예시" abuseReports: "신고" reportAbuse: "신고" -reportAbuseRenote: "이 리노트 신고" +reportAbuseRenote: "이 리노트 신고하기" reportAbuseOf: "{name} 님을 신고하기" fillAbuseReportDescription: "신고하려는 이유를 자세히 알려주세요. 특정 게시물을 신고할 때에는 게시물의 URL도 포함해 주세요." abuseReported: "신고를 보냈어요! 신고해 주셔서 감사합니다." @@ -772,7 +791,7 @@ defaultNavigationBehaviour: "기본 탐색 동작" editTheseSettingsMayBreakAccount: "이 설정을 변경하면 계정이 손상될 수 있으니 주의해 주세요!" instanceTicker: "노트의 서버 정보" waitingFor: "{x}을(를) 기다리고 있어요" -random: "랜덤" +random: "무작위" system: "시스템" switchUi: "UI 전환" desktop: "데스크탑" @@ -837,7 +856,7 @@ needReloadToApply: "변경 사항은 페이지를 다시 불러오면 적용돼 showTitlebar: "타이틀 바를 표시하기" clearCache: "캐시 비우기" onlineUsersCount: "{n}명이 접속 중" -nUsers: "{n} 유저" +nUsers: "{n} 사용자" nNotes: "{n} 노트" sendErrorReports: "오류 보고서 보내기" sendErrorReportsDescription: "이 설정을 활성화하면, 문제가 발생했을 때 오류에 대한 상세 정보를 CherryPick에 보내 더 나은 소프트웨어를 만드는 데에 도움을 줄 수 있어요." @@ -883,7 +902,7 @@ addDescription: "설명 추가" userPagePinTip: "각 노트의 메뉴에서 「프로필에 고정」을 선택하는 것으로, 여기에 노트를 표시해 둘 수 있어요." notSpecifiedMentionWarning: "수신자가 선택되지 않은 멘션이 있어요" info: "정보" -userInfo: "유저 정보" +userInfo: "사용자 정보" unknown: "알 수 없음" onlineStatus: "온라인 상태" hideOnlineStatus: "온라인 상태 숨기기" @@ -899,7 +918,7 @@ switchAccount: "계정 바꾸기" enabled: "활성화" disabled: "비활성화" quickAction: "빠른 동작" -user: "유저" +user: "사용자" administration: "관리" accounts: "계정" switch: "전환" @@ -940,7 +959,7 @@ whatIsNew: "패치 정보 보기" translate: "번역" translatedFrom: "{x}에서 번역" accountDeletionInProgress: "계정 삭제 작업을 진행하는 중이에요" -usernameInfo: "서버에서 계정을 식별하기 위한 이름이에요. 알파벳(a~z, A~Z), 숫자(0~9) 및 언더바(_)를 사용할 수 있어요. 사용자명은 한번 만들면 나중에 변경할 수 없으니 신중하게 입력해 주세요." +usernameInfo: "서버에서 계정을 식별하기 위한 이름이에요. 알파벳(a~z, A~Z), 숫자(0~9) 및 언더바(_)를 사용할 수 있어요. 사용자 이름은 한번 만들면 나중에 변경할 수 없으니 신중하게 입력해 주세요." aiChanMode: "아이 모드" devMode: "개발자 모드" keepCw: "CW 유지하기" @@ -959,13 +978,13 @@ unread: "읽지 않음" filter: "필터" controlPanel: "제어판" manageAccounts: "계정 관리" -makeReactionsPublic: "리액션 목록을 공개하기" +makeReactionsPublic: "리액션 목록 공개하기" makeReactionsPublicDescription: "나의 리액션을 누구나 볼 수 있게 설정해요." classic: "클래식" -muteThread: "이 글타래를 뮤트" +muteThread: "이 글타래 뮤트" unmuteThread: "글타래 뮤트 해제" -ffVisibility: "내 인맥의 공개 범위" -ffVisibilityDescription: "나의 팔로우와 팔로워 정보에 대한 공개 범위를 설정할 수 있어요." +followingVisibility: "팔로우의 공개 범위" +followersVisibility: "팔로워의 공개 범위" continueThread: "이 글타래 이어서 보기" deleteAccountConfirm: "계정이 삭제되고 되돌릴 수 없게 돼요. 그래도 계속할까요? " incorrectPassword: "비밀번호가 다른 것 같아요!" @@ -1009,7 +1028,7 @@ noEmailServerWarning: "메일 서버를 아직 설정하지 않았어요." thereIsUnresolvedAbuseReportWarning: "해결되지 않은 신고가 있어요." recommended: "추천" check: "체크" -driveCapOverrideLabel: "이 유저의 드라이브 용량을 변경" +driveCapOverrideLabel: "이 사용자의 드라이브 용량을 변경" driveCapOverrideCaption: "0 이하를 지정하면 해제돼요." requireAdminForView: "열람하려면 관리자 계정으로 로그인 해야해요." isSystemAccount: "시스템에 의해 자동으로 생성되어 관리되는 계정이에요." @@ -1040,7 +1059,7 @@ cannotUploadBecauseExceedsFileSizeLimit: "파일 크기가 너무 크기 때문 beta: "베타" enableAutoSensitive: "자동으로 민감한 미디어 탐지" enableAutoSensitiveDescription: "사용 가능한 경우, 기계학습을 통해 자동으로 미디어에 NSFW를 설정할 거예요. 이 기능을 해제하더라도, 서버 정책에 따라 자동으로 설정될 수 있어요." -activeEmailValidationDescription: "유저가 입력한 메일 주소가 일회용 메일인지, 실제로 통신할 수 있는 지 엄격하게 검사해요. 해제하면 이메일 형식에 대해서만 검사해요." +activeEmailValidationDescription: "사용자가 입력한 메일 주소가 일회용 메일인지, 실제로 통신할 수 있는 지 엄격하게 검사해요. 해제하면 이메일 형식에 대해서만 검사해요." navbar: "내비게이션 바" shuffle: "셔플" account: "계정" @@ -1067,7 +1086,7 @@ show: "표시" neverShow: "다시 보지 않기" remindMeLater: "나중에 알림" didYouLikeMisskey: "CherryPick이 마음에 드시나요?" -pleaseDonate: "{host}은(는) 무료 소프트웨어 CherryPick을 사용하고 있어요. 후원을 통해 저희의 개발이 이어질 수 있게 도와주세요!" +pleaseDonate: "CherryPick은 {host}에서 사용하는 무료 소프트웨어에요. 후원을 통해 앞으로도 개발을 계속할 수 있게 도와주세요!" roles: "역할" role: "역할" noRole: "역할이 없어요" @@ -1077,7 +1096,7 @@ assign: "할당" unassign: "할당 취소" color: "색" manageCustomEmojis: "커스텀 이모지 관리" -manageAvatarDecorations: "아이콘 장식 관리" +manageAvatarDecorations: "아바타 장식 관리" youCannotCreateAnymore: "더 이상 생성할 수 없어요." cannotPerformTemporary: "일시적으로 사용할 수 없음" cannotPerformTemporaryDescription: "조작 횟수 제한을 초과하여 일시적으로 사용할 수 없어요. 잠시 후 다시 시도해 주세요." @@ -1090,7 +1109,7 @@ selectFromPresets: "프리셋에서 선택" achievements: "도전 과제" gotInvalidResponseError: "서버의 응답이 올바르지 않아요.." gotInvalidResponseErrorDescription: "서버가 다운되었거나 점검 중일 가능성이 있어요. 잠시 후에 다시 접속해 주세요." -thisPostMayBeAnnoying: "이 게시물은 다른 유저에게 피해를 줄 가능성이 있어요!" +thisPostMayBeAnnoying: "이 게시물은 다른 사용자에게 피해를 줄 가능성이 있어요!" thisPostMayBeAnnoyingHome: "홈에 게시" thisPostMayBeAnnoyingCancel: "그만두기" thisPostMayBeAnnoyingIgnore: "이대로 게시" @@ -1113,12 +1132,14 @@ reactionAcceptance: "리액션 수신" likeOnly: "좋아요만 받기" likeOnlyForRemote: "리모트에서는 좋아요만 받기" nonSensitiveOnly: "민감한 이모지를 제외하고 받기" -nonSensitiveOnlyForLocalLikeOnlyForRemote: "민감한 이모지를 제외하고 받기 (리모트에서는 좋아요만 받기)" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "민감한 이모지를 제외하고 받기(리모트에서는 좋아요만 받기)" rolesAssignedToMe: "나에게 할당된 역할" resetPasswordConfirm: "비밀번호를 재설정할까요?" sensitiveWords: "민감한 단어" sensitiveWordsDescription: "설정한 단어가 포함된 노트의 공개 범위를 '홈'으로 강제해요. 개행으로 구분하여 여러 개를 지정할 수 있어요." sensitiveWordsDescription2: "공백으로 구분하면 AND로 지정되고, 키워드를 슬래시로 둘러싸면 정규 표현식이 돼요." +hiddenTags: "숨긴 해시태그" +hiddenTagsDescription: "설정한 태그가 트렌드에 표시되지 않아요. 줄 바꿈으로 하나씩 나눠서 설정할 수 있어요." notesSearchNotAvailable: "노트 검색을 이용할 수 없어요." license: "라이선스" unfavoriteConfirm: "즐겨찾기를 해제할까요?" @@ -1127,10 +1148,11 @@ drivecleaner: "드라이브 정리" retryAllQueuesNow: "모든 큐를 다시 시도" retryAllQueuesConfirmTitle: "지금 다시 시도할까요?" retryAllQueuesConfirmText: "일시적으로 서버의 부하가 증가할 수 있어요!" -enableChartsForRemoteUser: "리모트 유저의 차트를 생성" -enableChartsForFederatedInstances: "리모트 서버의 차트를 생성" -showClipButtonInNoteFooter: "노트 동작에 클립을 추가" +enableChartsForRemoteUser: "리모트 사용자 차트 생성" +enableChartsForFederatedInstances: "리모트 서버 차트 생성" +showClipButtonInNoteFooter: "노트 동작에 클립 버튼 추가" reactionsDisplaySize: "리액션 표시 크기" +limitWidthOfReaction: "리액션의 최대 폭을 제한하고 작게 표시" noteIdOrUrl: "노트 ID 및 URL" video: "동영상" videos: "동영상" @@ -1160,8 +1182,8 @@ serverRules: "서버 규칙" pleaseConfirmBelowBeforeSignup: "이 서버에 가입하기 전에 아래 사항을 확인해 주세요." pleaseAgreeAllToContinue: "계속하시려면 모든 항목에 동의해야 해요." continue: "계속" -preservedUsernames: "예약된 사용자명" -preservedUsernamesDescription: "예약할 사용자명을 한 줄에 하나씩 입력해 주세요. 여기에서 지정한 사용자명으로는 계정을 생성할 수 없게 돼요. 단, 관리자 권한으로 계정을 생성할 때에는 해당되지 않으며, 이미 존재하는 계정도 영향을 받지 않아요." +preservedUsernames: "예약된 사용자 이름" +preservedUsernamesDescription: "예약할 사용자 이름을 한 줄에 하나씩 입력해 주세요. 여기에서 지정한 사용자 이름으로는 계정을 생성할 수 없게 돼요. 단, 관리자 권한으로 계정을 생성할 때에는 해당되지 않으며, 이미 존재하는 계정도 영향을 받지 않아요." createNoteFromTheFile: "이 파일로 노트 작성" archive: "아카이브" channelArchiveConfirmTitle: "{name} 을(를) 아카이브할까요?" @@ -1187,7 +1209,7 @@ additionalEmojiDictionary: "이모지 추가 사전" installed: "설치됨" branding: "브랜딩" enableServerMachineStats: "서버의 머신 사양을 공개하기" -enableIdenticonGeneration: "유저마다 Identicon 생성 유효화" +enableIdenticonGeneration: "사용자마다 Identicon 생성 유효화" turnOffToImprovePerformance: "이 기능을 끄면 성능이 향상될 수 있어요." createInviteCode: "초대 코드 생성" createWithOptions: "옵션을 지정하여 생성" @@ -1214,7 +1236,7 @@ emailToReceiveAbuseReport: "신고 알림을 받을 수 있는 이메일 주소" emailToReceiveAbuseReportCaption: "신고 알림을 받을 이메일 주소를 지정해 주세요. 이곳의 입력란을 비워두면 메일 서버의 이메일 주소가 사용돼요." dialog: "다이얼로그" icon: "아이콘" -forYou: "당신에게" +forYou: "나에게" currentAnnouncements: "현재 공지사항" pastAnnouncements: "과거 공지사항" youHaveUnreadAnnouncements: "읽지 않은 공지사항이 있어요." @@ -1249,12 +1271,13 @@ impressumDescription: "독일 등의 일부 나라와 지역에서는 꼭 표시 privacyPolicy: "개인정보 보호 정책" privacyPolicyUrl: "개인정보 보호 정책 URL" tosAndPrivacyPolicy: "약관 및 개인정보 보호 정책" -avatarDecorations: "아이콘 장식" +avatarDecorations: "아바타 장식" attach: "붙이기" -detach: "떼기" +detach: "제거" +detachAll: "모두 제거" angle: "각도" flip: "플립" -showAvatarDecorations: "아이콘 장식 표시" +showAvatarDecorations: "아바타 장식 표시" releaseToRefresh: "놓아서 새로 고침" refreshing: "새로 고침 중" pullDownToRefresh: "당겨서 새로 고침" @@ -1264,7 +1287,13 @@ signupPendingError: "메일 주소 확인중에 문제가 발생했어요. 링 cwNotationRequired: "'내용 숨기기'를 체크했을 경우 주석을 작성해야 해요." doReaction: "리액션 추가" code: "코드" -tryReloadIfNotApplied: "설정을 반영하려면 페이지를 다시 불러와야 해요." +reloadRequiredToApplySettings: "설정을 반영하려면 페이지를 다시 불러와야 해요." +remainingN: "남음: {n}" +overwriteContentConfirm: "현재 내용을 덮어쓰기 하게 돼요. 그래도 계속 진행할까요?" +seasonalScreenEffect: "계절에 따른 화면 연출" +decorate: "장식하기" +addMfmFunction: "장식 추가" +enableQuickAddMfmFunction: "고급 MFM 선택기 표시하기" showUnreadNotificationsCount: "읽지 않은 알림 수 표시" showCatOnly: "고양이만 보기" additionalPermissionsForFlash: "Play에 대한 추가 권한" @@ -1288,15 +1317,15 @@ _showingAnimatedImages: _messaging: direct: "다이렉트 메시지" _announcement: - forExistingUsers: "기존 유저에게만 알리기" - forExistingUsersDescription: "활성화하면 이 공지사항을 게시한 시점에서 이미 가입한 유저에게만 표시해요. 비활성화하면 게시 후에 가입한 유저에게도 표시해요." + forExistingUsers: "기존 사용자에게만 알리기" + forExistingUsersDescription: "활성화하면 이 공지사항을 게시한 시점에서 이미 가입한 사용자에게만 표시해요. 비활성화하면 게시 후에 가입한 사용자에게도 표시해요." needConfirmationToRead: "읽음으로 표시하기 전에 확인하기" needConfirmationToReadDescription: "활성화하면 이 공지사항을 읽음으로 표시하기 전에 확인 알림창을 표시해요. '모두 읽음'의 대상에서도 제외돼요." end: "공지 내리기" tooManyActiveAnnouncementDescription: "공지사항이 너무 많으면 사용자 경험에 영향을 끼칠 가능성이 있어요. 오래된 공지사항은 아카이브하는 것을 권장해요." readConfirmTitle: "읽음으로 표시할까요?" readConfirmText: "\"{title}\"을(를) 읽음으로 표시해요." - shouldNotBeUsedToPresentPermanentInfo: "신규 유저의 사용자 경험에 악영향을 끼칠 수 있으므로, 일시적인 알림 수단으로만 사용하고 고정된 정보에는 사용을 지양하는 것을 추천해요." + shouldNotBeUsedToPresentPermanentInfo: "신규 사용자의 사용자 경험에 악영향을 끼칠 수 있으므로, 일시적인 알림 수단으로만 사용하고 고정된 정보에는 사용을 지양하는 것을 추천해요." dialogAnnouncementUxWarn: "다이얼로그 형태의 알림이 동시에 2개 이상 존재하는 경우, 사용자 경험에 악영향을 끼칠 수 있으므로 신중히 결정하는 것을 권장드려요." silence: "조용히 알림" silenceDescription: "활성화하면 공지사항에 대한 알림이 가지 않게 되며, 확인 버튼을 누르지 않아도 공지사항이 읽음으로 표시돼요." @@ -1308,7 +1337,7 @@ _cherrypick: function: "고유 기능" functionDescription: "CherryPick이 추가하는 고유 기능을 활성화/비활성화할 수 있어요." nickname: "닉네임 기능" - nicknameDescription: "유저 페이지에서 이름을 클릭 또는 탭하여 원하는 이름으로 변경할 수 있어요. 변경한 이름은 자신에게만 반영돼요.\n자주 이름을 바꾸는 사용자를 식별하는 데 사용할 수 있어요." + nicknameDescription: "사용자 페이지에서 이름을 클릭 또는 탭하여 원하는 이름으로 변경할 수 있어요. 변경한 이름은 자신에게만 반영돼요.\n자주 이름을 바꾸는 사용자를 식별하는 데 사용할 수 있어요." useEnterToSend: "Enter 키를 눌러 보내기" useEnterToSendDescription: "옵션을 활성화하면 줄 바꿈은 Shift + Enter 키로 할 수 있어요. 대화를 전송할 때는 옵션의 영향을 받지 않아요." postFormVisibilityHotkey: "단축키로 공개 범위 전환하기" @@ -1333,7 +1362,8 @@ _cherrypick: renameTheButtonInPostFormToNya: "노트 작성 화면의 '노트' 버튼을 '냥!'으로 변경" renameTheButtonInPostFormToNyaDescription: "냐앙냥냥냥냐냥?" enableLongPressOpenAccountMenu: "길게 눌러 계정 메뉴 열기" - friendlyShowAvatarDecorationsInNavBtn: "플로팅 버튼에 아이콘 장식 표시" + enableLongPressOpenAccountMenuDescription: "화면 아래쪽의 타임라인 탭을 길게 눌러 열 수 있어요." + friendlyShowAvatarDecorationsInNavBtn: "플로팅 버튼에 아바타 장식 표시" _bannerDisplay: all: "전부" topBottom: "상단 및 하단" @@ -1355,7 +1385,7 @@ _initialAccountSetting: mfmAndAnimatedImagesSetting: "MFM 및 움직이는 이미지 설정" theseSettingsCanEditLater: "이 설정들은 나중에도 변경할 수 있어요." youCanEditMoreSettingsInSettingsPageLater: "이 외에도 '설정' 페이지에서 다양한 설정을 나의 입맛에 맞게 조절할 수 있으니 꼭 확인해 보세요!" - followUsers: "관심사가 맞는 유저를 팔로우하여 타임라인을 가꾸어 보세요." + followUsers: "관심사가 맞는 사람을 팔로우하여 타임라인을 가꾸어 보세요." pushNotificationDescription: "푸시 알림을 활성화하면 {name}의 알림을 나의 기기에서 받아볼 수 있어요." initialAccountSettingCompleted: "초기 설정을 모두 완료했어요!" haveFun: "{name}와 함께 즐거운 시간 보내세요!" @@ -1390,9 +1420,9 @@ _initialTutorial: reactDone: "'-' 버튼을 눌러서 리액션을 취소할 수 있어요." _timeline: title: "타임라인에 대하여" - description1: "CherryPick에는 종류에 따라 여러 가지의 타임라인으로 구성되어 있어요. (서버에 따라서는 일부 타임라인을 사용할 수 없는 경우도 있어요)" + description1: "CherryPick에는 종류에 따라 여러 가지의 타임라인으로 구성되어 있어요.(서버에 따라서는 일부 타임라인을 사용할 수 없는 경우도 있어요)" home: "내가 팔로우 중인 계정의 노트를 볼 수 있어요." - local: "이 서버에 있는 모든 유저의 게시물을 볼 수 있어요." + local: "이 서버에 있는 모든 사용자의 게시물을 볼 수 있어요." social: "홈 타임라인과 로컬 타임라인의 게시물을 모두 볼 수 있어요." global: "연결되어 있는 모든 서버의 게시물을 볼 수 있어요." description2: "각각의 타임라인은 화면 상단에서 언제든지 변경할 수 있어요." @@ -1402,13 +1432,13 @@ _initialTutorial: description1: "CherryPick에 노트를 쓸 때에는 다양한 옵션을 설정할 수 있어요. 노트를 작성하는 화면은 이렇게 생겼답니다." _visibility: description: "노트를 볼 수 있는 사람을 제한할 수 있어요." - public: "모든 유저에게 노트를 공개해요." - home: "홈 타임라인에서만 노트를 공개해요. 팔로워, 프로필 화면, 리노트를 통해서 다른 유저가 노트의 내용을 볼 수 있어요." + public: "모든 사용자에게 노트를 공개해요." + home: "홈 타임라인에서만 노트를 공개해요. 팔로워, 프로필 화면, 리노트를 통해서 다른 사용자가 노트의 내용을 볼 수 있어요." followers: "팔로워에게만 노트를 공개해요. 자기 자신을 제외하고는 리노트를 할 수 없고, 팔로워 외에는 노트의 내용을 볼 수 없어요." - direct: "지정한 유저에게만 노트가 공개되며, 노트에 지정된 상대방에게 알림이 보내져요." + direct: "지정한 사용자에게만 노트가 공개되며, 노트에 지정된 상대방에게 알림이 보내져요." doNotSendConfidencialOnDirect1: "민감한 정보를 보낼 때에는 주의해 주세요." - doNotSendConfidencialOnDirect2: "서버 관리자는 기술적으로 노트의 내용을 열람할 수 있기 때문에, 신뢰할 수 없는 서버의 유저에게 다이렉트 메시지를 보내는 경우, 노트를 보내기 전에 민감한 정보가 포함되어 있는지 먼저 확인해 주세요." - localOnly: "다른 서버에 노트를 보내지 않아요. 앞서 설정한 공개 범위와 상관 없이 다른 서버의 유저는 이 노트를 볼 수 없어요." + doNotSendConfidencialOnDirect2: "서버 관리자는 기술적으로 노트의 내용을 열람할 수 있기 때문에, 신뢰할 수 없는 서버의 사용자에게 다이렉트 메시지를 보내는 경우, 노트를 보내기 전에 민감한 정보가 포함되어 있는지 먼저 확인해 주세요." + localOnly: "다른 서버에 노트를 보내지 않아요. 앞서 설정한 공개 범위와 상관 없이 다른 서버의 사용자는 이 노트를 볼 수 없어요." _cw: title: "내용 가리기 (CW)" description: "본문 대신에 '내용에 대한 주석'에 입력한 텍스트가 먼저 표시돼요. '더 보기' 버튼을 누르면 숨겨진 본문이 표시돼요." @@ -1430,7 +1460,7 @@ _initialTutorial: description: "여기에서 소개한 기능은 최소한의 사용을 위한 가장 기본적인 기능만을 다뤘어요. CherryPick의 사용 방법을 더 자세히 알아보려면 {link}를 확인해 주세요!" _timelineDescription: home: "홈 타임라인에서는, 내가 팔로우한 계정의 게시물을 볼 수 있어요." - local: "로컬 타임라인에서는, 이 서버의 모든 유저의 게시물을 볼 수 있어요." + local: "로컬 타임라인에서는, 이 서버의 모든 사용자의 게시물을 볼 수 있어요." social: "소셜 타임라인에서는, 홈 타임라인과 로컬 타임라인의 게시물을 모두 볼 수 있어요." global: "글로벌 타임라인에서는, 여기와 연결된 다른 모든 서버의 게시물을 볼 수 있어요." _serverRules: @@ -1471,6 +1501,8 @@ _serverSettings: shortName: "약칭" shortNameDescription: "서버의 정식 명칭이 긴 경우, 대신 표시할 수 있는 약칭이나 통칭." fanoutTimelineDescription: "활성화하면 각종 타임라인을 가져올 때의 성능을 대폭 향상하며, 데이터베이스의 부하를 줄일 수 있어요. 단, Redis의 메모리 사용량이 증가하게 되고, 서버의 메모리 용량이 작거나, 서비스가 불안정해지는 경우 해당 설정을 비활성화해 주세요." + fanoutTimelineDbFallback: "데이터베이스 폴백" + fanoutTimelineDbFallbackDescription: "활성화하면 타임라인의 캐시되어 있지 않은 부분에 대해서는 DB에 추가로 쿼리하는 폴백 처리를 수행해요. 비활성화하면 폴백 처리를 하지 않아 서버의 부하를 줄일 수 있지만, 타임라인을 가져올 수 있는 범위가 한정돼요." _accountMigration: moveFrom: "다른 계정에서 이 계정으로 이사" moveFromSub: "다른 계정에 대한 별칭을 생성" @@ -1490,9 +1522,9 @@ _achievements: earnedAt: "달성 일시" _types: _notes1: - title: "체리픽 시작했는데요" + title: "체리픽 계정을 만들었어요" description: "첫 노트를 작성했어요!" - flavor: "CherryPick에 오신 것을 환영합니다!" + flavor: "CherryPick에 어서 오세요!" _notes10: title: "노트 조금" description: "10개의 노트를 작성했어요" @@ -1503,16 +1535,16 @@ _achievements: title: "노트로 뒤덮여버렸어" description: "500개의 노트를 작성했어요" _notes1000: - title: "노트만 산더미" + title: "노트가 산더미" description: "1,000개의 노트를 작성했어요" _notes5000: - title: "노트가 어디서 솟아?" + title: "솟아나는 노트" description: "5,000개의 노트를 작성했어요" _notes10000: title: "슈퍼 노트" description: "10,000개의 노트를 작성했어요" _notes20000: - title: "노트 더 없어?" + title: "더 많은 노트가 필요해" description: "20,000개의 노트를 작성했어요" _notes30000: title: "노트노트노트" @@ -1540,26 +1572,26 @@ _achievements: description: "100,000개의 노트를 작성했어요" flavor: "이만큼 쓸 일도 없겠지만... 다른 할 일이 있진 않으신가요?" _login3: - title: "비기너 I" + title: "초보자 I" description: "총 3일간 로그인했어요" - flavor: "오늘부터 여러분도 미스키스트에요!" + flavor: "오늘부터 여러분도 체리피키스트에요!" _login7: - title: "비기너 II" + title: "초보자 II" description: "총 7일간 로그인했어요" flavor: "슬슬 익숙해지셨나요?" _login15: - title: "비기너 III" + title: "초보자 III" description: "총 15일간 로그인했어요" _login30: - title: "미스키스트 I" + title: "체리피키스트 I" description: "총 30일간 로그인했어요" _login60: - title: "미스키스트 II" + title: "체리피키스트 II" description: "총 60일간 로그인했어요" _login100: - title: "미스키스트 III" + title: "체리피키스트 III" description: "총 100일간 로그인했어요" - flavor: "그 유저, 미스키스트이다" + flavor: "그 사람, 체리피키스트이다" _login200: title: "단골 I" description: "총 200일간 로그인했어요" @@ -1701,6 +1733,9 @@ _achievements: _setNameToSyuilo: title: "신 콤플렉스" description: "이름을 syuilo로 설정했어요. 어라..?" + _setNameToNoriDev: + title: "신 콤플렉스 (CherryPick)" + description: "이름을 noridev로 설정했어요. 어라..?" _passedSinceAccountCreated1: title: "1주년" description: "계정을 생성하고 1년이 지났어요" @@ -1724,7 +1759,7 @@ _achievements: _brainDiver: title: "Brain Diver" description: "Brain Diver로의 링크를 첨부했어요" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "테스트 과잉" description: "매우 짧은 시간 안에 알림 테스트를 여러 번 수행했어요" @@ -1741,7 +1776,9 @@ _role: assignTarget: "할당 대상" descriptionOfAssignTarget: "수동을 선택하면 누가 이 역할에 포함되는지를 수동으로 관리할 수 있어요.\n조건부를 선택하면 조건을 설정해 일치하는 사용자를 자동으로 포함시킬 수 있어요." manual: "수동" + manualRoles: "수동 역할" conditional: "조건부" + conditionalRoles: "조건부 역할" condition: "조건" isConditionalRole: "조건부 역할이에요." isPublic: "역할 공개" @@ -1753,7 +1790,7 @@ _role: chooseRoleToAssign: "할당할 역할 선택" iconUrl: "아이콘 URL" asBadge: "배지로 표시" - descriptionOfAsBadge: "활성화하면 유저명 옆에 역할의 아이콘이 표시돼요." + descriptionOfAsBadge: "활성화하면 사용자 이름 옆에 역할의 아이콘이 표시돼요." isExplorable: "역할 타임라인 공개" descriptionOfIsExplorable: "활성화하면 역할 타임라인을 공개해요. 비활성화하면 타임라인이 공개되지 않아요." displayOrder: "표시 순서" @@ -1775,7 +1812,7 @@ _role: inviteLimitCycle: "초대 발급 간격" inviteExpirationTime: "초대 만료 기간" canManageCustomEmojis: "커스텀 이모지 관리" - canManageAvatarDecorations: "아이콘 장식 관리" + canManageAvatarDecorations: "아바타 장식 관리" driveCapacity: "드라이브 용량" alwaysMarkNsfw: "파일을 항상 NSFW로 지정" pinMax: "고정할 수 있는 노트 수" @@ -1784,24 +1821,25 @@ _role: webhookMax: "생성할 수 있는 웹훅 수" clipMax: "생성할 수 있는 클립 수" noteEachClipsMax: "각 클립에 추가할 수 있는 노트 수" - userListMax: "생성할 수 있는 유저 리스트 수" - userEachUserListsMax: "유저 리스트당 최대 사용자 수" + userListMax: "생성할 수 있는 사용자 리스트 수" + userEachUserListsMax: "사용자 리스트당 최대 사용자 수" rateLimitFactor: "요청 빈도 제한" descriptionOfRateLimitFactor: "작을수록 제한이 완화되고, 클수록 제한이 강화돼요." canHideAds: "광고 숨기기" canSearchNotes: "노트 검색 이용 가능 여부" canUseTranslator: "번역 기능 이용 가능 여부" + avatarDecorationLimit: "최대로 붙일 수 있는 아바타 장식 개수" _condition: isLocal: "로컬 사용자" isRemote: "리모트 사용자" - createdLessThan: "가입한 지 다음 일수 이내인 유저" - createdMoreThan: "가입한 지 다음 일수 이상인 유저" - followersLessThanOrEq: "팔로워 수가 다음 이하인 유저" - followersMoreThanOrEq: "팔로워 수가 다음 이상인 유저" - followingLessThanOrEq: "팔로잉 수가 다음 이하인 유저" - followingMoreThanOrEq: "팔로잉 수가 다음 이상인 유저" - notesLessThanOrEq: "노트 수가 다음 이하인 유저" - notesMoreThanOrEq: "노트 수가 다음 이상인 유저" + createdLessThan: "가입한 지 다음 일수 이내인 사용자" + createdMoreThan: "가입한 지 다음 일수 이상인 사용자" + followersLessThanOrEq: "팔로워 수가 다음 이하인 사용자" + followersMoreThanOrEq: "팔로워 수가 다음 이상인 사용자" + followingLessThanOrEq: "팔로잉 수가 다음 이하인 사용자" + followingMoreThanOrEq: "팔로잉 수가 다음 이상인 사용자" + notesLessThanOrEq: "노트 수가 다음 이하인 사용자" + notesMoreThanOrEq: "노트 수가 다음 이상인 사용자" and: "다음을 모두 만족" or: "다음을 하나라도 만족" not: "다음을 만족하지 않음" @@ -1823,13 +1861,14 @@ _emailUnavailable: disposable: "임시 이메일 주소는 사용할 수 없어요" mx: "메일 서버가 올바르지 않아요" smtp: "메일 서버가 응답하지 않아요. 잠시 후에 다시 시도하거나, 관리자에게 문의해 주세요." + banned: "이 메일 주소는 사용할 수 없어요" _ffVisibility: public: "공개" followers: "팔로워에게만 공개" private: "비공개" _signup: almostThere: "거의 다 끝났어요!" - emailAddressInfo: "사용할 메일 주소를 입력해 주세요. 이메일 주소는 다른 유저에게 공개되지 않아요." + emailAddressInfo: "사용할 메일 주소를 입력해 주세요. 이메일 주소는 다른 사용자에게 공개되지 않아요." emailSent: "입력한 메일 주소({email})로 확인 메일을 보내드렸어요! 가입을 완료하려면 보내드린 메일에 있는 링크로 접속해 주세요.\n만약 메일이 오지 않는다면 스팸 메일함을 확인해 주세요!" _accountDelete: accountDelete: "계정 삭제" @@ -1891,7 +1930,7 @@ _registry: domain: "도메인" createKey: "키 생성" _aboutMisskey: - about: "CherryPick은 Misskey를 기반으로 2021년부터 개발되어 오고 있는 커스터마이즈 클라이언트에요." + about: "CherryPick은 Misskey를 기반으로 2021년부터 개발되어 오고 있는 커스터마이즈 오픈소스 소프트웨어에요." contributors: "주요 기여자" allContributors: "모든 기여자" source: "소스 코드" @@ -1904,7 +1943,6 @@ _aboutMisskey: serverStatus: "서버 상태" donate: "코코넥트에 기부하기" _cherrypick: - about: "이 Misskey는 NoriDev에 의해 커스텀 되었어요!" translation: "CherryPick 번역하기" donate: "CherryPick에 기부하기" relayServer: "릴레이 서버" @@ -1918,7 +1956,7 @@ _mfm: intro: "MFM는 Misskey 기반 클라이언트의 다양한 곳에서 사용할 수 있는 전용 마크업 언어에요. 여기에서 MFM에서 사용할 수 있는 구문을 확인할 수 있어요." dummy: "CherryPick으로 연합우주의 세계가 펼쳐집니다" mention: "멘션" - mentionDescription: "골뱅이표(@) 뒤에 사용자명을 넣어 특정 유저를 나타낼 수 있어요." + mentionDescription: "골뱅이표(@) 뒤에 사용자 이름을 넣어 특정 사용자를 지정할 수 있어요." hashtag: "해시태그" hashtagDescription: "샵 또는 우물정자(#)를 앞에 붙여서 해시태그를 나타낼 수 있어요." url: "URL" @@ -1993,7 +2031,7 @@ _mfm: rubyDescription: "글자 위에 루비를 표시해요." _instanceTicker: none: "보이지 않음" - remote: "리모트 유저에게만 보이기" + remote: "리모트 사용자에게만 보이기" always: "항상 보이기" _serverDisconnectedBehavior: reload: "자동으로 새로고침" @@ -2094,7 +2132,7 @@ _theme: driveFolderBg: "드라이브 폴더 배경" wallpaperOverlay: "배경화면 오버레이" badge: "배지" - messageBg: "채팅 배경" + messageBg: "대화 배경" accentDarken: "강조 색상 (어두움)" accentLighten: "강조 색상 (밝음)" fgHighlighted: "강조된 텍스트" @@ -2107,6 +2145,14 @@ _sfx: chatBg: "대화 (백그라운드)" antenna: "안테나 수신" channel: "채널 알림" + reaction: "리액션 선택" +_soundSettings: + driveFile: "드라이브에 있는 오디오 파일 사용" + driveFileWarn: "드라이브에 있는 파일을 선택해 주세요." + driveFileTypeWarn: "이 파일은 지원되지 않는 형식이에요." + driveFileTypeWarnDescription: "오디오 파일을 선택해 주세요." + driveFileDurationWarn: "오디오가 너무 길어요." + driveFileDurationWarnDescription: "긴 오디오를 사용하는 경우 CherryPick 사용자 경험에 영향을 끼칠 수 있어요. 그래도 사용하시겠어요?" _ago: future: "미래" justNow: "방금 전" @@ -2118,6 +2164,14 @@ _ago: monthsAgo: "{n}개월 전" yearsAgo: "{n}년 전" invalid: "없음" +_timeIn: + seconds: "{n}초 후" + minutes: "{n}분 후" + hours: "{n}시간 후" + days: "{n}일 후" + weeks: "{n}주 후" + months: "{n}개월 후" + years: "{n}년 후" _time: second: "초" minute: "분" @@ -2177,8 +2231,8 @@ _permissions: "write:pages": "페이지를 편집합니다" "read:page-likes": "페이지의 좋아요를 확인합니다" "write:page-likes": "페이지에 좋아요를 추가하거나 취소합니다" - "read:user-groups": "유저 그룹을 조회합니다" - "write:user-groups": "유저 그룹을 만들거나, 초대하거나, 이름을 변경하거나, 양도하거나, 삭제합니다" + "read:user-groups": "사용자 그룹을 조회합니다" + "write:user-groups": "사용자 그룹을 만들거나, 초대하거나, 이름을 변경하거나, 양도하거나, 삭제합니다" "read:channels": "채널을 보기" "write:channels": "채널을 추가하거나 삭제합니다" "read:gallery": "갤러리를 봅니다" @@ -2189,6 +2243,55 @@ _permissions: "write:flash": "Play를 조작합니다" "read:flash-likes": "Play의 좋아요를 봅니다" "write:flash-likes": "Play의 좋아요를 조작합니다" + "read:admin:abuse-user-reports": "사용자 신고 보기" + "write:admin:delete-account": "사용자 계정 삭제" + "write:admin:delete-all-files-of-a-user": "사용자의 모든 파일 삭제" + "read:admin:index-stats": "데이터베이스 색인 정보 보기" + "read:admin:table-stats": "데이터베이스 테이블 정보 보기" + "read:admin:user-ips": "사용자 IP 주소 보기" + "read:admin:meta": "인스턴스 메타데이터 보기" + "write:admin:reset-password": "사용자 비밀번호 재설정하기" + "write:admin:resolve-abuse-user-report": "사용자 신고 처리하기" + "write:admin:send-email": "이메일 보내기" + "read:admin:server-info": "서버 정보 보기" + "read:admin:show-moderation-log": "모더레이션 기록 보기" + "read:admin:show-user": "사용자 개인정보 보기" + "read:admin:show-users": "사용자 개인정보 보기" + "write:admin:suspend-user": "사용자 정지하기" + "write:admin:unset-user-avatar": "사용자 아바타 삭제하기" + "write:admin:unset-user-banner": "사용자 배너 삭제하기" + "write:admin:unsuspend-user": "사용자 정지 해제하기" + "write:admin:meta": "인스턴스 메타데이터 수정하기" + "write:admin:user-note": "모더레이션 노트 수정하기" + "write:admin:roles": "역할 수정하기" + "read:admin:roles": "역할 보기" + "write:admin:relays": "릴레이 수정하기" + "read:admin:relays": "릴레이 보기" + "write:admin:invite-codes": "초대 코드 수정하기" + "read:admin:invite-codes": "초대 코드 보기" + "write:admin:announcements": "공지사항 수정하기" + "read:admin:announcements": "공지사항 보기" + "write:admin:avatar-decorations": "아바타 장식 수정하기" + "read:admin:avatar-decorations": "아바타 장식 보기" + "write:admin:federation": "연합 정보 수정하기" + "write:admin:account": "사용자 계정 수정하기" + "read:admin:account": "사용자 정보 보기" + "write:admin:emoji": "이모지 수정하기" + "read:admin:emoji": "이모지 보기" + "write:admin:queue": "작업 대기열 수정하기" + "read:admin:queue": "작업 대기열 정보 보기" + "write:admin:promo": "프로모션 기록 수정하기" + "write:admin:drive": "사용자 드라이브 수정하기" + "read:admin:drive": "사용자 드라이브 정보 보기" + "read:admin:stream": "관리자용 WebSocket API 사용하기" + "write:admin:ad": "광고 수정하기" + "read:admin:ad": "광고 보기" + "write:invite-codes": "초대 코드 만들기" + "read:invite-codes": "초대 코드 불러오기" + "write:clip-favorite": "클립의 좋아요 수정하기" + "read:clip-favorite": "클립의 좋아요 보기" + "read:federation": "연합 정보 불러오기" + "write:report-abuse": "위반 내용 신고하기" _auth: shareAccessTitle: "애플리케이션 접근 허가" shareAccess: "\"{name}\" 이 계정에 접근하는 것을 허용할까요?" @@ -2201,11 +2304,11 @@ _auth: pleaseLogin: "애플리케이션의 접근을 허가하려면 먼저 로그인해 주세요." _antennaSources: all: "모든 노트" - homeTimeline: "팔로우중인 유저의 노트" - users: "지정한 유저의 노트" - userList: "지정한 리스트에 속한 유저의 노트" - userGroup: "지정한 그룹에 속한 유저의 노트" - userBlacklist: "지정한 유저를 제외한 모든 노트" + homeTimeline: "팔로우중인 사용자의 노트" + users: "지정한 사용자의 노트" + userList: "지정한 리스트에 속한 사용자의 노트" + userGroup: "지정한 그룹에 속한 사용자의 노트" + userBlacklist: "지정한 사용자를 제외한 모든 노트" _weekday: sunday: "일요일" monday: "월요일" @@ -2234,16 +2337,17 @@ _widgets: postForm: "글 입력란" slideshow: "슬라이드 쇼" button: "버튼" - onlineUsers: "온라인 유저" + onlineUsers: "온라인 상태인 사용자" jobQueue: "작업 대기열" serverMetric: "서버 통계" aiscript: "AiScript 콘솔" aiscriptApp: "AiScript 앱" aichan: "아이" - userList: "유저 리스트" + userList: "사용자 리스트" _userList: chooseList: "리스트 선택" clicker: "클리커" + birthdayFollowings: "오늘 생일인 사용자" _cw: hide: "숨기기" show: "더 보기" @@ -2273,13 +2377,13 @@ _poll: remainingSeconds: "종료까지 앞으로 {s}초" _visibility: public: "공개" - publicDescription: "모든 유저에게 공개" + publicDescription: "모든 사용자에게 공개" home: "홈" homeDescription: "홈 타임라인에만 공개" followers: "팔로워" followersDescription: "팔로워에게만 공개" specified: "다이렉트" - specifiedDescription: "지정한 유저에게만 공개" + specifiedDescription: "지정한 사용자에게만 공개" disableFederation: "연합에 보내지 않기" disableFederationDescription: "다른 서버로 보내지 않을래요" _postForm: @@ -2296,7 +2400,7 @@ _postForm: f: "작성해주시길 기다리고 있어요..." _profile: name: "이름" - username: "유저명" + username: "사용자 이름" description: "자기소개" youCanIncludeHashtags: "해시 태그를 포함할 수 있어요." metadata: "추가 정보" @@ -2307,6 +2411,7 @@ _profile: changeAvatar: "아바타 이미지 변경" changeBanner: "배너 이미지 변경" verifiedLinkDescription: "내용에 자신의 프로필로 향하는 링크가 포함된 페이지의 URL을 삽입하면 소유자 인증 마크가 표시돼요." + avatarDecorationMax: "최대 {max}개까지 장식을 달 수 있어요." _exportOrImport: allNotes: "모든 노트" favoritedNotes: "즐겨찾기한 노트" @@ -2314,15 +2419,15 @@ _exportOrImport: muteList: "뮤트" blockingList: "차단" userLists: "리스트" - excludeMutingUsers: "뮤트한 유저 제외하기" + excludeMutingUsers: "뮤트한 사용자 제외하기" excludeInactiveUsers: "휴면 중인 계정 제외하기" - withReplies: "가져오기한 유저의 답글을 타임라인에 포함" + withReplies: "가져오기한 사용자의 답글을 타임라인에 포함" _charts: federation: "연합" apRequest: "요청" - usersIncDec: "유저 수 증감" - usersTotal: "유저 수 합계" - activeUsers: "활성 유저 수" + usersIncDec: "사용자 수 증감" + usersTotal: "사용자 수 합계" + activeUsers: "활성 사용자 수" notesIncDec: "노트 수 증감" localNotesIncDec: "로컬 노트 수 증감" remoteNotesIncDec: "리모트 노트 수 증감" @@ -2333,8 +2438,8 @@ _charts: storageUsageTotal: "스토리지 사용량 합계" _instanceCharts: requests: "요청" - users: "유저 수 증감" - usersTotal: "누적 유저 수" + users: "사용자 수 증감" + usersTotal: "누적 사용자 수" notes: "노트 수 증감" notesTotal: "누적 노트 수" ff: "팔로잉/팔로워 증감" @@ -2421,9 +2526,8 @@ _notification: youGotMention: "{name} 님이 나를 멘션했어요!" youGotReply: "{name} 님이 답글을 달았어요!" youGotQuote: "{name} 님이 인용했어요!" + youGotReact: "{name} 님이 반응했어요!" youRenoted: "{name} 님이 리노트했어요!" - youGotMessagingMessageFromUser: "{name} 님이 보낸 채팅이 있어요!" - youGotMessagingMessageFromGroup: "{name}에서 보낸 채팅이 있어요!" youWereFollowed: "새로운 팔로워가 있어요!" youReceivedFollowRequest: "새로운 팔로우 요청이 있어요!" yourFollowRequestAccepted: "팔로우 요청이 수락됐어요!" @@ -2431,6 +2535,7 @@ _notification: pollEnded: "투표 결과가 발표됐어요!" newNote: "새 게시물" unreadAntennaNote: "안테나 {name}" + roleAssigned: "새 역할이 할당됐어요!" emptyPushNotificationMessage: "새 알림이 있어요!" achievementEarned: "도전 과제를 달성했어요!" testNotification: "알림 테스트" @@ -2442,7 +2547,7 @@ _notification: followedBySomeUsers: "{n}명에게 팔로우됨" _types: all: "전부" - note: "유저의 새 게시물" + note: "사용자의 새 게시물" follow: "팔로잉" mention: "멘션" reply: "답글" @@ -2450,9 +2555,10 @@ _notification: quote: "인용" reaction: "리액션" pollEnded: "투표가 종료됨" - receiveFollowRequest: "팔로우 요청을 받았을 때" - followRequestAccepted: "팔로우 요청이 승인되었을 때" - groupInvited: "그룹에 초대되었을 때" + receiveFollowRequest: "팔로우 요청을 받음" + followRequestAccepted: "팔로우 요청이 승인됨" + groupInvited: "그룹에 초대됨" + roleAssigned: "역할이 할당됨" achievementEarned: "도전 과제 획득" app: "연동된 앱을 통한 알림" _actions: @@ -2529,11 +2635,11 @@ _moderationLogTypes: deleteDriveFile: "파일 삭제" deleteNote: "노트 삭제" createGlobalAnnouncement: "전역 공지사항 생성" - createUserAnnouncement: "유저 공지사항 생성" + createUserAnnouncement: "사용자 공지사항 생성" updateGlobalAnnouncement: "전역 공지사항 편집" - updateUserAnnouncement: "유저 공지사항 편집" + updateUserAnnouncement: "사용자 공지사항 편집" deleteGlobalAnnouncement: "전역 공지사항 삭제" - deleteUserAnnouncement: "유저 공지사항 삭제" + deleteUserAnnouncement: "사용자 공지사항 삭제" resetPassword: "비밀번호 재설정" suspendRemoteInstance: "리모트 서버를 정지" unsuspendRemoteInstance: "리모트 서버의 정지를 해제" @@ -2544,9 +2650,11 @@ _moderationLogTypes: createAd: "광고 생성" deleteAd: "광고 삭제" updateAd: "광고 편집" - createAvatarDecoration: "아이콘 장식 추가" - updateAvatarDecoration: "아이콘 장식 편집" - deleteAvatarDecoration: "아이콘 장식 삭제" + createAvatarDecoration: "아바타 장식 추가" + updateAvatarDecoration: "아바타 장식 편집" + deleteAvatarDecoration: "아바타 장식 삭제" + unsetUserAvatar: "이 사용자의 아바타 제거" + unsetUserBanner: "이 사용자의 배너 제거" _fileViewer: title: "파일 상세" type: "파일 유형" @@ -2587,16 +2695,16 @@ _externalResourceInstaller: description: "제공된 데이터의 무결성을 확인하지 못했어요. 보안을 위해 설치가 중단되었어요. 사이트 관리자에게 문의해 주세요." _pluginParseFailed: title: "AiScript 오류" - description: "데이터는 가져올 수 있었으나, AiScript 구문 분석에서 오류가 발생해 불러오지 못했어요. 플러그인 제작자에게 문의해 주세요. 오류에 대한 자세한 내용은 자바스크립트 콘솔에서 확인할 수 있어요." + description: "데이터는 가져올 수 있었으나, AiScript 구문 분석에서 오류가 발생해 불러오지 못했어요. 플러그인 제작자에게 문의해 주세요. 오류에 대한 자세한 내용은 브라우저에 내장된 개발자 도구의 JavaScript 콘솔에서 확인하실 수 있어요." _pluginInstallFailed: title: "플러그인 설치에 실패했어요" - description: "플러그인 설치 중 문제가 발생했어요. 다시 시도해 주세요. 오류에 대한 자세한 내용은 자바스크립트 콘솔을 참조해 주세요." + description: "플러그인 설치 중 문제가 발생했어요. 다시 시도해 주세요. 오류에 대한 자세한 내용은 브라우저에 내장된 개발자 도구의 JavaScript 콘솔에서 확인하실 수 있어요." _themeParseFailed: title: "테마 분석 오류" - description: "데이터는 가져올 수 있었으나, 테마 파일 분석 중 오류가 발생해 불러오지 못했어요. 테마 제작자에게 문의해 주세요. 오류에 대한 자세한 내용은 자바스크립트 콘솔에서 확인할 수 있어요." + description: "데이터는 가져올 수 있었으나, 테마 파일 분석 중 오류가 발생해 불러오지 못했어요. 테마 제작자에게 문의해 주세요. 오류에 대한 자세한 내용은 브라우저에 내장된 개발자 도구의 JavaScript 콘솔에서 확인하실 수 있어요." _themeInstallFailed: title: "테마 설치에 실패했어요" - description: "테마를 설치하는 동안 문제가 발생했어요. 다시 시도해 주세요. 오류에 대한 자세한 내용은 자바스크립트 콘솔을 참고해 주세요." + description: "테마를 설치하는 동안 문제가 발생했어요. 다시 시도해 주세요. 오류에 대한 자세한 내용은 브라우저에 내장된 개발자 도구의 JavaScript 콘솔에서 확인하실 수 있어요." _dataSaver: _media: title: "미디어 불러오기 방지" @@ -2608,8 +2716,8 @@ _dataSaver: title: "URL 미리보기 썸네일" description: "URL 미리보기의 썸네일 이미지를 불러오지 않아요." _code: - title: "코드 하이라이트" - description: "MFM 등에서 코드 하이라이트 기법을 사용하는 경우, 탭하기 전까지는 코드 하이라이트를 불러오지 않아요. 코드 하이라이트는 강조할 언어마다 해당 정의 파일을 불러와야 하지만, 이를 자동으로 불러오지 않기 때문에 통신량 감소를 기대할 수 있어요." + title: "코드 문법 강조" + description: "MFM 등에서 코드 문법 강조 기법을 사용할 때, 탭하기 전까지는 불러오지 않아요. 코드 문법 강조 기능은 강조할 언어마다 해당 정의 파일을 불러와야 하지만, 이를 자동으로 불러오지 않게 되어 데이터 사용량을 줄일 수 있어요." _abuse: _resolver: 1hour: "1시간" diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml index 8d43ecced6..6bb11f0388 100644 --- a/locales/lo-LA.yml +++ b/locales/lo-LA.yml @@ -320,7 +320,6 @@ administrator: "ຜູ້ບໍລິຫານ" token: "ໂທເຄັນ" share: "ແບ່ງປັນ" notFound: "ບໍ່ພົບ" -cacheClear: "ລຶບລ້າງແຄສ" help: "ຊ່ວຍເຫຼືອ" close: "ປິດ" invites: "ເຊີນ" diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index 2957d574b2..a29e3738a8 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -119,7 +119,6 @@ sensitive: "NSFW" add: "Toevoegen" reaction: "Reacties" reactions: "Reacties" -reactionSetting: "Reacties die in de reactie-selector worden getoond" reactionSettingDescription2: "Sleep om opnieuw te ordenen, Klik om te verwijderen, Druk op \"+\" om toe te voegen" rememberNoteVisibility: "Vergeet niet de notitie zichtbaarheidsinstellingen" attachCancel: "Verwijder bijlage" @@ -396,7 +395,6 @@ reduceUiAnimation: "Verminder beweging in de UI" share: "Delen" notFound: "Niet gevonden" uploadFolder: "Standaardmap voor uploaden" -cacheClear: "Cache verwijderen" markAsReadAllNotifications: "Markeer alle meldingen als gelezen" markAsReadAllUnreadNotes: "Markeer alle berichten als gelezen" markAsReadAllTalkMessages: "Markeer alle berichten als gelezen" diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 2eae35f60c..c21bf65ced 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -102,7 +102,6 @@ clickToShow: "Klikk for å vise" add: "Legg til" reaction: "Reaksjon" reactions: "Reaksjoner" -reactionSetting: "Reaksjoner som vises i reaksjonsvelgeren" reactionSettingDescription2: "Dra for å endre rekkefølgen, klikk for å slette, trykk \"+\" for å legge til." rememberNoteVisibility: "Husk innstillingene for synlighet av Notes" attachCancel: "Fjern vedlegg" @@ -517,6 +516,8 @@ _achievements: title: "Rett og slett heldig" _setNameToSyuilo: description: "Du satte navnet ditt til \"syuilo\"" + _setNameToNoriDev: + description: "Du satte navnet ditt til \"noridev\"" _passedSinceAccountCreated1: title: "Ett års jubileum" description: "Det har gått ett år siden kontoen din ble opprettet" @@ -537,7 +538,7 @@ _achievements: flavor: "Er du på riktig nettsted?" _brainDiver: title: "Brain Diver" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _role: options: "Alternativ" _priority: diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 31aa449877..94afb06a9f 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -111,7 +111,6 @@ sensitive: "NSFW" add: "Dodaj" reaction: "Reakcja" reactions: "Reakcja" -reactionSetting: "Reakcje do pokazania w wyborniku reakcji" reactionSettingDescription2: "Przeciągnij aby zmienić kolejność, naciśnij aby usunąć, naciśnij „+” aby dodać" rememberNoteVisibility: "Zapamiętuj ustawienia widoczności wpisu" attachCancel: "Usuń załącznik" @@ -407,7 +406,6 @@ share: "Udostępnij" notFound: "Nie znaleziono" notFoundDescription: "Nie ma strony odpowiadającej określonemu adresowi URL." uploadFolder: "Domyślne położenie wysłanych" -cacheClear: "Wyczyść pamięć podręczną" markAsReadAllNotifications: "Oznacz wszystkie powiadomienia jako przeczytane" markAsReadAllUnreadNotes: "Oznacz wszystkie wpisy jako przeczytane" markAsReadAllTalkMessages: "Oznacz wszystkie wiadomości jako przeczytane" @@ -820,8 +818,6 @@ makeReactionsPublicDescription: "To spowoduje, że lista wszystkich Twoich dotyc classic: "Klasyczny" muteThread: "Wycisz wątek" unmuteThread: "Wyłącz wyciszenie wątku" -ffVisibility: "Widoczność obserwowanych/obserwujących" -ffVisibilityDescription: "Pozwala skonfigurować, kto może zobaczyć, kogo obserwujesz i kto Cię obserwuje." continueThread: "Pokaż kontynuację wątku" deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie Twojego konta. Kontynuować?" incorrectPassword: "Nieprawidłowe hasło." @@ -1413,8 +1409,6 @@ _notification: youGotReply: "{name} odpowiedział(a) Tobie" youGotQuote: "{name} zacytował(a) Ciebie" youRenoted: "{name} udostępnił(a) Twój wpis" - youGotMessagingMessageFromUser: "{name} wysłał(a) Ci wiadomość" - youGotMessagingMessageFromGroup: "Została wysłana wiadomość do grupy {name}" youWereFollowed: "Zaobserwował(a) Cię" youReceivedFollowRequest: "Otrzymałeś(-aś) prośbę o możliwość obserwacji" yourFollowRequestAccepted: "Twoja prośba o możliwość obserwacji została przyjęta" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index 72aaf90450..87c78340cb 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -121,7 +121,6 @@ sensitive: "Conteúdo sensível" add: "Adicionar" reaction: "Reações" reactions: "Reações" -reactionSetting: "Quais reações exibir no seletor de reações" reactionSettingDescription2: "Arraste para reordenar, clique para excluir, pressione + para adicionar." rememberNoteVisibility: "Lembrar das configurações de visibilidade de notas" attachCancel: "Remover anexo" @@ -431,7 +430,6 @@ share: "Compartilhar" notFound: "Não encontrado" notFoundDescription: "Não havia página correspondente ao URL especificado." uploadFolder: "Destino de upload padrão" -cacheClear: "Excluir memória transitória" markAsReadAllNotifications: "Marcar todas as notificações como lidas" markAsReadAllUnreadNotes: "Marcar todas as postagens como lidas" markAsReadAllTalkMessages: "Marcar todas as conversas como lidas" @@ -860,8 +858,6 @@ makeReactionsPublicDescription: "Isto vai deixar o histórico de todas as suas r classic: "Clássico" muteThread: "Silenciar esta conversa" unmuteThread: "Desativar silêncio desta conversa" -ffVisibility: "Visibilidade de Seguidos/Seguidores" -ffVisibilityDescription: "Permite configurar quem pode ver quem lhe segue e quem você está seguindo." continueThread: "Ver mais desta conversa" deleteAccountConfirm: "Deseja realmente excluir a conta?" incorrectPassword: "Senha inválida." diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 29cdfaa17e..7f6e64cd6d 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -2,6 +2,7 @@ _lang_: "Română" headlineMisskey: "O rețea conectată prin note" introMisskey: "Bine ai venit! CherryPick este un serviciu de microblogging open source și decentralizat.\nCreează \"note\" cu care să îți poți împărți gândurile cu oricine din jurul tău. 📡\nCu \"reacții\" îți poți expirma rapid părerea despre notele oricui. 👍\nHai să explorăm o lume nouă! 🚀" +poweredByMisskeyDescription: "{name} este unul dintre serviciile care se folosește de platforma open source CherryPick." monthAndDay: "{day}/{month}" search: "Caută" notifications: "Notificări" @@ -12,12 +13,14 @@ fetchingAsApObject: "Se aduce din Fediverse..." ok: "OK" gotIt: "Am înțeles!" cancel: "Anulează" +noThankYou: "Nu, mulțumesc." enterUsername: "Introdu numele de utilizator" renotedBy: "Re-notat de {user}" noNotes: "Nicio notă" noNotifications: "Nicio notificare" instance: "Instanță" settings: "Setări" +notificationSettings: "Setări notificări" basicSettings: "Setări generale" otherSettings: "Alte Setări" openInWindow: "Deschide într-o fereastră" @@ -42,12 +45,20 @@ pin: "Fixează pe profil" unpin: "Anulati fixare" copyContent: "Copiază conținutul" copyLink: "Copiază link-ul" +copyLinkRenote: "Copiază linkul pentru renote" delete: "Şterge" deleteAndEdit: "Șterge și editează" deleteAndEditConfirm: "Ești sigur că vrei să ștergi această notă și să o editezi? Vei pierde reacțiile, re-notele și răspunsurile acesteia." addToList: "Adaugă în listă" +addToAntenna: "Adaugă la antenă" sendMessage: "Trimite un mesaj" +copyRSS: "Copiază RSS" copyUsername: "Copiază numele de utilizator" +copyUserId: "Copiază numele de utilizator" +copyNoteId: "Copiază ID-ul notiței" +copyFileId: "Copiază ID-ul fișierului" +copyFolderId: "Copiază ID-ul folderului" +copyProfileUrl: "Copiază URL profil" searchUser: "Caută un utilizator" reply: "Răspunde" loadMore: "Incarcă mai mult" @@ -100,6 +111,8 @@ renoted: "Re-notat." cantRenote: "Această postare nu poate fi re-notată." cantReRenote: "O re-notă nu poate fi re-notată." quote: "Citează" +inChannelRenote: "Renotează în canal" +inChannelQuote: "Citează în canal" pinnedNote: "Notă fixată" pinned: "Fixat pe profil" you: "Tu" @@ -108,7 +121,6 @@ sensitive: "NSFW" add: "Adaugă" reaction: "Reacție" reactions: "Reacție" -reactionSetting: "Reacții care să apară in selectorul de reacții" reactionSettingDescription2: "Trage pentru a rearanja, apasă pe \"+\" pentru a adăuga." rememberNoteVisibility: "Amintește setarea de vizibilitate a notelor" attachCancel: "Înlătură atașament" @@ -117,6 +129,8 @@ unmarkAsSensitive: "Demarchează ca NSFW" enterFileName: "Introduceţi numele fişierului" mute: "Amuțește" unmute: "Înlătură amuțirea" +renoteMute: "Renotări pe modul silențios" +renoteUnmute: "Scoate renotările de pe modul silențios" block: "Blochează" unblock: "Deblochează" suspend: "Suspendă" @@ -126,7 +140,10 @@ unblockConfirm: "Ești sigur ca vrei să deblochezi acest cont?" suspendConfirm: "Ești sigur ca vrei să suspendezi acest cont?" unsuspendConfirm: "Ești sigur ca vrei să nu mai suspendezi acest cont?" selectList: "Selectează o listă" +editList: "Editați lista" +selectChannel: "Selectaţi canalul" selectAntenna: "Selectează o antenă" +editAntenna: "Editează antena" selectWidget: "Selectați un widget" editWidgets: "Editează widget-urile" editWidgetsExit: "Terminat" @@ -139,6 +156,7 @@ addEmoji: "Adaugă un emoji" settingGuide: "Setări recomandate" cacheRemoteFiles: "Ține fișierele externe in cache" cacheRemoteFilesDescription: "Când această setare este dezactivată, fișierele externe sunt încărcate direct din instanța externă. Dezactivarea va scădea utilizarea spațiului de stocare, dar va crește traficul, deoarece thumbnail-urile nu vor fi generate." +youCanCleanRemoteFilesCache: "Poți goli cache-ul prin a apăsa pe butonul de 🗑️ din fereastra de gestionare a fișierelor." flagAsBot: "Marchează acest cont ca bot" flagAsBotDescription: "Activează această opțiune dacă acest cont este controlat de un program. Daca e activată, aceasta va juca rolul unui indicator pentru dezvoltatori pentru a preveni interacțiunea în lanțuri infinite cu ceilalți boți și ajustează sistemele interne al CherryPick pentru a trata acest cont drept un bot." flagAsCat: "Marchează acest cont ca pisică" @@ -393,7 +411,6 @@ share: "Distribuie" notFound: "Nu a fost găsit" notFoundDescription: "N-a fost găsită nicio pagină cu acest URL." uploadFolder: "Folder implicit pentru încărcări" -cacheClear: "Golește cache-ul" markAsReadAllNotifications: "Marchează toate notificările drept citit" markAsReadAllUnreadNotes: "Marchează toate notele drept citit" markAsReadAllTalkMessages: "Marchează toate mesajele drept citit" @@ -650,6 +667,8 @@ _sfx: chat: "Chat" _ago: invalid: "Nu e nimic de văzut aici" +_2fa: + renewTOTPCancel: "Nu, mulțumesc." _widgets: profile: "Profil" instanceInfo: "Informații despre instanță" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index c7455967fd..0321bcd52e 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -61,7 +61,7 @@ copyProfileUrl: "Скопировать URL профиля " searchUser: "Поиск людей" reply: "Ответ" loadMore: "Показать еще" -showMore: "Показать еще" +showMore: "Показать ещё" showLess: "Закрыть" youGotNewFollower: "Новый подписчик" receiveFollowRequest: "Получен запрос на подписку" @@ -120,7 +120,12 @@ sensitive: "Содержимое не для всех" add: "Добавить" reaction: "Реакции" reactions: "Реакции" -reactionSetting: "Реакции, отображаемые в палитре" +emojiPicker: "Палитра эмодзи" +pinnedEmojisForReactionSettingDescription: "Здесь можно закрепить эмодзи для реакций" +pinnedEmojisSettingDescription: "Здесь можно закрепить эмодзи в общей палитре" +emojiPickerDisplay: "Внешний вид палитры" +overwriteFromPinnedEmojisForReaction: "Заменить на эмодзи из списка реакций" +overwriteFromPinnedEmojis: "Заменить на эмодзи из общего списка закреплённых" reactionSettingDescription2: "Расставляйте перетаскиванием, удаляйте нажатием, добавляйте кнопкой «+»." rememberNoteVisibility: "Запоминать видимость заметок" attachCancel: "Удалить вложение" @@ -429,7 +434,6 @@ share: "Поделиться" notFound: "Не найдено" notFoundDescription: "Страница по указанной ссылке не найдена" uploadFolder: "Место загрузки по умолчанию" -cacheClear: "Очистка кэша" markAsReadAllNotifications: "Отметить все уведомления как прочитанные" markAsReadAllUnreadNotes: "Отметить все заметки как прочитанные" markAsReadAllTalkMessages: "Отметить все реплики как прочитанные" @@ -655,7 +659,7 @@ create: "Создать" notificationSetting: "Настройки уведомлений" notificationSettingDesc: "Выберите тип уведомлений для отображения" useGlobalSetting: "Использовать глобальные настройки" -useGlobalSettingDesc: "Если включено, будут использоваться настройки учётной записи. Если включить, этот виджет можно будет настроить индивидуально." +useGlobalSettingDesc: "Если включено, будут использоваться настройки учётной записи. Если отключить, этот виджет можно будет настроить индивидуально." other: "Другие" regenerateLoginToken: "Создать новый токен для входа" regenerateLoginTokenDescription: "Создаёт новый токен, используемый внутри программы во время входа. Обычно в этом нет необходимости. При создании все устройства будут отключены." @@ -693,7 +697,7 @@ createNewClip: "Новая подборка" unclip: "Убрать из подборки" confirmToUnclipAlreadyClippedNote: "Эта заметка уже есть в подборке «{name}». Удалить из этой подборки?" public: "Общедоступно" -private: "Показываются только вам" +private: "Личное" i18nInfo: "CherryPick переводят на разные языки добровольцы со всего света. Ваша помощь тоже пригодится здесь: {link}." manageAccessTokens: "Управление токенами доступа" accountInfo: "Сведения об учётной записи" @@ -870,8 +874,6 @@ makeReactionsPublicDescription: "Список сделанных вами реа classic: "Классика" muteThread: "Скрыть цепочку" unmuteThread: "Отменить сокрытие цепочки" -ffVisibility: "Видимость подписок и подписчиков" -ffVisibilityDescription: "Здесь можно настроить, кто будет видеть ваши подписки и подписчиков." continueThread: "Показать следующие ответы" deleteAccountConfirm: "Учётная запись будет безвозвратно удалена. Подтверждаете?" incorrectPassword: "Пароль неверен." @@ -969,7 +971,7 @@ numberOfProfileView: "Количество профилей для просмо like: "Нравится!" unlike: "Отменить «нравится»" numberOfLikes: "Количество лайков" -show: "Отображение" +show: "Показать" neverShow: "Больше не показывать" remindMeLater: "Напомнить позже" didYouLikeMisskey: "Вам нравится CherryPick?" @@ -1071,8 +1073,10 @@ options: "Настройки ролей" specifyUser: "Указанный пользователь" failedToPreviewUrl: "Предварительный просмотр недоступен" update: "Обновить" +rolesThatCanBeUsedThisEmojiAsReaction: "Роли тех, кому можно использовать эти эмодзи как реакцию" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Если здесь ничего не указать, в качестве реакции эту эмодзи сможет использовать каждый." later: "Позже" -goToMisskey: "К Misskey" +goToMisskey: "К CherryPick" additionalEmojiDictionary: "Дополнительные словари эмодзи" installed: "Установлено" branding: "Бренд" @@ -1085,6 +1089,7 @@ doYouAgree: "Согласны?" icon: "Аватар" replies: "Ответы" renotes: "Репост" +loadReplies: "Показать ответы" flip: "Переворот" _initialAccountSetting: accountCreated: "Аккаунт успешно создан!" @@ -1095,7 +1100,12 @@ _initialAccountSetting: skipAreYouSure: "Пропустить настройку?" _initialTutorial: _note: - description: "Посты в Misskey называются 'Заметками.' Заметки отсортированы в хронологическом порядке в ленте и обновляются в режиме реального времени." + description: "Посты в CherryPick называются 'Заметками.' Заметки отсортированы в хронологическом порядке в ленте и обновляются в режиме реального времени." +_timelineDescription: + home: "В персональной ленте располагаются заметки тех, на которых вы подписаны." + local: "Местная лента показывает заметки всех пользователей этого сайта." + social: "В социальной ленте собирается всё, что есть в персональной и местной лентах." + global: "В глобальную ленту попадает вообще всё со связанных инстансов." _serverSettings: iconUrl: "Адрес на иконку роли" _achievements: @@ -1313,6 +1323,9 @@ _achievements: _setNameToSyuilo: title: "Комплекс бога" description: "Установлено «syuilo» в качестве имени" + _setNameToNoriDev: + title: "Комплекс бога (CherryPick)" + description: "Установлено «noridev» в качестве имени" _passedSinceAccountCreated1: title: "Первая годовщина" description: "Прошёл 1 год с момента регистрации" @@ -1671,6 +1684,14 @@ _ago: monthsAgo: "{n} мес. назад" yearsAgo: "{n} г. назад" invalid: "Ничего нет" +_timeIn: + seconds: "Через {n} с" + minutes: "Через {n} мин" + hours: "Через {n} ч" + days: "Через {n} сут" + weeks: "Через {n} нед." + months: "Через {n} мес." + years: "Через {n} г." _time: second: "с" minute: "мин" @@ -1787,7 +1808,7 @@ _widgets: clicker: "Счётчик щелчков" _cw: hide: "Спрятать" - show: "Показать еще" + show: "Показать" chars: "знаков: {count}" files: "файлов: {count}" _poll: @@ -1961,8 +1982,6 @@ _notification: youGotReply: "{name} отвечает вам." youGotQuote: "{name} цитирует вас." youRenoted: "{name} передаёт вашу заметку." - youGotMessagingMessageFromUser: "{name} пишет вам." - youGotMessagingMessageFromGroup: "Новое сообщение в группе «{name}»." youWereFollowed: "У вас новый подписчик." youReceivedFollowRequest: "У вас новый запрос на подписку." yourFollowRequestAccepted: "Ваш запрос на подписку одобрен." diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 6a9ff5ad8e..e84bf3bab0 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -113,7 +113,6 @@ sensitive: "NSFW" add: "Pridať" reaction: "Reakcie" reactions: "Reakcie" -reactionSetting: "Reakcie zobrazené vo výbere reakcií" reactionSettingDescription2: "Ťahaním preusporiadate, kliknutím odstránite, Stlačením \"+\" pridáte" rememberNoteVisibility: "Zapamätať nastavenia viditeľnosti poznámky" attachCancel: "Odstrániť prílohu" @@ -411,7 +410,6 @@ share: "Zdieľať" notFound: "Nenájdené" notFoundDescription: "Nenašla sa žiadna stránka na zadanej URL." uploadFolder: "Predvolený priečinok pre nahrávanie" -cacheClear: "Vyčistiť cache" markAsReadAllNotifications: "Označiť všetky oznámenia ako prečítané" markAsReadAllUnreadNotes: "Označiť všetky poznámky ako prečítané" markAsReadAllTalkMessages: "Označiť všetky správy ako prečítané" @@ -835,8 +833,6 @@ makeReactionsPublicDescription: "Toto spraví všetky vaše minulé reakcie vidi classic: "Klasika" muteThread: "Ztíšiť vlákno" unmuteThread: "Zrušiť stíšenie vlákna" -ffVisibility: "Viditeľnosť sledujúcich/sledovaných" -ffVisibilityDescription: "Umožňuje nastaviť kto vidí koho sledujete a kto vás sleduje." continueThread: "Zobraziť pokračovanie vlákna" deleteAccountConfirm: "Toto nezvrátiteľne vymaže váš účet. Pokračovať?" incorrectPassword: "Nesprávne heslo." @@ -1474,8 +1470,6 @@ _notification: youGotReply: "{name} vám odpovedal/a" youGotQuote: "{name} vás citoval/a" youRenoted: "{name} preposlal/a vašu poznámku" - youGotMessagingMessageFromUser: "{name} vám poslal/a správu" - youGotMessagingMessageFromGroup: "Prišla správa do skupiny {name}" youWereFollowed: "Máte nového sledujúceho" youReceivedFollowRequest: "Dostali ste žiadosť o sledovanie" yourFollowRequestAccepted: "Vaša žiadosť o sledovanie bola prijatá" diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index c8537c68a1..87064f78bc 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -118,7 +118,6 @@ sensitive: "Känsligt innehåll" add: "Lägg till" reaction: "Reaktioner" reactions: "Reaktioner" -reactionSetting: "Reaktioner som ska visas i reaktionsväljaren" reactionSettingDescription2: "Dra för att omordna, klicka för att radera, tryck \"+\" för att lägga till." rememberNoteVisibility: "Komihåg notvisningsinställningar" attachCancel: "Ta bort bilaga" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index bb70fce82a..dfbe4ce63f 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -121,7 +121,6 @@ sensitive: "เนื้อหาที่ละเอียดอ่อน NSFW add: "เพิ่ม" reaction: "รีแอคชั่น" reactions: "รีแอคชั่น" -reactionSetting: "รีแอคชั่นไปยังแสดงผลในตัวเลือกการรีแอคชั่น" reactionSettingDescription2: "กดลากเพื่อจัดลำดับใหม่ กดคลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม" rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นตัวโน้ต" attachCancel: "ลบไฟล์ออกที่แนบมา" @@ -195,6 +194,7 @@ perHour: "ทุกชั่วโมง" perDay: "ต่อวัน" stopActivityDelivery: "หยุดส่งกิจกรรม" blockThisInstance: "บล็อกอินสแตนซ์นี้" +silenceThisInstance: "ปกปิดอินสแตนซ์นี้" operations: "ดำเนินการ" software: "ซอฟต์แวร์" version: "เวอร์ชั่น" @@ -214,6 +214,7 @@ clearCachedFiles: "ล้างแคช" clearCachedFilesConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะลบไฟล์ระยะไกลที่แคชไว้ทั้งหมด?" blockedInstances: "อินสแตนซ์ที่ ถูกบล็อก" blockedInstancesDescription: "ระบุชื่อโฮสต์ของอินสแตนซ์ที่คุณต้องการบล็อก อินสแตนซ์ที่อยู่ในรายการนั้นจะไม่สามารถพูดคุยกับอินสแตนซ์นี้ได้อีกต่อไป" +silencedInstances: "ปกปิดอินสแตนซ์นี้แล้ว" muteAndBlock: "ปิดเสียงและบล็อก" mutedUsers: "ผู้ใช้ที่ถูกปิดเสียง" blockedUsers: "ผู้ใช้ที่ถูกบล็อก" @@ -434,7 +435,6 @@ share: "แชร์" notFound: "ไม่พบหน้าที่ต้องการ" notFoundDescription: "ไม่พบหน้าที่สอดคล้องตรงกันกับ URL นี้นะ" uploadFolder: "โฟลเดอร์เริ่มต้นสำหรับอัพโหลด" -cacheClear: "ล้างแคช" markAsReadAllNotifications: "ทำเครื่องหมายการแจ้งเตือนทั้งหมดว่าอ่านแล้ว" markAsReadAllUnreadNotes: "ทำเครื่องหมายโน้ตทั้งหมดว่าอ่านแล้ว" markAsReadAllTalkMessages: "ทำเครื่องหมายข้อความทั้งหมดว่าอ่านแล้ว" @@ -572,6 +572,10 @@ output: "เอาท์พุต" script: "สคริปต์" disablePagesScript: "ปิดการใช้งาน AiScript บนเพจ" updateRemoteUser: "อัปเดตข้อมูลผู้ใช้งานระยะไกล" +unsetUserAvatar: "เลิกตั้งอวตาร" +unsetUserAvatarConfirm: "คุณแน่ใจหรือไม่ว่าต้องการเลิกตั้งอวตาร?" +unsetUserBanner: "เลิกตั้งแบนเนอร์" +unsetUserBannerConfirm: "คุณแน่ใจหรือไม่ว่าต้องการเลิกตั้งแบนเนอร์เลยมั้ย?" deleteAllFiles: "ลบไฟล์ทั้งหมด" deleteAllFilesConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะลบไฟล์ทั้งหมด?" removeAllFollowing: "เลิกติดตามผู้ใช้ที่ติดตามทั้งหมด" @@ -643,6 +647,7 @@ smtpSecure: "ใช้โดยนัย SSL/TLS สำหรับการเ smtpSecureInfo: "ปิดสิ่งนี้เมื่อใช้ STARTTLS" testEmail: "ทดสอบการส่งอีเมล" wordMute: "ปิดเสียงคำ" +hardWordMute: "ปิดเสียงคำยาก" regexpError: "ข้อผิดพลาดของนิพจน์ทั่วไป" regexpErrorDescription: "เกิดข้อผิดพลาดในนิพจน์ทั่วไปในบรรทัดที่ {line} ของการปิดเสียงคำ {tab} ของคุณ:" instanceMute: "ปิดเสียง อินสแตนซ์" @@ -876,8 +881,6 @@ makeReactionsPublicDescription: "การทำเช่นนี้จะท classic: "คลาสสิค" muteThread: "ปิดเสียงเธรด" unmuteThread: "เปิดเสียงเธรด" -ffVisibility: "การมองเห็นผู้ติดตาม/ผู้ติดตาม" -ffVisibilityDescription: "ช่วยให้คุณสามารถกำหนดค่าได้ว่าใครสามารถดูได้ว่าคุณติดตามใครและใครติดตามคุณบ้าง" continueThread: "ดูความต่อเนื่องเธรด" deleteAccountConfirm: "การดำเนินการนี้จะลบบัญชีของคุณอย่างถาวรเลยนะ แน่ใจหรอดำเนินการ?" incorrectPassword: "รหัสผ่านไม่ถูกต้อง" @@ -989,6 +992,7 @@ assign: "กำหนด" unassign: "ยังไม่มอบหมาย" color: "สี" manageCustomEmojis: "จัดการอีโมจิแบบกำหนดเอง" +manageAvatarDecorations: "จัดการตกแต่งอวตาร" youCannotCreateAnymore: "คุณถึงขีดจํากัดการสร้างแล้วนะ" cannotPerformTemporary: "ไม่สามารถใช้การได้ชั่วคราว" cannotPerformTemporaryDescription: "ไม่สามารถดําเนินการได้ชั่วคราว เนื่องจากเกินขีดจํากัดการดําเนินการ กรุณารอสักครู่แล้วลองใหม่อีกครั้ง" @@ -1146,7 +1150,19 @@ impressumUrl: "URL อิมเพรสชั่น" privacyPolicy: "นโยบายความเป็นส่วนตัว" privacyPolicyUrl: "URL นโยบายความเป็นส่วนตัว" tosAndPrivacyPolicy: "เงื่อนไขในการให้บริการและนโยบายความเป็นส่วนตัว" +avatarDecorations: "การตกแต่งอวตาร" +attach: "แนบ" +detach: "นำออก" +angle: "แองเกิล" flip: "ย้อนกลับ" +showAvatarDecorations: "แสดงตกแต่งอวตาร" +releaseToRefresh: "ปล่อยเพื่อรีเฟรช" +refreshing: "กำลังรีเฟรช..." +pullDownToRefresh: "ดึงลงเพื่อรีเฟรช" +disableStreamingTimeline: "ปิดใช้งานอัปเดตไทม์ไลน์แบบเรียลไทม์" +useGroupedNotifications: "แสดงผลการแจ้งเตือนแบบกลุ่มแล้ว" +signupPendingError: "มีปัญหาในการตรวจสอบที่อยู่อีเมลลิงก์อาจหมดอายุแล้ว" +doReaction: "เพิ่มรีแอคชั่น" _announcement: forExistingUsers: "ผู้ใช้งานที่มีอยู่เท่านั้น" forExistingUsersDescription: "การประกาศนี้จะแสดงต่อผู้ใช้ที่มีอยู่ ณ จุดที่เผยแพร่นั้นๆถ้าหากเปิดใช้งาน ถ้าหากปิดใช้งานผู้ที่กำลังสมัครใหม่หลังจากโพสต์แล้วนั้นก็จะเห็นเช่นกัน" @@ -1156,6 +1172,7 @@ _announcement: tooManyActiveAnnouncementDescription: "การมีประกาศที่ใช้งานมากเกินไปนั้นอาจจะทำให้ประสบการณ์ของผู้ใช้งานนั้นดูแย่ลง โปรดกรุณาพิจารณาการเก็บประกาศที่ล้าสมัยด้วยนะค่ะ" readConfirmTitle: "ทำเครื่องหมายบอกว่าอ่านแล้วเลยมั้ย?" readConfirmText: "การดำเนินการนี้จะทำเครื่องหมายเนื้อหาของ \"{title}\" บอกว่าอ่านแล้วนะ" + silence: "ไม่มีการแจ้งเตือน" _initialAccountSetting: accountCreated: "คุณได้สร้างบัญชีของคุณสำเร็จเรียบร้อยแล้ว!" letsStartAccountSetup: "สำหรับผู้เริ่มต้นมาตั้งค่าโปรไฟล์ของคุณกันเถอะ" @@ -1168,8 +1185,31 @@ _initialAccountSetting: pushNotificationDescription: "กำลังเปิดใช้งานการแจ้งเตือนแบบพุชจะช่วยให้คุณได้รับการแจ้งเตือนจาก {name} โดยตรงบนอุปกรณ์ของคุณนะ" initialAccountSettingCompleted: "ตั้งค่าโปรไฟล์เสร็จสมบูรณ์แล้ว!" haveFun: "ขอให้สนุก {name}!" + startTutorial: "เริ่มการฝึกสอน" skipAreYouSure: "ต้องการข้ามการตั้งค่าโปรไฟล์จริงๆแบบนั้นหรอ?" laterAreYouSure: "ต้องการตั้งค่าโปรไฟล์ในภายหลังจริงๆอย่างงั้นหรอ?" +_initialTutorial: + launchTutorial: "เริ่มบทช่วยสอน" + title: "บทช่วยสอน" + wellDone: "ทำได้ดีมาก!" + skipAreYouSure: "ต้องการออกจากบทช่วยสอนใช่ไหม?" + _landing: + title: "ยินดีต้อนรับสู่บทช่วยสอน" + _note: + title: "โน้ตคืออะไร?" + _reaction: + title: "รีแอคชั่นคืออะไร?" + _timeline: + title: "แนวคิดเรื่องของไทม์ไลน์" + _postNote: + title: "ตั้งค่ากำลังโพสต์โน้ต" + _visibility: + description: "คุณสามารถจำกัดผู้ที่สามารถดูโน้ตของคุณได้นะ" + public: "โน้ตของคุณนั้นจะปรากฏแก่ผู้ใช้งานทุกคน" + _cw: + title: "คำเตือนเกี่ยวกับเนื้อหา" + _exampleNote: + cw: "นี่อาจจะทำให้คุณหิวอย่างแน่นอน!" _serverRules: description: "ชุดของกฎที่จะแสดงก่อนการลงทะเบียนเราขอแนะนำให้ตั้งค่าสรุปข้อกำหนดในการให้บริการ" _serverSettings: @@ -1408,6 +1448,9 @@ _achievements: _setNameToSyuilo: title: "พระเจ้าคอมเพล็กซ์" description: "ตั้งชื่อของคุณเป็น \"syuilo\"" + _setNameToNoriDev: + title: "พระเจ้าคอมเพล็กซ์ (CherryPick)" + description: "ตั้งชื่อของคุณเป็น \"noridev\"" _passedSinceAccountCreated1: title: "ครบรอบหนึ่งปี" description: "ผ่านไปหนึ่งปีแล้วนะตั้งแต่บัญชีของคุณถูกสร้างขึ้นมาน่ะ" @@ -1431,7 +1474,7 @@ _achievements: _brainDiver: title: "Brain Diver" description: "โพสต์ลิงก์ไปยัง Brain Diver" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "ทดสอบโอเวอร์โฟลว์" description: "ทดสอบการแจ้งเตือนทริกเกอร์ซ้ำๆ ภายในระยะเวลาอันสั้นๆ" @@ -1479,6 +1522,7 @@ _role: inviteLimitCycle: "จำกัดการเชิญไว้คูลดาวน์" inviteExpirationTime: "วันหมดอายุของรหัสการเชิญ" canManageCustomEmojis: "จัดการอีโมจิแบบกำหนดเอง" + canManageAvatarDecorations: "จัดการตกแต่งอวตาร" driveCapacity: "ความจุของไดรฟ์" alwaysMarkNsfw: "ทำเครื่องหมายไฟล์ว่าเป็น NSFW เสมอ" pinMax: "จํานวนสูงสุดของโน้ตที่ปักหมุดไว้" @@ -2092,8 +2136,6 @@ _notification: youGotReply: "{name} ตอบกลับถึงคุณ" youGotQuote: "{name} อ้างถึงคุณ" youRenoted: "รีโน้ตจาก {name}" - youGotMessagingMessageFromUser: "{name} ได้ส่งข้อความแชทถึงคุณ" - youGotMessagingMessageFromGroup: "ข้อความแชทถูกส่งไปยัง {name} กลุ่ม" youWereFollowed: "ได้ติดตามคุณ" youReceivedFollowRequest: "คุณมีคำขอติดตามใหม่น่ะ" yourFollowRequestAccepted: "คำขอติดตามของคุณได้รับการยอมรับแล้วน่ะ" @@ -2219,3 +2261,15 @@ _fileViewer: uploadedAt: "วันที่เข้าร่วม" attachedNotes: "โน้ตที่แนบมาด้วย" thisPageCanBeSeenFromTheAuthor: "หน้าเพจนี้จะสามารถปรากฏได้โดยผู้ใช้ที่อัปโหลดไฟล์นี้เท่านั้น" +_externalResourceInstaller: + _plugin: + metaTitle: "ข้อมูลส่วนเสริม" + _theme: + metaTitle: "ข้อมูลธีม" + _vendorInfo: + title: "ข้อมูลผู้จัดจำหน่าย" + _errors: + _pluginParseFailed: + title: "ข้อผิดพลาด AiScript" + _themeParseFailed: + title: "การแยกวิเคราะห์ธีมล้มเหลว" diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index 8cad592738..120b9f4230 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -121,7 +121,6 @@ sensitive: "Hassas içerik" add: "Ekle" reaction: "Tepkiler" reactions: "Tepkiler" -reactionSetting: "Palette görünecek tepkiler" reactionSettingDescription2: "Sıralamak için sürükleyin, silmek için tıklayın, eklemek için \"+\" tuşuna tıklayın." rememberNoteVisibility: "Görünürlük ayarlarını hatırla" attachCancel: "Eki sil" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 758ae934ca..73ce06a155 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -55,6 +55,7 @@ copyRSS: "Скопіювати RSS" copyUsername: "Скопіювати ім’я користувача" copyUserId: "Копіювати ID користувача" copyNoteId: "блокнот ID користувача" +copyFileId: "Скопіювати ідентифікатор файлу." searchUser: "Пошук користувачів" reply: "Відповісти" loadMore: "Показати більше" @@ -115,7 +116,6 @@ sensitive: "NSFW" add: "Додати" reaction: "Реакції" reactions: "Реакції" -reactionSetting: "Налаштування реакцій" reactionSettingDescription2: "Перемістити щоб змінити порядок, Клацнути мишою щоб видалити, Натиснути \"+\" щоб додати." rememberNoteVisibility: "Пам’ятати параметри видимісті" attachCancel: "Видалити вкладення" @@ -133,6 +133,7 @@ unblockConfirm: "Ви впевнені, що хочете розблокуват suspendConfirm: "Ви впевнені, що хочете призупинити цей акаунт?" unsuspendConfirm: "Ви впевнені, що хочете відновити цей акаунт?" selectList: "Виберіть список" +editList: "Редагувати список." selectChannel: "Виберіть канал" selectAntenna: "Виберіть антену" selectWidget: "Виберіть віджет" @@ -408,7 +409,6 @@ share: "Поділитись" notFound: "Не знайдено" notFoundDescription: "Сторінка за вказаною адресою не знайдена." uploadFolder: "Місце для завантаження за замовчуванням" -cacheClear: "Очистити кеш" markAsReadAllNotifications: "Позначити всі сповіщення як прочитані" markAsReadAllUnreadNotes: "Позначити всі нотатки як прочитані" markAsReadAllTalkMessages: "Позначити всі повідомлення як прочитані" @@ -459,6 +459,7 @@ language: "Мова" uiLanguage: "Мова інтерфейсу" groupInvited: "Запрошення до групи" aboutX: "Про {x}" +native: "місцевий" disableDrawer: "Не використовувати висувні меню" youHaveNoGroups: "Немає груп" joinOrCreateGroup: "Отримуйте запрошення до груп або створюйте свої власні групи." @@ -539,6 +540,8 @@ output: "Вихід" script: "Скрипт" disablePagesScript: "Вимкнути AiScript на Сторінках" updateRemoteUser: "Оновити інформацію про віддаленого користувача" +unsetUserAvatar: "Деактивувати піктограму." +unsetUserBanner: "Випустити прапор." deleteAllFiles: "Видалити всі файли" deleteAllFilesConfirm: "Ви дійсно хочете видалити всі файли?" removeAllFollowing: "Скасувати всі підписки" @@ -826,7 +829,6 @@ makeReactionsPublicDescription: "Це зробить список усіх ва classic: "Класичний" muteThread: "Приглушити тред" unmuteThread: "Скасувати глушіння" -ffVisibility: "Видимість підписок/підписників" continueThread: "Показати продовження треду" deleteAccountConfirm: "Це незворотно видалить ваш акаунт. Продовжити?" incorrectPassword: "Неправильний пароль." @@ -1121,6 +1123,9 @@ _achievements: _setNameToSyuilo: title: "Комплекс бога" description: "Встановлено ім'я \"syuilo\"" + _setNameToNoriDev: + title: "Комплекс бога (CherryPick)" + description: "Встановлено ім'я \"noridev\"" _passedSinceAccountCreated1: title: "Перша річниця" description: "Минув рік з моменту створення акаунта" @@ -1141,7 +1146,7 @@ _achievements: _brainDiver: title: "Brain Diver" description: "Відправити посилання на \"Brain Diver\"" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _role: new: "Нова роль" edit: "Змінити роль" @@ -1641,8 +1646,6 @@ _notification: youGotReply: "{name} відповідає" youGotQuote: "{name} цитує вас" youRenoted: "{name} поширює" - youGotMessagingMessageFromUser: "Повідомлення від {name}" - youGotMessagingMessageFromGroup: "Нове повідомлення в групі {name}" youWereFollowed: "Новий підписник" youReceivedFollowRequest: "Ви отримали запит на підписку" yourFollowRequestAccepted: "Запит на підписку прийнято" diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml index 81be4f9b52..162eef6fa8 100644 --- a/locales/uz-UZ.yml +++ b/locales/uz-UZ.yml @@ -120,7 +120,6 @@ sensitive: "Sezuvchan" add: "Qo'shish" reaction: "Reaktsiyalar" reactions: "Reaktsiyalar" -reactionSetting: "Reaksiyalar ro'yxati" reactionSettingDescription2: "Qayta tartiblash uchun ushlab turib siljiting, oʻchirish uchun bosing, qoʻshish uchun “+” tugmasini bosing." rememberNoteVisibility: "Qaydning ko'rinish sozlamarini eslab qolish" attachCancel: "Qo'shimchani olib tashlash" @@ -428,7 +427,6 @@ share: "Yuborish" notFound: "Topilmadi" notFoundDescription: "Ushbu sahifa topilmadi" uploadFolder: "Jildni yuklash" -cacheClear: "Keshni tozalash" markAsReadAllNotifications: "Bildirishnomalarni o'qilgan deb belgilash" markAsReadAllUnreadNotes: "Barch xabarlarni oq'ilgan deb belgilash" markAsReadAllTalkMessages: "Barcha suhbatlarni o'qilgan deb belgilang" @@ -650,7 +648,7 @@ createNewClip: "Yangi klip yaratish" unclip: "qirqish\n" confirmToUnclipAlreadyClippedNote: "Ushbu xat allaqachon \"{name}\" klipga tegishli. Uni ushbu klipdan olib tashlashni xohlaysizmi?" public: "Ommaviy" -i18nInfo: "Misskey bir qancha volontyorlar yordamida bir qancha tillarga tarjima qilingan. Ushbu {link} orqali ularga yordam berishingiz mumkin." +i18nInfo: "CherryPick bir qancha volontyorlar yordamida bir qancha tillarga tarjima qilingan. Ushbu {link} orqali ularga yordam berishingiz mumkin." manageAccessTokens: "Kirish tokenlarini boshqarish" accountInfo: "Akkount haqida ma'lumot" notesCount: "Xatlar soni" @@ -778,7 +776,7 @@ hashtags: "Hashteglar" troubleshooting: "Muammolarni bartaraf qilish" useBlurEffect: "Interfeysda xiralashtiruvchi effektlardan foydalanish" learnMore: "Batafsilroq" -misskeyUpdated: "Misskey yangilandi!" +misskeyUpdated: "CherryPick yangilandi!" whatIsNew: "O'zgarishlarni ko'rish" translate: "Tarjima qilish" translatedFrom: "{x} tilidan tarjima qilindi" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index 1b51b7c20b..1c4313aef5 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -121,7 +121,6 @@ sensitive: "Nhạy cảm" add: "Thêm" reaction: "Biểu cảm" reactions: "Biểu cảm" -reactionSetting: "Chọn những biểu cảm hiển thị" reactionSettingDescription2: "Kéo để sắp xếp, nhấn để xóa, nhấn \"+\" để thêm." rememberNoteVisibility: "Lưu kiểu tút mặc định" attachCancel: "Gỡ tập tin đính kèm" @@ -433,7 +432,6 @@ share: "Chia sẻ" notFound: "Không tìm thấy" notFoundDescription: "Không tìm thấy trang nào tương ứng với URL này." uploadFolder: "Thư mục tải lên mặc định" -cacheClear: "Xóa bộ nhớ đệm" markAsReadAllNotifications: "Đánh dấu tất cả các thông báo là đã đọc" markAsReadAllUnreadNotes: "Đánh dấu tất cả các tút là đã đọc" markAsReadAllTalkMessages: "Đánh dấu tất cả các tin nhắn là đã đọc" @@ -871,8 +869,6 @@ makeReactionsPublicDescription: "Điều này sẽ hiển thị công khai danh classic: "Cổ điển" muteThread: "Không quan tâm nữa" unmuteThread: "Quan tâm tút này" -ffVisibility: "Hiển thị Theo dõi/Người theo dõi" -ffVisibilityDescription: "Quyết định ai có thể xem những người bạn theo dõi và những người theo dõi bạn." continueThread: "Tiếp tục xem chuỗi tút" deleteAccountConfirm: "Điều này sẽ khiến tài khoản bị xóa vĩnh viễn. Vẫn tiếp tục?" incorrectPassword: "Sai mật khẩu." @@ -1037,7 +1033,7 @@ position: "Vị trí" serverRules: "Luật của máy chủ" youFollowing: "Đang theo dõi" later: "Để sau" -goToMisskey: "Tới Misskey" +goToMisskey: "Tới CherryPick" installed: "Đã tải xuống" branding: "Thương hiệu" turnOffToImprovePerformance: "Tắt mục này có thể cải thiện hiệu năng." @@ -1092,7 +1088,7 @@ _accountMigration: moveFromLabel: "Tài khoản gốc #{n}" moveTo: "Chuyển tài khoản này vào một tài khoản khác" moveCannotBeUndone: "Việc chuyển tài khoản không thể huỷ." - moveAccountDescription: "Điều này sẽ chuyển tài khoản này sang một tài khoản khác.\n ・Những người theo dõi sẽ tự động được chuyển sang tài khoản mới\n ・Tài khoản này sẽ tự bỏ theo dõi những người mà bạn đã theo dõi trước đây\n ・Bạn sẽ không thể đăng tút mới, v.v trên tài khoản này\n\nDù việc chuyển người theo dõi được diễn ra tự động, bạn vẫn phải tự chuẩn bị một vài bước để chuyển danh sách những người dùng bạn đang theo dõi. Để làm vậy, vui lòng thực hiện việc xuất dữ liệu những người dùng đã theo dõi mà sau này bạn sẽ dùng để nhập vào tài khoản mới ở menu Cài đặt. Hành động tương tự áp dụng với danh sách những người dùng bị chặn hoặc tắt tiếng.\n\n(Điều này áp dụng cho phiên bản Misskey v13.12.0 và sau này. Các phần mềm ActivityPub khác , ví dụ như Mastodon, sẽ có thể hoạt động khác đi.)" + moveAccountDescription: "Điều này sẽ chuyển tài khoản này sang một tài khoản khác.\n ・Những người theo dõi sẽ tự động được chuyển sang tài khoản mới\n ・Tài khoản này sẽ tự bỏ theo dõi những người mà bạn đã theo dõi trước đây\n ・Bạn sẽ không thể đăng tút mới, v.v trên tài khoản này\n\nDù việc chuyển người theo dõi được diễn ra tự động, bạn vẫn phải tự chuẩn bị một vài bước để chuyển danh sách những người dùng bạn đang theo dõi. Để làm vậy, vui lòng thực hiện việc xuất dữ liệu những người dùng đã theo dõi mà sau này bạn sẽ dùng để nhập vào tài khoản mới ở menu Cài đặt. Hành động tương tự áp dụng với danh sách những người dùng bị chặn hoặc tắt tiếng.\n\n(Điều này áp dụng cho phiên bản CherryPick v13.12.0 và sau này. Các phần mềm ActivityPub khác , ví dụ như Mastodon, sẽ có thể hoạt động khác đi.)" startMigration: "Chuyển" movedAndCannotBeUndone: "\nTài khoản này đã được chuyển đi.\nViệc di chuyển tài khoản không thể bị huỷ bỏ." movedTo: "Tài khoản mới:" @@ -1168,7 +1164,7 @@ _achievements: title: "Khách hàng thường xuyên cấp III" description: "Tổng số ngày đăng nhập đạt 400 ngày" _login1000: - flavor: "Cảm ơn bạn đã sử dụng Misskey!" + flavor: "Cảm ơn bạn đã sử dụng CherryPick!" _noteFavorited1: title: "Nhà thiên văn học" _myNoteFavorited1: @@ -1231,9 +1227,9 @@ _achievements: description: "Tìm thấy được những kho báu cất giấu" _client30min: title: "Giải lao xỉu" - description: "Giữ Misskey mở trong ít nhất 30 phút" + description: "Giữ CherryPick mở trong ít nhất 30 phút" _client60min: - description: "Giữ Misskey mở trong ít nhất 60 phút" + description: "Giữ CherryPick mở trong ít nhất 60 phút" _noteDeletedWithin1min: title: "Xem như không có gì đâu nha" _postedAtLateNight: @@ -1270,6 +1266,9 @@ _achievements: _setNameToSyuilo: title: "Ngưỡng mộ với vị thần" description: "Đạt tên là syuilo" + _setNameToNoriDev: + title: "Ngưỡng mộ với vị thần (CherryPick)" + description: "Đạt tên là noridev" _passedSinceAccountCreated1: title: "Kỷ niệm một năm" _loggedInOnBirthday: @@ -1868,8 +1867,6 @@ _notification: youGotReply: "{name} trả lời bạn" youGotQuote: "{name} trích dẫn tút của bạn" youRenoted: "{name} đăng lại tút của bạn" - youGotMessagingMessageFromUser: "{name} nhắn tin cho bạn" - youGotMessagingMessageFromGroup: "Một tin nhắn trong nhóm {name}" youWereFollowed: "đã theo dõi bạn" youReceivedFollowRequest: "Bạn vừa có một yêu cầu theo dõi" yourFollowRequestAccepted: "Yêu cầu theo dõi của bạn đã được chấp nhận" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index eb117273a7..c547b7b00d 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -121,7 +121,6 @@ sensitive: "敏感内容" add: "添加" reaction: "回应" reactions: "回应" -reactionSetting: "在选择器中显示回应" reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。" rememberNoteVisibility: "保存上次设置的可见性" attachCancel: "删除附件" @@ -311,6 +310,7 @@ folderName: "文件夹名称" createFolder: "创建文件夹" renameFolder: "重命名文件夹" deleteFolder: "删除文件夹" +folder: "文件夹" addFile: "添加文件" emptyDrive: "网盘中无文件" emptyFolder: "此文件夹中无文件" @@ -437,7 +437,6 @@ share: "分享" notFound: "未找到" notFoundDescription: "没有与指定 URL 对应的页面。" uploadFolder: "默认上传文件夹" -cacheClear: "清空缓存" markAsReadAllNotifications: "将所有通知标为已读" markAsReadAllUnreadNotes: "将所有帖子标记为已读" markAsReadAllTalkMessages: "将所有聊天标记为已读" @@ -879,8 +878,6 @@ makeReactionsPublicDescription: "将您发表过的回应设置成公开可见 classic: "经典" muteThread: "屏蔽帖子列表" unmuteThread: "取消屏蔽帖子列表" -ffVisibility: "关注关系的可见范围" -ffVisibilityDescription: "您可以设置您的关注/关注者信息的公开范围" continueThread: "查看更多帖子" deleteAccountConfirm: "将要删除账户。是否确认?" incorrectPassword: "密码错误" @@ -1145,6 +1142,7 @@ mutualFollow: "互相关注" fileAttachedOnly: "仅限媒体" showRepliesToOthersInTimeline: "在时间线上显示给其他人的回复" hideRepliesToOthersInTimeline: "在时间线上隐藏给其他人的回复" +avatarDecorations: "头像挂件" flip: "翻转" _announcement: forExistingUsers: "仅限现有用户" @@ -1177,7 +1175,7 @@ _serverSettings: appIconUsageExample: "例如:作为书签添加到 PWA 或手机主屏幕的时候" appIconStyleRecommendation: "因为有可能会被裁切为圆形或者圆角矩形,建议使用边缘带有留白背景的图标。" appIconResolutionMustBe: "分辨率必须为 {resolution}。" - manifestJsonOverride: "覆盖 mainfest.json" + manifestJsonOverride: "覆盖 manifest.json" shortName: "简称" shortNameDescription: "如果服务器的正式名称很长,可以用简称或者別名来替代。" _accountMigration: @@ -1410,6 +1408,9 @@ _achievements: _setNameToSyuilo: title: "像神一样呐" description: "将名称设定为 syuilo" + _setNameToNoriDev: + title: "像神一样呐 (CherryPick)" + description: "将名称设定为 noridev" _passedSinceAccountCreated1: title: "一周年" description: "账户创建时间超过 1 年" @@ -1433,7 +1434,7 @@ _achievements: _brainDiver: title: "Brain Diver" description: "发布了包含 Brain Diver 链接的帖子" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "过度测试" description: "短时间内连续测试通知" @@ -1789,6 +1790,9 @@ _ago: monthsAgo: "{n} 月前" yearsAgo: "{n} 年前" invalid: "没有" +_timeIn: + seconds: "{n}秒后" + days: "{n}天后" _time: second: "秒" minute: "分" @@ -2092,8 +2096,6 @@ _notification: youGotReply: "来自{name}的回复" youGotQuote: "来自{name}的引用" youRenoted: "来自{name}的转发" - youGotMessagingMessageFromUser: "来自{name}的聊天" - youGotMessagingMessageFromGroup: "来自{name}的群聊" youWereFollowed: "关注了你。" youReceivedFollowRequest: "您有新的关注请求" yourFollowRequestAccepted: "您的关注请求已通过" @@ -2212,3 +2214,7 @@ _moderationLogTypes: _fileViewer: url: "URL" uploadedAt: "添加日期" +_externalResourceInstaller: + _errors: + _pluginParseFailed: + title: "AiScript 错误" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index dcb8716681..bd1563fe6a 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -121,7 +121,12 @@ sensitive: "敏感內容" add: "新增" reaction: "反應" reactions: "反應" -reactionSetting: "在選擇器中顯示反應" +emojiPicker: "表情符號選擇器" +pinnedEmojisForReactionSettingDescription: "選擇反應時可以設定要固定顯示在頂端的表情符號" +pinnedEmojisSettingDescription: "輸入表情符號時可以設定要固定顯示在頂端的表情符號" +emojiPickerDisplay: "顯示表情符號選擇器" +overwriteFromPinnedEmojisForReaction: "從反應複寫設定" +overwriteFromPinnedEmojis: "從一般複寫設定" reactionSettingDescription2: "拖動以交換,點擊以刪除,按下「+」以新增。" rememberNoteVisibility: "記住貼文可見性" attachCancel: "移除附件" @@ -261,6 +266,7 @@ removed: "已刪除" removeAreYouSure: "確定要刪掉「{x}」嗎?" deleteAreYouSure: "確定要刪掉「{x}」嗎?" resetAreYouSure: "確定要重設嗎?" +areYouSure: "是否確定?" saved: "已儲存" messaging: "聊天" upload: "上傳" @@ -292,13 +298,13 @@ birthday: "生日" yearsOld: "{age} 歲" registeredDate: "註冊日期" location: "位置" -theme: "外觀主題" -themeForLightMode: "在淺色模式下使用的主題" -themeForDarkMode: "在深色模式下使用的主題" +theme: "佈景主題" +themeForLightMode: "在淺色模式下使用的佈景主題" +themeForDarkMode: "在深色模式下使用的佈景主題" light: "淺色" dark: "深色" -lightThemes: "淺色主題" -darkThemes: "深色主題" +lightThemes: "淺色佈景主題" +darkThemes: "深色佈景主題" syncDeviceDarkMode: "與設備的深色模式同步" drive: "雲端硬碟" fileName: "檔案名稱" @@ -311,6 +317,7 @@ folderName: "資料夾名稱" createFolder: "新增資料夾" renameFolder: "重新命名資料夾" deleteFolder: "刪除資料夾" +folder: "資料夾" addFile: "加入附件" emptyDrive: "雲端硬碟為空" emptyFolder: "資料夾為空" @@ -437,7 +444,6 @@ share: "分享" notFound: "查無項目" notFoundDescription: "查無此頁" uploadFolder: "預設上傳資料夾" -cacheClear: "清除快取" markAsReadAllNotifications: "標記所有通知為已讀" markAsReadAllUnreadNotes: "標記所有貼文為已讀" markAsReadAllTalkMessages: "標記所有訊息為已讀" @@ -556,6 +562,8 @@ showInPage: "在頁面中顯示" popout: "彈出式視窗" volume: "音量" masterVolume: "主音量" +notUseSound: "關閉音效" +useSoundOnlyWhenActive: "瀏覽器在前景運作時,CherryPick 才會發出音效" details: "詳細資訊" chooseEmoji: "選擇您的表情符號" unableToProcess: "操作無法完成" @@ -576,6 +584,10 @@ output: "輸出" script: "腳本" disablePagesScript: "停用頁面的 AiScript 腳本" updateRemoteUser: "更新遠端使用者資訊" +unsetUserAvatar: "移除使用者的大頭貼" +unsetUserAvatarConfirm: "確定要移除使用者的大頭貼嗎?" +unsetUserBanner: "移除使用者的橫幅圖像" +unsetUserBannerConfirm: "確定要移除使用者的橫幅圖像嗎?" deleteAllFiles: "刪除所有檔案" deleteAllFilesConfirm: "要刪除所有檔案嗎?" removeAllFollowing: "解除所有追隨" @@ -601,12 +613,12 @@ deletedNote: "已刪除的貼文" invisibleNote: "私密的貼文" enableInfiniteScroll: "啟用自動滾動頁面模式" visibility: "可見性" -poll: "投票" +poll: "票選活動" useCw: "隱藏內容" enablePlayer: "開啟播放器" disablePlayer: "關閉播放器" expandTweet: "展開推文" -themeEditor: "主題編輯器" +themeEditor: "佈景主題編輯器" description: "描述" describeFile: "新增標題" enterFileDescription: "輸入標題" @@ -632,11 +644,11 @@ tokenRequested: "允許存取帳戶" pluginTokenRequestedDescription: "此外掛將擁有在此設定的權限。" notificationType: "通知形式" edit: "編輯" -emailServer: "電郵伺服器" -enableEmail: "啟用發送電郵功能" -emailConfigInfo: "用於確認電郵地址及密碼重置" +emailServer: "電子郵件伺服器" +enableEmail: "啟用發送電子郵件功能" +emailConfigInfo: "用於確認電子郵件地址及密碼重置" email: "電子郵件" -emailAddress: "電郵地址" +emailAddress: "電子郵件位址" smtpConfig: "SMTP 伺服器設定" smtpHost: "主機" smtpPort: "埠" @@ -647,6 +659,7 @@ smtpSecure: "在 SMTP 連接中使用隱式 SSL/TLS" smtpSecureInfo: "使用 STARTTLS 時關閉。" testEmail: "測試郵件發送" wordMute: "被靜音的文字" +hardWordMute: "硬文字靜音" regexpError: "正規表達式錯誤" regexpErrorDescription: "{tab} 靜音文字的第 {line} 行的正規表達式有錯誤:" instanceMute: "被靜音的實例" @@ -730,7 +743,7 @@ disableShowingAnimatedImages: "不播放動態圖檔" highlightSensitiveMedia: "強調敏感標記" verificationEmailSent: "已發送驗證電子郵件。請點擊進入電子郵件中的鏈接完成驗證。" notSet: "未設定" -emailVerified: "已成功驗證您的電郵" +emailVerified: "已成功驗證您的電子郵件地址" noteFavoritesCount: "我的最愛貼文的數目" pageLikesCount: "頁面被按讚次數" pageLikedCount: "頁面被按讚次數" @@ -782,11 +795,11 @@ capacity: "容量" inUse: "已使用" editCode: "編輯代碼" apply: "套用" -receiveAnnouncementFromInstance: "接收由本實例發出的電郵通知" +receiveAnnouncementFromInstance: "接收來自伺服器的通知" emailNotification: "郵件通知" publish: "發布" inChannelSearch: "頻道内搜尋" -useReactionPickerForContextMenu: "點擊右鍵開啟反應工具欄" +useReactionPickerForContextMenu: "點擊右鍵開啟反應選擇器" typingUsers: "{users}輸入中" jumpToSpecifiedDate: "跳轉到特定日期" showingPastTimeline: "顯示過往的時間軸" @@ -843,7 +856,7 @@ previewNoteText: "預覽文本" customCss: "自定義 CSS" customCssWarn: "這個設定必須由具備相關知識的人員操作,不當的設定可能導致客戶端無法正常使用。" global: "全域" -squareAvatars: "頭像以方形顯示" +squareAvatars: "大頭貼以方形顯示" sent: "發送" received: "收取" searchResult: "搜尋結果" @@ -880,8 +893,8 @@ makeReactionsPublicDescription: "將您做過的反應設為公開可見。" classic: "經典" muteThread: "將貼文串設為靜音" unmuteThread: "將貼文串的靜音解除" -ffVisibility: "連繫的可見性" -ffVisibilityDescription: "您可以設定追隨或追隨者資訊的公開範圍" +followingVisibility: "追隨中的可見性" +followersVisibility: "追隨者的可見性" continueThread: "查看更多貼文" deleteAccountConfirm: "將要刪除帳戶。是否確定?" incorrectPassword: "密碼錯誤。" @@ -896,13 +909,13 @@ overridedDeviceKind: "裝置類型" smartphone: "智慧型手機" tablet: "平板" auto: "自動" -themeColor: "主題顏色" +themeColor: "佈景主題顏色" size: "大小" numberOfColumn: "列數" searchByGoogle: "搜尋" -instanceDefaultLightTheme: "實例預設的淺色主題" -instanceDefaultDarkTheme: "實例預設的深色主題" -instanceDefaultThemeDescription: "輸入物件形式的主題代碼" +instanceDefaultLightTheme: "實例預設的淺色佈景主題" +instanceDefaultDarkTheme: "實例預設的深色佈景主題" +instanceDefaultThemeDescription: "輸入物件形式的佈景主題代碼" mutePeriod: "靜音的期限" period: "期限" indefinitely: "無期限" @@ -956,7 +969,7 @@ cannotUploadBecauseExceedsFileSizeLimit: "由於超過了檔案大小的限制 beta: "測試版" enableAutoSensitive: "自動 NSFW 判定" enableAutoSensitiveDescription: "如果可用,它將使用機器學習技術判斷檔案是否需要標記為敏感。即使關閉此功能,也可能會依實例規則而自動啟用。" -activeEmailValidationDescription: "積極驗證使用者的電郵地址,以判斷它是否可以通訊。關閉此選項代表只會檢查地址是否符合格式。" +activeEmailValidationDescription: "主動地驗證使用者的電子郵件地址,以確定是否是一次性地址以及是否可以真正與其進行通訊。關閉時,僅檢查格式是否正確。" navbar: "導覽列" shuffle: "隨機" account: "帳戶" @@ -1034,6 +1047,8 @@ resetPasswordConfirm: "重設密碼?" sensitiveWords: "敏感詞" sensitiveWordsDescription: "將含有設定詞彙的貼文可見性設為發送至首頁。可以用換行來進行複數的設定。" sensitiveWordsDescription2: "空格代表「以及」(AND),斜線包圍關鍵字代表使用正規表達式。" +hiddenTags: "隱藏標籤" +hiddenTagsDescription: "設定的標籤不會在趨勢中顯示,換行可以設定多個標籤。" notesSearchNotAvailable: "無法使用搜尋貼文功能。" license: "授權" unfavoriteConfirm: "要取消收錄我的最愛嗎?" @@ -1046,6 +1061,7 @@ enableChartsForRemoteUser: "生成遠端使用者的圖表" enableChartsForFederatedInstances: "生成遠端伺服器的圖表" showClipButtonInNoteFooter: "新增摘錄按鈕至貼文" reactionsDisplaySize: "反應的顯示尺寸" +limitWidthOfReaction: "限制反應的最大寬度,並縮小顯示尺寸。" noteIdOrUrl: "貼文ID或URL" video: "影片" videos: "影片" @@ -1161,6 +1177,7 @@ tosAndPrivacyPolicy: "服務條款和隱私政策" avatarDecorations: "頭像裝飾" attach: "裝上" detach: "取下" +detachAll: "移除所有裝飾" angle: "角度" flip: "翻轉" showAvatarDecorations: "顯示頭像裝飾" @@ -1172,6 +1189,14 @@ useGroupedNotifications: "分組顯示通知訊息" signupPendingError: "驗證您的電子郵件地址時出現問題。連結可能已過期。" cwNotationRequired: "如果開啟「隱藏內容」,則需要註解說明。" doReaction: "做出反應" +code: "程式碼" +reloadRequiredToApplySettings: "需要重新載入頁面設定才能生效。" +remainingN: "剩餘:{n}" +overwriteContentConfirm: "確定要覆蓋目前的內容嗎?" +seasonalScreenEffect: "隨季節變換畫面的呈現" +decorate: "設置頭像裝飾" +addMfmFunction: "插入MFM功能語法" +enableQuickAddMfmFunction: "顯示高級MFM選擇器" _announcement: forExistingUsers: "僅限既有的使用者" forExistingUsersDescription: "啟用代表僅向現存使用者顯示;停用代表張貼後註冊的新使用者也會看到。" @@ -1208,7 +1233,7 @@ _initialTutorial: skipAreYouSure: "結束教學模式?" _landing: title: "歡迎使用本教學課程" - description: "在這裡您可以查看CherryPick的基本使用方法和功能。" + description: "在這裡您可以查看 CherryPick 的基本使用方法和功能。" _note: title: "什麼是貼文?" description: "在CherryPick上發布的內容稱為「貼文」。貼文在時間軸上按時間順序排列,並即時更新。" @@ -1512,6 +1537,9 @@ _achievements: _setNameToSyuilo: title: "神與您同在" description: "將名稱設定為 syuilo" + _setNameToNoriDev: + title: "神與您同在 (CherryPick)" + description: "將名稱設定為 noridev" _passedSinceAccountCreated1: title: "一週年" description: "帳戶加入時間已超過一年" @@ -1535,7 +1563,7 @@ _achievements: _brainDiver: title: "Brain Driver" description: "發佈一篇含歌曲《Brain Driver》連結的貼文" - flavor: "CherryPick-CherryPick La-Tu-Ma" + flavor: "Misskey-Misskey La-Tu-Ma" _smashTestNotificationButton: title: "過度測試" description: "極短時間內連續測試通知" @@ -1552,7 +1580,9 @@ _role: assignTarget: "指派目標" descriptionOfAssignTarget: "手動是以手動管理這個角色包含的人員。\n符合條件是設定條件以自動包含符合條件的使用者。" manual: "手動" + manualRoles: "手動角色" conditional: "符合條件" + conditionalRoles: "有條件的角色" condition: "條件" isConditionalRole: "這是條件角色。" isPublic: "角色為公開" @@ -1602,6 +1632,7 @@ _role: canHideAds: "不顯示廣告" canSearchNotes: "可否搜尋貼文" canUseTranslator: "使用翻譯功能" + avatarDecorationLimit: "頭像裝飾的最大設置量" _condition: isLocal: "本地使用者" isRemote: "遠端使用者" @@ -1630,6 +1661,7 @@ _emailUnavailable: disposable: "不是永久可用的地址" mx: "郵件伺服器不正確" smtp: "郵件伺服器沒有應答" + banned: "無法使用此電子郵件地址註冊" _ffVisibility: public: "公開" followers: "只有關注您的使用者能看到" @@ -1813,17 +1845,17 @@ _instanceMute: title: "將隱藏被設定的實例貼文。" heading: "將實例靜音" _theme: - explore: "取得佈景主題" + explore: "探索佈景主題" install: "安裝佈景主題" - manage: "佈景主題管理員" - code: "主題代碼" + manage: "管理佈景主題" + code: "佈景主題代碼" description: "描述" installed: "{name}已安裝" - installedThemes: "已經安裝的主題" - builtinThemes: "標準主題" - alreadyInstalled: "此主題已經安裝" - invalid: "主題格式錯誤" - make: "製作主題" + installedThemes: "已經安裝的佈景主題" + builtinThemes: "標準佈景主題" + alreadyInstalled: "已安裝此佈景主題" + invalid: "佈景主題格式錯誤" + make: "製作佈景主題" base: "基於" addConstant: "添加常數" constant: "常數" @@ -1840,7 +1872,7 @@ _theme: darken: "暗度" lighten: "亮度" inputConstantName: "請輸入常數名稱" - importInfo: "您可以在此貼上主題代碼,將其匯入編輯器中" + importInfo: "您可以在此貼上佈景主題代碼,將其匯入編輯器中" deleteConstantConfirm: "確定要刪除常數{const}嗎?" keys: accent: "重點色彩" @@ -1891,6 +1923,14 @@ _sfx: chatBg: "聊天背景" antenna: "天線接收" channel: "頻道通知" + reaction: "選擇反應時" +_soundSettings: + driveFile: "使用雲端硬碟的音效檔案" + driveFileWarn: "請選擇雲端硬碟中的檔案" + driveFileTypeWarn: "不支援此檔案" + driveFileTypeWarnDescription: "請選擇音效檔案" + driveFileDurationWarn: "音效太長了" + driveFileDurationWarnDescription: "使用長音效檔可能會影響 CherryPick 的使用體驗。仍要使用此檔案嗎?" _ago: future: "未來" justNow: "剛剛" @@ -2036,6 +2076,7 @@ _widgets: _userList: chooseList: "選擇清單" clicker: "點擊器" + birthdayFollowings: "今天生日的使用者" _cw: hide: "隱藏" show: "顯示內容" @@ -2045,7 +2086,7 @@ _poll: noOnlyOneChoice: "需要至少兩個選項。" choiceN: "選項 {n}" noMore: "沒辦法再添加選項了" - canMultipleVote: "可以多次投票" + canMultipleVote: "允許複選" expiration: "期限" infinite: "無期限" at: "結束時間" @@ -2054,7 +2095,7 @@ _poll: deadlineTime: "小時" duration: "時長" votesCount: "{n} 票" - totalVotes: "合共 {n} 票" + totalVotes: "一共{n}票" vote: "投票" showResult: "顯示結果" voted: "已投票" @@ -2098,6 +2139,7 @@ _profile: changeAvatar: "更換大頭貼" changeBanner: "變更橫幅圖像" verifiedLinkDescription: "如果輸入包含您個人資料的網站 URL,欄位旁邊將出現驗證圖示。" + avatarDecorationMax: "最多可以設置 {max} 個裝飾。" _exportOrImport: allNotes: "所有貼文" favoritedNotes: "「我的最愛」貼文" @@ -2112,7 +2154,7 @@ _charts: federation: "聯邦宇宙" apRequest: "請求" usersIncDec: "使用者增減" - usersTotal: "使用者合共" + usersTotal: "使用者總數" activeUsers: "活躍使用者" notesIncDec: "貼文増減" localNotesIncDec: "本地貼文増減" @@ -2214,8 +2256,6 @@ _notification: youGotReply: "{name}回覆了您" youGotQuote: "{name}引用了您" youRenoted: "{name} 轉發了你的貼文" - youGotMessagingMessageFromUser: "{name}發送給您的訊息" - youGotMessagingMessageFromGroup: "{name}發送給您的訊息" youWereFollowed: "您有新的追隨者" youReceivedFollowRequest: "您有新的追隨請求" yourFollowRequestAccepted: "您的追隨請求已通過" @@ -2223,6 +2263,7 @@ _notification: pollEnded: "問卷調查已產生結果" newNote: "新的貼文" unreadAntennaNote: "天線 {name}" + roleAssigned: "已授予角色" emptyPushNotificationMessage: "推送通知已更新" achievementEarned: "獲得成就" testNotification: "通知測試" @@ -2245,6 +2286,7 @@ _notification: receiveFollowRequest: "已收到追隨請求" followRequestAccepted: "追隨請求已接受" groupInvited: "加入社群邀請" + roleAssigned: "已授予角色" achievementEarned: "獲得成就" app: "應用程式通知" _actions: @@ -2339,6 +2381,8 @@ _moderationLogTypes: createAvatarDecoration: "建立頭像裝飾" updateAvatarDecoration: "更新頭像裝飾" deleteAvatarDecoration: "刪除頭像裝飾" + unsetUserAvatar: "移除使用者的大頭貼" + unsetUserBanner: "移除使用者的橫幅圖像" _fileViewer: title: "檔案詳細資訊" type: "檔案類型 " @@ -2354,8 +2398,8 @@ _externalResourceInstaller: title: "要安裝此外掛嘛?" metaTitle: "外掛資訊" _theme: - title: "要安裝此外觀主題嘛?" - metaTitle: "外觀主題資訊" + title: "要安裝此佈景主題嗎?" + metaTitle: "佈景主題資訊" _meta: base: "基本配色方案" _vendorInfo: @@ -2383,8 +2427,21 @@ _externalResourceInstaller: title: "外掛安裝失敗" description: "安裝插件時出現問題。請再試一次。請參閱 Javascript 控制台以取得錯誤詳細資訊。" _themeParseFailed: - title: "外觀主題解析錯誤" - description: "已取得資料但解析外觀主題時發生錯誤,導致無法載入。請聯絡主題作者。請檢查 Javascript 控制台以取得錯誤詳細資訊。" + title: "佈景主題解析錯誤" + description: "已取得資料但解析佈景主題時發生錯誤,導致無法載入。請聯絡佈景主題的作者。請檢查 Javascript 控制台以取得錯誤詳細資訊。" _themeInstallFailed: - title: "無法安裝外觀主題" - description: "安裝外觀主題時出現問題。請再試一次。請參閱 Javascript 控制台以取得錯誤詳細資訊。" + title: "無法安裝佈景主題" + description: "安裝佈景主題時出現問題。請再試一次。請參閱 Javascript 控制台以取得錯誤詳細資訊。" +_dataSaver: + _media: + title: "載入媒體檔案" + description: "防止自動載入圖片和影片。點擊隱藏的圖片/影片即可載入。" + _avatar: + title: "大頭貼" + description: "停止顯示大頭貼的動畫。由於動畫圖片的檔案大小可能比普通圖片大,這可以進一步減少資料流量。" + _urlPreview: + title: "網址預覽縮圖" + description: "將不再自動載入網址預覽縮圖。" + _code: + title: "程式碼突出顯示" + description: "如果使用了 MFM 的程式碼突顯標記,則在點擊之前不會載入。程式碼突顯要求加載每種程式語言的突顯定義檔案,但由於這些檔案不再自動載入,因此有望減少資料流量。" diff --git a/package.json b/package.json index e38be7e2d2..f2f8064b67 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "cherrypick", - "version": "4.6.0-beta.2", - "basedMisskeyVersion": "2023.12.0-beta.2", + "version": "4.6.0", + "basedMisskeyVersion": "2023.12.2", "codename": "nasubi", "repository": { "type": "git", "url": "https://github.com/kokonect-link/cherrypick.git" }, - "packageManager": "pnpm@8.10.5", + "packageManager": "pnpm@8.12.1", "workspaces": [ "packages/frontend", "packages/backend", @@ -19,7 +19,7 @@ "build-assets": "node ./scripts/build-assets.mjs", "build": "pnpm build-pre && pnpm -r build && pnpm build-assets", "build-storybook": "pnpm --filter frontend build-storybook", - "build-cherrypick-js-with-types": "pnpm --filter backend build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/cherrypick-js/generator/api.json && pnpm --filter cherrypick-js update-autogen-code && pnpm --filter cherrypick-js build", + "build-cherrypick-js-with-types": "pnpm --filter backend build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/cherrypick-js/generator/api.json && pnpm --filter cherrypick-js update-autogen-code && pnpm --filter cherrypick-js build && pnpm --filter cherrypick-js api", "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", "start:docker": "pnpm check:connect && cd packages/backend && exec node ./built/boot/entry.js", "start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js", @@ -30,7 +30,7 @@ "migrateandstart": "pnpm migrate && pnpm start", "migrateandstart:docker": "pnpm migrate && exec pnpm start:docker", "watch": "pnpm dev", - "dev": "node ./scripts/dev.mjs", + "dev": "node scripts/dev.mjs", "lint": "pnpm -r lint", "cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts", "cy:run": "pnpm cypress run", @@ -50,18 +50,18 @@ }, "dependencies": { "execa": "8.0.1", - "cssnano": "6.0.1", + "cssnano": "6.0.2", "js-yaml": "4.1.0", "postcss": "8.4.32", - "terser": "5.24.0", - "typescript": "5.3.2" + "terser": "5.26.0", + "typescript": "5.3.3" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "6.13.1", - "@typescript-eslint/parser": "6.13.1", + "@typescript-eslint/eslint-plugin": "6.14.0", + "@typescript-eslint/parser": "6.14.0", "cross-env": "7.0.3", - "cypress": "13.6.0", - "eslint": "8.55.0", + "cypress": "13.6.1", + "eslint": "8.56.0", "start-server-and-test": "2.0.3", "ncp": "2.0.0" }, diff --git a/packages/backend/.swcrc b/packages/backend/.swcrc index d9f047b6ac..0504a2d389 100644 --- a/packages/backend/.swcrc +++ b/packages/backend/.swcrc @@ -11,7 +11,7 @@ "decoratorMetadata": true }, "experimental": { - "keepImportAttributes": true + "keepImportAssertions": true }, "baseUrl": "src", "paths": { diff --git a/packages/backend/jest.config.cjs b/packages/backend/jest.config.cjs index 97d777c862..5a4aa4e15a 100644 --- a/packages/backend/jest.config.cjs +++ b/packages/backend/jest.config.cjs @@ -160,7 +160,6 @@ module.exports = { testMatch: [ "/test/unit/**/*.ts", "/src/**/*.test.ts", - "/test/e2e/**/*.ts", ], // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped diff --git a/packages/backend/jest.config.e2e.cjs b/packages/backend/jest.config.e2e.cjs new file mode 100644 index 0000000000..4502da47df --- /dev/null +++ b/packages/backend/jest.config.e2e.cjs @@ -0,0 +1,15 @@ +/* +* For a detailed explanation regarding each configuration property and type check, visit: +* https://jestjs.io/docs/en/configuration.html +*/ + +const base = require('./jest.config.cjs') + +module.exports = { + ...base, + globalSetup: "/built-test/entry.js", + setupFilesAfterEnv: ["/test/jest.setup.ts"], + testMatch: [ + "/test/e2e/**/*.ts", + ], +}; diff --git a/packages/backend/jest.config.unit.cjs b/packages/backend/jest.config.unit.cjs new file mode 100644 index 0000000000..aa5992936b --- /dev/null +++ b/packages/backend/jest.config.unit.cjs @@ -0,0 +1,14 @@ +/* +* For a detailed explanation regarding each configuration property and type check, visit: +* https://jestjs.io/docs/en/configuration.html +*/ + +const base = require('./jest.config.cjs') + +module.exports = { + ...base, + testMatch: [ + "/test/unit/**/*.ts", + "/src/**/*.test.ts", + ], +}; diff --git a/packages/backend/migration/1681429921400-Event.js b/packages/backend/migration/1681429921400-Event.js index 3c9e35c6dc..2cd2657a12 100644 --- a/packages/backend/migration/1681429921400-Event.js +++ b/packages/backend/migration/1681429921400-Event.js @@ -15,7 +15,6 @@ export class Event1681429921400 { await queryRunner.query(`COMMENT ON COLUMN "user"."isRoot" IS 'Whether the User is the root.'`); await queryRunner.query(`COMMENT ON COLUMN "ad"."startsAt" IS 'The expired date of the Ad.'`); await queryRunner.query(`ALTER TABLE "antenna" ALTER COLUMN "lastUsedAt" DROP DEFAULT`); - await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."createdAt" IS 'The created date of the Muting.'`); await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muteeId" IS 'The mutee user ID.'`); await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."muterId" IS 'The muter user ID.'`); await queryRunner.query(`ALTER TABLE "poll" DROP CONSTRAINT "FK_da851e06d0dfe2ef397d8b1bf1b"`); diff --git a/packages/backend/migration/1702718871541-ffVisibility.js b/packages/backend/migration/1702718871541-ffVisibility.js new file mode 100644 index 0000000000..8908a496db --- /dev/null +++ b/packages/backend/migration/1702718871541-ffVisibility.js @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class ffVisibility1702718871541 { + constructor() { + this.name = 'ffVisibility1702718871541'; + } + async up(queryRunner) { + await queryRunner.query(`CREATE TYPE "public"."user_profile_followingvisibility_enum" AS ENUM('public', 'followers', 'private')`); + await queryRunner.query(`CREATE CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followingvisibility_enum") WITH INOUT AS ASSIGNMENT`); + await queryRunner.query(`CREATE TYPE "public"."user_profile_followersVisibility_enum" AS ENUM('public', 'followers', 'private')`); + await queryRunner.query(`CREATE CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followersVisibility_enum") WITH INOUT AS ASSIGNMENT`); + await queryRunner.query(`ALTER TABLE "user_profile" ADD "followingVisibility" "public"."user_profile_followingvisibility_enum" NOT NULL DEFAULT 'public'`); + await queryRunner.query(`ALTER TABLE "user_profile" ADD "followersVisibility" "public"."user_profile_followersVisibility_enum" NOT NULL DEFAULT 'public'`); + await queryRunner.query(`UPDATE "user_profile" SET "followingVisibility" = "ffVisibility"`); + await queryRunner.query(`UPDATE "user_profile" SET "followersVisibility" = "ffVisibility"`); + await queryRunner.query(`DROP CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followersVisibility_enum")`); + await queryRunner.query(`DROP CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followingvisibility_enum")`); + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "ffVisibility"`); + await queryRunner.query(`DROP TYPE "public"."user_profile_ffvisibility_enum"`); + } + async down(queryRunner) { + await queryRunner.query(`CREATE TYPE "public"."user_profile_ffvisibility_enum" AS ENUM('public', 'followers', 'private')`); + await queryRunner.query(`ALTER TABLE "user_profile" ADD "ffVisibility" "public"."user_profile_ffvisibility_enum" NOT NULL DEFAULT 'public'`); + + await queryRunner.query(`CREATE CAST ("public"."user_profile_followingvisibility_enum" AS "public"."user_profile_ffvisibility_enum") WITH INOUT AS ASSIGNMENT`); + await queryRunner.query(`UPDATE "user_profile" SET "ffVisibility" = "followingVisibility"`); + await queryRunner.query(`DROP CAST ("public"."user_profile_followingvisibility_enum" AS "public"."user_profile_ffvisibility_enum")`); + + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "followersVisibility"`); + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "followingVisibility"`); + await queryRunner.query(`DROP TYPE "public"."user_profile_followersVisibility_enum"`); + await queryRunner.query(`DROP TYPE "public"."user_profile_followingvisibility_enum"`); + } +} diff --git a/packages/backend/migration/1703209889304-bannedEmailDomains.js b/packages/backend/migration/1703209889304-bannedEmailDomains.js new file mode 100644 index 0000000000..8d7f09e22e --- /dev/null +++ b/packages/backend/migration/1703209889304-bannedEmailDomains.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class bannedEmailDomains1703209889304 { + constructor() { + this.name = 'bannedEmailDomains1703209889304'; + } + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "bannedEmailDomains" character varying(1024) array NOT NULL DEFAULT '{}'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "bannedEmailDomains"`); + } +} diff --git a/packages/backend/migration/1703658526000-supportTrueMailApi.js b/packages/backend/migration/1703658526000-supportTrueMailApi.js new file mode 100644 index 0000000000..5453dd70f2 --- /dev/null +++ b/packages/backend/migration/1703658526000-supportTrueMailApi.js @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SupportTrueMailApi1703658526000 { + name = 'SupportTrueMailApi1703658526000' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "truemailInstance" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "truemailAuthKey" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "enableTruemailApi" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableTruemailApi"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "truemailInstance"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "truemailAuthKey"`); + } +} diff --git a/packages/backend/migration/1704185628000-note-updated-at2.js b/packages/backend/migration/1704185628000-note-updated-at2.js new file mode 100644 index 0000000000..b3fee061e4 --- /dev/null +++ b/packages/backend/migration/1704185628000-note-updated-at2.js @@ -0,0 +1,20 @@ +export class NoteUpdatedAt1704185628000 { + name = 'NoteUpdatedAt1704185628000' + + async up(queryRunner) { + await queryRunner.query(`SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'note' AND column_name = 'updatedAt'`) + .then(updatedAt => { + if (updatedAt.length > 0) { + return []; + } else { + return [ + queryRunner.query(`ALTER TABLE "note" ADD "updatedAt" TIMESTAMP WITH TIME ZONE`) + ]; + } + }) + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "updatedAt"`); + } +} diff --git a/packages/backend/migration/1704373210054-support-mcaptcha.js b/packages/backend/migration/1704373210054-support-mcaptcha.js new file mode 100644 index 0000000000..e6d36a0371 --- /dev/null +++ b/packages/backend/migration/1704373210054-support-mcaptcha.js @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SupportMcaptcha1704373210054 { + name = 'SupportMcaptcha1704373210054' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "enableMcaptcha" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "mcaptchaSitekey" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "mcaptchaSecretKey" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "mcaptchaInstanceUrl" character varying(1024)`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "mcaptchaInstanceUrl"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "mcaptchaSecretKey"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "mcaptchaSitekey"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableMcaptcha"`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index d3b5254786..65bde7460b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "engines": { - "node": ">=18.16.0" + "node": ">=20.10.0" }, "scripts": { "start": "node ./built/boot/entry.js", @@ -13,17 +13,24 @@ "revert": "pnpm typeorm migration:revert -d ormconfig.js", "check:connect": "node ./check_connect.js", "build": "swc src -d built -D", + "build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc", "watch:swc": "swc src -d built -D -w", "build:tsc": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json", "watch": "node watch.mjs", + "restart": "pnpm build && pnpm start", + "dev": "nodemon -w src -e ts,js,mjs,cjs,json --exec \"cross-env NODE_ENV=development pnpm run restart\"", "typecheck": "tsc --noEmit", "eslint": "eslint --quiet \"src/**/*.ts\"", "lint": "pnpm typecheck && pnpm eslint", - "jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit", - "jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit", + "jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.unit.cjs", + "jest:e2e": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.e2e.cjs", + "jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --config jest.config.unit.cjs", + "jest-and-coverage:e2e": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --config jest.config.e2e.cjs", "jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache", "test": "pnpm jest", + "test:e2e": "pnpm build && pnpm build:test && pnpm jest:e2e", "test-and-coverage": "pnpm jest-and-coverage", + "test-and-coverage:e2e": "pnpm build && pnpm build:test && pnpm jest-and-coverage:e2e", "generate-api-json": "node ./generate_api_json.js", "schema:sync": "pnpm typeorm schema:sync -d ormconfig.js" }, @@ -61,13 +68,13 @@ "dependencies": { "@aws-sdk/client-s3": "3.412.0", "@aws-sdk/lib-storage": "3.412.0", - "@bull-board/api": "5.10.1", - "@bull-board/fastify": "5.10.1", - "@bull-board/ui": "5.10.1", - "@discordapp/twemoji": "14.1.2", - "@fastify/accepts": "4.2.0", + "@bull-board/api": "5.10.2", + "@bull-board/fastify": "5.10.2", + "@bull-board/ui": "5.10.2", + "@discordapp/twemoji": "15.0.2", + "@fastify/accepts": "4.3.0", "@fastify/cookie": "9.2.0", - "@fastify/cors": "8.4.1", + "@fastify/cors": "8.5.0", "@fastify/express": "2.3.0", "@fastify/http-proxy": "9.3.0", "@fastify/multipart": "8.0.0", @@ -75,6 +82,8 @@ "@fastify/view": "8.2.0", "@google-cloud/logging": "^10.5.0", "@google-cloud/translate": "^7.2.1", + "@misskey-dev/sharp-read-bmp": "^1.1.1", + "@misskey-dev/summaly": "^5.0.3", "@nestjs/common": "10.2.10", "@nestjs/core": "10.2.10", "@nestjs/testing": "10.2.10", @@ -84,6 +93,7 @@ "@smithy/node-http-handler": "2.1.10", "@swc/cli": "0.1.63", "@swc/core": "1.3.100", + "@twemoji/parser": "15.0.0", "@vitalets/google-translate-api": "9.2.0", "accepts": "1.3.8", "ajv": "8.12.0", @@ -92,13 +102,13 @@ "bcryptjs": "2.4.3", "blurhash": "2.0.5", "body-parser": "1.20.2", - "bullmq": "4.14.4", + "bullmq": "4.15.4", "cacheable-lookup": "7.0.0", "cbor": "9.0.1", "chalk": "5.3.0", "chalk-template": "1.1.0", "cherrypick-js": "workspace:*", - "cherrypick-mfm-js": "github:kokonect-link/mfm.js", + "cherrypick-mfm-js": "0.24.0-cherrypick.4", "chokidar": "3.5.3", "cli-highlight": "2.1.11", "color-convert": "2.0.1", @@ -111,7 +121,7 @@ "file-type": "18.7.0", "fluent-ffmpeg": "2.1.2", "form-data": "4.0.0", - "got": "13.0.0", + "got": "14.0.0", "happy-dom": "10.0.3", "hpagent": "1.2.0", "http-link-header": "1.1.1", @@ -122,10 +132,10 @@ "js-yaml": "4.1.0", "jsdom": "23.0.1", "json5": "2.2.3", - "jsonld": "8.3.1", + "jsonld": "8.3.2", "jsrsasign": "10.9.0", "meilisearch": "0.36.0", - "microformats-parser": "1.5.2", + "microformats-parser": "2.0.2", "mime-types": "2.1.35", "ms": "3.0.0-canary.1", "nanoid": "5.0.4", @@ -137,7 +147,7 @@ "oauth2orize": "1.12.0", "oauth2orize-pkce": "0.1.2", "os-utils": "0.0.14", - "otpauth": "9.2.0", + "otpauth": "9.2.1", "parse5": "7.1.2", "pg": "8.11.3", "pkce-challenge": "4.0.1", @@ -151,35 +161,34 @@ "ratelimiter": "3.4.1", "re2": "1.20.9", "redis-lock": "0.1.4", - "reflect-metadata": "0.1.13", + "reflect-metadata": "0.1.14", "rename": "1.0.4", "rss-parser": "3.13.0", "rxjs": "7.8.1", "sanitize-html": "2.11.0", "secure-json-parse": "2.7.0", "sharp": "0.32.6", - "sharp-read-bmp": "github:misskey-dev/sharp-read-bmp", "slacc": "0.0.10", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", "strip-ansi": "^7.1.0", - "summaly": "github:misskey-dev/summaly", "systeminformation": "5.21.20", "tinycolor2": "1.6.0", "tmp": "0.2.1", "tsc-alias": "1.8.8", "tsconfig-paths": "4.2.0", - "twemoji-parser": "14.0.0", "typeorm": "0.3.17", - "typescript": "5.3.2", + "typescript": "5.3.3", "ulid": "2.3.0", "vary": "1.1.2", "web-push": "3.6.6", - "ws": "8.14.2", + "ws": "8.15.1", "xev": "3.0.2" }, "devDependencies": { "@jest/globals": "29.7.0", + "@misskey-dev/eslint-plugin": "^1.0.0", + "@nestjs/platform-express": "^10.3.0", "@simplewebauthn/typescript-types": "8.3.4", "@swc/jest": "0.2.29", "@types/accepts": "1.3.7", @@ -191,14 +200,14 @@ "@types/content-disposition": "0.5.8", "@types/fluent-ffmpeg": "2.1.24", "@types/http-link-header": "1.0.5", - "@types/jest": "29.5.10", + "@types/jest": "29.5.11", "@types/js-yaml": "4.0.9", "@types/jsdom": "21.1.6", "@types/jsonld": "1.5.13", "@types/jsrsasign": "10.5.12", "@types/mime-types": "2.1.4", "@types/ms": "0.7.34", - "@types/node": "20.10.3", + "@types/node": "20.10.5", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.14", "@types/oauth": "0.9.4", @@ -221,15 +230,18 @@ "@types/vary": "1.1.3", "@types/web-push": "3.6.3", "@types/ws": "8.5.10", - "@typescript-eslint/eslint-plugin": "6.13.1", - "@typescript-eslint/parser": "6.13.1", + "@typescript-eslint/eslint-plugin": "6.14.0", + "@typescript-eslint/parser": "6.14.0", "aws-sdk-client-mock": "3.0.0", "cross-env": "7.0.3", - "eslint": "8.55.0", - "eslint-plugin-import": "2.29.0", + "eslint": "8.56.0", + "eslint-plugin-import": "2.29.1", "execa": "8.0.1", + "fkill": "^9.0.0", "jest": "29.7.0", "jest-mock": "29.7.0", + "nodemon": "3.0.2", + "pid-port": "^1.0.0", "simple-oauth2": "5.0.0" } } diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts index 82726e034e..4915d22659 100644 --- a/packages/backend/src/GlobalModule.ts +++ b/packages/backend/src/GlobalModule.ts @@ -3,7 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { setTimeout } from 'node:timers/promises'; import process from 'node:process'; import { Global, Inject, Module } from '@nestjs/common'; import * as Redis from 'ioredis'; @@ -14,6 +13,7 @@ import { DI } from './di-symbols.js'; import { Config, loadConfig } from './config.js'; import { createPostgresDataSource } from './postgres.js'; import { RepositoryModule } from './models/RepositoryModule.js'; +import { allSettled } from './misc/promise-tracker.js'; import type { Provider, OnApplicationShutdown } from '@nestjs/common'; const $config: Provider = { @@ -35,7 +35,7 @@ const $meilisearch: Provider = { useFactory: (config: Config) => { if (config.meilisearch) { return new MeiliSearch({ - host: `${config.meilisearch.ssl ? 'https' : 'http' }://${config.meilisearch.host}:${config.meilisearch.port}`, + host: `${config.meilisearch.ssl ? 'https' : 'http'}://${config.meilisearch.host}:${config.meilisearch.port}`, apiKey: config.meilisearch.apiKey, }); } else { @@ -94,11 +94,23 @@ const $redisForTimelines: Provider = { inject: [DI.config], }; +const $redisForJobQueue: Provider = { + provide: DI.redisForJobQueue, + useFactory: (config: Config) => { + return new Redis.Redis({ + ...config.redisForJobQueue, + maxRetriesPerRequest: null, + keyPrefix: undefined, + }); + }, + inject: [DI.config], +}; + @Global() @Module({ imports: [RepositoryModule], - providers: [$config, $db, $meilisearch, $cloudLogging, $redis, $redisForPub, $redisForSub, $redisForTimelines], - exports: [$config, $db, $meilisearch, $cloudLogging, $redis, $redisForPub, $redisForSub, $redisForTimelines, RepositoryModule], + providers: [$config, $db, $meilisearch, $cloudLogging, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForJobQueue], + exports: [$config, $db, $meilisearch, $cloudLogging, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForJobQueue, RepositoryModule], }) export class GlobalModule implements OnApplicationShutdown { constructor( @@ -107,23 +119,20 @@ export class GlobalModule implements OnApplicationShutdown { @Inject(DI.redisForPub) private redisForPub: Redis.Redis, @Inject(DI.redisForSub) private redisForSub: Redis.Redis, @Inject(DI.redisForTimelines) private redisForTimelines: Redis.Redis, - ) {} + @Inject(DI.redisForJobQueue) private redisForJobQueue: Redis.Redis, + ) { } public async dispose(): Promise { - if (process.env.NODE_ENV === 'test') { - // XXX: - // Shutting down the existing connections causes errors on Jest as - // Misskey has asynchronous postgres/redis connections that are not - // awaited. - // Let's wait for some random time for them to finish. - await setTimeout(5000); - } + // Wait for all potential DB queries + await allSettled(); + // And then disconnect from DB await Promise.all([ this.db.destroy(), this.redisClient.disconnect(), this.redisForPub.disconnect(), this.redisForSub.disconnect(), this.redisForTimelines.disconnect(), + this.redisForJobQueue.disconnect(), ]); } diff --git a/packages/backend/src/core/AchievementService.ts b/packages/backend/src/core/AchievementService.ts index aa1546a90d..b1abdb7d45 100644 --- a/packages/backend/src/core/AchievementService.ts +++ b/packages/backend/src/core/AchievementService.ts @@ -83,10 +83,13 @@ export const ACHIEVEMENT_TYPES = [ 'clickedClickHere', 'justPlainLucky', 'setNameToSyuilo', + 'setNameToNoriDev', 'cookieClicked', 'brainDiver', 'smashTestNotificationButton', 'tutorialCompleted', + 'bubbleGameExplodingHead', + 'bubbleGameDoubleExplodingHead', ] as const; @Injectable() diff --git a/packages/backend/src/core/AvatarDecorationService.ts b/packages/backend/src/core/AvatarDecorationService.ts index 6ad546f4f7..06849ede1a 100644 --- a/packages/backend/src/core/AvatarDecorationService.ts +++ b/packages/backend/src/core/AvatarDecorationService.ts @@ -158,7 +158,7 @@ export class AvatarDecorationService implements OnApplicationShutdown { let name; let description; for (const decoration of allDecorations) { - if (decoration.id == avatarDecorationId) { + if (decoration.id === avatarDecorationId) { name = decoration.name; description = decoration.description; break; @@ -189,9 +189,9 @@ export class AvatarDecorationService implements OnApplicationShutdown { id: findDecoration?.id ?? '', angle: avatarDecorations.angle ?? 0, flipH: avatarDecorations.flipH ?? false, + offsetX: avatarDecorations.offsetX ?? 0, + offsetY: avatarDecorations.offsetY ?? 0, scale: avatarDecorations.scale ?? 1, - moveX: avatarDecorations.moveX ?? 0, - moveY: avatarDecorations.moveY ?? 0, opacity: avatarDecorations.opacity ?? 1, }]; await this.usersRepository.update({ id: user.id }, updates); diff --git a/packages/backend/src/core/CaptchaService.ts b/packages/backend/src/core/CaptchaService.ts index c5c55af269..04f5829317 100644 --- a/packages/backend/src/core/CaptchaService.ts +++ b/packages/backend/src/core/CaptchaService.ts @@ -73,6 +73,37 @@ export class CaptchaService { } } + // https://codeberg.org/Gusted/mCaptcha/src/branch/main/mcaptcha.go + @bindThis + public async verifyMcaptcha(secret: string, siteKey: string, instanceHost: string, response: string | null | undefined): Promise { + if (response == null) { + throw new Error('mcaptcha-failed: no response provided'); + } + + const endpointUrl = new URL('/api/v1/pow/siteverify', instanceHost); + const result = await this.httpRequestService.send(endpointUrl.toString(), { + method: 'POST', + body: JSON.stringify({ + key: siteKey, + secret: secret, + token: response, + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (result.status !== 200) { + throw new Error('mcaptcha-failed: mcaptcha didn\'t return 200 OK'); + } + + const resp = (await result.json()) as { valid: boolean }; + + if (!resp.valid) { + throw new Error('mcaptcha-request-failed'); + } + } + @bindThis public async verifyTurnstile(secret: string, response: string | null | undefined): Promise { if (response == null) { diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts index aa7e135469..868f40e384 100644 --- a/packages/backend/src/core/DriveService.ts +++ b/packages/backend/src/core/DriveService.ts @@ -7,7 +7,7 @@ import { randomUUID } from 'node:crypto'; import * as fs from 'node:fs'; import { Inject, Injectable } from '@nestjs/common'; import sharp from 'sharp'; -import { sharpBmp } from 'sharp-read-bmp'; +import { sharpBmp } from '@misskey-dev/sharp-read-bmp'; import { IsNull } from 'typeorm'; import { DeleteObjectCommandInput, PutObjectCommandInput, NoSuchKey } from '@aws-sdk/client-s3'; import { DI } from '@/di-symbols.js'; @@ -669,7 +669,7 @@ export class DriveService { public async updateFile(file: MiDriveFile, values: Partial, updater: MiUser) { const alwaysMarkNsfw = (await this.roleService.getUserPolicies(file.userId)).alwaysMarkNsfw; - if (values.name && !this.driveFileEntityService.validateFileName(file.name)) { + if (values.name != null && !this.driveFileEntityService.validateFileName(values.name)) { throw new DriveService.InvalidFileNameError(); } diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index 55a6d955df..437abcbed0 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -3,12 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { URLSearchParams } from 'node:url'; import * as nodemailer from 'nodemailer'; import { Inject, Injectable } from '@nestjs/common'; import { validate as validateEmail } from 'deep-email-validator'; -import { SubOutputFormat } from 'deep-email-validator/dist/output/output.js'; import { MetaService } from '@/core/MetaService.js'; +import { UtilityService } from '@/core/UtilityService.js'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import type Logger from '@/logger.js'; @@ -30,6 +29,7 @@ export class EmailService { private metaService: MetaService, private loggerService: LoggerService, + private utilityService: UtilityService, private httpRequestService: HttpRequestService, ) { this.logger = this.loggerService.getLogger('email'); @@ -155,7 +155,7 @@ export class EmailService { @bindThis public async validateEmailForAccount(emailAddress: string): Promise<{ available: boolean; - reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp'; + reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist'; }> { const meta = await this.metaService.fetch(); @@ -164,36 +164,46 @@ export class EmailService { email: emailAddress, }); - const verifymailApi = meta.enableVerifymailApi && meta.verifymailAuthKey != null; - let validated; + let validated: { + valid: boolean, + reason?: string | null, + }; - if (meta.enableActiveEmailValidation && meta.verifymailAuthKey) { - if (verifymailApi) { + if (meta.enableActiveEmailValidation) { + if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) { validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey); + } else if (meta.enableTruemailApi && meta.truemailInstance && meta.truemailAuthKey != null) { + validated = await this.trueMail(meta.truemailInstance, emailAddress, meta.truemailAuthKey); } else { - validated = meta.enableActiveEmailValidation ? await validateEmail({ + validated = await validateEmail({ email: emailAddress, validateRegex: true, validateMx: true, validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので validateDisposable: true, // 捨てアドかどうかチェック validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので - }) : { valid: true, reason: null }; + }); } } else { validated = { valid: true, reason: null }; } - const available = exist === 0 && validated.valid; + const emailDomain: string = emailAddress.split('@')[1]; + const isBanned = this.utilityService.isBlockedHost(meta.bannedEmailDomains, emailDomain); + + const available = exist === 0 && validated.valid && !isBanned; return { available, reason: available ? null : exist !== 0 ? 'used' : + isBanned ? 'banned' : validated.reason === 'regex' ? 'format' : validated.reason === 'disposable' ? 'disposable' : validated.reason === 'mx' ? 'mx' : validated.reason === 'smtp' ? 'smtp' : + validated.reason === 'network' ? 'network' : + validated.reason === 'blacklist' ? 'blacklist' : null, }; } @@ -258,4 +268,67 @@ export class EmailService { reason: null, }; } + + private async trueMail(truemailInstance: string, emailAddress: string, truemailAuthKey: string): Promise<{ + valid: boolean; + reason: 'used' | 'format' | 'blacklist' | 'mx' | 'smtp' | 'network' | T | null; + }> { + const endpoint = truemailInstance + '?email=' + emailAddress; + try { + const res = await this.httpRequestService.send(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + Authorization: truemailAuthKey, + }, + }); + + const json = (await res.json()) as { + email: string; + success: boolean; + errors?: { + list_match?: string; + regex?: string; + mx?: string; + smtp?: string; + } | null; + }; + + if (json.email === undefined || (json.email !== undefined && json.errors?.regex)) { + return { + valid: false, + reason: 'format', + }; + } + if (json.errors?.smtp) { + return { + valid: false, + reason: 'smtp', + }; + } + if (json.errors?.mx) { + return { + valid: false, + reason: 'mx', + }; + } + if (!json.success) { + return { + valid: false, + reason: json.errors?.list_match as T || 'blacklist', + }; + } + + return { + valid: true, + reason: null, + }; + } catch (error) { + return { + valid: false, + reason: 'network', + }; + } + } } diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts index b2c279a5a1..b25d058cc1 100644 --- a/packages/backend/src/core/FanoutTimelineEndpointService.ts +++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts @@ -28,6 +28,7 @@ type TimelineOptions = { redisTimelines: FanoutTimelineName[], noteFilter?: (note: MiNote) => boolean, alwaysIncludeMyNotes?: boolean; + ignoreAuthorFromBlock?: boolean; ignoreAuthorFromMute?: boolean; excludeNoFiles?: boolean; excludeReplies?: boolean; @@ -61,11 +62,15 @@ export class FanoutTimelineEndpointService { // 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]); + const shouldPrepend = ps.sinceId && !ps.untilId; + const idCompare: (a: string, b: string) => number = shouldPrepend ? (a, b) => a < b ? -1 : 1 : (a, b) => a > b ? -1 : 1; + const redisResult = await this.fanoutTimelineService.getMulti(ps.redisTimelines, ps.untilId, ps.sinceId); + // TODO: いい感じにgetMulti内でソート済だからuniqするときにredisResultが全てソート済なのを利用して再ソートを避けたい const redisResultIds = Array.from(new Set(redisResult.flat(1))); - redisResultIds.sort((a, b) => a > b ? -1 : 1); + redisResultIds.sort(idCompare); noteIds = redisResultIds.slice(0, ps.limit); shouldFallbackToDb = shouldFallbackToDb || (noteIds.length === 0); @@ -115,7 +120,7 @@ export class FanoutTimelineEndpointService { const parentFilter = filter; filter = (note) => { - if (isUserRelated(note, userIdsWhoBlockingMe, ps.ignoreAuthorFromMute)) return false; + if (isUserRelated(note, userIdsWhoBlockingMe, ps.ignoreAuthorFromBlock)) return false; if (isUserRelated(note, userIdsWhoMeMuting, ps.ignoreAuthorFromMute)) return false; if (isPureRenote(note) && isUserRelated(note, userIdsWhoMeMutingRenotes, ps.ignoreAuthorFromMute)) return false; if (isInstanceMuted(note, userMutedInstances)) return false; @@ -132,32 +137,43 @@ export class FanoutTimelineEndpointService { const remainingToRead = ps.limit - redisTimeline.length; // DBからの取り直しを減らす初回と同じ割合以上で成功すると仮定するが、クエリの長さを考えて三倍まで - const countToGet = remainingToRead * Math.ceil(Math.min(1.1 / lastSuccessfulRate, 3)); + const countToGet = Math.ceil(remainingToRead * Math.min(1.1 / lastSuccessfulRate, 3)); noteIds = redisResultIds.slice(readFromRedis, readFromRedis + countToGet); readFromRedis += noteIds.length; - const gotFromDb = await this.getAndFilterFromDb(noteIds, filter); + const gotFromDb = await this.getAndFilterFromDb(noteIds, filter, idCompare); redisTimeline.push(...gotFromDb); lastSuccessfulRate = gotFromDb.length / noteIds.length; if (ps.allowPartial ? redisTimeline.length !== 0 : redisTimeline.length >= ps.limit) { // 十分Redisからとれた - return redisTimeline.slice(0, ps.limit); + const result = redisTimeline.slice(0, ps.limit); + if (shouldPrepend) result.reverse(); + return result; } } // まだ足りない分はDBにフォールバック const remainingToRead = ps.limit - redisTimeline.length; - const gotFromDb = await ps.dbFallback(noteIds[noteIds.length - 1], ps.sinceId, remainingToRead); - redisTimeline.push(...gotFromDb); - return redisTimeline; + let dbUntil: string | null; + let dbSince: string | null; + if (shouldPrepend) { + redisTimeline.reverse(); + dbUntil = ps.untilId; + dbSince = noteIds[noteIds.length - 1]; + } else { + dbUntil = noteIds[noteIds.length - 1]; + dbSince = ps.sinceId; + } + const gotFromDb = await ps.dbFallback(dbUntil, dbSince, remainingToRead); + return shouldPrepend ? [...gotFromDb, ...redisTimeline] : [...redisTimeline, ...gotFromDb]; } return await ps.dbFallback(ps.untilId, ps.sinceId, ps.limit); } - private async getAndFilterFromDb(noteIds: string[], noteFilter: (note: MiNote) => boolean): Promise { + private async getAndFilterFromDb(noteIds: string[], noteFilter: (note: MiNote) => boolean, idCompare: (a: string, b: string) => number): Promise { const query = this.notesRepository.createQueryBuilder('note') .where('note.id IN (:...noteIds)', { noteIds: noteIds }) .innerJoinAndSelect('note.user', 'user') @@ -169,7 +185,7 @@ export class FanoutTimelineEndpointService { const notes = (await query.getMany()).filter(noteFilter); - notes.sort((a, b) => a.id > b.id ? -1 : 1); + notes.sort((a, b) => idCompare(a.id, b.id)); return notes; } diff --git a/packages/backend/src/core/FeaturedService.ts b/packages/backend/src/core/FeaturedService.ts index a6fbb0a927..ff45a601c7 100644 --- a/packages/backend/src/core/FeaturedService.ts +++ b/packages/backend/src/core/FeaturedService.ts @@ -77,6 +77,17 @@ export class FeaturedService { return Array.from(ranking.keys()); } + @bindThis + private async removeFromRanking(name: string, windowRange: number, element: string): Promise { + const currentWindow = this.getCurrentWindow(windowRange); + const previousWindow = currentWindow - 1; + + const redisPipeline = this.redisClient.pipeline(); + redisPipeline.zrem(`${name}:${currentWindow}`, element); + redisPipeline.zrem(`${name}:${previousWindow}`, element); + await redisPipeline.exec(); + } + @bindThis public updateGlobalNotesRanking(noteId: MiNote['id'], score = 1): Promise { return this.updateRankingOf('featuredGlobalNotesRanking', GLOBAL_NOTES_RANKING_WINDOW, noteId, score); @@ -126,4 +137,9 @@ export class FeaturedService { public getHashtagsRanking(threshold: number): Promise { return this.getRankingOf('featuredHashtagsRanking', HASHTAG_RANKING_WINDOW, threshold); } + + @bindThis + public removeHashtagsFromRanking(hashtag: string): Promise { + return this.removeFromRanking('featuredHashtagsRanking', HASHTAG_RANKING_WINDOW, hashtag); + } } diff --git a/packages/backend/src/core/HashtagService.ts b/packages/backend/src/core/HashtagService.ts index 061339ebed..c1c573c543 100644 --- a/packages/backend/src/core/HashtagService.ts +++ b/packages/backend/src/core/HashtagService.ts @@ -15,6 +15,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import { FeaturedService } from '@/core/FeaturedService.js'; import { MetaService } from '@/core/MetaService.js'; +import { UtilityService } from '@/core/UtilityService.js'; @Injectable() export class HashtagService { @@ -29,6 +30,7 @@ export class HashtagService { private featuredService: FeaturedService, private idService: IdService, private metaService: MetaService, + private utilityService: UtilityService, ) { } @@ -161,6 +163,7 @@ export class HashtagService { const instance = await this.metaService.fetch(); const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t)); if (hiddenTags.includes(hashtag)) return; + if (this.utilityService.isSensitiveWordIncluded(hashtag, instance.sensitiveWords)) return; // YYYYMMDDHHmm (10分間隔) const now = new Date(); diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index 082b3956b9..05d708aa5a 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -150,11 +150,14 @@ export class HttpRequestService { controller.abort(); }, timeout); - const res = await fetch(url, { + const bearcaps = url.startsWith('bear:?') ? this.parseBearcaps(url) : undefined; + + const res = await fetch(bearcaps?.url ?? url, { method: args.method ?? 'GET', headers: { 'User-Agent': this.config.userAgent, ...(args.headers ?? {}), + ...(bearcaps?.token ? { Authorization: `Bearer ${bearcaps.token}` } : {}), }, body: args.body, size: args.size ?? 10 * 1024 * 1024, @@ -168,4 +171,17 @@ export class HttpRequestService { return res; } + + // Bearcaps https://docs.joinmastodon.org/spec/bearcaps/ + // bear:?t=&u=https://example.com/foo' + // -> GET https://example.com/foo Authorization: Bearer + private parseBearcaps(url: string): { url: string, token: string | undefined } | undefined { + const params = new URLSearchParams(url.split('?')[1]); + if (!params.has('u')) return undefined; + + return { + url: params.get('u')!, + token: params.get('t') ?? undefined, + }; + } } diff --git a/packages/backend/src/core/MetaService.ts b/packages/backend/src/core/MetaService.ts index c6aa4732f3..464c53e1f2 100644 --- a/packages/backend/src/core/MetaService.ts +++ b/packages/backend/src/core/MetaService.ts @@ -11,6 +11,7 @@ import { MiMeta } from '@/models/Meta.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { bindThis } from '@/decorators.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; +import { FeaturedService } from '@/core/FeaturedService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; @Injectable() @@ -25,6 +26,7 @@ export class MetaService implements OnApplicationShutdown { @Inject(DI.db) private db: DataSource, + private featuredService: FeaturedService, private globalEventService: GlobalEventService, ) { //this.onMessage = this.onMessage.bind(this); @@ -95,6 +97,8 @@ export class MetaService implements OnApplicationShutdown { @bindThis public async update(data: Partial): Promise { + let before: MiMeta | undefined; + const updated = await this.db.transaction(async transactionalEntityManager => { const metas = await transactionalEntityManager.find(MiMeta, { order: { @@ -102,10 +106,10 @@ export class MetaService implements OnApplicationShutdown { }, }); - const meta = metas[0]; + before = metas[0]; - if (meta) { - await transactionalEntityManager.update(MiMeta, meta.id, data); + if (before) { + await transactionalEntityManager.update(MiMeta, before.id, data); const metas = await transactionalEntityManager.find(MiMeta, { order: { @@ -119,6 +123,21 @@ export class MetaService implements OnApplicationShutdown { } }); + if (data.hiddenTags) { + process.nextTick(() => { + const hiddenTags = new Set(data.hiddenTags); + if (before) { + for (const previousHiddenTag of before.hiddenTags) { + hiddenTags.delete(previousHiddenTag); + } + } + + for (const hiddenTag of hiddenTags) { + this.featuredService.removeHashtagsFromRanking(hiddenTag); + } + }); + } + this.globalEventService.publishInternalEvent('metaUpdated', updated); return updated; diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index bd04e9e422..cc2ecbea02 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -14,7 +14,8 @@ import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mf import { extractHashtags } from '@/misc/extract-hashtags.js'; import type { IMentionedRemoteUsers } from '@/models/Note.js'; import { MiNote } from '@/models/Note.js'; -import { MiEvent, IEvent } from '@/models/Event.js'; +import { MiEvent } from '@/models/Event.js'; +import type { IEvent } from '@/models/Event.js'; import type { ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; import type { MiDriveFile } from '@/models/DriveFile.js'; import type { MiApp } from '@/models/App.js'; @@ -59,6 +60,7 @@ import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { UtilityService } from '@/core/UtilityService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js'; import { isReply } from '@/misc/is-reply.js'; +import { trackPromise } from '@/misc/promise-tracker.js'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; @@ -258,7 +260,7 @@ export class NoteCreateService implements OnApplicationShutdown { if (data.visibility === 'public' && data.channel == null) { const sensitiveWords = meta.sensitiveWords; - if (this.isSensitive(data, sensitiveWords)) { + if (this.utilityService.isSensitiveWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) { data.visibility = 'home'; } else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) { data.visibility = 'home'; @@ -298,7 +300,7 @@ export class NoteCreateService implements OnApplicationShutdown { } // Check blocking - if (data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0)) { + if (data.renote && !this.isQuote(data)) { if (data.renote.userHost === null) { if (data.renote.userId !== user.id) { const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id); @@ -646,7 +648,7 @@ export class NoteCreateService implements OnApplicationShutdown { // If it is renote if (data.renote) { - const type = data.text ? 'quote' : 'renote'; + const type = this.isQuote(data) ? 'quote' : 'renote'; // Notify if (data.renote.userHost === null) { @@ -700,7 +702,7 @@ export class NoteCreateService implements OnApplicationShutdown { this.relayService.deliverToRelays(user, noteActivity); } - dm.execute(); + trackPromise(dm.execute()); })(); } //#endregion @@ -729,28 +731,9 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - private isSensitive(note: Option, sensitiveWord: string[]): boolean { - if (sensitiveWord.length > 0) { - const text = note.cw ?? note.text ?? ''; - if (text === '') return false; - const matched = sensitiveWord.some(filter => { - // represents RegExp - const regexp = filter.match(/^\/(.+)\/(.*)$/); - // This should never happen due to input sanitisation. - if (!regexp) { - const words = filter.split(' '); - return words.every(keyword => text.includes(keyword)); - } - try { - return new RE2(regexp[1], regexp[2]).test(text); - } catch (err) { - // This should never happen due to input sanitisation. - return false; - } - }); - if (matched) return true; - } - return false; + private isQuote(note: Option): note is Option & { renote: MiNote } { + // sync with misc/is-quote.ts + return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll); } @bindThis @@ -818,7 +801,7 @@ export class NoteCreateService implements OnApplicationShutdown { private async renderNoteOrRenoteActivity(data: Option, note: MiNote) { if (data.localOnly) return null; - const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0) + const content = data.renote && !this.isQuote(data) ? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note) : this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note); @@ -930,6 +913,7 @@ export class NoteCreateService implements OnApplicationShutdown { // ダイレクトのとき、そのリストが対象外のユーザーの場合 if ( note.visibility === 'specified' && + note.userId !== userListMembership.userListUserId && !note.visibleUserIds.some(v => v === userListMembership.userListUserId) ) continue; diff --git a/packages/backend/src/core/NoteReadService.ts b/packages/backend/src/core/NoteReadService.ts index 15f23f0090..f1414aab59 100644 --- a/packages/backend/src/core/NoteReadService.ts +++ b/packages/backend/src/core/NoteReadService.ts @@ -14,6 +14,7 @@ import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import type { NoteUnreadsRepository, MutingsRepository, NoteThreadMutingsRepository } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; +import { trackPromise } from '@/misc/promise-tracker.js'; @Injectable() export class NoteReadService implements OnApplicationShutdown { @@ -107,7 +108,7 @@ export class NoteReadService implements OnApplicationShutdown { // TODO: ↓まとめてクエリしたい - this.noteUnreadsRepository.countBy({ + trackPromise(this.noteUnreadsRepository.countBy({ userId: userId, isMentioned: true, }).then(mentionsCount => { @@ -115,9 +116,9 @@ export class NoteReadService implements OnApplicationShutdown { // 全て既読になったイベントを発行 this.globalEventService.publishMainStream(userId, 'readAllUnreadMentions'); } - }); + })); - this.noteUnreadsRepository.countBy({ + trackPromise(this.noteUnreadsRepository.countBy({ userId: userId, isSpecified: true, }).then(specifiedCount => { @@ -125,7 +126,7 @@ export class NoteReadService implements OnApplicationShutdown { // 全て既読になったイベントを発行 this.globalEventService.publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); } - }); + })); } } diff --git a/packages/backend/src/core/NoteUpdateService.ts b/packages/backend/src/core/NoteUpdateService.ts index 418e5bb292..217c40aa46 100644 --- a/packages/backend/src/core/NoteUpdateService.ts +++ b/packages/backend/src/core/NoteUpdateService.ts @@ -220,7 +220,8 @@ export class NoteUpdateService implements OnApplicationShutdown { //#region AP deliver if (this.userEntityService.isLocalUser(user)) { await (async () => { - // @ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error const noteActivity = await this.renderNoteActivity(note, user); await this.deliverToConcerned(user, note, noteActivity); diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts index 41a9ce2d6e..b6d0ef5e27 100644 --- a/packages/backend/src/core/NotificationService.ts +++ b/packages/backend/src/core/NotificationService.ts @@ -20,6 +20,7 @@ import { CacheService } from '@/core/CacheService.js'; import type { Config } from '@/config.js'; import { UserListService } from '@/core/UserListService.js'; import type { FilterUnionByProperty } from '@/types.js'; +import { trackPromise } from '@/misc/promise-tracker.js'; @Injectable() export class NotificationService implements OnApplicationShutdown { @@ -74,7 +75,18 @@ export class NotificationService implements OnApplicationShutdown { } @bindThis - public async createNotification( + public createNotification( + notifieeId: MiUser['id'], + type: T, + data: Omit, 'type' | 'id' | 'createdAt' | 'notifierId'>, + notifierId?: MiUser['id'] | null, + ) { + trackPromise( + this.#createNotificationInternal(notifieeId, type, data, notifierId), + ); + } + + async #createNotificationInternal( notifieeId: MiUser['id'], type: T, data: Omit, 'type' | 'id' | 'createdAt' | 'notifierId'>, diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts index 7d96c9e112..640169960b 100644 --- a/packages/backend/src/core/QueueModule.ts +++ b/packages/backend/src/core/QueueModule.ts @@ -3,12 +3,13 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { setTimeout } from 'node:timers/promises'; import { Inject, Module, OnApplicationShutdown } from '@nestjs/common'; import * as Bull from 'bullmq'; +import * as Redis from 'ioredis'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { QUEUE, baseQueueOptions } from '@/queue/const.js'; +import { allSettled } from '@/misc/promise-tracker.js'; import type { Provider } from '@nestjs/common'; import type { DeliverJobData, InboxJobData, EndedPollNotificationJobData, WebhookDeliverJobData, RelationshipJobData } from '../queue/types.js'; @@ -23,50 +24,50 @@ export type WebhookDeliverQueue = Bull.Queue; const $system: Provider = { provide: 'queue:system', - useFactory: (config: Config) => new Bull.Queue(QUEUE.SYSTEM, baseQueueOptions(config, QUEUE.SYSTEM)), - inject: [DI.config], + useFactory: (config: Config, redisForJobQueue: Redis.Redis) => new Bull.Queue(QUEUE.SYSTEM, baseQueueOptions(config, QUEUE.SYSTEM, redisForJobQueue)), + inject: [DI.config, DI.redisForJobQueue], }; const $endedPollNotification: Provider = { provide: 'queue:endedPollNotification', - useFactory: (config: Config) => new Bull.Queue(QUEUE.ENDED_POLL_NOTIFICATION, baseQueueOptions(config, QUEUE.ENDED_POLL_NOTIFICATION)), - inject: [DI.config], + useFactory: (config: Config, redisForJobQueue: Redis.Redis) => new Bull.Queue(QUEUE.ENDED_POLL_NOTIFICATION, baseQueueOptions(config, QUEUE.ENDED_POLL_NOTIFICATION, redisForJobQueue)), + inject: [DI.config, DI.redisForJobQueue], }; const $deliver: Provider = { provide: 'queue:deliver', - useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)), - inject: [DI.config], + useFactory: (config: Config, redisForJobQueue: Redis.Redis) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER, redisForJobQueue)), + inject: [DI.config, DI.redisForJobQueue], }; const $inbox: Provider = { provide: 'queue:inbox', - useFactory: (config: Config) => new Bull.Queue(QUEUE.INBOX, baseQueueOptions(config, QUEUE.INBOX)), - inject: [DI.config], + useFactory: (config: Config, redisForJobQueue: Redis.Redis) => new Bull.Queue(QUEUE.INBOX, baseQueueOptions(config, QUEUE.INBOX, redisForJobQueue)), + inject: [DI.config, DI.redisForJobQueue], }; const $db: Provider = { provide: 'queue:db', - useFactory: (config: Config) => new Bull.Queue(QUEUE.DB, baseQueueOptions(config, QUEUE.DB)), - inject: [DI.config], + useFactory: (config: Config, redisForJobQueue: Redis.Redis) => new Bull.Queue(QUEUE.DB, baseQueueOptions(config, QUEUE.DB, redisForJobQueue)), + inject: [DI.config, DI.redisForJobQueue], }; const $relationship: Provider = { provide: 'queue:relationship', - useFactory: (config: Config) => new Bull.Queue(QUEUE.RELATIONSHIP, baseQueueOptions(config, QUEUE.RELATIONSHIP)), - inject: [DI.config], + useFactory: (config: Config, redisForJobQueue: Redis.Redis) => new Bull.Queue(QUEUE.RELATIONSHIP, baseQueueOptions(config, QUEUE.RELATIONSHIP, redisForJobQueue)), + inject: [DI.config, DI.redisForJobQueue], }; const $objectStorage: Provider = { provide: 'queue:objectStorage', - useFactory: (config: Config) => new Bull.Queue(QUEUE.OBJECT_STORAGE, baseQueueOptions(config, QUEUE.OBJECT_STORAGE)), - inject: [DI.config], + useFactory: (config: Config, redisForJobQueue: Redis.Redis) => new Bull.Queue(QUEUE.OBJECT_STORAGE, baseQueueOptions(config, QUEUE.OBJECT_STORAGE, redisForJobQueue)), + inject: [DI.config, DI.redisForJobQueue], }; const $webhookDeliver: Provider = { provide: 'queue:webhookDeliver', - useFactory: (config: Config) => new Bull.Queue(QUEUE.WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.WEBHOOK_DELIVER)), - inject: [DI.config], + useFactory: (config: Config, redisForJobQueue: Redis.Redis) => new Bull.Queue(QUEUE.WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.WEBHOOK_DELIVER, redisForJobQueue)), + inject: [DI.config, DI.redisForJobQueue], }; @Module({ @@ -106,14 +107,9 @@ export class QueueModule implements OnApplicationShutdown { ) {} public async dispose(): Promise { - if (process.env.NODE_ENV === 'test') { - // XXX: - // Shutting down the existing connections causes errors on Jest as - // Misskey has asynchronous postgres/redis connections that are not - // awaited. - // Let's wait for some random time for them to finish. - await setTimeout(5000); - } + // Wait for all potential queue jobs + await allSettled(); + // And then close all queues await Promise.all([ this.systemQueue.close(), this.endedPollNotificationQueue.close(), diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index 0a4c2d2d5e..54fa4ee82b 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -13,6 +13,7 @@ import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js'; +import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js'; import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js'; import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js'; import type httpSignature from '@peertube/http-signature'; @@ -75,11 +76,15 @@ export class QueueService { if (content == null) return null; if (to == null) return null; + const contentBody = JSON.stringify(content); + const digest = ApRequestCreator.createDigest(contentBody); + const data: DeliverJobData = { user: { id: user.id, }, - content, + content: contentBody, + digest, to, isSharedInbox, }; @@ -104,6 +109,8 @@ export class QueueService { @bindThis public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map) { if (content == null) return null; + const contentBody = JSON.stringify(content); + const digest = ApRequestCreator.createDigest(contentBody); const opts = { attempts: this.config.deliverJobMaxAttempts ?? 12, @@ -118,10 +125,11 @@ export class QueueService { name: d[0], data: { user, - content, + content: contentBody, + digest, to: d[0], isSharedInbox: d[1], - } as DeliverJobData, + }, opts, }))); @@ -175,6 +183,16 @@ export class QueueService { }); } + @bindThis + public createExportClipsJob(user: ThinUser) { + return this.dbQueue.add('exportClips', { + user: { id: user.id }, + }, { + removeOnComplete: true, + removeOnFail: true, + }); + } + @bindThis public createExportFavoritesJob(user: ThinUser) { return this.dbQueue.add('exportFavorites', { diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 11cd8f54b3..7758586aba 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -28,6 +28,7 @@ import { UserBlockingService } from '@/core/UserBlockingService.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { RoleService } from '@/core/RoleService.js'; import { FeaturedService } from '@/core/FeaturedService.js'; +import { trackPromise } from '@/misc/promise-tracker.js'; const FALLBACK = '❤'; const PER_NOTE_REACTION_USER_PAIR_CACHE_MAX = 16; @@ -138,7 +139,7 @@ export class ReactionService { reaction = reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; // センシティブ - if ((note.reactionAcceptance === 'nonSensitiveOnly') && emoji.isSensitive) { + if ((note.reactionAcceptance === 'nonSensitiveOnly' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && emoji.isSensitive) { reaction = FALLBACK; } } else { @@ -268,7 +269,7 @@ export class ReactionService { } } - dm.execute(); + trackPromise(dm.execute()); } //#endregion } @@ -316,7 +317,7 @@ export class ReactionService { dm.addDirectRecipe(reactee as MiRemoteUser); } dm.addFollowersRecipe(); - dm.execute(); + trackPromise(dm.execute()); } //#endregion } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 9e094e4ec8..3597cb4325 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -6,7 +6,14 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; import { In } from 'typeorm'; -import type { MiRole, MiRoleAssignment, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/_.js'; +import { ModuleRef } from '@nestjs/core'; +import type { + MiRole, + MiRoleAssignment, + RoleAssignmentsRepository, + RolesRepository, + UsersRepository, +} from '@/models/_.js'; import { MemoryKVCache, MemorySingleCache } from '@/misc/cache.js'; import type { MiUser } from '@/models/User.js'; import { DI } from '@/di-symbols.js'; @@ -16,12 +23,13 @@ import { CacheService } from '@/core/CacheService.js'; import type { RoleCondFormulaValue } from '@/models/Role.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; -import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { IdService } from '@/core/IdService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; import type { Packed } from '@/misc/json-schema.js'; import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; -import type { OnApplicationShutdown } from '@nestjs/common'; +import { NotificationService } from '@/core/NotificationService.js'; +import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common'; export type RolePolicies = { gtlAvailable: boolean; @@ -48,6 +56,7 @@ export type RolePolicies = { userListLimit: number; userEachUserListsLimit: number; rateLimitFactor: number; + avatarDecorationLimit: number; }; export const DEFAULT_POLICIES: RolePolicies = { @@ -75,17 +84,21 @@ export const DEFAULT_POLICIES: RolePolicies = { userListLimit: 10, userEachUserListsLimit: 50, rateLimitFactor: 1, + avatarDecorationLimit: 1, }; @Injectable() -export class RoleService implements OnApplicationShutdown { +export class RoleService implements OnApplicationShutdown, OnModuleInit { private rolesCache: MemorySingleCache; private roleAssignmentByUserIdCache: MemoryKVCache; + private notificationService: NotificationService; public static AlreadyAssignedError = class extends Error {}; public static NotAssignedError = class extends Error {}; constructor( + private moduleRef: ModuleRef, + @Inject(DI.redis) private redisClient: Redis.Redis, @@ -120,6 +133,10 @@ export class RoleService implements OnApplicationShutdown { this.redisForSub.on('message', this.onMessage); } + async onModuleInit() { + this.notificationService = this.moduleRef.get(NotificationService.name); + } + @bindThis private async onMessage(_: string, data: string): Promise { const obj = JSON.parse(data); @@ -329,6 +346,7 @@ export class RoleService implements OnApplicationShutdown { userListLimit: calc('userListLimit', vs => Math.max(...vs)), userEachUserListsLimit: calc('userEachUserListsLimit', vs => Math.max(...vs)), rateLimitFactor: calc('rateLimitFactor', vs => Math.max(...vs)), + avatarDecorationLimit: calc('avatarDecorationLimit', vs => Math.max(...vs)), }; } @@ -427,6 +445,12 @@ export class RoleService implements OnApplicationShutdown { this.globalEventService.publishInternalEvent('userRoleAssigned', created); + if (role.isPublic) { + this.notificationService.createNotification(userId, 'roleAssigned', { + roleId: roleId, + }); + } + if (moderator) { const user = await this.usersRepository.findOneByOrFail({ id: userId }); this.moderationLogService.log(moderator, 'assignRole', { diff --git a/packages/backend/src/core/SearchService.ts b/packages/backend/src/core/SearchService.ts index 90e1326793..1db602fbe6 100644 --- a/packages/backend/src/core/SearchService.ts +++ b/packages/backend/src/core/SearchService.ts @@ -12,6 +12,8 @@ import { MiNote } from '@/models/Note.js'; import { MiUser } from '@/models/_.js'; import type { NotesRepository } from '@/models/_.js'; import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; +import { isUserRelated } from '@/misc/is-user-related.js'; +import { CacheService } from '@/core/CacheService.js'; import { QueryService } from '@/core/QueryService.js'; import { IdService } from '@/core/IdService.js'; import type { Index, MeiliSearch } from 'meilisearch'; @@ -74,6 +76,7 @@ export class SearchService { @Inject(DI.notesRepository) private notesRepository: NotesRepository, + private cacheService: CacheService, private queryService: QueryService, private idService: IdService, ) { @@ -193,8 +196,19 @@ export class SearchService { limit: pagination.limit, }); if (res.hits.length === 0) return []; - const notes = await this.notesRepository.findBy({ + const [ + userIdsWhoMeMuting, + userIdsWhoBlockingMe, + ] = me ? await Promise.all([ + this.cacheService.userMutingsCache.fetch(me.id), + this.cacheService.userBlockedCache.fetch(me.id), + ]) : [new Set(), new Set()]; + const notes = (await this.notesRepository.findBy({ id: In(res.hits.map(x => x.id)), + })).filter(note => { + if (me && isUserRelated(note, userIdsWhoBlockingMe)) return false; + if (me && isUserRelated(note, userIdsWhoMeMuting)) return false; + return true; }); return notes.sort((a, b) => a.id > b.id ? -1 : 1); } else { diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts index d522551aff..0ce6182769 100644 --- a/packages/backend/src/core/UserListService.ts +++ b/packages/backend/src/core/UserListService.ts @@ -3,30 +3,34 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown, OnModuleInit } from '@nestjs/common'; import * as Redis from 'ioredis'; +import { ModuleRef } from '@nestjs/core'; import type { UserListMembershipsRepository } from '@/models/_.js'; import type { MiUser } from '@/models/User.js'; import type { MiUserList } from '@/models/UserList.js'; import type { MiUserListMembership } from '@/models/UserListMembership.js'; import { IdService } from '@/core/IdService.js'; +import type { GlobalEvents } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { DI } from '@/di-symbols.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { ProxyAccountService } from '@/core/ProxyAccountService.js'; import { bindThis } from '@/decorators.js'; -import { RoleService } from '@/core/RoleService.js'; import { QueueService } from '@/core/QueueService.js'; import { RedisKVCache } from '@/misc/cache.js'; -import type { GlobalEvents } from '@/core/GlobalEventService.js'; +import { RoleService } from '@/core/RoleService.js'; @Injectable() -export class UserListService implements OnApplicationShutdown { +export class UserListService implements OnApplicationShutdown, OnModuleInit { public static TooManyUsersError = class extends Error {}; public membersCache: RedisKVCache>; + private roleService: RoleService; constructor( + private moduleRef: ModuleRef, + @Inject(DI.redis) private redisClient: Redis.Redis, @@ -38,7 +42,6 @@ export class UserListService implements OnApplicationShutdown { private userEntityService: UserEntityService, private idService: IdService, - private roleService: RoleService, private globalEventService: GlobalEventService, private proxyAccountService: ProxyAccountService, private queueService: QueueService, @@ -54,6 +57,10 @@ export class UserListService implements OnApplicationShutdown { this.redisForSub.on('message', this.onMessage); } + async onModuleInit() { + this.roleService = this.moduleRef.get(RoleService.name); + } + @bindThis private async onMessage(_: string, data: string): Promise { const obj = JSON.parse(data); diff --git a/packages/backend/src/core/UtilityService.ts b/packages/backend/src/core/UtilityService.ts index 83d9a29eae..6f2b398bbb 100644 --- a/packages/backend/src/core/UtilityService.ts +++ b/packages/backend/src/core/UtilityService.ts @@ -6,6 +6,7 @@ import { URL } from 'node:url'; import { toASCII } from 'punycode'; import { Inject, Injectable } from '@nestjs/common'; +import RE2 from 're2'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { bindThis } from '@/decorators.js'; @@ -41,6 +42,33 @@ export class UtilityService { return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`)); } + @bindThis + public isSensitiveWordIncluded(text: string, sensitiveWords: string[]): boolean { + if (sensitiveWords.length === 0) return false; + if (text === '') return false; + + const regexpregexp = /^\/(.+)\/(.*)$/; + + const matched = sensitiveWords.some(filter => { + // represents RegExp + const regexp = filter.match(regexpregexp); + // This should never happen due to input sanitisation. + if (!regexp) { + const words = filter.split(' '); + return words.every(keyword => text.includes(keyword)); + } + try { + // TODO: RE2インスタンスをキャッシュ + return new RE2(regexp[1], regexp[2]).test(text); + } catch (err) { + // This should never happen due to input sanitisation. + return false; + } + }); + + return matched; + } + @bindThis public extractDbHost(uri: string): string { const url = new URL(uri); diff --git a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts index 939de242bb..06adcf4d87 100644 --- a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts +++ b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts @@ -144,7 +144,7 @@ class DeliverManager { } // deliver - this.queueService.deliverMany(this.actor, this.activity, inboxes); + await this.queueService.deliverMany(this.actor, this.activity, inboxes); } } diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 568031f532..97ded05367 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -106,6 +106,8 @@ export class ApInboxService { } catch (err) { if (err instanceof Error || typeof err === 'string') { this.logger.error(err); + } else { + throw err; } } } @@ -290,7 +292,7 @@ export class ApInboxService { const targetUri = getApId(activity.object); - this.announceNote(actor, activity, targetUri); + await this.announceNote(actor, activity, targetUri); } @bindThis @@ -325,7 +327,7 @@ export class ApInboxService { } catch (err) { // 対象が4xxならスキップ if (err instanceof StatusError) { - if (err.isClientError) { + if (!err.isRetryable) { this.logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`); return; } @@ -416,7 +418,7 @@ export class ApInboxService { }); if (isPost(object)) { - this.createNote(resolver, actor, object, false, activity); + await this.createNote(resolver, actor, object, false, activity); } else { this.logger.warn(`Unknown type: ${getApType(object)}`); } @@ -447,7 +449,7 @@ export class ApInboxService { await this.apNoteService.createNote(note, resolver, silent); return 'ok'; } catch (err) { - if (err instanceof StatusError && err.isClientError) { + if (err instanceof StatusError && !err.isRetryable) { return `skip ${err.statusCode}`; } else { throw err; diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index 5ce1e5347b..de98b29752 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -34,9 +34,9 @@ type PrivateKey = { }; export class ApRequestCreator { - static createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record }): Signed { + static createSignedPost(args: { key: PrivateKey, url: string, body: string, digest?: string, additionalHeaders: Record }): Signed { const u = new URL(args.url); - const digestHeader = `SHA-256=${crypto.createHash('sha256').update(args.body).digest('base64')}`; + const digestHeader = args.digest ?? this.createDigest(args.body); const request: Request = { url: u.href, @@ -59,6 +59,10 @@ export class ApRequestCreator { }; } + static createDigest(body: string) { + return `SHA-256=${crypto.createHash('sha256').update(body).digest('base64')}`; + } + static createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record }): Signed { const u = new URL(args.url); @@ -145,8 +149,8 @@ export class ApRequestService { } @bindThis - public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown): Promise { - const body = JSON.stringify(object); + public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, digest?: string): Promise { + const body = typeof object === 'string' ? object : JSON.stringify(object); const keypair = await this.userKeypairService.getUserKeypair(user.id); @@ -157,6 +161,7 @@ export class ApRequestService { }, url, body, + digest, additionalHeaders: { }, }); diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index a67f7afd2a..0ad5a4c712 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -241,7 +241,7 @@ export class ApNoteService { return { status: 'ok', res }; } catch (e) { return { - status: (e instanceof StatusError && e.isClientError) ? 'permerror' : 'temperror', + status: (e instanceof StatusError && !e.isRetryable) ? 'permerror' : 'temperror', }; } }; diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index fba1b098ed..fff81d3770 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -370,6 +370,7 @@ export class NoteEntityService implements OnModuleInit { color: channel.color, isSensitive: channel.isSensitive, allowRenoteToExternal: channel.allowRenoteToExternal, + userId: channel.userId, } : undefined, mentions: note.mentions.length > 0 ? note.mentions : undefined, uri: note.uri ?? undefined, diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index 528c513e3a..da51797579 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -15,8 +15,8 @@ import type { Packed } from '@/misc/json-schema.js'; import { bindThis } from '@/decorators.js'; import { isNotNull } from '@/misc/is-not-null.js'; import { FilterUnionByProperty, notificationTypes } from '@/types.js'; +import { RoleEntityService } from './RoleEntityService.js'; import type { OnModuleInit } from '@nestjs/common'; -import type { CustomEmojiService } from '../CustomEmojiService.js'; import type { UserEntityService } from './UserEntityService.js'; import type { NoteEntityService } from './NoteEntityService.js'; import type { UserGroupInvitationEntityService } from './UserGroupInvitationEntityService.js'; @@ -28,8 +28,8 @@ const NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES = new Set(['note', 'mention', 're export class NotificationEntityService implements OnModuleInit { private userEntityService: UserEntityService; private noteEntityService: NoteEntityService; + private roleEntityService: RoleEntityService; private userGroupInvitationEntityService: UserGroupInvitationEntityService; - private customEmojiService: CustomEmojiService; constructor( private moduleRef: ModuleRef, @@ -49,15 +49,14 @@ export class NotificationEntityService implements OnModuleInit { //private userEntityService: UserEntityService, //private noteEntityService: NoteEntityService, //private userGroupInvitationEntityService: UserGroupInvitationEntityService, - //private customEmojiService: CustomEmojiService, ) { } onModuleInit() { this.userEntityService = this.moduleRef.get('UserEntityService'); this.noteEntityService = this.moduleRef.get('NoteEntityService'); + this.roleEntityService = this.moduleRef.get('RoleEntityService'); this.userGroupInvitationEntityService = this.moduleRef.get('UserGroupInvitationEntityService'); - this.customEmojiService = this.moduleRef.get('CustomEmojiService'); } @bindThis @@ -88,6 +87,7 @@ export class NotificationEntityService implements OnModuleInit { detail: false, }) ) : undefined; + const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined; return await awaitAll({ id: notification.id, @@ -99,6 +99,9 @@ export class NotificationEntityService implements OnModuleInit { ...(notification.type === 'reaction' ? { reaction: notification.reaction, } : {}), + ...(notification.type === 'roleAssigned' ? { + role: role, + } : {}), // ...(notification.type === 'pollEnded' ? { // note: this.noteEntityService.pack(notification.note ?? notification.noteId!, { id: notification.notifieeId }, { // detail: true, @@ -106,7 +109,7 @@ export class NotificationEntityService implements OnModuleInit { // }), // } : {}), ...(notification.type === 'groupInvited' ? { - invitation: this.userGroupInvitationEntityService.pack(notification.userGroupInvitationId!), + invitation: this.userGroupInvitationEntityService.pack(notification.userGroupInvitationId), } : {}), ...(notification.type === 'achievementEarned' ? { achievement: notification.achievement, @@ -158,10 +161,10 @@ export class NotificationEntityService implements OnModuleInit { validNotifications = validNotifications.filter(x => (x.type !== 'receiveFollowRequest') || reqs.some(r => r.followerId === x.notifierId)); } - const groupInvitedNotifications = validNotifications.filter(x => x.type === 'groupInvited'); + const groupInvitedNotifications = validNotifications.filter((x): x is FilterUnionByProperty => x.type === 'groupInvited'); if (groupInvitedNotifications.length > 0) { const existingInvitationIds = await this.userGroupInvitationsRepository.find({ - where: { id: In(groupInvitedNotifications.map(x => x.userGroupInvitationId!)) }, + where: { id: In(groupInvitedNotifications.map(x => x.userGroupInvitationId)) }, }); validNotifications = validNotifications.filter(x => (x.type !== 'groupInvited') || existingInvitationIds.some(r => r.id === x.userGroupInvitationId)); } @@ -240,6 +243,8 @@ export class NotificationEntityService implements OnModuleInit { }); } + const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined; + return await awaitAll({ id: notification.id, createdAt: new Date(notification.createdAt).toISOString(), @@ -250,8 +255,11 @@ export class NotificationEntityService implements OnModuleInit { ...(notification.type === 'reaction' ? { reaction: notification.reaction, } : {}), + ...(notification.type === 'roleAssigned' ? { + role: role, + } : {}), ...(notification.type === 'groupInvited' ? { - invitation: this.userGroupInvitationEntityService.pack(notification.userGroupInvitationId!), + invitation: this.userGroupInvitationEntityService.pack(notification.userGroupInvitationId), } : {}), ...(notification.type === 'achievementEarned' ? { achievement: notification.achievement, @@ -308,10 +316,10 @@ export class NotificationEntityService implements OnModuleInit { validNotifications = validNotifications.filter(x => (x.type !== 'receiveFollowRequest') || reqs.some(r => r.followerId === x.notifierId)); } - const groupInvitedNotifications = validNotifications.filter(x => x.type === 'groupInvited'); + const groupInvitedNotifications = validNotifications.filter((x): x is FilterUnionByProperty => x.type === 'groupInvited'); if (groupInvitedNotifications.length > 0) { const existingInvitationIds = await this.userGroupInvitationsRepository.find({ - where: { id: In(groupInvitedNotifications.map(x => x.userGroupInvitationId!)) }, + where: { id: In(groupInvitedNotifications.map(x => x.userGroupInvitationId)) }, }); validNotifications = validNotifications.filter(x => (x.type !== 'groupInvited') || existingInvitationIds.some(r => r.id === x.userGroupInvitationId)); } diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 6e265dba32..d4d3676ca3 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -368,13 +368,13 @@ export class UserEntityService implements OnModuleInit { const profile = opts.detail ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null; const followingCount = profile == null ? null : - (profile.ffVisibility === 'public') || isMe ? user.followingCount : - (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount : + (profile.followingVisibility === 'public') || isMe ? user.followingCount : + (profile.followingVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount : null; const followersCount = profile == null ? null : - (profile.ffVisibility === 'public') || isMe ? user.followersCount : - (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : + (profile.followersVisibility === 'public') || isMe ? user.followersCount : + (profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : null; const isModerator = isMe && opts.detail ? this.roleService.isModerator(user) : null; @@ -398,9 +398,9 @@ export class UserEntityService implements OnModuleInit { id: ud.id, angle: ud.angle || undefined, flipH: ud.flipH || undefined, + offsetX: ud.offsetX || undefined, + offsetY: ud.offsetY || undefined, scale: ud.scale || undefined, - moveX: ud.moveX || undefined, - moveY: ud.moveY || undefined, opacity: ud.opacity || undefined, url: decorations.find(d => d.id === ud.id)!.url, }))) : [], @@ -455,7 +455,8 @@ export class UserEntityService implements OnModuleInit { pinnedPageId: profile!.pinnedPageId, pinnedPage: profile!.pinnedPageId ? this.pageEntityService.pack(profile!.pinnedPageId, me) : null, publicReactions: profile!.publicReactions, - ffVisibility: profile!.ffVisibility, + followersVisibility: profile!.followersVisibility, + followingVisibility: profile!.followingVisibility, twoFactorEnabled: profile!.twoFactorEnabled, usePasswordLessLogin: profile!.usePasswordLessLogin, securityKeys: profile!.twoFactorEnabled diff --git a/packages/backend/src/daemons/QueueStatsService.ts b/packages/backend/src/daemons/QueueStatsService.ts index ce646d2acd..b839cb36c7 100644 --- a/packages/backend/src/daemons/QueueStatsService.ts +++ b/packages/backend/src/daemons/QueueStatsService.ts @@ -6,6 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import Xev from 'xev'; import * as Bull from 'bullmq'; +import * as Redis from 'ioredis'; import { QueueService } from '@/core/QueueService.js'; import { bindThis } from '@/decorators.js'; import { DI } from '@/di-symbols.js'; @@ -25,6 +26,9 @@ export class QueueStatsService implements OnApplicationShutdown { @Inject(DI.config) private config: Config, + @Inject(DI.redisForJobQueue) + private redisForJobQueue: Redis.Redis, + private queueService: QueueService, ) { } @@ -43,8 +47,8 @@ export class QueueStatsService implements OnApplicationShutdown { let activeDeliverJobs = 0; let activeInboxJobs = 0; - const deliverQueueEvents = new Bull.QueueEvents(QUEUE.DELIVER, baseQueueOptions(this.config, QUEUE.DELIVER)); - const inboxQueueEvents = new Bull.QueueEvents(QUEUE.INBOX, baseQueueOptions(this.config, QUEUE.INBOX)); + const deliverQueueEvents = new Bull.QueueEvents(QUEUE.DELIVER, baseQueueOptions(this.config, QUEUE.DELIVER, this.redisForJobQueue)); + const inboxQueueEvents = new Bull.QueueEvents(QUEUE.INBOX, baseQueueOptions(this.config, QUEUE.INBOX, this.redisForJobQueue)); deliverQueueEvents.on('active', () => { activeDeliverJobs++; diff --git a/packages/backend/src/daemons/ServerStatsService.ts b/packages/backend/src/daemons/ServerStatsService.ts index a8b337c479..e587837f9c 100644 --- a/packages/backend/src/daemons/ServerStatsService.ts +++ b/packages/backend/src/daemons/ServerStatsService.ts @@ -37,7 +37,7 @@ export class ServerStatsService implements OnApplicationShutdown { const log = [] as any[]; ev.on('requestServerStatsLog', x => { - ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length ?? 50)); + ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length)); }); const tick = async () => { diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts index 4d1da11d03..5854945a6f 100644 --- a/packages/backend/src/di-symbols.ts +++ b/packages/backend/src/di-symbols.ts @@ -12,6 +12,7 @@ export const DI = { redisForPub: Symbol('redisForPub'), redisForSub: Symbol('redisForSub'), redisForTimelines: Symbol('redisForTimelines'), + redisForJobQueue: Symbol('redisForJobQueue'), //#region Repositories usersRepository: Symbol('usersRepository'), diff --git a/packages/backend/src/logger.ts b/packages/backend/src/logger.ts index 21d9b053e3..5609615206 100644 --- a/packages/backend/src/logger.ts +++ b/packages/backend/src/logger.ts @@ -77,8 +77,11 @@ export default class Logger { let log = `${l} ${worker}\t[${contexts.join(' ')}]\t${m}`; if (envOption.withLogTime) log = chalk.gray(time) + ' ' + log; - console.log(important ? chalk.bold(log) : log); - if (level === 'error' && data) console.log(data); + const args: unknown[] = [important ? chalk.bold(log) : log]; + if (data != null) { + args.push(data); + } + console.log(...args); this.writeCloudLogging(level, log, timestamp, level === 'error' || level === 'warning' ? data : null); } diff --git a/packages/backend/src/misc/api-permissions.ts b/packages/backend/src/misc/api-permissions.ts deleted file mode 100644 index 7d31e07230..0000000000 --- a/packages/backend/src/misc/api-permissions.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export const kinds = [ - 'read:account', - 'write:account', - 'read:blocks', - 'write:blocks', - 'read:drive', - 'write:drive', - 'read:favorites', - 'write:favorites', - 'read:following', - 'write:following', - 'read:messaging', - 'write:messaging', - 'read:mutes', - 'write:mutes', - 'write:notes', - 'read:notifications', - 'write:notifications', - 'read:reactions', - 'write:reactions', - 'write:votes', - 'read:pages', - 'write:pages', - 'write:page-likes', - 'read:page-likes', - 'read:user-groups', - 'write:user-groups', - 'read:channels', - 'write:channels', - 'read:gallery', - 'write:gallery', - 'read:gallery-likes', - 'write:gallery-likes', -]; -// IF YOU ADD KINDS(PERMISSIONS), YOU MUST ADD TRANSLATIONS (under _permissions). diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index 4e71f20445..746d3ad198 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -55,7 +55,10 @@ export class RedisKVCache { const cached = await this.redisClient.get(`kvcache:${this.name}:${key}`); if (cached == null) return undefined; - return this.fromRedisConverter(cached); + const parsed = this.fromRedisConverter(cached); + if (parsed == null) return undefined; + this.memoryCache.set(key, parsed); + return parsed; } @bindThis diff --git a/packages/backend/src/misc/emoji-regex.ts b/packages/backend/src/misc/emoji-regex.ts index 292e7cbe3d..63151ef5d8 100644 --- a/packages/backend/src/misc/emoji-regex.ts +++ b/packages/backend/src/misc/emoji-regex.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -// taken from twemoji-parser/dist/lib/regex.js -const twemojiRegex = /(?:\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83e\udef1\ud83c\udffb\u200d\ud83e\udef2\ud83c[\udffc-\udfff]|\ud83e\udef1\ud83c\udffc\u200d\ud83e\udef2\ud83c[\udffb\udffd-\udfff]|\ud83e\udef1\ud83c\udffd\u200d\ud83e\udef2\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\udef1\ud83c\udffe\u200d\ud83e\udef2\ud83c[\udffb-\udffd\udfff]|\ud83e\udef1\ud83c\udfff\u200d\ud83e\udef2\ud83c[\udffb-\udffe]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d\udc8f\ud83c[\udffb-\udfff]|\ud83d\udc91\ud83c[\udffb-\udfff]|\ud83e\udd1d\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d\udc8f\udc91]|\ud83e\udd1d)|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd4\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83d\ude36\u200d\ud83c\udf2b\ufe0f|\u2764\ufe0f\u200d\ud83d\udd25|\u2764\ufe0f\u200d\ud83e\ude79|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83d\ude2e\u200d\ud83d\udca8|\ud83d\ude35\u200d\ud83d\udcab|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:[©®\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd-\uddcf\uddd1-\udddd\udec3-\udec5\udef0-\udef6]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udc8e\udc90\udc92-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded7\udedd-\udedf\udeeb\udeec\udef4-\udefc\udfe0-\udfeb\udff0]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd3f-\udd45\udd47-\udd76\udd78-\uddb4\uddb7\uddba\uddbc-\uddcc\uddd0\uddde-\uddff\ude70-\ude74\ude78-\ude7c\ude80-\ude86\ude90-\udeac\udeb0-\udeba\udec0-\udec2\uded0-\uded9\udee0-\udee7]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g; +// taken from @twemoji/parser/dist/lib/regex.js +const twemojiRegex = /(?:\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83e\udef1\ud83c\udffb\u200d\ud83e\udef2\ud83c[\udffc-\udfff]|\ud83e\udef1\ud83c\udffc\u200d\ud83e\udef2\ud83c[\udffb\udffd-\udfff]|\ud83e\udef1\ud83c\udffd\u200d\ud83e\udef2\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\udef1\ud83c\udffe\u200d\ud83e\udef2\ud83c[\udffb-\udffd\udfff]|\ud83e\udef1\ud83c\udfff\u200d\ud83e\udef2\ud83c[\udffb-\udffe]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d\udc8f\ud83c[\udffb-\udfff]|\ud83d\udc91\ud83c[\udffb-\udfff]|\ud83e\udd1d\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d\udc8f\udc91]|\ud83e\udd1d)|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd4\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83d\ude36\u200d\ud83c\udf2b\ufe0f|\u2764\ufe0f\u200d\ud83d\udd25|\u2764\ufe0f\u200d\ud83e\ude79|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83d\ude2e\u200d\ud83d\udca8|\ud83d\ude35\u200d\ud83d\udcab|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b|\ud83d\udc26\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:[©®\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|\ud83e\udef0|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd-\uddcf\uddd1-\udddd\udec3-\udec5\udef1-\udef8]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udc8e\udc90\udc92-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded7\udedc-\udedf\udeeb\udeec\udef4-\udefc\udfe0-\udfeb\udff0]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd3f-\udd45\udd47-\udd76\udd78-\uddb4\uddb7\uddba\uddbc-\uddcc\uddd0\uddde-\uddff\ude70-\ude7c\ude80-\ude88\ude90-\udebd\udebf-\udec2\udece-\udedb\udee0-\udee8]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g; export const emojiRegex = new RegExp(`(${twemojiRegex.source})`); diff --git a/packages/backend/src/misc/is-quote.ts b/packages/backend/src/misc/is-quote.ts index 787afac822..d53d7a6be8 100644 --- a/packages/backend/src/misc/is-quote.ts +++ b/packages/backend/src/misc/is-quote.ts @@ -7,5 +7,6 @@ import type { MiNote } from '@/models/Note.js'; // eslint-disable-next-line import/no-default-export export default function(note: MiNote): boolean { + // sync with NoteCreateService.isQuote return note.renoteId != null && (note.text != null || note.hasPoll || (note.fileIds != null && note.fileIds.length > 0)); } diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index f3d59e3e88..5441b1cc46 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -40,6 +40,7 @@ import { packedFlashSchema } from '@/models/json-schema/flash.js'; import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js'; import { packedSigninSchema } from '@/models/json-schema/signin.js'; import { packedRoleLiteSchema, packedRoleSchema } from '@/models/json-schema/role.js'; +import { packedAdSchema } from '@/models/json-schema/ad.js'; export const refs = { UserLite: packedUserLiteSchema, @@ -52,6 +53,7 @@ export const refs = { UserList: packedUserListSchema, UserGroup: packedUserGroupSchema, + Ad: packedAdSchema, Announcement: packedAnnouncementSchema, App: packedAppSchema, MessagingMessage: packedMessagingMessageSchema, diff --git a/packages/backend/src/misc/promise-tracker.ts b/packages/backend/src/misc/promise-tracker.ts new file mode 100644 index 0000000000..dee04ee1f2 --- /dev/null +++ b/packages/backend/src/misc/promise-tracker.ts @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +const promiseRefs: Set>> = new Set(); + +/** + * This tracks promises that other modules decided not to wait for, + * and makes sure they are all settled before fully closing down the server. + */ +export function trackPromise(promise: Promise) { + if (process.env.NODE_ENV !== 'test') { + return; + } + const ref = new WeakRef(promise); + promiseRefs.add(ref); + promise.finally(() => promiseRefs.delete(ref)); +} + +export async function allSettled(): Promise { + await Promise.allSettled([...promiseRefs].map(r => r.deref())); +} diff --git a/packages/backend/src/misc/status-error.ts b/packages/backend/src/misc/status-error.ts index 97d1cb6fb0..57e001d720 100644 --- a/packages/backend/src/misc/status-error.ts +++ b/packages/backend/src/misc/status-error.ts @@ -7,6 +7,7 @@ export class StatusError extends Error { public statusCode: number; public statusMessage?: string; public isClientError: boolean; + public isRetryable: boolean; constructor(message: string, statusCode: number, statusMessage?: string) { super(message); @@ -14,5 +15,6 @@ export class StatusError extends Error { this.statusCode = statusCode; this.statusMessage = statusMessage; this.isClientError = typeof this.statusCode === 'number' && this.statusCode >= 400 && this.statusCode < 500; + this.isRetryable = !this.isClientError || this.statusCode === 429; } } diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 20b69c69d1..77c3edc90b 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -46,11 +46,6 @@ export class MiMeta { }) public maintainerEmail: string | null; - @Column('varchar', { - length: 1024, nullable: true, - }) - public emailToReceiveAbuseReport: string | null; - @Column('boolean', { default: false, }) @@ -196,6 +191,29 @@ export class MiMeta { }) public hcaptchaSecretKey: string | null; + @Column('boolean', { + default: false, + }) + public enableMcaptcha: boolean; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public mcaptchaSitekey: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public mcaptchaSecretKey: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public mcaptchaInstanceUrl: string | null; + @Column('boolean', { default: false, }) @@ -570,6 +588,23 @@ export class MiMeta { }) public verifymailAuthKey: string | null; + @Column('boolean', { + default: false, + }) + public enableTruemailApi: boolean; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public truemailInstance: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public truemailAuthKey: string | null; + @Column('boolean', { default: true, }) @@ -590,11 +625,6 @@ export class MiMeta { }) public enableIdenticonGeneration: boolean; - @Column('boolean', { - default: false, - }) - public doNotSendNotificationEmailsForAbuseReport: boolean; - @Column('jsonb', { default: { }, }) @@ -613,6 +643,13 @@ export class MiMeta { }) public manifestJsonOverride: string; + @Column('varchar', { + length: 1024, + array: true, + default: '{}', + }) + public bannedEmailDomains: string[]; + @Column('varchar', { length: 1024, array: true, default: '{ "admin", "administrator", "root", "system", "maintainer", "host", "mod", "moderator", "owner", "superuser", "staff", "auth", "i", "me", "everyone", "all", "mention", "mentions", "example", "user", "users", "account", "accounts", "official", "help", "helps", "support", "supports", "info", "information", "informations", "announce", "announces", "announcement", "announcements", "notice", "notification", "notifications", "dev", "developer", "developers", "tech", "misskey", "cherrypick" }', }) @@ -653,6 +690,16 @@ export class MiMeta { }) public notesPerOneAd: number; + @Column('boolean', { + default: false, + }) + public doNotSendNotificationEmailsForAbuseReport: boolean; + + @Column('varchar', { + length: 1024, nullable: true, + }) + public emailToReceiveAbuseReport: string | null; + @Column('boolean', { default: false, }) diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts index 9b2966b17b..81d000bb35 100644 --- a/packages/backend/src/models/Notification.ts +++ b/packages/backend/src/models/Notification.ts @@ -3,12 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { notificationTypes } from '@/types.js'; import { MiUser } from './User.js'; import { MiNote } from './Note.js'; -import { MiFollowRequest } from './FollowRequest.js'; import { MiUserGroupInvitation } from './UserGroupInvitation.js'; import { MiAccessToken } from './AccessToken.js'; +import { MiRole } from './Role.js'; export type MiNotification = { type: 'note'; @@ -70,10 +69,15 @@ export type MiNotification = { createdAt: string; notifierId: MiUser['id']; } | { - type: 'groupInvited'; - id: string; - createdAt: string; - notifierId: MiUser['id']; + type: 'roleAssigned'; + id: string; + createdAt: string; + roleId: MiRole['id']; +} | { + type: 'groupInvited'; + id: string; + createdAt: string; + notifierId: MiUser['id']; userGroupInvitationId: MiUserGroupInvitation['id']; } | { type: 'achievementEarned'; diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 0a5b199df2..4736f48ab1 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -143,12 +143,12 @@ export class MiUser { }) public avatarDecorations: { id: string; - angle: number; - flipH: boolean; - scale: number; - moveX: number; - moveY: number; - opacity: number; + angle?: number; + flipH?: boolean; + offsetX?: number; + offsetY?: number; + scale?: number; + opacity?: number; }[]; @Index() diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts index 66b323b86d..95b59dcb1d 100644 --- a/packages/backend/src/models/UserProfile.ts +++ b/packages/backend/src/models/UserProfile.ts @@ -4,7 +4,7 @@ */ import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; -import { obsoleteNotificationTypes, ffVisibility, notificationTypes } from '@/types.js'; +import { obsoleteNotificationTypes, followingVisibilities, followersVisibilities, notificationTypes } from '@/types.js'; import { id } from './util/id.js'; import { MiUser } from './User.js'; import { MiPage } from './Page.js'; @@ -94,10 +94,16 @@ export class MiUserProfile { public publicReactions: boolean; @Column('enum', { - enum: ffVisibility, + enum: followingVisibilities, default: 'public', }) - public ffVisibility: typeof ffVisibility[number]; + public followingVisibility: typeof followingVisibilities[number]; + + @Column('enum', { + enum: followersVisibilities, + default: 'public', + }) + public followersVisibility: typeof followersVisibilities[number]; @Column('varchar', { length: 128, nullable: true, diff --git a/packages/backend/src/models/json-schema/ad.ts b/packages/backend/src/models/json-schema/ad.ts new file mode 100644 index 0000000000..d139e5a72e --- /dev/null +++ b/packages/backend/src/models/json-schema/ad.ts @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export const packedAdSchema = { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, + nullable: false, + format: 'id', + example: 'xxxxxxxxxx', + }, + expiresAt: { + type: 'string', + optional: false, + nullable: false, + format: 'date-time', + }, + startsAt: { + type: 'string', + optional: false, + nullable: false, + format: 'date-time', + }, + place: { + type: 'string', + optional: false, + nullable: false, + }, + priority: { + type: 'string', + optional: false, + nullable: false, + }, + ratio: { + type: 'number', + optional: false, + nullable: false, + }, + url: { + type: 'string', + optional: false, + nullable: false, + }, + imageUrl: { + type: 'string', + optional: false, + nullable: false, + }, + memo: { + type: 'string', + optional: false, + nullable: false, + }, + dayOfWeek: { + type: 'integer', + optional: false, + nullable: false, + }, + }, +} as const; diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts index e11775ae28..665c1bb578 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -140,6 +140,10 @@ export const packedNoteSchema = { type: 'object', optional: true, nullable: true, }, + event: { + type: 'object', + optional: true, nullable: true, + }, channelId: { type: 'string', optional: true, nullable: true, @@ -170,6 +174,10 @@ export const packedNoteSchema = { type: 'boolean', optional: false, nullable: false, }, + userId: { + type: 'string', + optional: false, nullable: true, + }, }, }, localOnly: { diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts index dd2f32b14d..b0c6804bb8 100644 --- a/packages/backend/src/models/json-schema/role.ts +++ b/packages/backend/src/models/json-schema/role.ts @@ -145,6 +145,7 @@ export const packedRoleSchema = { userEachUserListsLimit: rolePolicyValue, canManageAvatarDecorations: rolePolicyValue, canUseTranslator: rolePolicyValue, + avatarDecorationLimit: rolePolicyValue, }, }, usersCount: { diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 62ba1c0227..b712d3448e 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -69,15 +69,15 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, - scale: { + offsetX: { type: 'number', nullable: false, optional: true, }, - moveX: { + offsetY: { type: 'number', nullable: false, optional: true, }, - moveY: { + scale: { type: 'number', nullable: false, optional: true, }, @@ -319,7 +319,12 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: false, }, - ffVisibility: { + followingVisibility: { + type: 'string', + nullable: false, optional: false, + enum: ['public', 'followers', 'private'], + }, + followersVisibility: { type: 'string', nullable: false, optional: false, enum: ['public', 'followers', 'private'], @@ -561,9 +566,7 @@ export const packedMeDetailedOnlySchema = { mention: notificationRecieveConfig, reaction: notificationRecieveConfig, pollEnded: notificationRecieveConfig, - achievementEarned: notificationRecieveConfig, receiveFollowRequest: notificationRecieveConfig, - followRequestAccepted: notificationRecieveConfig, groupInvited: notificationRecieveConfig, }, }, @@ -693,6 +696,10 @@ export const packedMeDetailedOnlySchema = { type: 'number', nullable: false, optional: false, }, + avatarDecorationLimit: { + type: 'number', + nullable: false, optional: false, + }, }, }, //#region secrets diff --git a/packages/backend/src/queue/QueueProcessorModule.ts b/packages/backend/src/queue/QueueProcessorModule.ts index aae9f438f2..0ce3e5ef70 100644 --- a/packages/backend/src/queue/QueueProcessorModule.ts +++ b/packages/backend/src/queue/QueueProcessorModule.ts @@ -24,6 +24,7 @@ import { ExportCustomEmojisProcessorService } from './processors/ExportCustomEmo import { ExportFollowingProcessorService } from './processors/ExportFollowingProcessorService.js'; import { ExportMutingProcessorService } from './processors/ExportMutingProcessorService.js'; import { ExportNotesProcessorService } from './processors/ExportNotesProcessorService.js'; +import { ExportClipsProcessorService } from './processors/ExportClipsProcessorService.js'; import { ExportUserListsProcessorService } from './processors/ExportUserListsProcessorService.js'; import { ExportAntennasProcessorService } from './processors/ExportAntennasProcessorService.js'; import { ImportBlockingProcessorService } from './processors/ImportBlockingProcessorService.js'; @@ -54,6 +55,7 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor DeleteDriveFilesProcessorService, ExportCustomEmojisProcessorService, ExportNotesProcessorService, + ExportClipsProcessorService, ExportFavoritesProcessorService, ExportFollowingProcessorService, ExportMutingProcessorService, diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts index cb5abf31b8..49920a8403 100644 --- a/packages/backend/src/queue/QueueProcessorService.ts +++ b/packages/backend/src/queue/QueueProcessorService.ts @@ -5,6 +5,7 @@ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Bull from 'bullmq'; +import * as Redis from 'ioredis'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import type Logger from '@/logger.js'; @@ -16,6 +17,7 @@ import { InboxProcessorService } from './processors/InboxProcessorService.js'; import { DeleteDriveFilesProcessorService } from './processors/DeleteDriveFilesProcessorService.js'; import { ExportCustomEmojisProcessorService } from './processors/ExportCustomEmojisProcessorService.js'; import { ExportNotesProcessorService } from './processors/ExportNotesProcessorService.js'; +import { ExportClipsProcessorService } from './processors/ExportClipsProcessorService.js'; import { ExportFollowingProcessorService } from './processors/ExportFollowingProcessorService.js'; import { ExportMutingProcessorService } from './processors/ExportMutingProcessorService.js'; import { ExportBlockingProcessorService } from './processors/ExportBlockingProcessorService.js'; @@ -84,6 +86,9 @@ export class QueueProcessorService implements OnApplicationShutdown { @Inject(DI.config) private config: Config, + @Inject(DI.redisForJobQueue) + private redisForJobQueue: Redis.Redis, + private queueLoggerService: QueueLoggerService, private webhookDeliverProcessorService: WebhookDeliverProcessorService, private endedPollNotificationProcessorService: EndedPollNotificationProcessorService, @@ -92,6 +97,7 @@ export class QueueProcessorService implements OnApplicationShutdown { private deleteDriveFilesProcessorService: DeleteDriveFilesProcessorService, private exportCustomEmojisProcessorService: ExportCustomEmojisProcessorService, private exportNotesProcessorService: ExportNotesProcessorService, + private exportClipsProcessorService: ExportClipsProcessorService, private exportFavoritesProcessorService: ExportFavoritesProcessorService, private exportFollowingProcessorService: ExportFollowingProcessorService, private exportMutingProcessorService: ExportMutingProcessorService, @@ -146,7 +152,7 @@ export class QueueProcessorService implements OnApplicationShutdown { default: throw new Error(`unrecognized job type ${job.name} for system`); } }, { - ...baseQueueOptions(this.config, QUEUE.SYSTEM), + ...baseQueueOptions(this.config, QUEUE.SYSTEM, this.redisForJobQueue), autorun: false, }); @@ -155,8 +161,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.systemQueueWorker .on('active', (job) => systemLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => systemLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => systemLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => systemLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => systemLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => systemLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => systemLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -166,6 +172,7 @@ export class QueueProcessorService implements OnApplicationShutdown { case 'deleteDriveFiles': return this.deleteDriveFilesProcessorService.process(job); case 'exportCustomEmojis': return this.exportCustomEmojisProcessorService.process(job); case 'exportNotes': return this.exportNotesProcessorService.process(job); + case 'exportClips': return this.exportClipsProcessorService.process(job); case 'exportFavorites': return this.exportFavoritesProcessorService.process(job); case 'exportFollowing': return this.exportFollowingProcessorService.process(job); case 'exportMuting': return this.exportMutingProcessorService.process(job); @@ -185,7 +192,7 @@ export class QueueProcessorService implements OnApplicationShutdown { default: throw new Error(`unrecognized job type ${job.name} for db`); } }, { - ...baseQueueOptions(this.config, QUEUE.DB), + ...baseQueueOptions(this.config, QUEUE.DB, this.redisForJobQueue), autorun: false, }); @@ -194,14 +201,14 @@ export class QueueProcessorService implements OnApplicationShutdown { this.dbQueueWorker .on('active', (job) => dbLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => dbLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => dbLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => dbLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => dbLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => dbLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => dbLogger.warn(`stalled id=${jobId}`)); //#endregion //#region deliver this.deliverQueueWorker = new Bull.Worker(QUEUE.DELIVER, (job) => this.deliverProcessorService.process(job), { - ...baseQueueOptions(this.config, QUEUE.DELIVER), + ...baseQueueOptions(this.config, QUEUE.DELIVER, this.redisForJobQueue), autorun: false, concurrency: this.config.deliverJobConcurrency ?? 128, limiter: { @@ -218,18 +225,18 @@ export class QueueProcessorService implements OnApplicationShutdown { this.deliverQueueWorker .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) .on('completed', (job, result) => deliverLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => deliverLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) - .on('error', (err: Error) => deliverLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => deliverLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) + .on('error', (err: Error) => deliverLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => deliverLogger.warn(`stalled id=${jobId}`)); //#endregion //#region inbox this.inboxQueueWorker = new Bull.Worker(QUEUE.INBOX, (job) => this.inboxProcessorService.process(job), { - ...baseQueueOptions(this.config, QUEUE.INBOX), + ...baseQueueOptions(this.config, QUEUE.INBOX, this.redisForJobQueue), autorun: false, concurrency: this.config.inboxJobConcurrency ?? 16, limiter: { - max: this.config.inboxJobPerSec ?? 16, + max: this.config.inboxJobPerSec ?? 32, duration: 1000, }, settings: { @@ -242,14 +249,14 @@ export class QueueProcessorService implements OnApplicationShutdown { this.inboxQueueWorker .on('active', (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`)) .on('completed', (job, result) => inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`)) - .on('failed', (job, err) => inboxLogger.warn(`failed(${err}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => inboxLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => inboxLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => inboxLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => inboxLogger.warn(`stalled id=${jobId}`)); //#endregion //#region webhook deliver this.webhookDeliverQueueWorker = new Bull.Worker(QUEUE.WEBHOOK_DELIVER, (job) => this.webhookDeliverProcessorService.process(job), { - ...baseQueueOptions(this.config, QUEUE.WEBHOOK_DELIVER), + ...baseQueueOptions(this.config, QUEUE.WEBHOOK_DELIVER, this.redisForJobQueue), autorun: false, concurrency: 64, limiter: { @@ -266,8 +273,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.webhookDeliverQueueWorker .on('active', (job) => webhookLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) .on('completed', (job, result) => webhookLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => webhookLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) - .on('error', (err: Error) => webhookLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => webhookLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) + .on('error', (err: Error) => webhookLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => webhookLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -281,7 +288,7 @@ export class QueueProcessorService implements OnApplicationShutdown { default: throw new Error(`unrecognized job type ${job.name} for relationship`); } }, { - ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP), + ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP, this.redisForJobQueue), autorun: false, concurrency: this.config.relashionshipJobConcurrency ?? 16, limiter: { @@ -295,8 +302,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.relationshipQueueWorker .on('active', (job) => relationshipLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => relationshipLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => relationshipLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => relationshipLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => relationshipLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => relationshipLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => relationshipLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -308,7 +315,7 @@ export class QueueProcessorService implements OnApplicationShutdown { default: throw new Error(`unrecognized job type ${job.name} for objectStorage`); } }, { - ...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE), + ...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE, this.redisForJobQueue), autorun: false, concurrency: 16, }); @@ -318,14 +325,14 @@ export class QueueProcessorService implements OnApplicationShutdown { this.objectStorageQueueWorker .on('active', (job) => objectStorageLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => objectStorageLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => objectStorageLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => objectStorageLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => objectStorageLogger.warn(`stalled id=${jobId}`)); //#endregion //#region ended poll notification this.endedPollNotificationQueueWorker = new Bull.Worker(QUEUE.ENDED_POLL_NOTIFICATION, (job) => this.endedPollNotificationProcessorService.process(job), { - ...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION), + ...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION, this.redisForJobQueue), autorun: false, }); //#endregion diff --git a/packages/backend/src/queue/const.ts b/packages/backend/src/queue/const.ts index f1313dfe1d..6ebaaac047 100644 --- a/packages/backend/src/queue/const.ts +++ b/packages/backend/src/queue/const.ts @@ -5,6 +5,7 @@ import { Config } from '@/config.js'; import type * as Bull from 'bullmq'; +import type * as Redis from 'ioredis'; export const QUEUE = { DELIVER: 'deliver', @@ -17,12 +18,9 @@ export const QUEUE = { WEBHOOK_DELIVER: 'webhookDeliver', }; -export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions { +export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE], redisConnection: Redis.Redis): Bull.QueueOptions { return { - connection: { - ...config.redisForJobQueue, - keyPrefix: undefined, - }, + connection: redisConnection, prefix: config.redisForJobQueue.prefix ? `${config.redisForJobQueue.prefix}:queue:${queueName}` : `queue:${queueName}`, }; } diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts index 5e34db845e..3dd3d328a8 100644 --- a/packages/backend/src/queue/processors/DeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts @@ -72,7 +72,7 @@ export class DeliverProcessorService { } try { - await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content); + await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content, job.data.digest); // Update stats this.federatedInstanceService.fetch(host).then(i => { @@ -111,7 +111,7 @@ export class DeliverProcessorService { if (res instanceof StatusError) { // 4xx - if (res.isClientError) { + if (!res.isRetryable) { // 相手が閉鎖していることを明示しているため、配送停止する if (job.data.isSharedInbox && res.statusCode === 410) { this.federatedInstanceService.fetch(host).then(i => { diff --git a/packages/backend/src/queue/processors/ExportClipsProcessorService.ts b/packages/backend/src/queue/processors/ExportClipsProcessorService.ts new file mode 100644 index 0000000000..fc15e60ae4 --- /dev/null +++ b/packages/backend/src/queue/processors/ExportClipsProcessorService.ts @@ -0,0 +1,204 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import * as fs from 'node:fs'; +import { Writable } from 'node:stream'; +import { Inject, Injectable } from '@nestjs/common'; +import { MoreThan } from 'typeorm'; +import { format as dateFormat } from 'date-fns'; +import { DI } from '@/di-symbols.js'; +import type { ClipNotesRepository, ClipsRepository, MiClip, MiClipNote, MiUser, PollsRepository, UsersRepository } from '@/models/_.js'; +import type Logger from '@/logger.js'; +import { DriveService } from '@/core/DriveService.js'; +import { createTemp } from '@/misc/create-temp.js'; +import type { MiPoll } from '@/models/Poll.js'; +import type { MiNote } from '@/models/Note.js'; +import { bindThis } from '@/decorators.js'; +import { IdService } from '@/core/IdService.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbJobDataWithUser } from '../types.js'; + +@Injectable() +export class ExportClipsProcessorService { + private logger: Logger; + + constructor( + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + + @Inject(DI.pollsRepository) + private pollsRepository: PollsRepository, + + @Inject(DI.clipsRepository) + private clipsRepository: ClipsRepository, + + @Inject(DI.clipNotesRepository) + private clipNotesRepository: ClipNotesRepository, + + private driveService: DriveService, + private queueLoggerService: QueueLoggerService, + private idService: IdService, + ) { + this.logger = this.queueLoggerService.logger.createSubLogger('export-clips'); + } + + @bindThis + public async process(job: Bull.Job): Promise { + this.logger.info(`Exporting clips of ${job.data.user.id} ...`); + + const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); + if (user == null) { + return; + } + + // Create temp file + const [path, cleanup] = await createTemp(); + + this.logger.info(`Temp file is ${path}`); + + try { + const stream = Writable.toWeb(fs.createWriteStream(path, { flags: 'a' })); + const writer = stream.getWriter(); + writer.closed.catch(this.logger.error); + + await writer.write('['); + + await this.processClips(writer, user, job); + + await writer.write(']'); + await writer.close(); + + this.logger.succ(`Exported to: ${path}`); + + const fileName = 'clips-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.json'; + const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'json' }); + + this.logger.succ(`Exported to: ${driveFile.id}`); + } finally { + cleanup(); + } + } + + async processClips(writer: WritableStreamDefaultWriter, user: MiUser, job: Bull.Job) { + let exportedClipsCount = 0; + let cursor: MiClip['id'] | null = null; + + while (true) { + const clips = await this.clipsRepository.find({ + where: { + userId: user.id, + ...(cursor ? { id: MoreThan(cursor) } : {}), + }, + take: 100, + order: { + id: 1, + }, + }); + + if (clips.length === 0) { + job.updateProgress(100); + break; + } + + cursor = clips.at(-1)?.id ?? null; + + for (const clip of clips) { + // Stringify but remove the last `]}` + const content = JSON.stringify(this.serializeClip(clip)).slice(0, -2); + const isFirst = exportedClipsCount === 0; + await writer.write(isFirst ? content : ',\n' + content); + + await this.processClipNotes(writer, clip.id); + + await writer.write(']}'); + exportedClipsCount++; + } + + const total = await this.clipsRepository.countBy({ + userId: user.id, + }); + + job.updateProgress(exportedClipsCount / total); + } + } + + async processClipNotes(writer: WritableStreamDefaultWriter, clipId: string): Promise { + let exportedClipNotesCount = 0; + let cursor: MiClipNote['id'] | null = null; + + while (true) { + const clipNotes = await this.clipNotesRepository.find({ + where: { + clipId, + ...(cursor ? { id: MoreThan(cursor) } : {}), + }, + take: 100, + order: { + id: 1, + }, + relations: ['note', 'note.user'], + }) as (MiClipNote & { note: MiNote & { user: MiUser } })[]; + + if (clipNotes.length === 0) { + break; + } + + cursor = clipNotes.at(-1)?.id ?? null; + + for (const clipNote of clipNotes) { + let poll: MiPoll | undefined; + if (clipNote.note.hasPoll) { + poll = await this.pollsRepository.findOneByOrFail({ noteId: clipNote.note.id }); + } + const content = JSON.stringify(this.serializeClipNote(clipNote, poll)); + const isFirst = exportedClipNotesCount === 0; + await writer.write(isFirst ? content : ',\n' + content); + + exportedClipNotesCount++; + } + } + } + + private serializeClip(clip: MiClip): Record { + return { + id: clip.id, + name: clip.name, + description: clip.description, + lastClippedAt: clip.lastClippedAt?.toISOString(), + clipNotes: [], + }; + } + + private serializeClipNote(clip: MiClipNote & { note: MiNote & { user: MiUser } }, poll: MiPoll | undefined): Record { + return { + id: clip.id, + createdAt: this.idService.parse(clip.id).date.toISOString(), + note: { + id: clip.note.id, + text: clip.note.text, + createdAt: this.idService.parse(clip.note.id).date.toISOString(), + fileIds: clip.note.fileIds, + replyId: clip.note.replyId, + renoteId: clip.note.renoteId, + poll: poll, + cw: clip.note.cw, + visibility: clip.note.visibility, + visibleUserIds: clip.note.visibleUserIds, + localOnly: clip.note.localOnly, + reactionAcceptance: clip.note.reactionAcceptance, + uri: clip.note.uri, + url: clip.note.url, + user: { + id: clip.note.user.id, + name: clip.note.user.name, + username: clip.note.user.username, + host: clip.note.user.host, + uri: clip.note.user.uri, + }, + }, + }; + } +} diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index 4e28475d15..e557d5f663 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -85,7 +85,7 @@ export class InboxProcessorService { } catch (err) { // 対象が4xxならスキップ if (err instanceof StatusError) { - if (err.isClientError) { + if (!err.isRetryable) { throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`); } throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`); diff --git a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts b/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts index b3468cd336..2da45b4e8b 100644 --- a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts @@ -71,7 +71,7 @@ export class WebhookDeliverProcessorService { if (res instanceof StatusError) { // 4xx - if (res.isClientError) { + if (!res.isRetryable) { throw new Bull.UnrecoverableError(`${res.statusCode} ${res.statusMessage}`); } diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index e844e65704..41b57291e5 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -16,7 +16,9 @@ export type DeliverJobData = { /** Actor */ user: ThinUser; /** Activity */ - content: unknown; + content: string; + /** Digest header */ + digest: string; /** inbox URL to deliver */ to: string; /** whether it is sharedInbox */ diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index 0a50e62072..e3db75d42e 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -138,7 +138,7 @@ export class ActivityPubServerService { return; } - const algo = match[1]; + const algo = match[1].toUpperCase(); const digestValue = match[2]; if (algo !== 'SHA-256') { @@ -162,7 +162,13 @@ export class ActivityPubServerService { } } - this.queueService.inbox(request.body as IActivity, signature); + const activity = request.body as IActivity; + if (!activity.type || !signature.keyId) { + reply.code(400); + return; + } + + this.queueService.inbox(activity, signature); reply.code(202); } @@ -195,11 +201,11 @@ export class ActivityPubServerService { //#region Check ff visibility const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.followersVisibility === 'private') { reply.code(403); reply.header('Cache-Control', 'public, max-age=30'); return; - } else if (profile.ffVisibility === 'followers') { + } else if (profile.followersVisibility === 'followers') { reply.code(403); reply.header('Cache-Control', 'public, max-age=30'); return; @@ -287,11 +293,11 @@ export class ActivityPubServerService { //#region Check ff visibility const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.followingVisibility === 'private') { reply.code(403); reply.header('Cache-Control', 'public, max-age=30'); return; - } else if (profile.ffVisibility === 'followers') { + } else if (profile.followingVisibility === 'followers') { reply.code(403); reply.header('Cache-Control', 'public, max-age=30'); return; @@ -493,8 +499,7 @@ export class ActivityPubServerService { @bindThis public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { - // addConstraintStrategy の型定義がおかしいため - (fastify.addConstraintStrategy as any)({ + fastify.addConstraintStrategy({ name: 'apOrHtml', storage() { const store = {} as any; diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index 26ae6dd52a..08d3d78c40 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -9,7 +9,7 @@ import { dirname } from 'node:path'; import { Inject, Injectable } from '@nestjs/common'; import rename from 'rename'; import sharp from 'sharp'; -import { sharpBmp } from 'sharp-read-bmp'; +import { sharpBmp } from '@misskey-dev/sharp-read-bmp'; import type { Config } from '@/config.js'; import type { MiDriveFile, DriveFilesRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; @@ -61,6 +61,9 @@ export class FileServerService { public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { fastify.addHook('onRequest', (request, reply, done) => { reply.header('Content-Security-Policy', 'default-src \'none\'; img-src \'self\'; media-src \'self\'; style-src \'unsafe-inline\''); + if (process.env.NODE_ENV === 'development') { + reply.header('Access-Control-Allow-Origin', '*'); + } done(); }); diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index f7b134a3cd..278145b4ab 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -107,7 +107,8 @@ export class ServerService implements OnApplicationShutdown { fastify.register(this.activityPubServerService.createServer); fastify.register(this.nodeinfoServerService.createServer); fastify.register(this.wellKnownServerService.createServer); - fastify.register(this.oauth2ProviderService.createServer); + fastify.register(this.oauth2ProviderService.createServer, { prefix: '/oauth' }); + fastify.register(this.oauth2ProviderService.createTokenServer, { prefix: '/oauth/token' }); fastify.get<{ Params: { path: string }; Querystring: { static?: any; badge?: any; }; }>('/emoji/:path(.*)', async (request, reply) => { const path = request.params.path; diff --git a/packages/backend/src/server/WellKnownServerService.ts b/packages/backend/src/server/WellKnownServerService.ts index 9caf6343d6..0f7bff5163 100644 --- a/packages/backend/src/server/WellKnownServerService.ts +++ b/packages/backend/src/server/WellKnownServerService.ts @@ -16,6 +16,7 @@ import * as Acct from '@/misc/acct.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import { NodeinfoServerService } from './NodeinfoServerService.js'; +import { OAuth2ProviderService } from './oauth/OAuth2ProviderService.js'; import type { FindOptionsWhere } from 'typeorm'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; @@ -30,6 +31,7 @@ export class WellKnownServerService { private nodeinfoServerService: NodeinfoServerService, private userEntityService: UserEntityService, + private oauth2ProviderService: OAuth2ProviderService, ) { //this.createServer = this.createServer.bind(this); } @@ -87,6 +89,10 @@ export class WellKnownServerService { return { links: this.nodeinfoServerService.getLinks() }; }); + fastify.get('/.well-known/oauth-authorization-server', async () => { + return this.oauth2ProviderService.generateRFC8414(); + }); + /* TODO fastify.get('/.well-known/change-password', async (request, reply) => { }); diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index 9c0aee7d12..e65d1f50f1 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -332,7 +332,8 @@ export class ApiCallService implements OnApplicationShutdown { } } - if (token && ep.meta.kind && !token.permission.some(p => p === ep.meta.kind)) { + if (token && ((ep.meta.kind && !token.permission.some(p => p === ep.meta.kind)) + || (!ep.meta.kind && (ep.meta.requireCredential || ep.meta.requireModerator || ep.meta.requireAdmin)))) { throw new ApiError({ message: 'Your app does not have the necessary permissions to use this endpoint.', code: 'PERMISSION_DENIED', diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index ae10d06144..f3f3e87ffa 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -216,6 +216,7 @@ import * as ep___i_exportBlocking from './endpoints/i/export-blocking.js'; import * as ep___i_exportFollowing from './endpoints/i/export-following.js'; import * as ep___i_exportMute from './endpoints/i/export-mute.js'; import * as ep___i_exportNotes from './endpoints/i/export-notes.js'; +import * as ep___i_exportClips from './endpoints/i/export-clips.js'; import * as ep___i_exportFavorites from './endpoints/i/export-favorites.js'; import * as ep___i_exportUserLists from './endpoints/i/export-user-lists.js'; import * as ep___i_exportAntennas from './endpoints/i/export-antennas.js'; @@ -608,6 +609,7 @@ const $i_exportBlocking: Provider = { provide: 'ep:i/export-blocking', useClass: const $i_exportFollowing: Provider = { provide: 'ep:i/export-following', useClass: ep___i_exportFollowing.default }; const $i_exportMute: Provider = { provide: 'ep:i/export-mute', useClass: ep___i_exportMute.default }; const $i_exportNotes: Provider = { provide: 'ep:i/export-notes', useClass: ep___i_exportNotes.default }; +const $i_exportClips: Provider = { provide: 'ep:i/export-clips', useClass: ep___i_exportClips.default }; const $i_exportFavorites: Provider = { provide: 'ep:i/export-favorites', useClass: ep___i_exportFavorites.default }; const $i_exportUserLists: Provider = { provide: 'ep:i/export-user-lists', useClass: ep___i_exportUserLists.default }; const $i_exportAntennas: Provider = { provide: 'ep:i/export-antennas', useClass: ep___i_exportAntennas.default }; @@ -1005,6 +1007,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $i_exportFollowing, $i_exportMute, $i_exportNotes, + $i_exportClips, $i_exportFavorites, $i_exportUserLists, $i_exportAntennas, @@ -1395,6 +1398,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $i_exportFollowing, $i_exportMute, $i_exportNotes, + $i_exportClips, $i_exportFavorites, $i_exportUserLists, $i_exportAntennas, diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts index 30612062b5..865890591b 100644 --- a/packages/backend/src/server/api/SignupApiService.ts +++ b/packages/backend/src/server/api/SignupApiService.ts @@ -65,6 +65,7 @@ export class SignupApiService { 'hcaptcha-response'?: string; 'g-recaptcha-response'?: string; 'turnstile-response'?: string; + 'm-captcha-response'?: string; } }>, reply: FastifyReply, @@ -82,6 +83,12 @@ export class SignupApiService { }); } + if (instance.enableMcaptcha && instance.mcaptchaSecretKey && instance.mcaptchaSitekey && instance.mcaptchaInstanceUrl) { + await this.captchaService.verifyMcaptcha(instance.mcaptchaSecretKey, instance.mcaptchaSitekey, instance.mcaptchaInstanceUrl, body['m-captcha-response']).catch(err => { + throw new FastifyReplyError(400, err); + }); + } + if (instance.enableRecaptcha && instance.recaptchaSecretKey) { await this.captchaService.verifyRecaptcha(instance.recaptchaSecretKey, body['g-recaptcha-response']).catch(err => { throw new FastifyReplyError(400, err); diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index bec3928493..04bc2a8827 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -71,6 +71,10 @@ export class StreamingApiServerService { try { [user, app] = await this.authenticateService.authenticate(token); + + if (app !== null && !app.permission.some(p => p === 'read:account')) { + throw new AuthenticationError('Your app does not have necessary permissions to use websocket API.'); + } } catch (e) { if (e instanceof AuthenticationError) { socket.write([ diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index e322a89d95..194e0ab027 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { permissions } from 'cherrypick-js'; import type { Schema } from '@/misc/json-schema.js'; import { RolePolicies } from '@/core/RoleService.js'; @@ -215,6 +216,7 @@ import * as ep___i_exportBlocking from './endpoints/i/export-blocking.js'; import * as ep___i_exportFollowing from './endpoints/i/export-following.js'; import * as ep___i_exportMute from './endpoints/i/export-mute.js'; import * as ep___i_exportNotes from './endpoints/i/export-notes.js'; +import * as ep___i_exportClips from './endpoints/i/export-clips.js'; import * as ep___i_exportFavorites from './endpoints/i/export-favorites.js'; import * as ep___i_exportUserLists from './endpoints/i/export-user-lists.js'; import * as ep___i_exportAntennas from './endpoints/i/export-antennas.js'; @@ -605,6 +607,7 @@ const eps = [ ['i/export-following', ep___i_exportFollowing], ['i/export-mute', ep___i_exportMute], ['i/export-notes', ep___i_exportNotes], + ['i/export-clips', ep___i_exportClips], ['i/export-favorites', ep___i_exportFavorites], ['i/export-user-lists', ep___i_exportUserLists], ['i/export-antennas', ep___i_exportAntennas], @@ -786,7 +789,7 @@ const eps = [ ['retention', ep___retention], ]; -export interface IEndpointMeta { +interface IEndpointMetaBase { readonly stability?: 'deprecated' | 'experimental' | 'stable'; readonly tags?: ReadonlyArray; @@ -885,6 +888,23 @@ export interface IEndpointMeta { readonly cacheSec?: number; } +export type IEndpointMeta = (Omit & { + requireCredential?: false, + requireAdmin?: false, + requireModerator?: false, +}) | (Omit & { + secure: true, +}) | (Omit & { + requireCredential: true, + kind: (typeof permissions)[number], +}) | (Omit & { + requireModerator: true, + kind: (typeof permissions)[number], +}) | (Omit & { + requireAdmin: true, + kind: (typeof permissions)[number], +}) + export interface IEndpoint { name: string; meta: IEndpointMeta; 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 69f347e43d..f07972c331 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 @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:abuse-user-reports', res: { type: 'array', 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 ebcc820c53..569baad0f3 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts @@ -46,12 +46,12 @@ export default class extends Endpoint { // eslint- private userEntityService: UserEntityService, private signupService: SignupService, ) { - super(meta, paramDef, async (ps, _me) => { + super(meta, paramDef, async (ps, _me, token) => { const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null; const noUsers = (await this.usersRepository.countBy({ host: IsNull(), })) === 0; - if (!noUsers && !me?.isRoot) throw new Error('access denied'); + if ((!noUsers && !me?.isRoot) || token !== null) throw new Error('access denied'); const { account, secret } = await this.signupService.signup({ username: ps.username, diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts index 9db8abcb7a..a93e1c0fa4 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'write:admin:account', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts b/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts index 9a42a4fe68..70bf985709 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'read:admin:account', errors: { userNotFound: { @@ -23,6 +24,11 @@ export const meta = { id: 'cb865949-8af5-4062-a88c-ef55e8786d1d', }, }, + res: { + type: 'object', + optional: false, nullable: false, + ref: 'User', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts index 06eece1c81..852a558e41 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts @@ -15,6 +15,13 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:ad', + res: { + type: 'object', + optional: false, + nullable: false, + ref: 'Ad', + }, } as const; export const paramDef = { @@ -61,7 +68,18 @@ export default class extends Endpoint { // eslint- ad: ad, }); - return ad; + return { + id: ad.id, + expiresAt: ad.expiresAt.toISOString(), + startsAt: ad.startsAt.toISOString(), + dayOfWeek: ad.dayOfWeek, + url: ad.url, + imageUrl: ad.imageUrl, + priority: ad.priority, + ratio: ad.ratio, + place: ad.place, + memo: ad.memo, + }; }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts index 4181541550..9bc4a25888 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:ad', errors: { noSuchAd: { diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index c600d45db0..0d1eee847d 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -14,6 +14,18 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:ad', + res: { + type: 'array', + optional: false, + nullable: false, + items: { + type: 'object', + optional: false, + nullable: false, + ref: 'Ad', + }, + }, } as const; export const paramDef = { @@ -44,7 +56,18 @@ export default class extends Endpoint { // eslint- } const ads = await query.limit(ps.limit).getMany(); - return ads; + return ads.map(ad => ({ + id: ad.id, + expiresAt: ad.expiresAt.toISOString(), + startsAt: ad.startsAt.toISOString(), + dayOfWeek: ad.dayOfWeek, + url: ad.url, + imageUrl: ad.imageUrl, + memo: ad.memo, + place: ad.place, + priority: ad.priority, + ratio: ad.ratio, + })); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts index c6090583cf..dfe6e55e51 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:ad', errors: { noSuchAd: { diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 010c6567f4..603e9a2c96 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:announcements', res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts index e27adf3e88..c7e6aa1e39 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:announcements', errors: { noSuchAnnouncement: { diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index ab24533b2b..ae458afa35 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:announcements', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index b682279dd1..53b681f94f 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:announcements', errors: { noSuchAnnouncement: { diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts index e1f7bc060b..59cec7f075 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageAvatarDecorations', + kind: 'write:admin:avatar-decorations', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts index ba51fd9d3a..d5af225e9c 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageAvatarDecorations', + kind: 'write:admin:avatar-decorations', errors: { }, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts index 620501ecc3..c171c78580 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts @@ -17,6 +17,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageAvatarDecorations', + kind: 'read:admin:avatar-decorations', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts index 17e13588b5..2dbad159cf 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageAvatarDecorations', + kind: 'write:admin:avatar-decorations', errors: { }, diff --git a/packages/backend/src/server/api/endpoints/admin/delete-account.ts b/packages/backend/src/server/api/endpoints/admin/delete-account.ts index 5fc6c07aef..b6be624545 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-account.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'write:admin:delete-account', res: { }, diff --git a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts index 8fc9962dbf..02dcaa9c0c 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'write:admin:delete-all-files-of-a-user', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts index b8c2ad4f2c..76fec430c6 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:drive', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts index bb3ae0e7a4..5fc776e8c7 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:drive', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/drive/files.ts b/packages/backend/src/server/api/endpoints/admin/drive/files.ts index 503b39653c..c8bacf428d 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/files.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:drive', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts index efe556a951..0d35784c04 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:drive', errors: { noSuchFile: { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts index dd32aa6f48..46f5a2dc32 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index a86c84e90b..4ad3691da4 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', errors: { noSuchFile: { @@ -29,6 +30,8 @@ export const meta = { id: 'f7a3462c-4e6e-4069-8421-b9bd4f4c3975', }, }, + + ref: 'EmojiDetailed', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/adds.ts b/packages/backend/src/server/api/endpoints/admin/emoji/adds.ts index 4140f63e54..b7e38e3ff1 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/adds.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/adds.ts @@ -17,6 +17,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', errors: { noSuchFile: { @@ -30,6 +31,8 @@ export const meta = { id: 'f7a3462c-4e6e-4069-8421-b9bd4f4c3975', }, }, + + ref: 'EmojiDetailed', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts index 28c5b25ace..6f9b43d8e4 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts @@ -18,6 +18,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', errors: { noSuchEmoji: { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts index af67bbc40c..47d0cc605a 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index 780a1736ac..388e34a581 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', errors: { noSuchEmoji: { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index 2f613b709f..d24fb1025a 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -17,6 +17,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'read:admin:emoji', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts index 5293629f74..4b39631c0c 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts @@ -17,6 +17,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'read:admin:emoji', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts index e25c1fb569..9318d8ae9f 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts index 4ee043f071..2ac4da8748 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts index 8d36518298..4ae6d7edfc 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts index 240b8d9f07..31ec9b8e4e 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/steal.ts b/packages/backend/src/server/api/endpoints/admin/emoji/steal.ts index 6de29380c5..a9d9dd24bc 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/steal.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/steal.ts @@ -19,6 +19,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', errors: { noSuchEmoji: { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index cc4faefa5b..93f3fdae77 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', + kind: 'write:admin:emoji', errors: { noSuchEmoji: { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts index 4fca864ba2..7b6b024f40 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:federation', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index 46ef9b0074..ab9dd7194f 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:federation', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts index 14f267438a..4ba89eaa38 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:federation', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index a2321015e6..afba344966 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:federation', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts index c7a63f1b86..1ce08d1fcd 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts @@ -11,8 +11,19 @@ import { DI } from '@/di-symbols.js'; export const meta = { requireCredential: true, requireAdmin: true, + kind: 'read:admin:index-stats', tags: ['admin'], + res: { + type: 'array', + items: { + type: 'object', + properties: { + tablename: { type: 'string' }, + indexname: { type: 'string' }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts index 57a555c795..4db012b35b 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts @@ -11,6 +11,7 @@ import { DI } from '@/di-symbols.js'; export const meta = { requireCredential: true, requireAdmin: true, + kind: 'read:admin:table-stats', tags: ['admin'], diff --git a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts index e73a2c4468..7fa3159a85 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts @@ -14,6 +14,26 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:user-ips', + res: { + type: 'array', + optional: false, + nullable: false, + items: { + type: 'object', + optional: false, + nullable: false, + properties: { + ip: { type: 'string' }, + createdAt: { + type: 'string', + optional: false, + nullable: false, + format: 'date-time', + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/invite/create.ts b/packages/backend/src/server/api/endpoints/admin/invite/create.ts index 72674a193c..9bbb1b41f2 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/create.ts @@ -18,6 +18,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:invite-codes', errors: { invalidDateTime: { diff --git a/packages/backend/src/server/api/endpoints/admin/invite/list.ts b/packages/backend/src/server/api/endpoints/admin/invite/list.ts index 4bcf78a4b6..6a11418dd3 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/list.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:invite-codes', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/invite/revoke.ts b/packages/backend/src/server/api/endpoints/admin/invite/revoke.ts index 344fddeb54..83ee1d11bf 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/revoke.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/revoke.ts @@ -13,6 +13,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:invite-codes', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 9e98cd1af1..5d325d5850 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'read:admin:meta', res: { type: 'object', @@ -40,6 +41,18 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + enableMcaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + mcaptchaSiteKey: { + type: 'string', + optional: false, nullable: true, + }, + mcaptchaInstanceUrl: { + type: 'string', + optional: false, nullable: true, + }, enableRecaptcha: { type: 'boolean', optional: false, nullable: false, @@ -147,6 +160,14 @@ export const meta = { type: 'string', }, }, + bannedEmailDomains: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, preservedUsernames: { type: 'array', optional: false, nullable: false, @@ -158,6 +179,10 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + mcaptchaSecretKey: { + type: 'string', + optional: false, nullable: true, + }, recaptchaSecretKey: { type: 'string', optional: false, nullable: true, @@ -327,6 +352,18 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + enableTruemailApi: { + type: 'boolean', + optional: false, nullable: false, + }, + truemailInstance: { + type: 'string', + optional: false, nullable: true, + }, + truemailAuthKey: { + type: 'string', + optional: false, nullable: true, + }, enableChartsForRemoteUser: { type: 'boolean', optional: false, nullable: false, @@ -347,14 +384,6 @@ export const meta = { type: 'string', optional: false, nullable: false, }, - doNotSendNotificationEmailsForAbuseReport: { - type: 'boolean', - optional: false, nullable: false, - }, - emailToReceiveAbuseReport: { - type: 'string', - optional: false, nullable: true, - }, policies: { type: 'object', optional: false, nullable: false, @@ -431,10 +460,18 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + shortName: { + type: 'string', + optional: false, nullable: true, + }, objectStorageS3ForcePathStyle: { type: 'boolean', optional: false, nullable: false, }, + objectStorageRemoteS3ForcePathStyle: { + type: 'boolean', + optional: false, nullable: false, + }, privacyPolicyUrl: { type: 'string', optional: false, nullable: true, @@ -463,6 +500,14 @@ export const meta = { type: 'string', optional: false, nullable: false, }, + doNotSendNotificationEmailsForAbuseReport: { + type: 'boolean', + optional: false, nullable: false, + }, + emailToReceiveAbuseReport: { + type: 'string', + optional: false, nullable: true, + }, enableReceivePrerelease: { type: 'boolean', optional: false, nullable: false, @@ -516,6 +561,9 @@ export default class extends Endpoint { // eslint- emailRequiredForSignup: instance.emailRequiredForSignup, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, + enableMcaptcha: instance.enableMcaptcha, + mcaptchaSiteKey: instance.mcaptchaSitekey, + mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl, enableRecaptcha: instance.enableRecaptcha, recaptchaSiteKey: instance.recaptchaSiteKey, enableTurnstile: instance.enableTurnstile, @@ -550,6 +598,7 @@ export default class extends Endpoint { // eslint- sensitiveWords: instance.sensitiveWords, preservedUsernames: instance.preservedUsernames, hcaptchaSecretKey: instance.hcaptchaSecretKey, + mcaptchaSecretKey: instance.mcaptchaSecretKey, recaptchaSecretKey: instance.recaptchaSecretKey, turnstileSecretKey: instance.turnstileSecretKey, sensitiveMediaDetection: instance.sensitiveMediaDetection, @@ -602,12 +651,14 @@ export default class extends Endpoint { // eslint- enableActiveEmailValidation: instance.enableActiveEmailValidation, enableVerifymailApi: instance.enableVerifymailApi, verifymailAuthKey: instance.verifymailAuthKey, + enableTruemailApi: instance.enableTruemailApi, + truemailInstance: instance.truemailInstance, + truemailAuthKey: instance.truemailAuthKey, enableChartsForRemoteUser: instance.enableChartsForRemoteUser, enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances, enableServerMachineStats: instance.enableServerMachineStats, enableIdenticonGeneration: instance.enableIdenticonGeneration, - doNotSendNotificationEmailsForAbuseReport: instance.doNotSendNotificationEmailsForAbuseReport, - emailToReceiveAbuseReport: instance.emailToReceiveAbuseReport, + bannedEmailDomains: instance.bannedEmailDomains, policies: { ...DEFAULT_POLICIES, ...instance.policies }, manifestJsonOverride: instance.manifestJsonOverride, enableFanoutTimeline: instance.enableFanoutTimeline, @@ -617,6 +668,8 @@ export default class extends Endpoint { // eslint- perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax, perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax, notesPerOneAd: instance.notesPerOneAd, + doNotSendNotificationEmailsForAbuseReport: instance.doNotSendNotificationEmailsForAbuseReport, + emailToReceiveAbuseReport: instance.emailToReceiveAbuseReport, enableReceivePrerelease: instance.enableReceivePrerelease, skipVersion: instance.skipVersion, skipCherryPickVersion: instance.skipCherryPickVersion, diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts index d4da023def..ac6770a4f2 100644 --- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:promo', errors: { noSuchNote: { diff --git a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts index 31c35f2564..9e5f597b80 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts @@ -13,6 +13,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:queue', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts index 2eaf40f777..65d29c7b13 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:queue', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts index d0b90e099c..ed32d0f1a9 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:queue', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/queue/promote.ts b/packages/backend/src/server/api/endpoints/admin/queue/promote.ts index 5a5702a758..fa9805038c 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/promote.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/promote.ts @@ -13,6 +13,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:queue', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts index 91ef15f650..34da300c90 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:emoji', res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/admin/relays/add.ts b/packages/backend/src/server/api/endpoints/admin/relays/add.ts index ebb0f9e8f3..240a076320 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/add.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:relays', errors: { invalidUrl: { diff --git a/packages/backend/src/server/api/endpoints/admin/relays/list.ts b/packages/backend/src/server/api/endpoints/admin/relays/list.ts index 9e5b41cf51..d764e3c17f 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/list.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:relays', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts index a10351f88c..8fd8725e41 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:relays', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index b8b9ed0c2f..eb7034c05c 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:reset-password', res: { type: 'object', 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 74058f3c30..5f6bce6b24 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 @@ -17,6 +17,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:resolve-abuse-user-report', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/roles/assign.ts b/packages/backend/src/server/api/endpoints/admin/roles/assign.ts index b7f8a22673..13b6692a06 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/assign.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/assign.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:roles', errors: { noSuchRole: { diff --git a/packages/backend/src/server/api/endpoints/admin/roles/create.ts b/packages/backend/src/server/api/endpoints/admin/roles/create.ts index e6ce434c48..3d252eeab4 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/create.ts @@ -13,6 +13,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'write:admin:roles', res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/admin/roles/delete.ts b/packages/backend/src/server/api/endpoints/admin/roles/delete.ts index fe8a6cbff6..2a6ebea34b 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/delete.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'write:admin:roles', errors: { noSuchRole: { diff --git a/packages/backend/src/server/api/endpoints/admin/roles/list.ts b/packages/backend/src/server/api/endpoints/admin/roles/list.ts index 618d874061..c86e32d6d5 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/list.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:roles', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/roles/show.ts b/packages/backend/src/server/api/endpoints/admin/roles/show.ts index 1a536bcfc4..5350c95594 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/show.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/show.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:roles', errors: { noSuchRole: { diff --git a/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts b/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts index df2dd70b11..061e934547 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:roles', errors: { noSuchRole: { diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts index f3a4aa3df5..411c87f5a7 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts @@ -13,6 +13,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'write:admin:roles', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts index a823a4753a..582b9cc739 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'write:admin:roles', errors: { noSuchRole: { diff --git a/packages/backend/src/server/api/endpoints/admin/roles/users.ts b/packages/backend/src/server/api/endpoints/admin/roles/users.ts index 8e6ffbcc39..7de98434ff 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/users.ts @@ -18,6 +18,7 @@ export const meta = { requireCredential: false, requireAdmin: true, + kind: 'read:admin:roles', errors: { noSuchRole: { @@ -26,6 +27,20 @@ export const meta = { id: '224eff5e-2488-4b18-b3e7-f50d94421648', }, }, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string', format: 'misskey:id' }, + createdAt: { type: 'string', format: 'date-time' }, + user: { ref: 'UserDetailed' }, + expiresAt: { type: 'string', format: 'date-time', nullable: true }, + }, + required: ['id', 'createdAt', 'user'], + }, + }, } as const; export const paramDef = { @@ -78,7 +93,7 @@ export default class extends Endpoint { // eslint- id: assign.id, createdAt: this.idService.parse(assign.id).date.toISOString(), user: await this.userEntityService.pack(assign.user!, me, { detail: true }), - expiresAt: assign.expiresAt, + expiresAt: assign.expiresAt?.toISOString() ?? null, }))); }); } diff --git a/packages/backend/src/server/api/endpoints/admin/send-email.ts b/packages/backend/src/server/api/endpoints/admin/send-email.ts index f4a3bd872b..ed1f125695 100644 --- a/packages/backend/src/server/api/endpoints/admin/send-email.ts +++ b/packages/backend/src/server/api/endpoints/admin/send-email.ts @@ -12,6 +12,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:send-email', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/server-info.ts b/packages/backend/src/server/api/endpoints/admin/server-info.ts index b4cdff4fbf..15e26f5d3c 100644 --- a/packages/backend/src/server/api/endpoints/admin/server-info.ts +++ b/packages/backend/src/server/api/endpoints/admin/server-info.ts @@ -14,6 +14,7 @@ import { DI } from '@/di-symbols.js'; export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:server-info', tags: ['admin', 'meta'], diff --git a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts index e158a6051a..d70ddd021a 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts @@ -14,7 +14,8 @@ export const meta = { tags: ['admin'], requireCredential: true, - requireModerator: true, + requireAdmin: true, + kind: 'read:admin:show-moderation-log', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 042ede39b8..39a91b7a69 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:show-user', res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index 00354821f0..ca705ca307 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin:show-users', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts index 82ad8e94dc..0e1df29db9 100644 --- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts @@ -21,6 +21,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:suspend-user', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts index 00c5902eb0..65ecade35d 100644 --- a/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:unset-user-avatar', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts index 15122f59a0..31c3879b6b 100644 --- a/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:unset-user-banner', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts index 31500af29c..3e9095d8b2 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:unsuspend-user', } as const; export const paramDef = { 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 a4ae256f49..bed856a750 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'write:admin:meta', } as const; export const paramDef = { @@ -64,6 +65,10 @@ export const paramDef = { enableHcaptcha: { type: 'boolean' }, hcaptchaSiteKey: { type: 'string', nullable: true }, hcaptchaSecretKey: { type: 'string', nullable: true }, + enableMcaptcha: { type: 'boolean' }, + mcaptchaSiteKey: { type: 'string', nullable: true }, + mcaptchaInstanceUrl: { type: 'string', nullable: true }, + mcaptchaSecretKey: { type: 'string', nullable: true }, enableRecaptcha: { type: 'boolean' }, recaptchaSiteKey: { type: 'string', nullable: true }, recaptchaSecretKey: { type: 'string', nullable: true }, @@ -136,13 +141,15 @@ export const paramDef = { enableActiveEmailValidation: { type: 'boolean' }, enableVerifymailApi: { type: 'boolean' }, verifymailAuthKey: { type: 'string', nullable: true }, + enableTruemailApi: { type: 'boolean' }, + truemailInstance: { type: 'string', nullable: true }, + truemailAuthKey: { type: 'string', nullable: true }, enableChartsForRemoteUser: { type: 'boolean' }, enableChartsForFederatedInstances: { type: 'boolean' }, enableServerMachineStats: { type: 'boolean' }, enableIdenticonGeneration: { type: 'boolean' }, - doNotSendNotificationEmailsForAbuseReport: { type: 'boolean' }, - emailToReceiveAbuseReport: { type: 'string', nullable: true }, serverRules: { type: 'array', items: { type: 'string' } }, + bannedEmailDomains: { type: 'array', items: { type: 'string' } }, preservedUsernames: { type: 'array', items: { type: 'string' } }, manifestJsonOverride: { type: 'string' }, enableFanoutTimeline: { type: 'boolean' }, @@ -159,6 +166,8 @@ export const paramDef = { type: 'string', }, }, + doNotSendNotificationEmailsForAbuseReport: { type: 'boolean' }, + emailToReceiveAbuseReport: { type: 'string', nullable: true }, enableReceivePrerelease: { type: 'boolean' }, skipVersion: { type: 'boolean' }, skipCherryPickVersion: { type: 'string', nullable: true }, @@ -291,6 +300,22 @@ export default class extends Endpoint { // eslint- set.hcaptchaSecretKey = ps.hcaptchaSecretKey; } + if (ps.enableMcaptcha !== undefined) { + set.enableMcaptcha = ps.enableMcaptcha; + } + + if (ps.mcaptchaSiteKey !== undefined) { + set.mcaptchaSitekey = ps.mcaptchaSiteKey; + } + + if (ps.mcaptchaInstanceUrl !== undefined) { + set.mcaptchaInstanceUrl = ps.mcaptchaInstanceUrl; + } + + if (ps.mcaptchaSecretKey !== undefined) { + set.mcaptchaSecretKey = ps.mcaptchaSecretKey; + } + if (ps.enableRecaptcha !== undefined) { set.enableRecaptcha = ps.enableRecaptcha; } @@ -575,6 +600,26 @@ export default class extends Endpoint { // eslint- } } + if (ps.enableTruemailApi !== undefined) { + set.enableTruemailApi = ps.enableTruemailApi; + } + + if (ps.truemailInstance !== undefined) { + if (ps.truemailInstance === '') { + set.truemailInstance = null; + } else { + set.truemailInstance = ps.truemailInstance; + } + } + + if (ps.truemailAuthKey !== undefined) { + if (ps.truemailAuthKey === '') { + set.truemailAuthKey = null; + } else { + set.truemailAuthKey = ps.truemailAuthKey; + } + } + if (ps.enableChartsForRemoteUser !== undefined) { set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser; } @@ -591,14 +636,6 @@ export default class extends Endpoint { // eslint- set.enableIdenticonGeneration = ps.enableIdenticonGeneration; } - if (ps.doNotSendNotificationEmailsForAbuseReport !== undefined) { - set.doNotSendNotificationEmailsForAbuseReport = ps.doNotSendNotificationEmailsForAbuseReport; - } - - if (ps.emailToReceiveAbuseReport !== undefined) { - set.emailToReceiveAbuseReport = ps.emailToReceiveAbuseReport; - } - if (ps.serverRules !== undefined) { set.serverRules = ps.serverRules; } @@ -639,6 +676,18 @@ export default class extends Endpoint { // eslint- set.notesPerOneAd = ps.notesPerOneAd; } + if (ps.bannedEmailDomains !== undefined) { + set.bannedEmailDomains = ps.bannedEmailDomains; + } + + if (ps.doNotSendNotificationEmailsForAbuseReport !== undefined) { + set.doNotSendNotificationEmailsForAbuseReport = ps.doNotSendNotificationEmailsForAbuseReport; + } + + if (ps.emailToReceiveAbuseReport !== undefined) { + set.emailToReceiveAbuseReport = ps.emailToReceiveAbuseReport; + } + if (ps.enableReceivePrerelease !== undefined) { set.enableReceivePrerelease = ps.enableReceivePrerelease; } diff --git a/packages/backend/src/server/api/endpoints/admin/update-user-note.ts b/packages/backend/src/server/api/endpoints/admin/update-user-note.ts index 751e84af4f..38ca838a8c 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-user-note.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-user-note.ts @@ -14,6 +14,7 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'write:admin:user-note', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 4ff5c65192..5ef3038e05 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -14,6 +14,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { IdService } from '@/core/IdService.js'; import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { trackPromise } from '@/misc/promise-tracker.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -92,7 +93,7 @@ export default class extends Endpoint { // eslint- antenna.isActive = true; antenna.lastUsedAt = new Date(); - this.antennasRepository.update(antenna.id, antenna); + trackPromise(this.antennasRepository.update(antenna.id, antenna)); if (needPublishEvent) { this.globalEventService.publishInternalEvent('antennaUpdated', antenna); diff --git a/packages/backend/src/server/api/endpoints/ap/get.ts b/packages/backend/src/server/api/endpoints/ap/get.ts index 459cb838ad..42ddf90c22 100644 --- a/packages/backend/src/server/api/endpoints/ap/get.ts +++ b/packages/backend/src/server/api/endpoints/ap/get.ts @@ -12,6 +12,7 @@ export const meta = { tags: ['federation'], requireCredential: true, + kind: 'read:federation', limit: { duration: ms('1hour'), diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 5a37881b5b..43737bcb26 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -25,6 +25,7 @@ export const meta = { tags: ['federation'], requireCredential: true, + kind: 'read:account', limit: { duration: ms('1hour'), diff --git a/packages/backend/src/server/api/endpoints/endpoint.ts b/packages/backend/src/server/api/endpoints/endpoint.ts index 8d2c238746..2e2f1a09e6 100644 --- a/packages/backend/src/server/api/endpoints/endpoint.ts +++ b/packages/backend/src/server/api/endpoints/endpoint.ts @@ -11,6 +11,23 @@ export const meta = { requireCredential: false, tags: ['meta'], + + res: { + type: 'object', + nullable: true, + properties: { + params: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + type: { type: 'string' }, + }, + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/federation/stats.ts b/packages/backend/src/server/api/endpoints/federation/stats.ts index 8dffb836dd..9e2084b3e8 100644 --- a/packages/backend/src/server/api/endpoints/federation/stats.ts +++ b/packages/backend/src/server/api/endpoints/federation/stats.ts @@ -18,6 +18,38 @@ export const meta = { allowGet: true, cacheSec: 60 * 60, + + res: { + type: 'object', + optional: false, + nullable: false, + properties: { + topSubInstances: { + type: 'array', + optional: false, + nullable: false, + items: { + type: 'object', + optional: false, + nullable: false, + ref: 'FederationInstance', + }, + }, + otherFollowersCount: { type: 'number' }, + topPubInstances: { + type: 'array', + optional: false, + nullable: false, + items: { + type: 'object', + optional: false, + nullable: false, + ref: 'FederationInstance', + }, + }, + otherFollowingCount: { type: 'number' }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts index 0a1b05f344..721dff0202 100644 --- a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts +++ b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts @@ -11,7 +11,7 @@ import { GetterService } from '@/server/api/GetterService.js'; export const meta = { tags: ['federation'], - requireCredential: true, + requireCredential: false, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/fetch-external-resources.ts b/packages/backend/src/server/api/endpoints/fetch-external-resources.ts index f113e5b87a..34e576e2af 100644 --- a/packages/backend/src/server/api/endpoints/fetch-external-resources.ts +++ b/packages/backend/src/server/api/endpoints/fetch-external-resources.ts @@ -14,6 +14,7 @@ export const meta = { tags: ['meta'], requireCredential: true, + secure: true, limit: { duration: ms('1hour'), @@ -32,6 +33,18 @@ export const meta = { id: '693ba8ba-b486-40df-a174-72f8279b56a4', }, }, + + res: { + type: 'object', + properties: { + type: { + type: 'string', + }, + data: { + type: 'string', + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts index 283fe45b7a..f7f40f0216 100644 --- a/packages/backend/src/server/api/endpoints/fetch-rss.ts +++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts @@ -16,6 +16,18 @@ export const meta = { requireCredential: false, allowGet: true, cacheSec: 60 * 3, + + res: { + type: 'object', + properties: { + items: { + type: 'array', + items: { + type: 'object', + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/flash/create.ts b/packages/backend/src/server/api/endpoints/flash/create.ts index 12b70f06c3..df194df34e 100644 --- a/packages/backend/src/server/api/endpoints/flash/create.ts +++ b/packages/backend/src/server/api/endpoints/flash/create.ts @@ -27,6 +27,12 @@ export const meta = { errors: { }, + + res: { + type: 'object', + optional: false, nullable: false, + ref: 'Flash', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts index ec48e2aeca..b029c0739c 100644 --- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts +++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts @@ -16,6 +16,16 @@ export const meta = { requireCredential: false, allowGet: true, cacheSec: 60 * 1, + res: { + type: 'object', + optional: false, nullable: false, + properties: { + count: { + type: 'number', + nullable: false, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i.ts b/packages/backend/src/server/api/endpoints/i.ts index 9d617d597e..8876d1c382 100644 --- a/packages/backend/src/server/api/endpoints/i.ts +++ b/packages/backend/src/server/api/endpoints/i.ts @@ -14,6 +14,7 @@ export const meta = { tags: ['account'], requireCredential: true, + kind: 'read:account', res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index 421c1e14b6..e6a6a9de71 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -32,6 +32,16 @@ export const meta = { id: '798d6847-b1ed-4f9c-b1f9-163c42655995', }, }, + + res: { + type: 'object', + nullable: false, + optional: false, + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index 8218b7b09a..a851be60a6 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -36,6 +36,140 @@ export const meta = { id: 'bf32b864-449b-47b8-974e-f9a5468546f1', }, }, + + res: { + type: 'object', + nullable: false, + optional: false, + properties: { + rp: { + type: 'object', + properties: { + id: { + type: 'string', + nullable: true, + }, + }, + }, + user: { + type: 'object', + properties: { + id: { + type: 'string', + }, + name: { + type: 'string', + }, + displayName: { + type: 'string', + }, + }, + }, + challenge: { + type: 'string', + }, + pubKeyCredParams: { + type: 'array', + items: { + type: 'object', + properties: { + type: { + type: 'string', + }, + alg: { + type: 'number', + }, + }, + }, + }, + timeout: { + type: 'number', + nullable: true, + }, + excludeCredentials: { + type: 'array', + nullable: true, + items: { + type: 'object', + properties: { + id: { + type: 'string', + }, + type: { + type: 'string', + }, + transports: { + type: 'array', + items: { + type: 'string', + enum: [ + 'ble', + 'cable', + 'hybrid', + 'internal', + 'nfc', + 'smart-card', + 'usb', + ], + }, + }, + }, + }, + }, + authenticatorSelection: { + type: 'object', + nullable: true, + properties: { + authenticatorAttachment: { + type: 'string', + enum: [ + 'cross-platform', + 'platform', + ], + }, + requireResidentKey: { + type: 'boolean', + }, + userVerification: { + type: 'string', + enum: [ + 'discouraged', + 'preferred', + 'required', + ], + }, + }, + }, + attestation: { + type: 'string', + nullable: true, + enum: [ + 'direct', + 'enterprise', + 'indirect', + 'none', + ], + }, + extensions: { + type: 'object', + nullable: true, + properties: { + appid: { + type: 'string', + nullable: true, + }, + credProps: { + type: 'boolean', + nullable: true, + }, + hmacCreateSecret: { + type: 'boolean', + nullable: true, + }, + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts index bb3f3591b9..8180bc38c4 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts @@ -26,6 +26,19 @@ export const meta = { id: '78d6c839-20c9-4c66-b90a-fc0542168b48', }, }, + + res: { + type: 'object', + nullable: false, + optional: false, + properties: { + qr: { type: 'string' }, + url: { type: 'string' }, + secret: { type: 'string' }, + label: { type: 'string' }, + issuer: { type: 'string' }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/apps.ts b/packages/backend/src/server/api/endpoints/i/apps.ts index 7d5020dfe5..aca50639f6 100644 --- a/packages/backend/src/server/api/endpoints/i/apps.ts +++ b/packages/backend/src/server/api/endpoints/i/apps.ts @@ -13,6 +13,37 @@ export const meta = { requireCredential: true, secure: true, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + name: { + type: 'string', + }, + createdAt: { + type: 'string', + format: 'date-time', + }, + lastUsedAt: { + type: 'string', + format: 'date-time', + }, + permission: { + type: 'array', + uniqueItems: true, + items: { + type: 'string', + }, + }, + }, + }, + }, } as const; export const paramDef = { @@ -50,7 +81,7 @@ export default class extends Endpoint { // eslint- id: token.id, name: token.name ?? token.app?.name, createdAt: this.idService.parse(token.id).date.toISOString(), - lastUsedAt: token.lastUsedAt, + lastUsedAt: token.lastUsedAt?.toISOString(), permission: token.permission, }))); }); diff --git a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts index f7a5d05c0f..5e6d620bc7 100644 --- a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts +++ b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts @@ -14,6 +14,36 @@ export const meta = { requireCredential: true, secure: true, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + name: { + type: 'string', + }, + callbackUrl: { + type: 'string', + nullable: true, + }, + permission: { + type: 'array', + uniqueItems: true, + items: { + type: 'string', + }, + }, + isAuthorized: { + type: 'boolean', + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/claim-achievement.ts b/packages/backend/src/server/api/endpoints/i/claim-achievement.ts index c4b3a0ed28..02af198d66 100644 --- a/packages/backend/src/server/api/endpoints/i/claim-achievement.ts +++ b/packages/backend/src/server/api/endpoints/i/claim-achievement.ts @@ -10,6 +10,7 @@ import { AchievementService, ACHIEVEMENT_TYPES } from '@/core/AchievementService export const meta = { requireCredential: true, prohibitMoved: true, + kind: 'write:account', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/export-clips.ts b/packages/backend/src/server/api/endpoints/i/export-clips.ts new file mode 100644 index 0000000000..e0dd62817c --- /dev/null +++ b/packages/backend/src/server/api/endpoints/i/export-clips.ts @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import ms from 'ms'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { QueueService } from '@/core/QueueService.js'; + +export const meta = { + secure: true, + requireCredential: true, + limit: { + duration: ms('1day'), + max: 1, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private queueService: QueueService, + ) { + super(meta, paramDef, async (ps, me) => { + this.queueService.createExportClipsJob(me); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/i/move.ts b/packages/backend/src/server/api/endpoints/i/move.ts index 7c75198c86..88a5d368a2 100644 --- a/packages/backend/src/server/api/endpoints/i/move.ts +++ b/packages/backend/src/server/api/endpoints/i/move.ts @@ -64,6 +64,10 @@ export const meta = { id: 'b234a14e-9ebe-4581-8000-074b3c215962', }, }, + + res: { + type: 'object', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts index ff56b219b8..fb01e3b44e 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts @@ -9,6 +9,11 @@ import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, + kind: 'read:account', + + res: { + type: 'object', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts index af6fe49787..7f311d0f12 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts @@ -10,6 +10,7 @@ import { ApiError } from '../../../error.js'; export const meta = { requireCredential: true, + kind: 'read:account', errors: { noSuchKey: { @@ -18,6 +19,10 @@ export const meta = { id: '97a1e8e7-c0f7-47d2-957a-92e61256e01a', }, }, + + res: { + type: 'object', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/get.ts b/packages/backend/src/server/api/endpoints/i/registry/get.ts index 819a63891b..5e5e2552dc 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get.ts @@ -10,6 +10,7 @@ import { ApiError } from '../../../error.js'; export const meta = { requireCredential: true, + kind: 'read:account', errors: { noSuchKey: { @@ -18,6 +19,10 @@ export const meta = { id: 'ac3ed68a-62f0-422b-a7bc-d5e09e8f6a6a', }, }, + + res: { + type: 'object', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts index f2a96464cd..5732f391f9 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts @@ -3,12 +3,17 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, + kind: 'read:account', + + res: { + type: 'object', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys.ts b/packages/backend/src/server/api/endpoints/i/registry/keys.ts index ac008466f9..cd0d9bde7e 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys.ts @@ -9,6 +9,7 @@ import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, + kind: 'read:account', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/remove.ts b/packages/backend/src/server/api/endpoints/i/registry/remove.ts index 2ed6f21d41..e31fc35c10 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/remove.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/remove.ts @@ -12,6 +12,7 @@ import { ApiError } from '../../../error.js'; export const meta = { requireCredential: true, + kind: 'write:account', errors: { noSuchKey: { diff --git a/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts b/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts index a5088cab76..5abc0b0549 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts @@ -3,13 +3,35 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, secure: true, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + scopes: { + type: 'array', + items: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + domain: { + type: 'string', + nullable: true, + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/set.ts b/packages/backend/src/server/api/endpoints/i/registry/set.ts index ca7f45afe6..baa4292080 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/set.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/set.ts @@ -9,6 +9,7 @@ import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, + kind: 'write:account', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts index 22e0447f6b..d342a2fa96 100644 --- a/packages/backend/src/server/api/endpoints/i/update-email.ts +++ b/packages/backend/src/server/api/endpoints/i/update-email.ts @@ -40,6 +40,11 @@ export const meta = { id: 'a2defefb-f220-8849-0af6-17f816099323', }, }, + + res: { + type: 'object', + ref: 'UserDetailed', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index d712c3a0b4..08c119201d 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -137,15 +137,15 @@ export const paramDef = { birthday: { ...birthdaySchema, nullable: true }, lang: { type: 'string', enum: [null, ...Object.keys(langmap)] as string[], nullable: true }, avatarId: { type: 'string', format: 'misskey:id', nullable: true }, - avatarDecorations: { type: 'array', maxItems: 5, items: { + avatarDecorations: { type: 'array', maxItems: 16, items: { type: 'object', properties: { id: { type: 'string', format: 'misskey:id' }, angle: { type: 'number', nullable: true, maximum: 0.5, minimum: -0.5 }, flipH: { type: 'boolean', nullable: true }, + offsetX: { type: 'number', nullable: true, maximum: 0.25, minimum: -0.25 }, + offsetY: { type: 'number', nullable: true, maximum: 0.25, minimum: -0.25 }, scale: { type: 'number', nullable: true, maximum: 1.5, minimum: 0.5 }, - moveX: { type: 'number', nullable: true, maximum: 25, minimum: -25 }, - moveY: { type: 'number', nullable: true, maximum: 25, minimum: -25 }, opacity: { type: 'number', nullable: true, maximum: 1, minimum: 0.1 }, }, required: ['id'], @@ -178,7 +178,8 @@ export const paramDef = { receiveAnnouncementEmail: { type: 'boolean' }, alwaysMarkNsfw: { type: 'boolean' }, autoSensitive: { type: 'boolean' }, - ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, + followingVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, + followersVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, pinnedPageId: { type: 'string', format: 'misskey:id', nullable: true }, mutedWords: muteWords, hardMutedWords: muteWords, @@ -243,7 +244,8 @@ export default class extends Endpoint { // eslint- if (ps.lang !== undefined) profileUpdates.lang = ps.lang; if (ps.location !== undefined) profileUpdates.location = ps.location; if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday; - if (ps.ffVisibility !== undefined) profileUpdates.ffVisibility = ps.ffVisibility; + if (ps.followingVisibility !== undefined) profileUpdates.followingVisibility = ps.followingVisibility; + if (ps.followersVisibility !== undefined) profileUpdates.followersVisibility = ps.followersVisibility; function checkMuteWordCount(mutedWords: (string[] | string)[], limit: number) { // TODO: ちゃんと数える @@ -333,19 +335,21 @@ export default class extends Endpoint { // eslint- if (ps.avatarDecorations) { const decorations = await this.avatarDecorationService.getAll(true); - const myRoles = await this.roleService.getUserRoles(user.id); + const [myRoles, myPolicies] = await Promise.all([this.roleService.getUserRoles(user.id), this.roleService.getUserPolicies(user.id)]); const allRoles = await this.roleService.getRoles(); const decorationIds = decorations .filter(d => d.roleIdsThatCanBeUsedThisDecoration.filter(roleId => allRoles.some(r => r.id === roleId)).length === 0 || myRoles.some(r => d.roleIdsThatCanBeUsedThisDecoration.includes(r.id))) .map(d => d.id); + if (ps.avatarDecorations.length > myPolicies.avatarDecorationLimit) throw new ApiError(meta.errors.restrictedByRole); + updates.avatarDecorations = ps.avatarDecorations.filter(d => decorationIds.includes(d.id)).map(d => ({ id: d.id, angle: d.angle ?? 0, flipH: d.flipH ?? false, + offsetX: d.offsetX ?? 0, + offsetY: d.offsetY ?? 0, scale: d.scale ?? 1, - moveX: d.moveX ?? 0, - moveY: d.moveY ?? 0, opacity: d.opacity ?? 1, })); } diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts index 5f7d81cabc..47e2a0a1d6 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts @@ -27,6 +27,33 @@ export const meta = { id: '87a9bb19-111e-4e37-81d3-a3e7426453b0', }, }, + + res: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + name: { type: 'string' }, + on: { + type: 'array', + items: { + type: 'string', + enum: webhookEventTypes, + }, + }, + url: { type: 'string' }, + secret: { type: 'string' }, + active: { type: 'boolean' }, + latestSentAt: { type: 'string', format: 'date-time', nullable: true }, + latestStatus: { type: 'integer', nullable: true }, + }, + }, } as const; export const paramDef = { @@ -73,7 +100,17 @@ export default class extends Endpoint { // eslint- this.globalEventService.publishInternalEvent('webhookCreated', webhook); - return webhook; + return { + id: webhook.id, + userId: webhook.userId, + name: webhook.name, + on: webhook.on, + url: webhook.url, + secret: webhook.secret, + active: webhook.active, + latestSentAt: webhook.latestSentAt?.toISOString(), + latestStatus: webhook.latestStatus, + }; }); } } diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts index b9f809752b..0772145447 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts @@ -5,6 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; +import { webhookEventTypes } from '@/models/Webhook.js'; import type { WebhooksRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; @@ -14,6 +15,36 @@ export const meta = { requireCredential: true, kind: 'read:account', + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + name: { type: 'string' }, + on: { + type: 'array', + items: { + type: 'string', + enum: webhookEventTypes, + }, + }, + url: { type: 'string' }, + secret: { type: 'string' }, + active: { type: 'boolean' }, + latestSentAt: { type: 'string', format: 'date-time', nullable: true }, + latestStatus: { type: 'integer', nullable: true }, + }, + }, + }, } as const; export const paramDef = { @@ -33,7 +64,19 @@ export default class extends Endpoint { // eslint- userId: me.id, }); - return webhooks; + return webhooks.map(webhook => ( + { + id: webhook.id, + userId: webhook.userId, + name: webhook.name, + on: webhook.on, + url: webhook.url, + secret: webhook.secret, + active: webhook.active, + latestSentAt: webhook.latestSentAt?.toISOString(), + latestStatus: webhook.latestStatus, + } + )); }); } } diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts index 446cccf1b2..a81212faa6 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts @@ -5,6 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; +import { webhookEventTypes } from '@/models/Webhook.js'; import type { WebhooksRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '../../../error.js'; @@ -23,6 +24,33 @@ export const meta = { id: '50f614d9-3047-4f7e-90d8-ad6b2d5fb098', }, }, + + res: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + name: { type: 'string' }, + on: { + type: 'array', + items: { + type: 'string', + enum: webhookEventTypes, + }, + }, + url: { type: 'string' }, + secret: { type: 'string' }, + active: { type: 'boolean' }, + latestSentAt: { type: 'string', format: 'date-time', nullable: true }, + latestStatus: { type: 'integer', nullable: true }, + }, + }, } as const; export const paramDef = { @@ -49,7 +77,17 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchWebhook); } - return webhook; + return { + id: webhook.id, + userId: webhook.userId, + name: webhook.name, + on: webhook.on, + url: webhook.url, + secret: webhook.secret, + active: webhook.active, + latestSentAt: webhook.latestSentAt?.toISOString(), + latestStatus: webhook.latestStatus, + }; }); } } diff --git a/packages/backend/src/server/api/endpoints/invite/create.ts b/packages/backend/src/server/api/endpoints/invite/create.ts index 9b328b0ab0..97cc260337 100644 --- a/packages/backend/src/server/api/endpoints/invite/create.ts +++ b/packages/backend/src/server/api/endpoints/invite/create.ts @@ -19,6 +19,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canInvite', + kind: 'write:invite-codes', errors: { exceededCreateLimit: { diff --git a/packages/backend/src/server/api/endpoints/invite/delete.ts b/packages/backend/src/server/api/endpoints/invite/delete.ts index 11ad990210..7780877b20 100644 --- a/packages/backend/src/server/api/endpoints/invite/delete.ts +++ b/packages/backend/src/server/api/endpoints/invite/delete.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canInvite', + kind: 'write:invite-codes', errors: { noSuchCode: { diff --git a/packages/backend/src/server/api/endpoints/invite/limit.ts b/packages/backend/src/server/api/endpoints/invite/limit.ts index 6107ad2852..28974585b0 100644 --- a/packages/backend/src/server/api/endpoints/invite/limit.ts +++ b/packages/backend/src/server/api/endpoints/invite/limit.ts @@ -16,6 +16,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canInvite', + kind: 'read:invite-codes', res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/invite/list.ts b/packages/backend/src/server/api/endpoints/invite/list.ts index 691815f3ba..2234937417 100644 --- a/packages/backend/src/server/api/endpoints/invite/list.ts +++ b/packages/backend/src/server/api/endpoints/invite/list.ts @@ -15,6 +15,7 @@ export const meta = { requireCredential: true, requireRolePolicy: 'canInvite', + kind: 'read:invite-codes', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 483ec6bc73..1fe4a5c44b 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -112,6 +112,18 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + enableMcaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + mcaptchaSiteKey: { + type: 'string', + optional: false, nullable: true, + }, + mcaptchaInstanceUrl: { + type: 'string', + optional: false, nullable: true, + }, enableRecaptcha: { type: 'boolean', optional: false, nullable: false, @@ -168,20 +180,34 @@ export const meta = { type: 'object', optional: false, nullable: false, properties: { - place: { + id: { type: 'string', optional: false, nullable: false, + format: 'id', + example: 'xxxxxxxxxx', }, url: { type: 'string', optional: false, nullable: false, format: 'url', }, + place: { + type: 'string', + optional: false, nullable: false, + }, + ratio: { + type: 'number', + optional: false, nullable: false, + }, imageUrl: { type: 'string', optional: false, nullable: false, format: 'url', }, + dayOfWeek: { + type: 'integer', + optional: false, nullable: false, + }, }, }, }, @@ -342,6 +368,9 @@ export default class extends Endpoint { // eslint- emailRequiredForSignup: instance.emailRequiredForSignup, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, + enableMcaptcha: instance.enableMcaptcha, + mcaptchaSiteKey: instance.mcaptchaSitekey, + mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl, enableRecaptcha: instance.enableRecaptcha, recaptchaSiteKey: instance.recaptchaSiteKey, enableTurnstile: instance.enableTurnstile, diff --git a/packages/backend/src/server/api/endpoints/my/apps.ts b/packages/backend/src/server/api/endpoints/my/apps.ts index c845d9ca06..32a3cec6c5 100644 --- a/packages/backend/src/server/api/endpoints/my/apps.ts +++ b/packages/backend/src/server/api/endpoints/my/apps.ts @@ -13,6 +13,7 @@ export const meta = { tags: ['account', 'app'], requireCredential: true, + kind: 'read:account', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes.ts b/packages/backend/src/server/api/endpoints/notes.ts index e726f4c29e..2da1784e39 100644 --- a/packages/backend/src/server/api/endpoints/notes.ts +++ b/packages/backend/src/server/api/endpoints/notes.ts @@ -32,6 +32,7 @@ export const paramDef = { renote: { type: 'boolean' }, withFiles: { type: 'boolean' }, poll: { type: 'boolean' }, + event: { type: 'boolean' }, limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, @@ -78,6 +79,10 @@ export default class extends Endpoint { // eslint- query.andWhere(ps.poll ? 'note.hasPoll = TRUE' : 'note.hasPoll = FALSE'); } + if (ps.event !== undefined) { + query.andWhere(ps.event ? 'note.hasEvent = TRUE' : 'note.hasEvent = FALSE'); + } + // TODO //if (bot != undefined) { // query.isBot = bot; diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index b66f09b49d..3d6a551e36 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -25,6 +25,7 @@ export const meta = { tags: ['notes'], requireCredential: true, + kind: 'read:account', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/mentions.ts b/packages/backend/src/server/api/endpoints/notes/mentions.ts index f932952860..1c6edab1e7 100644 --- a/packages/backend/src/server/api/endpoints/notes/mentions.ts +++ b/packages/backend/src/server/api/endpoints/notes/mentions.ts @@ -16,6 +16,7 @@ export const meta = { tags: ['notes'], requireCredential: true, + kind: 'read:account', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts index b88c6c8254..d112844324 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts @@ -14,6 +14,7 @@ export const meta = { tags: ['notes'], requireCredential: true, + kind: 'read:account', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/state.ts b/packages/backend/src/server/api/endpoints/notes/state.ts index 20cc88b41c..e0725d3b42 100644 --- a/packages/backend/src/server/api/endpoints/notes/state.ts +++ b/packages/backend/src/server/api/endpoints/notes/state.ts @@ -12,6 +12,7 @@ export const meta = { tags: ['notes'], requireCredential: true, + kind: 'read:account', res: { type: 'object', diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index 81b4030d30..26cd358a1f 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -22,6 +22,7 @@ export const meta = { tags: ['notes'], requireCredential: true, + kind: 'read:account', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index 77a6a29f1d..42ec0b45f2 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -21,10 +21,15 @@ export const meta = { tags: ['notes'], requireCredential: true, + kind: 'read:account', res: { type: 'object', optional: false, nullable: false, + properties: { + sourceLang: { type: 'string' }, + text: { type: 'string' }, + }, }, errors: { diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index dd6bfd230b..d6f7537aa9 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -22,6 +22,7 @@ export const meta = { tags: ['notes', 'lists'], requireCredential: true, + kind: 'read:account', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts index b1af29b58e..e07fc66b63 100644 --- a/packages/backend/src/server/api/endpoints/promo/read.ts +++ b/packages/backend/src/server/api/endpoints/promo/read.ts @@ -15,6 +15,7 @@ export const meta = { tags: ['notes'], requireCredential: true, + kind: 'write:account', errors: { noSuchNote: { diff --git a/packages/backend/src/server/api/endpoints/roles/list.ts b/packages/backend/src/server/api/endpoints/roles/list.ts index 751ddfd093..2f6da65250 100644 --- a/packages/backend/src/server/api/endpoints/roles/list.ts +++ b/packages/backend/src/server/api/endpoints/roles/list.ts @@ -13,6 +13,7 @@ export const meta = { tags: ['role'], requireCredential: true, + kind: 'read:account', res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/roles/notes.ts b/packages/backend/src/server/api/endpoints/roles/notes.ts index 5b64b23d8e..d35adbbc05 100644 --- a/packages/backend/src/server/api/endpoints/roles/notes.ts +++ b/packages/backend/src/server/api/endpoints/roles/notes.ts @@ -18,6 +18,7 @@ export const meta = { tags: ['role', 'notes'], requireCredential: true, + kind: 'read:account', errors: { noSuchRole: { diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts index 04d24c552d..1d18bd6757 100644 --- a/packages/backend/src/server/api/endpoints/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/roles/users.ts @@ -24,6 +24,25 @@ export const meta = { id: '30aaaee3-4792-48dc-ab0d-cf501a575ac5', }, }, + + res: { + type: 'array', + items: { + type: 'object', + nullable: false, + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + user: { + type: 'object', + ref: 'User', + }, + }, + required: ['id', 'user'], + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index f6e358312b..86948b8795 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -15,6 +15,53 @@ export const meta = { cacheSec: 60 * 1, tags: ['meta'], + res: { + type: 'object', + optional: false, nullable: false, + properties: { + machine: { + type: 'string', + nullable: false, + }, + cpu: { + type: 'object', + nullable: false, + properties: { + model: { + type: 'string', + nullable: false, + }, + cores: { + type: 'number', + nullable: false, + }, + }, + }, + mem: { + type: 'object', + properties: { + total: { + type: 'number', + nullable: false, + }, + }, + }, + fs: { + type: 'object', + nullable: false, + properties: { + total: { + type: 'number', + nullable: false, + }, + used: { + type: 'number', + nullable: false, + }, + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/sw/register.ts b/packages/backend/src/server/api/endpoints/sw/register.ts index d75d7eea50..6b74ba4b60 100644 --- a/packages/backend/src/server/api/endpoints/sw/register.ts +++ b/packages/backend/src/server/api/endpoints/sw/register.ts @@ -14,6 +14,7 @@ export const meta = { tags: ['account'], requireCredential: true, + secure: true, description: 'Register to receive push notifications.', diff --git a/packages/backend/src/server/api/endpoints/sw/show-registration.ts b/packages/backend/src/server/api/endpoints/sw/show-registration.ts index 18b0360970..4f1f64727c 100644 --- a/packages/backend/src/server/api/endpoints/sw/show-registration.ts +++ b/packages/backend/src/server/api/endpoints/sw/show-registration.ts @@ -12,6 +12,7 @@ export const meta = { tags: ['account'], requireCredential: true, + secure: true, description: 'Check push notification registration exists.', diff --git a/packages/backend/src/server/api/endpoints/sw/update-registration.ts b/packages/backend/src/server/api/endpoints/sw/update-registration.ts index a376201e79..ad311d6985 100644 --- a/packages/backend/src/server/api/endpoints/sw/update-registration.ts +++ b/packages/backend/src/server/api/endpoints/sw/update-registration.ts @@ -13,6 +13,7 @@ export const meta = { tags: ['account'], requireCredential: true, + secure: true, description: 'Update push notification registration.', diff --git a/packages/backend/src/server/api/endpoints/test.ts b/packages/backend/src/server/api/endpoints/test.ts index 97696092ce..1ec8d00481 100644 --- a/packages/backend/src/server/api/endpoints/test.ts +++ b/packages/backend/src/server/api/endpoints/test.ts @@ -12,6 +12,30 @@ export const meta = { description: 'Endpoint for testing input validation.', requireCredential: false, + + res: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + required: { + type: 'boolean', + }, + string: { + type: 'string', + }, + default: { + type: 'string', + }, + nullableDefault: { + type: 'string', + default: 'hello', + nullable: true, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/users/achievements.ts b/packages/backend/src/server/api/endpoints/users/achievements.ts index 3506780374..88a85c6d15 100644 --- a/packages/backend/src/server/api/endpoints/users/achievements.ts +++ b/packages/backend/src/server/api/endpoints/users/achievements.ts @@ -9,7 +9,22 @@ import type { UserProfilesRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; export const meta = { - requireCredential: true, + requireCredential: false, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + name: { + type: 'string', + }, + unlockedAt: { + type: 'number', + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/users/featured-notes.ts b/packages/backend/src/server/api/endpoints/users/featured-notes.ts index 4779b065fa..42e3ed9a37 100644 --- a/packages/backend/src/server/api/endpoints/users/featured-notes.ts +++ b/packages/backend/src/server/api/endpoints/users/featured-notes.ts @@ -9,6 +9,8 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { DI } from '@/di-symbols.js'; import { FeaturedService } from '@/core/FeaturedService.js'; +import { CacheService } from '@/core/CacheService.js'; +import { isUserRelated } from '@/misc/is-user-related.js'; export const meta = { tags: ['notes'], @@ -46,8 +48,16 @@ export default class extends Endpoint { // eslint- private noteEntityService: NoteEntityService, private featuredService: FeaturedService, + private cacheService: CacheService, ) { super(meta, paramDef, async (ps, me) => { + const userIdsWhoBlockingMe = me ? await this.cacheService.userBlockedCache.fetch(me.id) : new Set(); + + // early return if me is blocked by requesting user + if (userIdsWhoBlockingMe.has(ps.userId)) { + return []; + } + let noteIds = await this.featuredService.getPerUserNotesRanking(ps.userId, 50); noteIds.sort((a, b) => a > b ? -1 : 1); @@ -60,6 +70,12 @@ export default class extends Endpoint { // eslint- return []; } + const [ + userIdsWhoMeMuting, + ] = me ? await Promise.all([ + this.cacheService.userMutingsCache.fetch(me.id), + ]) : [new Set()]; + const query = this.notesRepository.createQueryBuilder('note') .where('note.id IN (:...noteIds)', { noteIds: noteIds }) .innerJoinAndSelect('note.user', 'user') @@ -69,10 +85,14 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser') .leftJoinAndSelect('note.channel', 'channel'); - const notes = await query.getMany(); - notes.sort((a, b) => a.id > b.id ? -1 : 1); + const notes = (await query.getMany()).filter(note => { + if (me && isUserRelated(note, userIdsWhoBlockingMe, false)) return false; + if (me && isUserRelated(note, userIdsWhoMeMuting, true)) return false; - // TODO: ミュート等考慮 + return true; + }); + + notes.sort((a, b) => a.id > b.id ? -1 : 1); return await this.noteEntityService.packMany(notes, me); }); diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index 321fd1c0d0..bfa1c7d751 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -93,11 +93,11 @@ export default class extends Endpoint { // eslint- const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.followersVisibility === 'private') { if (me == null || (me.id !== user.id)) { throw new ApiError(meta.errors.forbidden); } - } else if (profile.ffVisibility === 'followers') { + } else if (profile.followersVisibility === 'followers') { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index c258ac4365..4b18df7228 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -101,11 +101,11 @@ export default class extends Endpoint { // eslint- const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.followingVisibility === 'private') { if (me == null || (me.id !== user.id)) { throw new ApiError(meta.errors.forbidden); } - } else if (profile.ffVisibility === 'followers') { + } else if (profile.followingVisibility === 'followers') { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { diff --git a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts index 5e2df3c512..3b40a28e96 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts @@ -18,6 +18,7 @@ import { UserListService } from '@/core/UserListService.js'; export const meta = { requireCredential: true, prohibitMoved: true, + kind: 'write:account', res: { type: 'object', optional: false, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/users/lists/favorite.ts b/packages/backend/src/server/api/endpoints/users/lists/favorite.ts index da0dfd6190..8d1b8a6157 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/favorite.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/favorite.ts @@ -12,6 +12,7 @@ import { DI } from '@/di-symbols.js'; export const meta = { requireCredential: true, + kind: 'write:account', errors: { noSuchList: { message: 'No such user list.', diff --git a/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts b/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts index f76c27db26..dfec7ed6e7 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts @@ -25,6 +25,35 @@ export const meta = { id: '7bc05c21-1d7a-41ae-88f1-66820f4dc686', }, }, + + res: { + type: 'array', + items: { + type: 'object', + nullable: false, + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + createdAt: { + type: 'string', + format: 'date-time', + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + user: { + type: 'object', + ref: 'User', + }, + withReplies: { + type: 'boolean', + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts b/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts index 8870fd3d3c..a9841c00b8 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts @@ -11,6 +11,7 @@ import { DI } from '@/di-symbols.js'; export const meta = { requireCredential: true, + kind: 'write:account', errors: { noSuchList: { message: 'No such user list.', diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 0cdc491b14..2bdfeb9677 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -87,6 +87,14 @@ export default class extends Endpoint { // eslint- if (ps.withReplies && ps.withFiles) throw new ApiError(meta.errors.bothWithRepliesAndWithFiles); + // early return if me is blocked by requesting user + if (me != null) { + const userIdsWhoBlockingMe = await this.cacheService.userBlockedCache.fetch(me.id); + if (userIdsWhoBlockingMe.has(ps.userId)) { + return []; + } + } + if (!serverSettings.enableFanoutTimeline) { const timeline = await this.getFromDb({ untilId, diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 9196fa2401..f4cb15363d 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -4,11 +4,12 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import type { UserProfilesRepository, NoteReactionsRepository } from '@/models/_.js'; +import type { UserProfilesRepository, NotesRepository, NoteReactionsRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { QueryService } from '@/core/QueryService.js'; import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js'; import { DI } from '@/di-symbols.js'; +import { MiNoteReaction } from '@/models/_.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -56,6 +57,9 @@ export default class extends Endpoint { // eslint- @Inject(DI.userProfilesRepository) private userProfilesRepository: UserProfilesRepository, + @Inject(DI.notesRepository) + private notesRepository: NotesRepository, + @Inject(DI.noteReactionsRepository) private noteReactionsRepository: NoteReactionsRepository, @@ -69,16 +73,23 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.reactionsNotPublic); } - const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere('reaction.userId = :userId', { userId: ps.userId }) - .leftJoinAndSelect('reaction.note', 'note'); + const query = this.notesRepository.createQueryBuilder('note') + .innerJoinAndSelect(qb => + this.queryService.makePaginationQuery( + qb + .from(this.noteReactionsRepository.metadata.targetName, 'reaction') + .where('"reaction"."userId" = :userId', { userId: ps.userId }), + ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate, + ), + 'reaction', + '"reaction"."noteId" = note.id', + ); this.queryService.generateVisibilityQuery(query, me); const reactions = await query .limit(ps.limit) - .getMany(); + .getRawMany(); return await Promise.all(reactions.map(reaction => this.noteReactionEntityService.pack(reaction, me, { withNote: true }))); }); diff --git a/packages/backend/src/server/api/endpoints/users/relation.ts b/packages/backend/src/server/api/endpoints/users/relation.ts index f974313572..eaa190d34c 100644 --- a/packages/backend/src/server/api/endpoints/users/relation.ts +++ b/packages/backend/src/server/api/endpoints/users/relation.ts @@ -11,6 +11,7 @@ export const meta = { tags: ['users'], requireCredential: true, + kind: 'read:account', description: 'Show the different kinds of relations between the authenticated user and the specified user(s).', diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index 07e76bfd53..8162cc1cb2 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -17,6 +17,7 @@ export const meta = { tags: ['users'], requireCredential: true, + kind: 'write:report-abuse', description: 'File a report.', diff --git a/packages/backend/src/server/api/endpoints/users/translate.ts b/packages/backend/src/server/api/endpoints/users/translate.ts index bb9c43ae93..2848711790 100644 --- a/packages/backend/src/server/api/endpoints/users/translate.ts +++ b/packages/backend/src/server/api/endpoints/users/translate.ts @@ -20,10 +20,15 @@ export const meta = { tags: ['users'], requireCredential: true, + kind: 'read:account', res: { type: 'object', optional: false, nullable: false, + properties: { + sourceLang: { type: 'string' }, + text: { type: 'string' }, + }, }, errors: { diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index f3d60b1105..b623307a7e 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -44,7 +44,7 @@ export function genOpenapiSpec(config: Config) { // 書き換えたりするのでディープコピーしておく。そのまま編集するとメモリ上の値が汚れて次回以降の出力に影響する const copiedEndpoints = JSON.parse(JSON.stringify(endpoints)) as IEndpoint[]; - for (const endpoint of copiedEndpoints.filter(ep => !ep.meta.secure)) { + for (const endpoint of copiedEndpoints) { const errors = {} as any; if (endpoint.meta.errors) { @@ -60,6 +60,11 @@ export function genOpenapiSpec(config: Config) { const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res) : {}; let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n'; + + if (endpoint.meta.secure) { + desc += '**Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties.\n'; + } + desc += `**Credential required**: *${endpoint.meta.requireCredential ? 'Yes' : 'No'}*`; if (endpoint.meta.kind) { const kind = endpoint.meta.kind; diff --git a/packages/backend/src/server/api/stream/ChannelsService.ts b/packages/backend/src/server/api/stream/ChannelsService.ts index 0a75f8b09a..f3bfaa0faa 100644 --- a/packages/backend/src/server/api/stream/ChannelsService.ts +++ b/packages/backend/src/server/api/stream/ChannelsService.ts @@ -21,6 +21,7 @@ import { MessagingIndexChannelService } from './channels/messaging-index.js'; import { DriveChannelService } from './channels/drive.js'; import { HashtagChannelService } from './channels/hashtag.js'; import { RoleTimelineChannelService } from './channels/role-timeline.js'; +import { type MiChannelService } from './channel.js'; @Injectable() export class ChannelsService { @@ -45,7 +46,7 @@ export class ChannelsService { } @bindThis - public getChannelService(name: string) { + public getChannelService(name: string): MiChannelService { switch (name) { case 'main': return this.mainChannelService; case 'homeTimeline': return this.homeTimelineChannelService; diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index 1c65ec04a9..979c28931e 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -254,6 +254,11 @@ export default class Connection { return; } + if (this.token && ((channelService.kind && !this.token.permission.some(p => p === channelService.kind)) + || (!channelService.kind && channelService.requireCredential))) { + return; + } + // 共有可能チャンネルに接続しようとしていて、かつそのチャンネルに既に接続していたら無意味なので無視 if (channelService.shouldShare && this.channels.some(c => c.chName === channel)) { return; diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts index 6d38cc34af..64408add60 100644 --- a/packages/backend/src/server/api/stream/channel.ts +++ b/packages/backend/src/server/api/stream/channel.ts @@ -16,6 +16,7 @@ export default abstract class Channel { public abstract readonly chName: string; public static readonly shouldShare: boolean; public static readonly requireCredential: boolean; + public static readonly kind?: string | null; protected get user() { return this.connection.user; @@ -76,3 +77,10 @@ export default abstract class Channel { public onMessage?(type: string, body: any): void; } + +export type MiChannelService = { + shouldShare: boolean; + requireCredential: T; + kind: T extends true ? string : string | null | undefined; + create: (id: string, connection: Connection) => Channel; +} diff --git a/packages/backend/src/server/api/stream/channels/admin.ts b/packages/backend/src/server/api/stream/channels/admin.ts index 3dadd80b67..84a64493d9 100644 --- a/packages/backend/src/server/api/stream/channels/admin.ts +++ b/packages/backend/src/server/api/stream/channels/admin.ts @@ -5,12 +5,13 @@ import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class AdminChannel extends Channel { public readonly chName = 'admin'; public static shouldShare = true; - public static requireCredential = true; + public static requireCredential = true as const; + public static kind = 'read:admin:stream'; @bindThis public async init(params: any) { @@ -22,9 +23,10 @@ class AdminChannel extends Channel { } @Injectable() -export class AdminChannelService { +export class AdminChannelService implements MiChannelService { public readonly shouldShare = AdminChannel.shouldShare; public readonly requireCredential = AdminChannel.requireCredential; + public readonly kind = AdminChannel.kind; constructor( ) { diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts index a687d7bbb4..c3588f9f75 100644 --- a/packages/backend/src/server/api/stream/channels/antenna.ts +++ b/packages/backend/src/server/api/stream/channels/antenna.ts @@ -8,12 +8,13 @@ import { isUserRelated } from '@/misc/is-user-related.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class AntennaChannel extends Channel { public readonly chName = 'antenna'; public static shouldShare = false; - public static requireCredential = false; + public static requireCredential = true as const; + public static kind = 'read:account'; private antennaId: string; constructor( @@ -62,9 +63,10 @@ class AntennaChannel extends Channel { } @Injectable() -export class AntennaChannelService { +export class AntennaChannelService implements MiChannelService { public readonly shouldShare = AntennaChannel.shouldShare; public readonly requireCredential = AntennaChannel.requireCredential; + public readonly kind = AntennaChannel.kind; constructor( private noteEntityService: NoteEntityService, diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts index 086e7b8262..272c5fa863 100644 --- a/packages/backend/src/server/api/stream/channels/channel.ts +++ b/packages/backend/src/server/api/stream/channels/channel.ts @@ -11,12 +11,12 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class ChannelChannel extends Channel { public readonly chName = 'channel'; public static shouldShare = false; - public static requireCredential = false; + public static requireCredential = false as const; private channelId: string; private typers: Record = {}; private emitTypersIntervalId: ReturnType; @@ -106,9 +106,10 @@ class ChannelChannel extends Channel { } @Injectable() -export class ChannelChannelService { +export class ChannelChannelService implements MiChannelService { public readonly shouldShare = ChannelChannel.shouldShare; public readonly requireCredential = ChannelChannel.requireCredential; + public readonly kind = ChannelChannel.kind; constructor( private noteEntityService: NoteEntityService, diff --git a/packages/backend/src/server/api/stream/channels/drive.ts b/packages/backend/src/server/api/stream/channels/drive.ts index f4fc356c70..09607cb436 100644 --- a/packages/backend/src/server/api/stream/channels/drive.ts +++ b/packages/backend/src/server/api/stream/channels/drive.ts @@ -5,12 +5,13 @@ import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class DriveChannel extends Channel { public readonly chName = 'drive'; public static shouldShare = true; - public static requireCredential = true; + public static requireCredential = true as const; + public static kind = 'read:account'; @bindThis public async init(params: any) { @@ -22,9 +23,10 @@ class DriveChannel extends Channel { } @Injectable() -export class DriveChannelService { +export class DriveChannelService implements MiChannelService { public readonly shouldShare = DriveChannel.shouldShare; public readonly requireCredential = DriveChannel.requireCredential; + public readonly kind = DriveChannel.kind; constructor( ) { diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index fc74ced541..351c8a4956 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -12,12 +12,12 @@ import { MetaService } from '@/core/MetaService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class GlobalTimelineChannel extends Channel { public readonly chName = 'globalTimeline'; public static shouldShare = false; - public static requireCredential = false; + public static requireCredential = false as const; private withRenotes: boolean; private withFiles: boolean; @@ -91,9 +91,10 @@ class GlobalTimelineChannel extends Channel { } @Injectable() -export class GlobalTimelineChannelService { +export class GlobalTimelineChannelService implements MiChannelService { public readonly shouldShare = GlobalTimelineChannel.shouldShare; public readonly requireCredential = GlobalTimelineChannel.requireCredential; + public readonly kind = GlobalTimelineChannel.kind; constructor( private metaService: MetaService, diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts index c46d0eb706..529fb377e8 100644 --- a/packages/backend/src/server/api/stream/channels/hashtag.ts +++ b/packages/backend/src/server/api/stream/channels/hashtag.ts @@ -9,12 +9,12 @@ import { isUserRelated } from '@/misc/is-user-related.js'; import type { Packed } from '@/misc/json-schema.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class HashtagChannel extends Channel { public readonly chName = 'hashtag'; public static shouldShare = false; - public static requireCredential = false; + public static requireCredential = false as const; private q: string[][]; constructor( @@ -70,9 +70,10 @@ class HashtagChannel extends Channel { } @Injectable() -export class HashtagChannelService { +export class HashtagChannelService implements MiChannelService { public readonly shouldShare = HashtagChannel.shouldShare; public readonly requireCredential = HashtagChannel.requireCredential; + public readonly kind = HashtagChannel.kind; constructor( private noteEntityService: NoteEntityService, diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 2bb888bbce..880d8ab259 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -10,12 +10,13 @@ import { isInstanceMuted } from '@/misc/is-instance-muted.js'; import type { Packed } from '@/misc/json-schema.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class HomeTimelineChannel extends Channel { public readonly chName = 'homeTimeline'; public static shouldShare = false; - public static requireCredential = true; + public static requireCredential = true as const; + public static kind = 'read:account'; private withRenotes: boolean; private withFiles: boolean; @@ -99,9 +100,10 @@ class HomeTimelineChannel extends Channel { } @Injectable() -export class HomeTimelineChannelService { +export class HomeTimelineChannelService implements MiChannelService { public readonly shouldShare = HomeTimelineChannel.shouldShare; public readonly requireCredential = HomeTimelineChannel.requireCredential; + public readonly kind = HomeTimelineChannel.kind; constructor( private noteEntityService: NoteEntityService, diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 0180c51d38..954134c301 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -12,12 +12,13 @@ import { MetaService } from '@/core/MetaService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class HybridTimelineChannel extends Channel { public readonly chName = 'hybridTimeline'; public static shouldShare = false; - public static requireCredential = true; + public static requireCredential = true as const; + public static kind = 'read:account'; private withRenotes: boolean; private withReplies: boolean; private withFiles: boolean; @@ -95,7 +96,6 @@ class HybridTimelineChannel extends Channel { if (this.user && note.renoteId && !note.text) { if (note.renote && Object.keys(note.renote.reactions).length > 0) { - console.log(note.renote.reactionAndUserPairCache); const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id); note.renote.myReaction = myRenoteReaction; } @@ -114,9 +114,10 @@ class HybridTimelineChannel extends Channel { } @Injectable() -export class HybridTimelineChannelService { +export class HybridTimelineChannelService implements MiChannelService { public readonly shouldShare = HybridTimelineChannel.shouldShare; public readonly requireCredential = HybridTimelineChannel.requireCredential; + public readonly kind = HybridTimelineChannel.kind; constructor( private metaService: MetaService, diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 7f258d60ea..dc5a267236 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -11,12 +11,12 @@ import { MetaService } from '@/core/MetaService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class LocalTimelineChannel extends Channel { public readonly chName = 'localTimeline'; public static shouldShare = false; - public static requireCredential = false; + public static requireCredential = false as const; private withRenotes: boolean; private withReplies: boolean; private withFiles: boolean; @@ -90,9 +90,10 @@ class LocalTimelineChannel extends Channel { } @Injectable() -export class LocalTimelineChannelService { +export class LocalTimelineChannelService implements MiChannelService { public readonly shouldShare = LocalTimelineChannel.shouldShare; public readonly requireCredential = LocalTimelineChannel.requireCredential; + public readonly kind = LocalTimelineChannel.kind; constructor( private metaService: MetaService, diff --git a/packages/backend/src/server/api/stream/channels/main.ts b/packages/backend/src/server/api/stream/channels/main.ts index 3e205dd629..83de100a5e 100644 --- a/packages/backend/src/server/api/stream/channels/main.ts +++ b/packages/backend/src/server/api/stream/channels/main.ts @@ -7,12 +7,13 @@ import { Injectable } from '@nestjs/common'; import { isInstanceMuted, isUserFromMutedInstance } from '@/misc/is-instance-muted.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class MainChannel extends Channel { public readonly chName = 'main'; public static shouldShare = true; - public static requireCredential = true; + public static requireCredential = true as const; + public static kind = 'read:account'; constructor( private noteEntityService: NoteEntityService, @@ -63,9 +64,10 @@ class MainChannel extends Channel { } @Injectable() -export class MainChannelService { +export class MainChannelService implements MiChannelService { public readonly shouldShare = MainChannel.shouldShare; public readonly requireCredential = MainChannel.requireCredential; + public readonly kind = MainChannel.kind; constructor( private noteEntityService: NoteEntityService, diff --git a/packages/backend/src/server/api/stream/channels/queue-stats.ts b/packages/backend/src/server/api/stream/channels/queue-stats.ts index 5f4d6d9e38..82e3e61bc4 100644 --- a/packages/backend/src/server/api/stream/channels/queue-stats.ts +++ b/packages/backend/src/server/api/stream/channels/queue-stats.ts @@ -6,14 +6,14 @@ import Xev from 'xev'; import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; const ev = new Xev(); class QueueStatsChannel extends Channel { public readonly chName = 'queueStats'; public static shouldShare = true; - public static requireCredential = false; + public static requireCredential = false as const; constructor(id: string, connection: Channel['connection']) { super(id, connection); @@ -53,9 +53,10 @@ class QueueStatsChannel extends Channel { } @Injectable() -export class QueueStatsChannelService { +export class QueueStatsChannelService implements MiChannelService { public readonly shouldShare = QueueStatsChannel.shouldShare; public readonly requireCredential = QueueStatsChannel.requireCredential; + public readonly kind = QueueStatsChannel.kind; constructor( ) { diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts index 0ac6a55205..4364f8b951 100644 --- a/packages/backend/src/server/api/stream/channels/role-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts @@ -10,12 +10,12 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class RoleTimelineChannel extends Channel { public readonly chName = 'roleTimeline'; public static shouldShare = false; - public static requireCredential = false; + public static requireCredential = false as const; private roleId: string; constructor( @@ -67,9 +67,10 @@ class RoleTimelineChannel extends Channel { } @Injectable() -export class RoleTimelineChannelService { +export class RoleTimelineChannelService implements MiChannelService { public readonly shouldShare = RoleTimelineChannel.shouldShare; public readonly requireCredential = RoleTimelineChannel.requireCredential; + public readonly kind = RoleTimelineChannel.kind; constructor( private noteEntityService: NoteEntityService, diff --git a/packages/backend/src/server/api/stream/channels/server-stats.ts b/packages/backend/src/server/api/stream/channels/server-stats.ts index 98598226f7..75516d6de3 100644 --- a/packages/backend/src/server/api/stream/channels/server-stats.ts +++ b/packages/backend/src/server/api/stream/channels/server-stats.ts @@ -6,14 +6,14 @@ import Xev from 'xev'; import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; const ev = new Xev(); class ServerStatsChannel extends Channel { public readonly chName = 'serverStats'; public static shouldShare = true; - public static requireCredential = false; + public static requireCredential = false as const; constructor(id: string, connection: Channel['connection']) { super(id, connection); @@ -53,9 +53,10 @@ class ServerStatsChannel extends Channel { } @Injectable() -export class ServerStatsChannelService { +export class ServerStatsChannelService implements MiChannelService { public readonly shouldShare = ServerStatsChannel.shouldShare; public readonly requireCredential = ServerStatsChannel.requireCredential; + public readonly kind = ServerStatsChannel.kind; constructor( ) { diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index 48056c7184..c1c2fd909f 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -11,16 +11,17 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import { isInstanceMuted } from '@/misc/is-instance-muted.js'; -import Channel from '../channel.js'; +import Channel, { type MiChannelService } from '../channel.js'; class UserListChannel extends Channel { public readonly chName = 'userList'; public static shouldShare = false; - public static requireCredential = false; + public static requireCredential = false as const; private listId: string; private membershipsMap: Record | undefined> = {}; private listUsersClock: NodeJS.Timeout; private withFiles: boolean; + private withRenotes: boolean; constructor( private userListsRepository: UserListsRepository, @@ -39,6 +40,7 @@ class UserListChannel extends Channel { public async init(params: any) { this.listId = params.listId as string; this.withFiles = params.withFiles ?? false; + this.withRenotes = params.withRenotes ?? true; // Check existence and owner const listExist = await this.userListsRepository.exist({ @@ -104,6 +106,8 @@ class UserListChannel extends Channel { } } + if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return; + // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.userIdsWhoMeMuting)) return; // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する @@ -137,9 +141,10 @@ class UserListChannel extends Channel { } @Injectable() -export class UserListChannelService { +export class UserListChannelService implements MiChannelService { public readonly shouldShare = UserListChannel.shouldShare; public readonly requireCredential = UserListChannel.requireCredential; + public readonly kind = UserListChannel.kind; constructor( @Inject(DI.userListsRepository) diff --git a/packages/backend/src/server/oauth/OAuth2ProviderService.ts b/packages/backend/src/server/oauth/OAuth2ProviderService.ts index 46e2b93328..0ae0d5f9af 100644 --- a/packages/backend/src/server/oauth/OAuth2ProviderService.ts +++ b/packages/backend/src/server/oauth/OAuth2ProviderService.ts @@ -11,15 +11,16 @@ import httpLinkHeader from 'http-link-header'; import ipaddr from 'ipaddr.js'; import oauth2orize, { type OAuth2, AuthorizationError, ValidateFunctionArity2, OAuth2Req, MiddlewareRequest } from 'oauth2orize'; import oauth2Pkce from 'oauth2orize-pkce'; +import fastifyCors from '@fastify/cors'; import fastifyView from '@fastify/view'; import pug from 'pug'; import bodyParser from 'body-parser'; import fastifyExpress from '@fastify/express'; import { verifyChallenge } from 'pkce-challenge'; import { mf2 } from 'microformats-parser'; +import { permissions as kinds } from 'cherrypick-js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; import { HttpRequestService } from '@/core/HttpRequestService.js'; -import { kinds } from '@/misc/api-permissions.js'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; @@ -348,25 +349,25 @@ export class OAuth2ProviderService { })); } + // https://datatracker.ietf.org/doc/html/rfc8414.html + // https://indieauth.spec.indieweb.org/#indieauth-server-metadata + public generateRFC8414() { + return { + issuer: this.config.url, + authorization_endpoint: new URL('/oauth/authorize', this.config.url), + token_endpoint: new URL('/oauth/token', this.config.url), + scopes_supported: kinds, + response_types_supported: ['code'], + grant_types_supported: ['authorization_code'], + service_documentation: 'https://misskey-hub.net', + code_challenge_methods_supported: ['S256'], + authorization_response_iss_parameter_supported: true, + }; + } + @bindThis public async createServer(fastify: FastifyInstance): Promise { - // https://datatracker.ietf.org/doc/html/rfc8414.html - // https://indieauth.spec.indieweb.org/#indieauth-server-metadata - fastify.get('/.well-known/oauth-authorization-server', async (_request, reply) => { - reply.send({ - issuer: this.config.url, - authorization_endpoint: new URL('/oauth/authorize', this.config.url), - token_endpoint: new URL('/oauth/token', this.config.url), - scopes_supported: kinds, - response_types_supported: ['code'], - grant_types_supported: ['authorization_code'], - service_documentation: 'https://misskey-hub.net', - code_challenge_methods_supported: ['S256'], - authorization_response_iss_parameter_supported: true, - }); - }); - - fastify.get('/oauth/authorize', async (request, reply) => { + fastify.get('/authorize', async (request, reply) => { const oauth2 = (request.raw as MiddlewareRequest).oauth2; if (!oauth2) { throw new Error('Unexpected lack of authorization information'); @@ -381,8 +382,7 @@ export class OAuth2ProviderService { scope: oauth2.req.scope.join(' '), }); }); - fastify.post('/oauth/decision', async () => { }); - fastify.post('/oauth/token', async () => { }); + fastify.post('/decision', async () => { }); fastify.register(fastifyView, { root: fileURLToPath(new URL('../web/views', import.meta.url)), @@ -394,7 +394,7 @@ export class OAuth2ProviderService { }); await fastify.register(fastifyExpress); - fastify.use('/oauth/authorize', this.#server.authorize(((areq, done) => { + fastify.use('/authorize', this.#server.authorize(((areq, done) => { (async (): Promise> => { // This should return client/redirectURI AND the error, or // the handler can't send error to the redirection URI @@ -409,7 +409,7 @@ export class OAuth2ProviderService { // "the server may want to resolve the domain name first and avoid fetching the document // if the IP address is within the loopback range defined by [RFC5735] // or any other implementation-specific internal IP address." - if (process.env.NODE_ENV !== 'test' || process.env.MISSKEY_TEST_CHECK_IP_RANGE === '1') { + if (process.env.NODE_ENV !== 'test' || process.env.CHERRYPICK_TEST_CHECK_IP_RANGE === '1') { const lookup = await dns.lookup(clientUrl.hostname); if (ipaddr.parse(lookup.address).range() !== 'unicast') { throw new AuthorizationError('client_id resolves to disallowed IP range.', 'invalid_request'); @@ -426,7 +426,7 @@ export class OAuth2ProviderService { } try { - const scopes = [...new Set(scope)].filter(s => kinds.includes(s)); + const scopes = [...new Set(scope)].filter(s => (kinds).includes(s)); if (!scopes.length) { throw new AuthorizationError('`scope` parameter has no known scope', 'invalid_scope'); } @@ -448,30 +448,24 @@ export class OAuth2ProviderService { return [null, clientInfo, redirectURI]; })().then(args => done(...args), err => done(err)); }) as ValidateFunctionArity2)); - fastify.use('/oauth/authorize', this.#server.errorHandler({ + fastify.use('/authorize', this.#server.errorHandler({ mode: 'indirect', modes: getQueryMode(this.config.url), })); - fastify.use('/oauth/authorize', this.#server.errorHandler()); + fastify.use('/authorize', this.#server.errorHandler()); - fastify.use('/oauth/decision', bodyParser.urlencoded({ extended: false })); - fastify.use('/oauth/decision', this.#server.decision((req, done) => { + fastify.use('/decision', bodyParser.urlencoded({ extended: false })); + fastify.use('/decision', this.#server.decision((req, done) => { const { body } = req as OAuth2DecisionRequest; this.#logger.info(`Received the decision. Cancel: ${!!body.cancel}`); req.user = body.login_token; done(null, undefined); })); - fastify.use('/oauth/decision', this.#server.errorHandler()); - - // Clients may use JSON or urlencoded - fastify.use('/oauth/token', bodyParser.urlencoded({ extended: false })); - fastify.use('/oauth/token', bodyParser.json({ strict: true })); - fastify.use('/oauth/token', this.#server.token()); - fastify.use('/oauth/token', this.#server.errorHandler()); + fastify.use('/decision', this.#server.errorHandler()); // Return 404 for any unknown paths under /oauth so that clients can know // whether a certain endpoint is supported or not. - fastify.all('/oauth/*', async (_request, reply) => { + fastify.all('/*', async (_request, reply) => { reply.code(404); reply.send({ error: { @@ -483,4 +477,17 @@ export class OAuth2ProviderService { }); }); } + + @bindThis + public async createTokenServer(fastify: FastifyInstance): Promise { + fastify.register(fastifyCors); + fastify.post('', async () => { }); + + await fastify.register(fastifyExpress); + // Clients may use JSON or urlencoded + fastify.use('', bodyParser.urlencoded({ extended: false })); + fastify.use('', bodyParser.json({ strict: true })); + fastify.use('', this.#server.token()); + fastify.use('', this.#server.errorHandler()); + } } diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts index 3bdf9d71e8..cdb67bb7e7 100644 --- a/packages/backend/src/server/web/FeedService.ts +++ b/packages/backend/src/server/web/FeedService.ts @@ -60,7 +60,7 @@ export class FeedService { title: `${author.name} (@${user.username}@${this.config.host})`, updated: notes.length !== 0 ? this.idService.parse(notes[0].id).date : undefined, generator: 'CherryPick', - description: `${user.notesCount} Notes, ${profile.ffVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.ffVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, + description: `${user.notesCount} Notes, ${profile.followingVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.followersVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, link: author.link, image: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user), feedLinks: { diff --git a/packages/backend/src/server/web/UrlPreviewService.ts b/packages/backend/src/server/web/UrlPreviewService.ts index f2c2aeff99..c5343c810a 100644 --- a/packages/backend/src/server/web/UrlPreviewService.ts +++ b/packages/backend/src/server/web/UrlPreviewService.ts @@ -4,7 +4,7 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import { summaly } from 'summaly'; +import { summaly } from '@misskey-dev/summaly'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { MetaService } from '@/core/MetaService.js'; diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index 91e9101123..ef8845c56a 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -183,6 +183,7 @@

Clear the browser cache / ブラウザのキャッシュをクリアする / 브라우저의 캐시 지우기

Update your os and browser / ブラウザおよびOSを最新バージョンに更新する / 브라우저와 OS를 최신 버전으로 업데이트 하기

Disable an adblocker / アドブロッカーを無効にする / 광고 차단기를 비활성화 하기

+

(Tor Browser) Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する / dom.webaudio.enabled를 true로 설정하기

Other options / その他のオプション / 기타 옵션 diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index fd80619675..1423d39b8a 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -36,7 +36,7 @@ html link(rel='prefetch' href=infoImageUrl) link(rel='prefetch' href=notFoundImageUrl) //- https://github.com/misskey-dev/misskey/issues/9842 - link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.37.0') + link(rel='stylesheet' href=`/assets/tabler-icons.${version}/tabler-icons.min.css`) link(rel='modulepreload' href=`/vite/${clientEntry.file}`) if !config.clientManifestExists diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index eb262e2f25..6e0fe4e5f9 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -14,19 +14,36 @@ * pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した * receiveFollowRequest - フォローリクエストされた * followRequestAccepted - 自分の送ったフォローリクエストが承認された + * roleAssigned - ロールが付与された * groupInvited - グループに招待された * achievementEarned - 実績を獲得 * app - アプリ通知 * test - テスト通知(サーバー側) */ -export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'achievementEarned', 'app', 'test'] as const; +export const notificationTypes = [ + 'note', + 'follow', + 'mention', + 'reply', + 'renote', + 'quote', + 'reaction', + 'pollEnded', + 'receiveFollowRequest', + 'followRequestAccepted', + 'roleAssigned', + 'groupInvited', + 'achievementEarned', + 'app', + 'test'] as const; export const obsoleteNotificationTypes = ['pollVote'/*, 'groupInvited'*/] as const; export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; export const mutedNoteReasons = ['word', 'manual', 'spam', 'other'] as const; -export const ffVisibility = ['public', 'followers', 'private'] as const; +export const followingVisibilities = ['public', 'followers', 'private'] as const; +export const followersVisibilities = ['public', 'followers', 'private'] as const; export const moderationLogTypes = [ 'updateServerSettings', diff --git a/packages/backend/test-server/.eslintrc.cjs b/packages/backend/test-server/.eslintrc.cjs new file mode 100644 index 0000000000..c261741a36 --- /dev/null +++ b/packages/backend/test-server/.eslintrc.cjs @@ -0,0 +1,32 @@ +module.exports = { + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + extends: [ + '../../shared/.eslintrc.js', + ], + rules: { + 'import/order': ['warn', { + 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], + 'pathGroups': [ + { + 'pattern': '@/**', + 'group': 'external', + 'position': 'after' + } + ], + }], + 'no-restricted-globals': [ + 'error', + { + 'name': '__dirname', + 'message': 'Not in ESModule. Use `import.meta.url` instead.' + }, + { + 'name': '__filename', + 'message': 'Not in ESModule. Use `import.meta.url` instead.' + } + ] + }, +}; diff --git a/packages/backend/test-server/.swcrc b/packages/backend/test-server/.swcrc new file mode 100644 index 0000000000..e3d6935169 --- /dev/null +++ b/packages/backend/test-server/.swcrc @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "typescript", + "dynamicImport": true, + "decorators": true + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true + }, + "experimental": { + "keepImportAssertions": true + }, + "baseUrl": "../built", + "paths": { + "@/*": ["*"] + }, + "target": "es2022" + }, + "minify": false +} diff --git a/packages/backend/test-server/entry.ts b/packages/backend/test-server/entry.ts new file mode 100644 index 0000000000..866a7e1f5b --- /dev/null +++ b/packages/backend/test-server/entry.ts @@ -0,0 +1,80 @@ +import { portToPid } from 'pid-port'; +import fkill from 'fkill'; +import Fastify from 'fastify'; +import { NestFactory } from '@nestjs/core'; +import { MainModule } from '@/MainModule.js'; +import { ServerService } from '@/server/ServerService.js'; +import { loadConfig } from '@/config.js'; +import { NestLogger } from '@/NestLogger.js'; + +const config = loadConfig(); +const originEnv = JSON.stringify(process.env); + +process.env.NODE_ENV = 'test'; + +/** + * テスト用のサーバインスタンスを起動する + */ +async function launch() { + await killTestServer(); + + console.log('starting application...'); + + const app = await NestFactory.createApplicationContext(MainModule, { + logger: new NestLogger(), + }); + const serverService = app.get(ServerService); + await serverService.launch(); + + await startControllerEndpoints(); + + // ジョブキューは必要な時にテストコード側で起動する + // ジョブキューが動くとテスト結果の確認に支障が出ることがあるので意図的に動かさないでいる + + console.log('application initialized.'); +} + +/** + * 既に重複したポートで待ち受けしているサーバがある場合はkillする + */ +async function killTestServer() { + // + try { + const pid = await portToPid(config.port); + if (pid) { + await fkill(pid, { force: true }); + } + } catch { + // NOP; + } +} + +/** + * 別プロセスに切り離してしまったが故に出来なくなった環境変数の書き換え等を実現するためのエンドポイントを作る + * @param port + */ +async function startControllerEndpoints(port = config.port + 1000) { + const fastify = Fastify(); + + fastify.post<{ Body: { key?: string, value?: string } }>('/env', async (req, res) => { + console.log(req.body); + const key = req.body['key']; + if (!key) { + res.code(400).send({ success: false }); + return; + } + + process.env[key] = req.body['value']; + + res.code(200).send({ success: true }); + }); + + fastify.post<{ Body: { key?: string, value?: string } }>('/env-reset', async (req, res) => { + process.env = JSON.parse(originEnv); + res.code(200).send({ success: true }); + }); + + await fastify.listen({ port: port, host: 'localhost' }); +} + +export default launch; diff --git a/packages/backend/test-server/tsconfig.json b/packages/backend/test-server/tsconfig.json new file mode 100644 index 0000000000..10313699c2 --- /dev/null +++ b/packages/backend/test-server/tsconfig.json @@ -0,0 +1,52 @@ +{ + "compilerOptions": { + "allowJs": true, + "noEmitOnError": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noUnusedParameters": false, + "noUnusedLocals": false, + "noFallthroughCasesInSwitch": true, + "declaration": false, + "sourceMap": true, + "target": "ES2022", + "module": "nodenext", + "moduleResolution": "nodenext", + "allowSyntheticDefaultImports": true, + "removeComments": false, + "noLib": false, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": false, + "skipLibCheck": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "resolveJsonModule": true, + "isolatedModules": true, + "rootDir": "../src", + "baseUrl": "./", + "paths": { + "@/*": ["../src/*"] + }, + "outDir": "../built-test", + "types": [ + "node" + ], + "typeRoots": [ + "../src/@types", + "../node_modules/@types", + "../node_modules" + ], + "lib": [ + "esnext" + ] + }, + "compileOnSave": false, + "include": [ + "./**/*.ts", + "../src/**/*.ts" + ], + "exclude": [ + "../src/**/*.test.ts" + ] +} diff --git a/packages/backend/test/docker-compose.yml b/packages/backend/test/docker-compose.yml index 2e97e4d179..f51f88ccde 100644 --- a/packages/backend/test/docker-compose.yml +++ b/packages/backend/test/docker-compose.yml @@ -7,7 +7,7 @@ services: - "127.0.0.1:56312:6379" dbtest: - image: postgres:13 + image: postgres:15 ports: - "127.0.0.1:54312:5432" environment: diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index eee6757495..e7e89002d0 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -10,7 +10,7 @@ import * as crypto from 'node:crypto'; import cbor from 'cbor'; import * as OTPAuth from 'otpauth'; import { loadConfig } from '@/config.js'; -import { api, signup, startServer } from '../utils.js'; +import { api, signup } from '../utils.js'; import type { AuthenticationResponseJSON, AuthenticatorAssertionResponseJSON, @@ -19,12 +19,10 @@ import type { PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON, } from '@simplewebauthn/typescript-types'; -import type { INestApplicationContext } from '@nestjs/common'; import type * as misskey from 'cherrypick-js'; describe('2要素認証', () => { - let app: INestApplicationContext; - let alice: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; const config = loadConfig(); const password = 'test'; @@ -185,14 +183,9 @@ describe('2要素認証', () => { }; beforeAll(async () => { - app = await startServer(); alice = await signup({ username, password }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('が設定でき、OTPでログインできる。', async () => { const registerResponse = await api('/i/2fa/register', { password, diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts index c94dad7a2c..1fb35574ad 100644 --- a/packages/backend/test/e2e/antennas.ts +++ b/packages/backend/test/e2e/antennas.ts @@ -6,24 +6,20 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { inspect } from 'node:util'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; import type { Packed } from '@/misc/json-schema.js'; import { - signup, + api, + failedApiCall, post, - userList, - page, role, - startServer, - api, + signup, successfulApiCall, - failedApiCall, - uploadFile, testPaginationConsistency, + uploadFile, + userList, } from '../utils.js'; import type * as misskey from 'cherrypick-js'; -import type { INestApplicationContext } from '@nestjs/common'; const compareBy = (selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => { return selector(a).localeCompare(selector(b)); @@ -37,7 +33,7 @@ describe('アンテナ', () => { // - srcのenumにgroupが残っている // - userGroupIdが残っている, isActiveがない type Antenna = misskey.entities.Antenna | Packed<'Antenna'>; - type User = misskey.entities.MeSignup; + type User = misskey.entities.SignupResponse; type Note = misskey.entities.Note; // アンテナを作成できる最小のパラメタ @@ -55,8 +51,6 @@ describe('アンテナ', () => { withReplies: false, }; - let app: INestApplicationContext; - let root: User; let alice: User; let bob: User; @@ -80,10 +74,6 @@ describe('アンテナ', () => { let userMutingAlice: User; let userMutedByAlice: User; - beforeAll(async () => { - app = await startServer(); - }, 1000 * 60 * 2); - beforeAll(async () => { root = await signup({ username: 'root' }); alice = await signup({ username: 'alice' }); @@ -137,10 +127,6 @@ describe('アンテナ', () => { await api('mute/create', { userId: userMutedByAlice.id }, alice); }, 1000 * 60 * 10); - afterAll(async () => { - await app.close(); - }); - beforeEach(async () => { // テスト間で影響し合わないように毎回全部消す。 for (const user of [alice, bob]) { diff --git a/packages/backend/test/e2e/api-visibility.ts b/packages/backend/test/e2e/api-visibility.ts index 658cbfc4f9..9654ecf35c 100644 --- a/packages/backend/test/e2e/api-visibility.ts +++ b/packages/backend/test/e2e/api-visibility.ts @@ -6,33 +6,22 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, startServer } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, signup } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('API visibility', () => { - let app: INestApplicationContext; - - beforeAll(async () => { - app = await startServer(); - }, 1000 * 60 * 2); - - afterAll(async () => { - await app.close(); - }); - describe('Note visibility', () => { //#region vars /** ヒロイン */ - let alice: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; /** フォロワー */ - let follower: misskey.entities.MeSignup; + let follower: misskey.entities.SignupResponse; /** 非フォロワー */ - let other: misskey.entities.MeSignup; + let other: misskey.entities.SignupResponse; /** 非フォロワーでもリプライやメンションをされた人 */ - let target: misskey.entities.MeSignup; + let target: misskey.entities.SignupResponse; /** specified mentionでmentionを飛ばされる人 */ - let target2: misskey.entities.MeSignup; + let target2: misskey.entities.SignupResponse; /** public-post */ let pub: any; diff --git a/packages/backend/test/e2e/api.ts b/packages/backend/test/e2e/api.ts index 3c19954221..576dd87454 100644 --- a/packages/backend/test/e2e/api.ts +++ b/packages/backend/test/e2e/api.ts @@ -7,27 +7,30 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { IncomingMessage } from 'http'; -import { signup, api, startServer, successfulApiCall, failedApiCall, uploadFile, waitFire, connectStream, relativeFetch } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { + api, + connectStream, + createAppToken, + failedApiCall, + relativeFetch, + signup, + successfulApiCall, + uploadFile, + waitFire, +} from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('API', () => { - let app: INestApplicationContext; - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; - let carol: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; + let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - describe('General validation', () => { test('wrong type', async () => { const res = await api('/test', { @@ -89,6 +92,11 @@ describe('API', () => { }); test('管理者専用のAPIのアクセス制限', async () => { + const application = await createAppToken(alice, ['read:account']); + const application2 = await createAppToken(alice, ['read:admin:index-stats']); + const application3 = await createAppToken(bob, []); + const application4 = await createAppToken(bob, ['read:admin:index-stats']); + // aliceは管理者、APIを使える await successfulApiCall({ endpoint: '/admin/get-index-stats', @@ -128,6 +136,42 @@ describe('API', () => { code: 'AUTHENTICATION_FAILED', id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14', }); + + await successfulApiCall({ + endpoint: '/admin/get-index-stats', + parameters: {}, + user: { token: application2 }, + }); + + await failedApiCall({ + endpoint: '/admin/get-index-stats', + parameters: {}, + user: { token: application }, + }, { + status: 403, + code: 'PERMISSION_DENIED', + id: '1370e5b7-d4eb-4566-bb1d-7748ee6a1838', + }); + + await failedApiCall({ + endpoint: '/admin/get-index-stats', + parameters: {}, + user: { token: application3 }, + }, { + status: 403, + code: 'ROLE_PERMISSION_DENIED', + id: 'c3d38592-54c0-429d-be96-5636b0431a61', + }); + + await failedApiCall({ + endpoint: '/admin/get-index-stats', + parameters: {}, + user: { token: application4 }, + }, { + status: 403, + code: 'ROLE_PERMISSION_DENIED', + id: 'c3d38592-54c0-429d-be96-5636b0431a61', + }); }); describe('Authentication header', () => { diff --git a/packages/backend/test/e2e/block.ts b/packages/backend/test/e2e/block.ts index 3505b5572a..006a3481a1 100644 --- a/packages/backend/test/e2e/block.ts +++ b/packages/backend/test/e2e/block.ts @@ -6,29 +6,21 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, startServer } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, signup } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('Block', () => { - let app: INestApplicationContext; - // alice blocks bob - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; - let carol: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; + let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('Block作成', async () => { const res = await api('/blocking/create', { userId: bob.id, diff --git a/packages/backend/test/e2e/clips.ts b/packages/backend/test/e2e/clips.ts index 25ec521d2c..231d426e38 100644 --- a/packages/backend/test/e2e/clips.ts +++ b/packages/backend/test/e2e/clips.ts @@ -18,25 +18,13 @@ import { paramDef as UnfavoriteParamDef } from '@/server/api/endpoints/clips/unf import { paramDef as AddNoteParamDef } from '@/server/api/endpoints/clips/add-note.js'; import { paramDef as RemoveNoteParamDef } from '@/server/api/endpoints/clips/remove-note.js'; import { paramDef as NotesParamDef } from '@/server/api/endpoints/clips/notes.js'; -import { - signup, - post, - startServer, - api, - successfulApiCall, - failedApiCall, - ApiRequest, - hiddenNote, -} from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, ApiRequest, failedApiCall, hiddenNote, post, signup, successfulApiCall } from '../utils.js'; describe('クリップ', () => { type User = Packed<'User'>; type Note = Packed<'Note'>; type Clip = Packed<'Clip'>; - let app: INestApplicationContext; - let alice: User; let bob: User; let aliceNote: Note; @@ -145,7 +133,6 @@ describe('クリップ', () => { }; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); @@ -160,10 +147,6 @@ describe('クリップ', () => { bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' }) as any; }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - afterEach(async () => { // テスト間で影響し合わないように毎回全部消す。 for (const user of [alice, bob]) { diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts index fb6b442516..7482eae9ae 100644 --- a/packages/backend/test/e2e/endpoints.ts +++ b/packages/backend/test/e2e/endpoints.ts @@ -10,30 +10,22 @@ import * as assert from 'assert'; // https://github.com/node-fetch/node-fetch/pull/1664 import { Blob } from 'node-fetch'; import { MiUser } from '@/models/_.js'; -import { startServer, signup, post, api, uploadFile, simpleGet, initTestDb } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, initTestDb, post, signup, simpleGet, uploadFile } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('Endpoints', () => { - let app: INestApplicationContext; - - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; - let carol: misskey.entities.MeSignup; - let dave: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; + let carol: misskey.entities.SignupResponse; + let dave: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); dave = await signup({ username: 'dave' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - describe('signup', () => { test('不正なユーザー名でアカウントが作成できない', async () => { const res = await api('signup', { @@ -710,6 +702,18 @@ describe('Endpoints', () => { assert.strictEqual(res.status, 400); }); + test('不正なファイル名で怒られる', async () => { + const file = (await uploadFile(alice)).body; + const newName = ''; + + const res = await api('/drive/files/update', { + fileId: file.id, + name: newName, + }, alice); + + assert.strictEqual(res.status, 400); + }); + test('間違ったIDで怒られる', async () => { const res = await api('/drive/files/update', { fileId: 'kyoppie', diff --git a/packages/backend/test/e2e/exports.ts b/packages/backend/test/e2e/exports.ts new file mode 100644 index 0000000000..8040f71658 --- /dev/null +++ b/packages/backend/test/e2e/exports.ts @@ -0,0 +1,193 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +process.env.NODE_ENV = 'test'; + +import * as assert from 'assert'; +import { api, port, post, signup, startJobQueue } from '../utils.js'; +import type { INestApplicationContext } from '@nestjs/common'; +import type * as misskey from 'cherrypick-js'; + +describe('export-clips', () => { + let queue: INestApplicationContext; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; + + // XXX: Any better way to get the result? + async function pollFirstDriveFile() { + while (true) { + const files = (await api('/drive/files', {}, alice)).body; + if (!files.length) { + await new Promise(r => setTimeout(r, 100)); + continue; + } + if (files.length > 1) { + throw new Error('Too many files?'); + } + const file = (await api('/drive/files/show', { fileId: files[0].id }, alice)).body; + const res = await fetch(new URL(new URL(file.url).pathname, `http://127.0.0.1:${port}`)); + return await res.json(); + } + } + + beforeAll(async () => { + queue = await startJobQueue(); + alice = await signup({ username: 'alice' }); + bob = await signup({ username: 'bob' }); + }, 1000 * 60 * 2); + + afterAll(async () => { + await queue.close(); + }); + + beforeEach(async () => { + // Clean all clips and files of alice + const clips = (await api('/clips/list', {}, alice)).body; + for (const clip of clips) { + const res = await api('/clips/delete', { clipId: clip.id }, alice); + if (res.status !== 204) { + throw new Error('Failed to delete clip'); + } + } + const files = (await api('/drive/files', {}, alice)).body; + for (const file of files) { + const res = await api('/drive/files/delete', { fileId: file.id }, alice); + if (res.status !== 204) { + throw new Error('Failed to delete file'); + } + } + }); + + test('basic export', async () => { + let res = await api('/clips/create', { + name: 'foo', + description: 'bar', + }, alice); + assert.strictEqual(res.status, 200); + + res = await api('/i/export-clips', {}, alice); + assert.strictEqual(res.status, 204); + + const exported = await pollFirstDriveFile(); + assert.strictEqual(exported[0].name, 'foo'); + assert.strictEqual(exported[0].description, 'bar'); + assert.strictEqual(exported[0].clipNotes.length, 0); + }); + + test('export with notes', async () => { + let res = await api('/clips/create', { + name: 'foo', + description: 'bar', + }, alice); + assert.strictEqual(res.status, 200); + const clip = res.body; + + const note1 = await post(alice, { + text: 'baz1', + }); + + const note2 = await post(alice, { + text: 'baz2', + poll: { + choices: ['sakura', 'izumi', 'ako'], + }, + }); + + for (const note of [note1, note2]) { + res = await api('/clips/add-note', { + clipId: clip.id, + noteId: note.id, + }, alice); + assert.strictEqual(res.status, 204); + } + + res = await api('/i/export-clips', {}, alice); + assert.strictEqual(res.status, 204); + + const exported = await pollFirstDriveFile(); + assert.strictEqual(exported[0].name, 'foo'); + assert.strictEqual(exported[0].description, 'bar'); + assert.strictEqual(exported[0].clipNotes.length, 2); + assert.strictEqual(exported[0].clipNotes[0].note.text, 'baz1'); + assert.strictEqual(exported[0].clipNotes[1].note.text, 'baz2'); + assert.deepStrictEqual(exported[0].clipNotes[1].note.poll.choices[0], 'sakura'); + }); + + test('multiple clips', async () => { + let res = await api('/clips/create', { + name: 'kawaii', + description: 'kawaii', + }, alice); + assert.strictEqual(res.status, 200); + const clip1 = res.body; + + res = await api('/clips/create', { + name: 'yuri', + description: 'yuri', + }, alice); + assert.strictEqual(res.status, 200); + const clip2 = res.body; + + const note1 = await post(alice, { + text: 'baz1', + }); + + const note2 = await post(alice, { + text: 'baz2', + }); + + res = await api('/clips/add-note', { + clipId: clip1.id, + noteId: note1.id, + }, alice); + assert.strictEqual(res.status, 204); + + res = await api('/clips/add-note', { + clipId: clip2.id, + noteId: note2.id, + }, alice); + assert.strictEqual(res.status, 204); + + res = await api('/i/export-clips', {}, alice); + assert.strictEqual(res.status, 204); + + const exported = await pollFirstDriveFile(); + assert.strictEqual(exported[0].name, 'kawaii'); + assert.strictEqual(exported[0].clipNotes.length, 1); + assert.strictEqual(exported[0].clipNotes[0].note.text, 'baz1'); + assert.strictEqual(exported[1].name, 'yuri'); + assert.strictEqual(exported[1].clipNotes.length, 1); + assert.strictEqual(exported[1].clipNotes[0].note.text, 'baz2'); + }); + + test('Clipping other user\'s note', async () => { + let res = await api('/clips/create', { + name: 'kawaii', + description: 'kawaii', + }, alice); + assert.strictEqual(res.status, 200); + const clip = res.body; + + const note = await post(bob, { + text: 'baz', + visibility: 'followers', + }); + + res = await api('/clips/add-note', { + clipId: clip.id, + noteId: note.id, + }, alice); + assert.strictEqual(res.status, 204); + + res = await api('/i/export-clips', {}, alice); + assert.strictEqual(res.status, 204); + + const exported = await pollFirstDriveFile(); + assert.strictEqual(exported[0].name, 'kawaii'); + assert.strictEqual(exported[0].clipNotes.length, 1); + assert.strictEqual(exported[0].clipNotes[0].note.text, 'baz'); + assert.strictEqual(exported[0].clipNotes[0].note.user.username, 'bob'); + }); +}); diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts index fb34b60e37..6d88e4bf8c 100644 --- a/packages/backend/test/e2e/fetch-resource.ts +++ b/packages/backend/test/e2e/fetch-resource.ts @@ -6,9 +6,8 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { startServer, channel, clip, cookie, galleryPost, signup, page, play, post, simpleGet, uploadFile } from '../utils.js'; +import { channel, clip, cookie, galleryPost, page, play, post, signup, simpleGet, uploadFile } from '../utils.js'; import type { SimpleGetResponse } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; import type * as misskey from 'cherrypick-js'; // Request Accept @@ -23,9 +22,7 @@ const HTML = 'text/html; charset=utf-8'; const JSON_UTF8 = 'application/json; charset=utf-8'; describe('Webリソース', () => { - let app: INestApplicationContext; - - let alice: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; let aliceUploadedFile: any; let alicesPost: any; let alicePage: any; @@ -34,7 +31,7 @@ describe('Webリソース', () => { let aliceGalleryPost: any; let aliceChannel: any; - let bob: misskey.entities.MeSignup; + let bob: misskey.entities.SignupResponse; type Request = { path: string, @@ -79,7 +76,6 @@ describe('Webリソース', () => { }; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); aliceUploadedFile = await uploadFile(alice); alicesPost = await post(alice, { @@ -96,10 +92,6 @@ describe('Webリソース', () => { bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - describe.each([ { path: '/', type: HTML }, { path: '/docs/ja-JP/about', type: HTML }, // "指定されたURLに該当するページはありませんでした。" diff --git a/packages/backend/test/e2e/ff-visibility.ts b/packages/backend/test/e2e/ff-visibility.ts index 2cfdd84dec..97220b5093 100644 --- a/packages/backend/test/e2e/ff-visibility.ts +++ b/packages/backend/test/e2e/ff-visibility.ts @@ -6,29 +6,22 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, startServer, simpleGet } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, signup, simpleGet } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('FF visibility', () => { - let app: INestApplicationContext; - - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - - test('ffVisibility が public なユーザーのフォロー/フォロワーを誰でも見れる', async () => { + test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => { await api('/i/update', { - ffVisibility: 'public', + followingVisibility: 'public', + followersVisibility: 'public', }, alice); const followingRes = await api('/users/following', { @@ -44,9 +37,88 @@ describe('FF visibility', () => { assert.strictEqual(Array.isArray(followersRes.body), true); }); - test('ffVisibility が followers なユーザーのフォロー/フォロワーを自分で見れる', async () => { + test('followingVisibility が public であれば followersVisibility の設定に関わらずユーザーのフォローを誰でも見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + }); + + test('followersVisibility が public であれば followingVisibility の設定に関わらずユーザーのフォロワーを誰でも見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'public', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'public', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'public', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + }); + + test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを自分で見れる', async () => { await api('/i/update', { - ffVisibility: 'followers', + followingVisibility: 'followers', + followersVisibility: 'followers', }, alice); const followingRes = await api('/users/following', { @@ -62,9 +134,88 @@ describe('FF visibility', () => { assert.strictEqual(Array.isArray(followersRes.body), true); }); - test('ffVisibility が followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => { + test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + }); + + test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + }); + + test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => { await api('/i/update', { - ffVisibility: 'followers', + followingVisibility: 'followers', + followersVisibility: 'followers', }, alice); const followingRes = await api('/users/following', { @@ -78,9 +229,82 @@ describe('FF visibility', () => { assert.strictEqual(followersRes.status, 400); }); - test('ffVisibility が followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => { + test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず非フォロワーが見れない', async () => { + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + }); + + test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず非フォロワーが見れない', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + }); + + test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => { await api('/i/update', { - ffVisibility: 'followers', + followingVisibility: 'followers', + followersVisibility: 'followers', }, alice); await api('/following/create', { @@ -100,9 +324,106 @@ describe('FF visibility', () => { assert.strictEqual(Array.isArray(followersRes.body), true); }); - test('ffVisibility が private なユーザーのフォロー/フォロワーを自分で見れる', async () => { + test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらずフォロワーが見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'public', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + }); + + test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらずフォロワーが見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'followers', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + }); + + test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを自分で見れる', async () => { await api('/i/update', { - ffVisibility: 'private', + followingVisibility: 'private', + followersVisibility: 'private', }, alice); const followingRes = await api('/users/following', { @@ -118,9 +439,88 @@ describe('FF visibility', () => { assert.strictEqual(Array.isArray(followersRes.body), true); }); - test('ffVisibility が private なユーザーのフォロー/フォロワーを他人が見れない', async () => { + test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + }); + + test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + }); + + test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを他人が見れない', async () => { await api('/i/update', { - ffVisibility: 'private', + followingVisibility: 'private', + followersVisibility: 'private', }, alice); const followingRes = await api('/users/following', { @@ -134,36 +534,129 @@ describe('FF visibility', () => { assert.strictEqual(followersRes.status, 400); }); + test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず他人が見れない', async () => { + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + }); + + test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず他人が見れない', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + }); + describe('AP', () => { - test('ffVisibility が public 以外ならばAPからは取得できない', async () => { + test('followingVisibility が public 以外ならばAPからはフォローを取得できない', async () => { { await api('/i/update', { - ffVisibility: 'public', + followingVisibility: 'public', }, alice); const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json'); - const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); assert.strictEqual(followingRes.status, 200); - assert.strictEqual(followersRes.status, 200); } { await api('/i/update', { - ffVisibility: 'followers', + followingVisibility: 'followers', }, alice); const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json'); - const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); assert.strictEqual(followingRes.status, 403); - assert.strictEqual(followersRes.status, 403); } { await api('/i/update', { - ffVisibility: 'private', + followingVisibility: 'private', }, alice); const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json'); - const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); assert.strictEqual(followingRes.status, 403); + } + }); + + test('followersVisibility が public 以外ならばAPからはフォロワーを取得できない', async () => { + { + await api('/i/update', { + followersVisibility: 'public', + }, alice); + + const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); + assert.strictEqual(followersRes.status, 200); + } + { + await api('/i/update', { + followersVisibility: 'followers', + }, alice); + + const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); + assert.strictEqual(followersRes.status, 403); + } + { + await api('/i/update', { + followersVisibility: 'private', + }, alice); + + const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); assert.strictEqual(followersRes.status, 403); } }); diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts index ca3f825f56..86e0cc57b6 100644 --- a/packages/backend/test/e2e/move.ts +++ b/packages/backend/test/e2e/move.ts @@ -3,35 +3,35 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { INestApplicationContext } from '@nestjs/common'; + process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { loadConfig } from '@/config.js'; import { MiUser, UsersRepository } from '@/models/_.js'; -import { jobQueue } from '@/boot/common.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; -import { uploadFile, signup, startServer, initTestDb, api, sleep, successfulApiCall } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { jobQueue } from '@/boot/common.js'; +import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('Account Move', () => { - let app: INestApplicationContext; let jq: INestApplicationContext; let url: URL; let root: any; - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; - let carol: misskey.entities.MeSignup; - let dave: misskey.entities.MeSignup; - let eve: misskey.entities.MeSignup; - let frank: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; + let carol: misskey.entities.SignupResponse; + let dave: misskey.entities.SignupResponse; + let eve: misskey.entities.SignupResponse; + let frank: misskey.entities.SignupResponse; let Users: UsersRepository; beforeAll(async () => { - app = await startServer(); jq = await jobQueue(); + const config = loadConfig(); url = new URL(config.url); const connection = await initTestDb(false); @@ -46,7 +46,7 @@ describe('Account Move', () => { }, 1000 * 60 * 2); afterAll(async () => { - await Promise.all([app.close(), jq.close()]); + await jq.close(); }); describe('Create Alias', () => { diff --git a/packages/backend/test/e2e/mute.ts b/packages/backend/test/e2e/mute.ts index 2c4e59b5e5..b231bf821f 100644 --- a/packages/backend/test/e2e/mute.ts +++ b/packages/backend/test/e2e/mute.ts @@ -6,29 +6,21 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, react, startServer, waitFire } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, react, signup, waitFire } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('Mute', () => { - let app: INestApplicationContext; - // alice mutes carol - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; - let carol: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; + let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('ミュート作成', async () => { const res = await api('/mute/create', { userId: carol.id, diff --git a/packages/backend/test/e2e/nodeinfo.ts b/packages/backend/test/e2e/nodeinfo.ts new file mode 100644 index 0000000000..a9e3f14624 --- /dev/null +++ b/packages/backend/test/e2e/nodeinfo.ts @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +process.env.NODE_ENV = 'test'; + +import * as assert from 'assert'; +import { relativeFetch } from '../utils.js'; + +describe('nodeinfo', () => { + test('nodeinfo 2.1', async () => { + const res = await relativeFetch('nodeinfo/2.1'); + assert.ok(res.ok); + assert.strictEqual(res.headers.get('Access-Control-Allow-Origin'), '*'); + + const nodeInfo = await res.json() as any; + assert.strictEqual(nodeInfo.software.name, 'cherrypick'); + }); + + test('nodeinfo 2.0', async () => { + const res = await relativeFetch('nodeinfo/2.0'); + assert.ok(res.ok); + assert.strictEqual(res.headers.get('Access-Control-Allow-Origin'), '*'); + + const nodeInfo = await res.json() as any; + assert.strictEqual(nodeInfo.software.name, 'cherrypick'); + }); +}); diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts index 179bb80398..a46e63f39c 100644 --- a/packages/backend/test/e2e/note.ts +++ b/packages/backend/test/e2e/note.ts @@ -8,29 +8,22 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { MiNote } from '@/models/Note.js'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; -import { signup, post, uploadUrl, startServer, initTestDb, api, uploadFile } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, initTestDb, post, signup, uploadFile, uploadUrl } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('Note', () => { - let app: INestApplicationContext; let Notes: any; - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); const connection = await initTestDb(true); Notes = connection.getRepository(MiNote); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('投稿できる', async () => { const post = { text: 'test', diff --git a/packages/backend/test/e2e/oauth.ts b/packages/backend/test/e2e/oauth.ts index 5e00ca1483..727788028a 100644 --- a/packages/backend/test/e2e/oauth.ts +++ b/packages/backend/test/e2e/oauth.ts @@ -4,20 +4,25 @@ */ /** - * Basic OAuth tests to make sure the library is correctly integrated to Misskey + * Basic OAuth tests to make sure the library is correctly integrated to CherryPick * and not regressed by version updates or potential migration to another library. */ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { AuthorizationCode, ResourceOwnerPassword, type AuthorizationTokenConfig, ClientCredentials, ModuleOptions } from 'simple-oauth2'; +import { + AuthorizationCode, + type AuthorizationTokenConfig, + ClientCredentials, + ModuleOptions, + ResourceOwnerPassword, +} from 'simple-oauth2'; import pkceChallenge from 'pkce-challenge'; import { JSDOM } from 'jsdom'; -import Fastify, { type FastifyReply, type FastifyInstance } from 'fastify'; -import { api, port, signup, startServer } from '../utils.js'; +import Fastify, { type FastifyInstance, type FastifyReply } from 'fastify'; +import { api, port, sendEnvUpdateRequest, signup } from '../utils.js'; import type * as misskey from 'cherrypick-js'; -import type { INestApplicationContext } from '@nestjs/common'; const host = `http://127.0.0.1:${port}`; @@ -75,7 +80,7 @@ function getMeta(html: string): { transactionId: string | undefined, clientName: }; } -function fetchDecision(transactionId: string, user: misskey.entities.MeSignup, { cancel }: { cancel?: boolean } = {}): Promise { +function fetchDecision(transactionId: string, user: misskey.entities.SignupResponse, { cancel }: { cancel?: boolean } = {}): Promise { return fetch(new URL('/oauth/decision', host), { method: 'post', body: new URLSearchParams({ @@ -90,14 +95,14 @@ function fetchDecision(transactionId: string, user: misskey.entities.MeSignup, { }); } -async function fetchDecisionFromResponse(response: Response, user: misskey.entities.MeSignup, { cancel }: { cancel?: boolean } = {}): Promise { +async function fetchDecisionFromResponse(response: Response, user: misskey.entities.SignupResponse, { cancel }: { cancel?: boolean } = {}): Promise { const { transactionId } = getMeta(await response.text()); assert.ok(transactionId); return await fetchDecision(transactionId, user, { cancel }); } -async function fetchAuthorizationCode(user: misskey.entities.MeSignup, scope: string, code_challenge: string): Promise<{ client: AuthorizationCode, code: string }> { +async function fetchAuthorizationCode(user: misskey.entities.SignupResponse, scope: string, code_challenge: string): Promise<{ client: AuthorizationCode, code: string }> { const client = new AuthorizationCode(clientConfig); const response = await fetch(client.authorizeURL({ @@ -134,7 +139,7 @@ function assertIndirectError(response: Response, error: string): void { assert.strictEqual(location.searchParams.get('error'), error); // https://datatracker.ietf.org/doc/html/rfc9207#name-response-parameter-iss - assert.strictEqual(location.searchParams.get('iss'), 'http://misskey.local'); + assert.strictEqual(location.searchParams.get('iss'), 'http://cherrypick.local'); // https://datatracker.ietf.org/doc/html/rfc6749.html#section-4.1.2.1 assert.ok(location.searchParams.has('state')); } @@ -147,16 +152,14 @@ async function assertDirectError(response: Response, status: number, error: stri } describe('OAuth', () => { - let app: INestApplicationContext; let fastify: FastifyInstance; - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; let sender: (reply: FastifyReply) => void; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); @@ -168,19 +171,18 @@ describe('OAuth', () => { }, 1000 * 60 * 2); beforeEach(async () => { - process.env.MISSKEY_TEST_CHECK_IP_RANGE = ''; + await sendEnvUpdateRequest({ key: 'CHERRYPICK_TEST_CHECK_IP_RANGE', value: '' }); sender = (reply): void => { reply.send(` -
Misklient +
Crpklient `); }; }); afterAll(async () => { await fastify.close(); - await app.close(); }); test('Full flow', async () => { @@ -200,7 +202,7 @@ describe('OAuth', () => { const meta = getMeta(await response.text()); assert.strictEqual(typeof meta.transactionId, 'string'); assert.ok(meta.transactionId); - assert.strictEqual(meta.clientName, 'Misklient'); + assert.strictEqual(meta.clientName, 'Crpklient'); const decisionResponse = await fetchDecision(meta.transactionId, alice); assert.strictEqual(decisionResponse.status, 302); @@ -812,7 +814,7 @@ describe('OAuth', () => { reply.header('Link', '; rel="redirect_uri"'); reply.send(` -
Misklient +
Crpklient `); }, 'Mixed links': reply => { @@ -820,14 +822,14 @@ describe('OAuth', () => { reply.send(` -
Misklient +
Crpklient `); }, 'Multiple items in Link header': reply => { reply.header('Link', '; rel="redirect_uri",; rel="redirect_uri"'); reply.send(` -
Misklient +
Crpklient `); }, 'Multiple items in HTML': reply => { @@ -835,7 +837,7 @@ describe('OAuth', () => { -
Misklient +
Crpklient `); }, }; @@ -861,7 +863,7 @@ describe('OAuth', () => { sender = (reply): void => { reply.send(` -
Misklient +
Crpklient `); }; @@ -881,7 +883,7 @@ describe('OAuth', () => { }); test('Disallow loopback', async () => { - process.env.MISSKEY_TEST_CHECK_IP_RANGE = '1'; + await sendEnvUpdateRequest({ key: 'CHERRYPICK_TEST_CHECK_IP_RANGE', value: '1' }); const client = new AuthorizationCode(clientConfig); const response = await fetch(client.authorizeURL({ @@ -918,7 +920,7 @@ describe('OAuth', () => { reply.header('Link', '; rel="redirect_uri"'); reply.send(` -
Misklient +
Crpklient `); reply.send(); }; @@ -941,4 +943,24 @@ describe('OAuth', () => { const response = await fetch(new URL('/oauth/foo', host)); assert.strictEqual(response.status, 404); }); + + describe('CORS', () => { + test('Token endpoint should support CORS', async () => { + const response = await fetch(new URL('/oauth/token', host), { method: 'POST' }); + assert.ok(!response.ok); + assert.strictEqual(response.headers.get('Access-Control-Allow-Origin'), '*'); + }); + + test('Authorize endpoint should not support CORS', async () => { + const response = await fetch(new URL('/oauth/authorize', host), { method: 'GET' }); + assert.ok(!response.ok); + assert.ok(!response.headers.has('Access-Control-Allow-Origin')); + }); + + test('Decision endpoint should not support CORS', async () => { + const response = await fetch(new URL('/oauth/decision', host), { method: 'POST' }); + assert.ok(!response.ok); + assert.ok(!response.headers.has('Access-Control-Allow-Origin')); + }); + }); }); diff --git a/packages/backend/test/e2e/renote-mute.ts b/packages/backend/test/e2e/renote-mute.ts index b1e7a745ec..a0771c6741 100644 --- a/packages/backend/test/e2e/renote-mute.ts +++ b/packages/backend/test/e2e/renote-mute.ts @@ -6,29 +6,21 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, react, startServer, waitFire, sleep } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, signup, sleep, waitFire } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('Renote Mute', () => { - let app: INestApplicationContext; - // alice mutes carol - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; - let carol: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; + let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('ミュート作成', async () => { const res = await api('/renote-mute/create', { userId: carol.id, diff --git a/packages/backend/test/e2e/streaming.ts b/packages/backend/test/e2e/streaming.ts index 9692bc4775..d385d163ac 100644 --- a/packages/backend/test/e2e/streaming.ts +++ b/packages/backend/test/e2e/streaming.ts @@ -6,13 +6,12 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; +import { WebSocket } from 'ws'; import { MiFollowing } from '@/models/Following.js'; -import { signup, api, post, startServer, initTestDb, waitFire } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, createAppToken, initTestDb, port, post, signup, waitFire } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('Streaming', () => { - let app: INestApplicationContext; let Followings: any; const follow = async (follower: any, followee: any) => { @@ -31,15 +30,15 @@ describe('Streaming', () => { describe('Streaming', () => { // Local users - let ayano: misskey.entities.MeSignup; - let kyoko: misskey.entities.MeSignup; - let chitose: misskey.entities.MeSignup; - let kanako: misskey.entities.MeSignup; + let ayano: misskey.entities.SignupResponse; + let kyoko: misskey.entities.SignupResponse; + let chitose: misskey.entities.SignupResponse; + let kanako: misskey.entities.SignupResponse; // Remote users - let akari: misskey.entities.MeSignup; - let chinatsu: misskey.entities.MeSignup; - let takumi: misskey.entities.MeSignup; + let akari: misskey.entities.SignupResponse; + let chinatsu: misskey.entities.SignupResponse; + let takumi: misskey.entities.SignupResponse; let kyokoNote: any; let kanakoNote: any; @@ -47,7 +46,6 @@ describe('Streaming', () => { let list: any; beforeAll(async () => { - app = await startServer(); const connection = await initTestDb(true); Followings = connection.getRepository(MiFollowing); @@ -94,10 +92,6 @@ describe('Streaming', () => { }, chitose); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - describe('Events', () => { test('mention event', async () => { const fired = await waitFire( @@ -560,6 +554,28 @@ describe('Streaming', () => { }); }); + test('Authentication', async () => { + const application = await createAppToken(ayano, []); + const application2 = await createAppToken(ayano, ['read:account']); + const socket = new WebSocket(`ws://127.0.0.1:${port}/streaming?i=${application}`); + const established = await new Promise((resolve, reject) => { + socket.on('error', () => resolve(false)); + socket.on('unexpected-response', () => resolve(false)); + setTimeout(() => resolve(true), 3000); + }); + + socket.close(); + assert.strictEqual(established, false); + + const fired = await waitFire( + { token: application2 }, 'hybridTimeline', + () => api('notes/create', { text: 'Hello, world!' }, ayano), + msg => msg.type === 'note' && msg.body.userId === ayano.id, + ); + + assert.strictEqual(fired, true); + }); + // XXX: QueryFailedError: duplicate key value violates unique constraint "IDX_347fec870eafea7b26c8a73bac" /* describe('Hashtag Timeline', () => { diff --git a/packages/backend/test/e2e/thread-mute.ts b/packages/backend/test/e2e/thread-mute.ts index 9f50055259..c0812fc6e4 100644 --- a/packages/backend/test/e2e/thread-mute.ts +++ b/packages/backend/test/e2e/thread-mute.ts @@ -6,28 +6,20 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, connectStream, startServer } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, connectStream, post, signup } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('Note thread mute', () => { - let app: INestApplicationContext; - - let alice: misskey.entities.MeSignup; - let bob: misskey.entities.MeSignup; - let carol: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; + let bob: misskey.entities.SignupResponse; + let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('notes/mentions にミュートしているスレッドの投稿が含まれない', async () => { const bobNote = await post(bob, { text: '@alice @carol root note' }); const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' }); diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index 94956047d4..1efe2609e0 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -6,13 +6,8 @@ // How to run: // pnpm jest -- e2e/timelines.ts -process.env.NODE_ENV = 'test'; -process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING = 'true'; - import * as assert from 'assert'; -import { signup, api, post, react, startServer, waitFire, sleep, uploadUrl, randomString } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; -import type * as misskey from 'cherrypick-js'; +import { api, post, randomString, sendEnvUpdateRequest, signup, sleep, uploadUrl } from '../utils.js'; function genHost() { return randomString() + '.example.com'; @@ -22,16 +17,6 @@ function waitForPushToTl() { return sleep(500); } -let app: INestApplicationContext; - -beforeAll(async () => { - app = await startServer(); -}, 1000 * 60 * 2); - -afterAll(async () => { - await app.close(); -}); - describe('Timelines', () => { describe('Home TL', () => { test.concurrent('自分の visibility: followers なノートが含まれる', async () => { @@ -335,8 +320,9 @@ describe('Timelines', () => { test.concurrent('フォローしているリモートユーザーのノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); await api('/following/create', { userId: bob.id }, alice); - await sleep(1000); + const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); @@ -349,8 +335,9 @@ describe('Timelines', () => { test.concurrent('フォローしているリモートユーザーの visibility: home なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); await api('/following/create', { userId: bob.id }, alice); - await sleep(1000); + const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); @@ -366,8 +353,8 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await sleep(1000); const [bobFile, carolFile] = await Promise.all([ - uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'), - uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'), + uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), + uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), ]); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [bobFile.id] }); @@ -666,7 +653,7 @@ describe('Timelines', () => { test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); @@ -763,8 +750,9 @@ describe('Timelines', () => { test.concurrent('フォローしているリモートユーザーのノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); await api('/following/create', { userId: bob.id }, alice); - await sleep(1000); + const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); @@ -777,8 +765,9 @@ describe('Timelines', () => { test.concurrent('フォローしているリモートユーザーの visibility: home なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); await api('/following/create', { userId: bob.id }, alice); - await sleep(1000); + const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); @@ -804,7 +793,7 @@ describe('Timelines', () => { test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); @@ -999,7 +988,7 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); @@ -1158,7 +1147,7 @@ describe('Timelines', () => { test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); diff --git a/packages/backend/test/e2e/user-notes.ts b/packages/backend/test/e2e/user-notes.ts index 811ffc4b6e..9d319270dc 100644 --- a/packages/backend/test/e2e/user-notes.ts +++ b/packages/backend/test/e2e/user-notes.ts @@ -6,20 +6,16 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, uploadUrl, startServer } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, signup, uploadUrl } from '../utils.js'; import type * as misskey from 'cherrypick-js'; describe('users/notes', () => { - let app: INestApplicationContext; - - let alice: misskey.entities.MeSignup; + let alice: misskey.entities.SignupResponse; let jpgNote: any; let pngNote: any; let jpgPngNote: any; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/kokonect-link/cherrypick/develop/packages/backend/test/resources/Lenna.jpg'); const png = await uploadUrl(alice, 'https://raw.githubusercontent.com/kokonect-link/cherrypick/develop/packages/backend/test/resources/Lenna.png'); @@ -34,10 +30,6 @@ describe('users/notes', () => { }); }, 1000 * 60 * 2); - afterAll(async() => { - await app.close(); - }); - test('withFiles', async () => { const res = await api('/users/notes', { userId: alice.id, diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 93cee0a8dd..af66afd33a 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -8,20 +8,8 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { inspect } from 'node:util'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; -import type { Packed } from '@/misc/json-schema.js'; -import { - signup, - post, - page, - role, - startServer, - api, - successfulApiCall, - failedApiCall, - uploadFile, -} from '../utils.js'; +import { api, page, post, role, signup, successfulApiCall, uploadFile } from '../utils.js'; import type * as misskey from 'cherrypick-js'; -import type { INestApplicationContext } from '@nestjs/common'; describe('ユーザー', () => { // エンティティとしてのユーザーを主眼においたテストを記述する @@ -112,7 +100,8 @@ describe('ユーザー', () => { pinnedPageId: user.pinnedPageId, pinnedPage: user.pinnedPage, publicReactions: user.publicReactions, - ffVisibility: user.ffVisibility, + followingVisibility: user.followingVisibility, + followersVisibility: user.followersVisibility, twoFactorEnabled: user.twoFactorEnabled, usePasswordLessLogin: user.usePasswordLessLogin, securityKeys: user.securityKeys, @@ -185,8 +174,6 @@ describe('ユーザー', () => { }); }; - let app: INestApplicationContext; - let root: User; let alice: User; let aliceNote: misskey.entities.Note; @@ -230,10 +217,6 @@ describe('ユーザー', () => { let userFollowRequesting: User; let userFollowRequested: User; - beforeAll(async () => { - app = await startServer(); - }, 1000 * 60 * 2); - beforeAll(async () => { root = await signup({ username: 'root' }); alice = await signup({ username: 'alice' }); @@ -321,10 +304,6 @@ describe('ユーザー', () => { await api('following/create', { userId: userFollowRequested.id }, userFollowRequesting); }, 1000 * 60 * 10); - afterAll(async () => { - await app.close(); - }); - beforeEach(async () => { alice = { ...alice, @@ -387,7 +366,8 @@ describe('ユーザー', () => { assert.strictEqual(response.pinnedPageId, null); assert.strictEqual(response.pinnedPage, null); assert.strictEqual(response.publicReactions, true); - assert.strictEqual(response.ffVisibility, 'public'); + 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); @@ -497,9 +477,12 @@ describe('ユーザー', () => { { parameters: (): object => ({ alwaysMarkNsfw: false }) }, { parameters: (): object => ({ autoSensitive: true }) }, { parameters: (): object => ({ autoSensitive: false }) }, - { parameters: (): object => ({ ffVisibility: 'private' }) }, - { parameters: (): object => ({ ffVisibility: 'followers' }) }, - { parameters: (): object => ({ ffVisibility: 'public' }) }, + { parameters: (): object => ({ followingVisibility: 'private' }) }, + { parameters: (): object => ({ followingVisibility: 'followers' }) }, + { parameters: (): object => ({ followingVisibility: 'public' }) }, + { parameters: (): object => ({ followersVisibility: 'private' }) }, + { parameters: (): object => ({ followersVisibility: 'followers' }) }, + { parameters: (): object => ({ followersVisibility: 'public' }) }, { parameters: (): object => ({ mutedWords: Array(19).fill(['xxxxx']) }) }, { parameters: (): object => ({ mutedWords: [['x'.repeat(194)]] }) }, { parameters: (): object => ({ mutedWords: [] }) }, diff --git a/packages/backend/test/e2e/well-known.ts b/packages/backend/test/e2e/well-known.ts new file mode 100644 index 0000000000..ede32a03e5 --- /dev/null +++ b/packages/backend/test/e2e/well-known.ts @@ -0,0 +1,103 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +process.env.NODE_ENV = 'test'; + +import * as assert from 'assert'; +import { host, origin, relativeFetch, signup } from '../utils.js'; +import type * as misskey from 'cherrypick-js'; + +describe('.well-known', () => { + let alice: misskey.entities.User; + + beforeAll(async () => { + alice = await signup({ username: 'alice' }); + }, 1000 * 60 * 2); + + test('nodeinfo', async () => { + const res = await relativeFetch('.well-known/nodeinfo'); + assert.ok(res.ok); + assert.strictEqual(res.headers.get('Access-Control-Allow-Origin'), '*'); + + const nodeInfo = await res.json(); + assert.deepStrictEqual(nodeInfo, { + links: [{ + rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1', + href: `${origin}/nodeinfo/2.1`, + }, { + rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0', + href: `${origin}/nodeinfo/2.0`, + }], + }); + }); + + test('webfinger', async () => { + const preflight = await relativeFetch(`.well-known/webfinger?resource=acct:alice@${host}`, { + method: 'options', + headers: { + 'Access-Control-Request-Method': 'GET', + Origin: 'http://example.com', + }, + }); + assert.ok(preflight.ok); + assert.strictEqual(preflight.headers.get('Access-Control-Allow-Headers'), 'Accept'); + + const res = await relativeFetch(`.well-known/webfinger?resource=acct:alice@${host}`); + assert.ok(res.ok); + assert.strictEqual(res.headers.get('Access-Control-Allow-Origin'), '*'); + assert.strictEqual(res.headers.get('Access-Control-Expose-Headers'), 'Vary'); + assert.strictEqual(res.headers.get('Vary'), 'Accept'); + + const webfinger = await res.json(); + + assert.deepStrictEqual(webfinger, { + subject: `acct:alice@${host}`, + links: [{ + rel: 'self', + type: 'application/activity+json', + href: `${origin}/users/${alice.id}`, + }, { + rel: 'http://webfinger.net/rel/profile-page', + type: 'text/html', + href: `${origin}/@alice`, + }, { + rel: 'http://ostatus.org/schema/1.0/subscribe', + template: `${origin}/authorize-follow?acct={uri}`, + }], + }); + }); + + test('host-meta', async () => { + const res = await relativeFetch('.well-known/host-meta'); + assert.ok(res.ok); + assert.strictEqual(res.headers.get('Access-Control-Allow-Origin'), '*'); + }); + + test('host-meta.json', async () => { + const res = await relativeFetch('.well-known/host-meta.json'); + assert.ok(res.ok); + assert.strictEqual(res.headers.get('Access-Control-Allow-Origin'), '*'); + + const hostMeta = await res.json(); + assert.deepStrictEqual(hostMeta, { + links: [{ + rel: 'lrdd', + type: 'application/jrd+json', + template: `${origin}/.well-known/webfinger?resource={uri}`, + }], + }); + }); + + test('oauth-authorization-server', async () => { + const res = await relativeFetch('.well-known/oauth-authorization-server'); + assert.ok(res.ok); + assert.strictEqual(res.headers.get('Access-Control-Allow-Origin'), '*'); + + const serverInfo = await res.json() as any; + assert.strictEqual(serverInfo.issuer, origin); + assert.strictEqual(serverInfo.authorization_endpoint, `${origin}/oauth/authorize`); + assert.strictEqual(serverInfo.token_endpoint, `${origin}/oauth/token`); + }); +}); diff --git a/packages/backend/test/jest.setup.ts b/packages/backend/test/jest.setup.ts new file mode 100644 index 0000000000..cf5b9bf24d --- /dev/null +++ b/packages/backend/test/jest.setup.ts @@ -0,0 +1,8 @@ +import { initTestDb, sendEnvResetRequest } from './utils.js'; + +beforeAll(async () => { + await Promise.all([ + initTestDb(false), + sendEnvResetRequest(), + ]); +}); diff --git a/packages/backend/test/misc/mock-resolver.ts b/packages/backend/test/misc/mock-resolver.ts index 0ff4c29bc9..c6ba188e5d 100644 --- a/packages/backend/test/misc/mock-resolver.ts +++ b/packages/backend/test/misc/mock-resolver.ts @@ -15,7 +15,13 @@ import type { LoggerService } from '@/core/LoggerService.js'; import type { MetaService } from '@/core/MetaService.js'; import type { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; -import type { NoteReactionsRepository, NotesRepository, PollsRepository, UsersRepository, FollowRequestsRepository } from '@/models/_.js'; +import type { + FollowRequestsRepository, + NoteReactionsRepository, + NotesRepository, + PollsRepository, + UsersRepository, +} from '@/models/_.js'; type MockResponse = { type: string; diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts index 99f9510907..77a8d3c587 100644 --- a/packages/backend/test/unit/AnnouncementService.ts +++ b/packages/backend/test/unit/AnnouncementService.ts @@ -10,7 +10,13 @@ import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; import { GlobalModule } from '@/GlobalModule.js'; import { AnnouncementService } from '@/core/AnnouncementService.js'; -import type { MiAnnouncement, AnnouncementsRepository, AnnouncementReadsRepository, UsersRepository, MiUser } from '@/models/_.js'; +import type { + AnnouncementReadsRepository, + AnnouncementsRepository, + MiAnnouncement, + MiUser, + UsersRepository, +} from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { genAidx } from '@/misc/id/aidx.js'; import { CacheService } from '@/core/CacheService.js'; diff --git a/packages/backend/test/unit/DriveService.ts b/packages/backend/test/unit/DriveService.ts index e50db1c01c..4a9843ffb4 100644 --- a/packages/backend/test/unit/DriveService.ts +++ b/packages/backend/test/unit/DriveService.ts @@ -6,7 +6,13 @@ process.env.NODE_ENV = 'test'; import { Test } from '@nestjs/testing'; -import { DeleteObjectCommandOutput, DeleteObjectCommand, NoSuchKey, InvalidObjectState, S3Client } from '@aws-sdk/client-s3'; +import { + DeleteObjectCommand, + DeleteObjectCommandOutput, + InvalidObjectState, + NoSuchKey, + S3Client, +} from '@aws-sdk/client-s3'; import { mockClient } from 'aws-sdk-client-mock'; import { GlobalModule } from '@/GlobalModule.js'; import { DriveService } from '@/core/DriveService.js'; diff --git a/packages/backend/test/unit/FileInfoService.ts b/packages/backend/test/unit/FileInfoService.ts index 9e164fbfc9..413c8402d1 100644 --- a/packages/backend/test/unit/FileInfoService.ts +++ b/packages/backend/test/unit/FileInfoService.ts @@ -10,7 +10,7 @@ import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; -import { describe, beforeAll, afterAll, test } from '@jest/globals'; +import { afterAll, beforeAll, describe, test } from '@jest/globals'; import { GlobalModule } from '@/GlobalModule.js'; import { FileInfoService } from '@/core/FileInfoService.js'; //import { DI } from '@/di-symbols.js'; diff --git a/packages/backend/test/unit/MetaService.ts b/packages/backend/test/unit/MetaService.ts index d3d84f4bd2..547f80c9a1 100644 --- a/packages/backend/test/unit/MetaService.ts +++ b/packages/backend/test/unit/MetaService.ts @@ -6,15 +6,13 @@ process.env.NODE_ENV = 'test'; import { jest } from '@jest/globals'; -import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; import { GlobalModule } from '@/GlobalModule.js'; -import type { MetasRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { MetaService } from '@/core/MetaService.js'; import { CoreModule } from '@/core/CoreModule.js'; -import type { DataSource } from 'typeorm'; import type { TestingModule } from '@nestjs/testing'; +import type { DataSource } from 'typeorm'; describe('MetaService', () => { let app: TestingModule; diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts index 7feae17051..4197f4b899 100644 --- a/packages/backend/test/unit/RoleService.ts +++ b/packages/backend/test/unit/RoleService.ts @@ -11,7 +11,7 @@ import { Test } from '@nestjs/testing'; import * as lolex from '@sinonjs/fake-timers'; import { GlobalModule } from '@/GlobalModule.js'; import { RoleService } from '@/core/RoleService.js'; -import type { MiRole, RolesRepository, RoleAssignmentsRepository, UsersRepository, MiUser } from '@/models/_.js'; +import type { MiRole, MiUser, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { MetaService } from '@/core/MetaService.js'; import { genAidx } from '@/misc/id/aidx.js'; @@ -19,6 +19,7 @@ import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; +import { NotificationService } from '@/core/NotificationService.js'; import { sleep } from '../utils.js'; import type { TestingModule } from '@nestjs/testing'; import type { MockFunctionMetadata } from 'jest-mock'; @@ -32,6 +33,7 @@ describe('RoleService', () => { let rolesRepository: RolesRepository; let roleAssignmentsRepository: RoleAssignmentsRepository; let metaService: jest.Mocked; + let notificationService: jest.Mocked; let clock: lolex.InstalledClock; function createUser(data: Partial = {}) { @@ -71,6 +73,16 @@ describe('RoleService', () => { CacheService, IdService, GlobalEventService, + { + provide: NotificationService, + useFactory: () => ({ + createNotification: jest.fn(), + }), + }, + { + provide: NotificationService.name, + useExisting: NotificationService, + }, ], }) .useMocker((token) => { @@ -93,6 +105,9 @@ describe('RoleService', () => { roleAssignmentsRepository = app.get(DI.roleAssignmentsRepository); metaService = app.get(MetaService) as jest.Mocked; + notificationService = app.get(NotificationService) as jest.Mocked; + + await roleService.onModuleInit(); }); afterEach(async () => { @@ -273,4 +288,57 @@ describe('RoleService', () => { expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true); }); }); + + describe('assign', () => { + test('公開ロールの場合は通知される', async () => { + const user = await createUser(); + const role = await createRole({ + isPublic: true, + name: 'a', + }); + + await roleService.assign(user.id, role.id); + + clock.uninstall(); + await sleep(100); + + const assignments = await roleAssignmentsRepository.find({ + where: { + userId: user.id, + roleId: role.id, + }, + }); + expect(assignments).toHaveLength(1); + + expect(notificationService.createNotification).toHaveBeenCalled(); + expect(notificationService.createNotification.mock.lastCall![0]).toBe(user.id); + expect(notificationService.createNotification.mock.lastCall![1]).toBe('roleAssigned'); + expect(notificationService.createNotification.mock.lastCall![2]).toEqual({ + roleId: role.id, + }); + }); + + test('非公開ロールの場合は通知されない', async () => { + const user = await createUser(); + const role = await createRole({ + isPublic: false, + name: 'a', + }); + + await roleService.assign(user.id, role.id); + + clock.uninstall(); + await sleep(100); + + const assignments = await roleAssignmentsRepository.find({ + where: { + userId: user.id, + roleId: role.id, + }, + }); + expect(assignments).toHaveLength(1); + + expect(notificationService.createNotification).not.toHaveBeenCalled(); + }); + }); }); diff --git a/packages/backend/test/unit/S3Service.ts b/packages/backend/test/unit/S3Service.ts index fe2cb671e0..20aa1148f7 100644 --- a/packages/backend/test/unit/S3Service.ts +++ b/packages/backend/test/unit/S3Service.ts @@ -6,7 +6,13 @@ process.env.NODE_ENV = 'test'; import { Test } from '@nestjs/testing'; -import { UploadPartCommand, CompleteMultipartUploadCommand, CreateMultipartUploadCommand, S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; +import { + CompleteMultipartUploadCommand, + CreateMultipartUploadCommand, + PutObjectCommand, + S3Client, + UploadPartCommand, +} from '@aws-sdk/client-s3'; import { mockClient } from 'aws-sdk-client-mock'; import { GlobalModule } from '@/GlobalModule.js'; import { CoreModule } from '@/core/CoreModule.js'; diff --git a/packages/backend/test/unit/misc/id.ts b/packages/backend/test/unit/misc/id.ts index 090429ac3c..14f6751126 100644 --- a/packages/backend/test/unit/misc/id.ts +++ b/packages/backend/test/unit/misc/id.ts @@ -4,13 +4,13 @@ */ import { ulid } from 'ulid'; -import { describe, test, expect } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { aidRegExp, genAid, parseAid } from '@/misc/id/aid.js'; import { aidxRegExp, genAidx, parseAidx } from '@/misc/id/aidx.js'; import { genMeid, meidRegExp, parseMeid } from '@/misc/id/meid.js'; import { genMeidg, meidgRegExp, parseMeidg } from '@/misc/id/meidg.js'; import { genObjectId, objectIdRegExp, parseObjectId } from '@/misc/id/object-id.js'; -import { ulidRegExp, parseUlid } from '@/misc/id/ulid.js'; +import { parseUlid, ulidRegExp } from '@/misc/id/ulid.js'; describe('misc:id', () => { test('aid', () => { diff --git a/packages/backend/test/unit/misc/others.ts b/packages/backend/test/unit/misc/others.ts index 6182590233..4f5b2d587f 100644 --- a/packages/backend/test/unit/misc/others.ts +++ b/packages/backend/test/unit/misc/others.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { describe, test, expect } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { contentDisposition } from '@/misc/content-disposition.js'; describe('misc:content-disposition', () => { diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index d03f7af9eb..4692d09f06 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -5,18 +5,19 @@ import * as assert from 'node:assert'; import { readFile } from 'node:fs/promises'; -import { isAbsolute, basename } from 'node:path'; +import { basename, isAbsolute } from 'node:path'; +import { randomUUID } from 'node:crypto'; import { inspect } from 'node:util'; import WebSocket, { ClientOptions } from 'ws'; import fetch, { File, RequestInit } from 'node-fetch'; import { DataSource } from 'typeorm'; import { JSDOM } from 'jsdom'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; -import { entities } from '../src/postgres.js'; -import { loadConfig } from '../src/config.js'; +import { entities } from '@/postgres.js'; +import { loadConfig } from '@/config.js'; import type * as misskey from 'cherrypick-js'; -export { server as startServer } from '@/boot/common.js'; +export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js'; interface UserToken { token: string; @@ -25,6 +26,8 @@ interface UserToken { const config = loadConfig(); export const port = config.port; +export const origin = config.url; +export const host = new URL(config.url).host; export const cookie = (me: UserToken): string => { return `token=${me.token};`; @@ -65,7 +68,11 @@ export const failedApiCall = async (request: ApiRequest, assertion: { return res.body; }; -const request = async (path: string, params: any, me?: UserToken): Promise<{ status: number, headers: Headers, body: any }> => { +const request = async (path: string, params: any, me?: UserToken): Promise<{ + status: number, + headers: Headers, + body: any +}> => { const bodyAuth: Record = {}; const headers: Record = { 'Content-Type': 'application/json', @@ -126,6 +133,15 @@ export const post = async (user: UserToken, params?: misskey.Endpoints['notes/cr return res.body ? res.body.createdNote : null; }; +export const createAppToken = async (user: UserToken, permissions: (typeof misskey.permissions)[number][]) => { + const res = await api('miauth/gen-token', { + session: randomUUID(), + permission: permissions, + }, user); + + return (res.body as misskey.entities.MiauthGenTokenResponse).token; +}; + // 非公開ノートをAPI越しに見たときのノート NoteEntityService.ts export const hiddenNote = (note: any): any => { const temp = { @@ -263,7 +279,11 @@ interface UploadOptions { * Upload file * @param user User */ -export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{ status: number, headers: Headers, body: misskey.Endpoints['drive/files/create']['res'] | null }> => { +export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{ + status: number, + headers: Headers, + body: misskey.Endpoints['drive/files/create']['res'] | null +}> => { const absPath = path == null ? new URL('resources/Lenna.jpg', import.meta.url) : isAbsolute(path.toString()) @@ -414,8 +434,8 @@ export const simpleGet = async (path: string, accept = '*/*', cookie: any = unde ]; const body = - jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() : - htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) : + jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() : + htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) : null; return { @@ -545,3 +565,34 @@ export function sleep(msec: number) { }, msec); }); } + +export async function sendEnvUpdateRequest(params: { key: string, value?: string }) { + const res = await fetch( + `http://localhost:${port + 1000}/env`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(params), + }, + ); + + if (res.status !== 200) { + throw new Error('server env update failed.'); + } +} + +export async function sendEnvResetRequest() { + const res = await fetch( + `http://localhost:${port + 1000}/env-reset`, + { + method: 'POST', + body: JSON.stringify({}), + }, + ); + + if (res.status !== 200) { + throw new Error('server env update failed.'); + } +} diff --git a/packages/cherrypick-js/.swcrc b/packages/cherrypick-js/.swcrc index d9f047b6ac..0504a2d389 100644 --- a/packages/cherrypick-js/.swcrc +++ b/packages/cherrypick-js/.swcrc @@ -11,7 +11,7 @@ "decoratorMetadata": true }, "experimental": { - "keepImportAttributes": true + "keepImportAssertions": true }, "baseUrl": "src", "paths": { diff --git a/packages/cherrypick-js/etc/cherrypick-js.api.md b/packages/cherrypick-js/etc/cherrypick-js.api.md index 5dd8e42281..e1d67d1611 100644 --- a/packages/cherrypick-js/etc/cherrypick-js.api.md +++ b/packages/cherrypick-js/etc/cherrypick-js.api.md @@ -21,6 +21,11 @@ declare namespace acct { } export { acct } +// Warning: (ae-forgotten-export) The symbol "components" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +type Ad = components['schemas']['Ad']; + // Warning: (ae-forgotten-export) The symbol "operations" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -59,15 +64,24 @@ type AdminAccountsDeleteRequest = operations['admin/accounts/delete']['requestBo // @public (undocumented) type AdminAccountsFindByEmailRequest = operations['admin/accounts/find-by-email']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminAccountsFindByEmailResponse = operations['admin/accounts/find-by-email']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminAdCreateRequest = operations['admin/ad/create']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminAdCreateResponse = operations['admin/ad/create']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminAdDeleteRequest = operations['admin/ad/delete']['requestBody']['content']['application/json']; // @public (undocumented) type AdminAdListRequest = operations['admin/ad/list']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminAdListResponse = operations['admin/ad/list']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminAdUpdateRequest = operations['admin/ad/update']['requestBody']['content']['application/json']; @@ -146,6 +160,9 @@ type AdminEmojiDeleteBulkRequest = operations['admin/emoji/delete-bulk']['reques // @public (undocumented) type AdminEmojiDeleteRequest = operations['admin/emoji/delete']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminEmojiImportZipRequest = operations['admin/emoji/import-zip']['requestBody']['content']['application/json']; + // @public (undocumented) type AdminEmojiListRemoteRequest = operations['admin/emoji/list-remote']['requestBody']['content']['application/json']; @@ -191,12 +208,18 @@ type AdminFederationRemoveAllFollowingRequest = operations['admin/federation/rem // @public (undocumented) type AdminFederationUpdateInstanceRequest = operations['admin/federation/update-instance']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminGetIndexStatsResponse = operations['admin/get-index-stats']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminGetTableStatsResponse = operations['admin/get-table-stats']['responses']['200']['content']['application/json']; // @public (undocumented) type AdminGetUserIpsRequest = operations['admin/get-user-ips']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminGetUserIpsResponse = operations['admin/get-user-ips']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminInviteCreateRequest = operations['admin/invite/create']['requestBody']['content']['application/json']; @@ -281,6 +304,9 @@ type AdminRolesUpdateRequest = operations['admin/roles/update']['requestBody'][' // @public (undocumented) type AdminRolesUsersRequest = operations['admin/roles/users']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminRolesUsersResponse = operations['admin/roles/users']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminSendEmailRequest = operations['admin/send-email']['requestBody']['content']['application/json']; @@ -323,8 +349,6 @@ type AdminUpdateMetaRequest = operations['admin/update-meta']['requestBody']['co // @public (undocumented) type AdminUpdateUserNoteRequest = operations['admin/update-user-note']['requestBody']['content']['application/json']; -// Warning: (ae-forgotten-export) The symbol "components" needs to be exported by the entry point index.d.ts -// // @public (undocumented) type Announcement = components['schemas']['Announcement']; @@ -402,8 +426,6 @@ class APIClient { fetch: FetchLike; // (undocumented) origin: string; - // (undocumented) - request(endpoint: E, params?: P, credential?: string | null): Promise>; } // @public (undocumented) @@ -436,6 +458,9 @@ type ApShowRequest = operations['ap/show']['requestBody']['content']['applicatio // @public (undocumented) type ApShowResponse = operations['ap/show']['responses']['200']['content']['application/json']; +// @public (undocumented) +type AuthAcceptRequest = operations['auth/accept']['requestBody']['content']['application/json']; + // @public (undocumented) type AuthSessionGenerateRequest = operations['auth/session/generate']['requestBody']['content']['application/json']; @@ -1037,6 +1062,9 @@ type EmptyResponse = Record | undefined; // @public (undocumented) type EndpointRequest = operations['endpoint']['requestBody']['content']['application/json']; +// @public (undocumented) +type EndpointResponse = operations['endpoint']['responses']['200']['content']['application/json']; + // Warning: (ae-forgotten-export) The symbol "Overwrite" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Endpoints_2" needs to be exported by the entry point index.d.ts // @@ -1058,6 +1086,18 @@ export type Endpoints = Overwrite; // @public (undocumented) @@ -1077,6 +1117,12 @@ declare namespace entities { EmojiUpdated, EmojiDeleted, AnnouncementCreated, + SignupRequest, + SignupResponse, + SignupPendingRequest, + SignupPendingResponse, + SigninRequest, + SigninResponse, EmptyRequest, EmptyResponse, AdminMetaResponse, @@ -1092,9 +1138,12 @@ declare namespace entities { AdminAccountsCreateResponse, AdminAccountsDeleteRequest, AdminAccountsFindByEmailRequest, + AdminAccountsFindByEmailResponse, AdminAdCreateRequest, + AdminAdCreateResponse, AdminAdDeleteRequest, AdminAdListRequest, + AdminAdListResponse, AdminAdUpdateRequest, AdminAnnouncementsCreateRequest, AdminAnnouncementsCreateResponse, @@ -1121,6 +1170,7 @@ declare namespace entities { AdminEmojiCopyResponse, AdminEmojiDeleteBulkRequest, AdminEmojiDeleteRequest, + AdminEmojiImportZipRequest, AdminEmojiListRemoteRequest, AdminEmojiListRemoteResponse, AdminEmojiListRequest, @@ -1136,8 +1186,10 @@ declare namespace entities { AdminFederationRefreshRemoteInstanceMetadataRequest, AdminFederationRemoveAllFollowingRequest, AdminFederationUpdateInstanceRequest, + AdminGetIndexStatsResponse, AdminGetTableStatsResponse, AdminGetUserIpsRequest, + AdminGetUserIpsResponse, AdminInviteCreateRequest, AdminInviteCreateResponse, AdminInviteListRequest, @@ -1179,6 +1231,7 @@ declare namespace entities { AdminRolesUnassignRequest, AdminRolesUpdateDefaultPoliciesRequest, AdminRolesUsersRequest, + AdminRolesUsersResponse, AnnouncementsRequest, AnnouncementsResponse, AntennasCreateRequest, @@ -1199,6 +1252,7 @@ declare namespace entities { AppCreateResponse, AppShowRequest, AppShowResponse, + AuthAcceptRequest, AuthSessionGenerateRequest, AuthSessionGenerateResponse, AuthSessionShowRequest, @@ -1305,6 +1359,7 @@ declare namespace entities { EmailAddressAvailableRequest, EmailAddressAvailableResponse, EndpointRequest, + EndpointResponse, EndpointsResponse, FederationFollowersRequest, FederationFollowersResponse, @@ -1318,6 +1373,7 @@ declare namespace entities { FederationUsersRequest, FederationUsersResponse, FederationStatsRequest, + FederationStatsResponse, FollowingCreateRequest, FollowingCreateResponse, FollowingDeleteRequest, @@ -1347,6 +1403,7 @@ declare namespace entities { GalleryPostsUnlikeRequest, GalleryPostsUpdateRequest, GalleryPostsUpdateResponse, + GetOnlineUsersCountResponse, GetAvatarDecorationsResponse, HashtagsListRequest, HashtagsListResponse, @@ -1358,13 +1415,36 @@ declare namespace entities { HashtagsUsersRequest, HashtagsUsersResponse, IResponse, + I2faDoneRequest, + I2faKeyDoneRequest, + I2faKeyDoneResponse, + I2faPasswordLessRequest, + I2faRegisterKeyRequest, + I2faRegisterKeyResponse, + I2faRegisterRequest, + I2faRegisterResponse, + I2faUpdateKeyRequest, + I2faRemoveKeyRequest, + I2faUnregisterRequest, + IAppsRequest, + IAppsResponse, + IAuthorizedAppsRequest, + IAuthorizedAppsResponse, IClaimAchievementRequest, + IChangePasswordRequest, + IDeleteAccountRequest, + IExportFollowingRequest, IFavoritesRequest, IFavoritesResponse, IGalleryLikesRequest, IGalleryLikesResponse, IGalleryPostsRequest, IGalleryPostsResponse, + IImportBlockingRequest, + IImportFollowingRequest, + IImportMutingRequest, + IImportUserListsRequest, + IImportAntennasRequest, INotificationsRequest, INotificationsResponse, INotificationsGroupedRequest, @@ -1376,21 +1456,37 @@ declare namespace entities { IPinRequest, IPinResponse, IReadAnnouncementRequest, + IRegenerateTokenRequest, IRegistryGetAllRequest, + IRegistryGetAllResponse, IRegistryGetDetailRequest, + IRegistryGetDetailResponse, IRegistryGetRequest, + IRegistryGetResponse, IRegistryKeysWithTypeRequest, + IRegistryKeysWithTypeResponse, IRegistryKeysRequest, IRegistryRemoveRequest, + IRegistryScopesWithDomainResponse, IRegistrySetRequest, + IRevokeTokenRequest, + ISigninHistoryRequest, + ISigninHistoryResponse, IUnpinRequest, IUnpinResponse, + IUpdateEmailRequest, + IUpdateEmailResponse, IUpdateRequest, IUpdateResponse, IUserGroupInvitesRequest, IUserGroupInvitesResponse, + IMoveRequest, + IMoveResponse, IWebhooksCreateRequest, + IWebhooksCreateResponse, + IWebhooksListResponse, IWebhooksShowRequest, + IWebhooksShowResponse, IWebhooksUpdateRequest, IWebhooksDeleteRequest, InviteCreateResponse, @@ -1411,6 +1507,8 @@ declare namespace entities { EmojisResponse, EmojiRequest, EmojiResponse, + MiauthGenTokenRequest, + MiauthGenTokenResponse, MuteCreateRequest, MuteDeleteRequest, MuteListRequest, @@ -1476,6 +1574,7 @@ declare namespace entities { NotesUserListTimelineRequest, NotesUserListTimelineResponse, NotificationsCreateRequest, + PagePushRequest, PagesCreateRequest, PagesCreateResponse, PagesDeleteRequest, @@ -1486,8 +1585,11 @@ declare namespace entities { PagesUnlikeRequest, PagesUpdateRequest, FlashCreateRequest, + FlashCreateResponse, FlashDeleteRequest, FlashFeaturedResponse, + FlashGenTokenRequest, + FlashGenTokenResponse, FlashLikeRequest, FlashShowRequest, FlashShowResponse, @@ -1504,10 +1606,12 @@ declare namespace entities { RolesShowRequest, RolesShowResponse, RolesUsersRequest, + RolesUsersResponse, RolesNotesRequest, RolesNotesResponse, RequestResetPasswordRequest, ResetPasswordRequest, + ServerInfoResponse, StatsResponse, SwShowRegistrationRequest, SwShowRegistrationResponse, @@ -1517,6 +1621,7 @@ declare namespace entities { SwRegisterResponse, SwUnregisterRequest, TestRequest, + TestResponse, UsernameAvailableRequest, UsernameAvailableResponse, UsersRequest, @@ -1566,6 +1671,7 @@ declare namespace entities { UsersListsCreateFromPublicResponse, UsersListsUpdateMembershipRequest, UsersListsGetMembershipsRequest, + UsersListsGetMembershipsResponse, UsersNotesRequest, UsersNotesResponse, UsersPagesRequest, @@ -1588,11 +1694,14 @@ declare namespace entities { UsersStatsRequest, UsersStatsResponse, UsersAchievementsRequest, + UsersAchievementsResponse, UsersUpdateMemoRequest, UsersTranslateRequest, UsersTranslateResponse, FetchRssRequest, + FetchRssResponse, FetchExternalResourcesRequest, + FetchExternalResourcesResponse, RetentionResponse, Error_2 as Error, UserLite, @@ -1604,6 +1713,7 @@ declare namespace entities { User, UserList, UserGroup, + Ad, Announcement, App, MessagingMessage, @@ -1669,6 +1779,9 @@ type FederationShowInstanceResponse = operations['federation/show-instance']['re // @public (undocumented) type FederationStatsRequest = operations['federation/stats']['requestBody']['content']['application/json']; +// @public (undocumented) +type FederationStatsResponse = operations['federation/stats']['responses']['200']['content']['application/json']; + // @public (undocumented) type FederationUpdateRemoteUserRequest = operations['federation/update-remote-user']['requestBody']['content']['application/json']; @@ -1681,6 +1794,9 @@ type FederationUsersResponse = operations['federation/users']['responses']['200' // @public (undocumented) type FetchExternalResourcesRequest = operations['fetch-external-resources']['requestBody']['content']['application/json']; +// @public (undocumented) +type FetchExternalResourcesResponse = operations['fetch-external-resources']['responses']['200']['content']['application/json']; + // @public (undocumented) type FetchLike = (input: string, init?: { method?: string; @@ -1699,7 +1815,7 @@ type FetchLike = (input: string, init?: { type FetchRssRequest = operations['fetch-rss']['requestBody']['content']['application/json']; // @public (undocumented) -export const ffVisibility: readonly ["public", "followers", "private"]; +type FetchRssResponse = operations['fetch-rss']['responses']['200']['content']['application/json']; // @public (undocumented) type Flash = components['schemas']['Flash']; @@ -1707,12 +1823,21 @@ type Flash = components['schemas']['Flash']; // @public (undocumented) type FlashCreateRequest = operations['flash/create']['requestBody']['content']['application/json']; +// @public (undocumented) +type FlashCreateResponse = operations['flash/create']['responses']['200']['content']['application/json']; + // @public (undocumented) type FlashDeleteRequest = operations['flash/delete']['requestBody']['content']['application/json']; // @public (undocumented) type FlashFeaturedResponse = operations['flash/featured']['responses']['200']['content']['application/json']; +// @public (undocumented) +type FlashGenTokenRequest = operations['flash/gen-token']['requestBody']['content']['application/json']; + +// @public (undocumented) +type FlashGenTokenResponse = operations['flash/gen-token']['responses']['200']['content']['application/json']; + // @public (undocumented) type FlashLikeRequest = operations['flash/like']['requestBody']['content']['application/json']; @@ -1740,6 +1865,9 @@ type FlashUnlikeRequest = operations['flash/unlike']['requestBody']['content'][' // @public (undocumented) type FlashUpdateRequest = operations['flash/update']['requestBody']['content']['application/json']; +// @public (undocumented) +export const followersVisibilities: readonly ["public", "followers", "private"]; + // @public (undocumented) type Following = components['schemas']['Following']; @@ -1788,6 +1916,9 @@ type FollowingUpdateRequest = operations['following/update']['requestBody']['con // @public (undocumented) type FollowingUpdateResponse = operations['following/update']['responses']['200']['content']['application/json']; +// @public (undocumented) +export const followingVisibilities: readonly ["public", "followers", "private"]; + // @public (undocumented) type GalleryFeaturedRequest = operations['gallery/featured']['requestBody']['content']['application/json']; @@ -1836,6 +1967,9 @@ type GalleryPostsUpdateResponse = operations['gallery/posts/update']['responses' // @public (undocumented) type GetAvatarDecorationsResponse = operations['get-avatar-decorations']['responses']['200']['content']['application/json']; +// @public (undocumented) +type GetOnlineUsersCountResponse = operations['get-online-users-count']['responses']['200']['content']['application/json']; + // @public (undocumented) type Hashtag = components['schemas']['Hashtag']; @@ -1866,12 +2000,66 @@ type HashtagsUsersRequest = operations['hashtags/users']['requestBody']['content // @public (undocumented) type HashtagsUsersResponse = operations['hashtags/users']['responses']['200']['content']['application/json']; +// @public (undocumented) +type I2faDoneRequest = operations['i/2fa/done']['requestBody']['content']['application/json']; + +// @public (undocumented) +type I2faKeyDoneRequest = operations['i/2fa/key-done']['requestBody']['content']['application/json']; + +// @public (undocumented) +type I2faKeyDoneResponse = operations['i/2fa/key-done']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type I2faPasswordLessRequest = operations['i/2fa/password-less']['requestBody']['content']['application/json']; + +// @public (undocumented) +type I2faRegisterKeyRequest = operations['i/2fa/register-key']['requestBody']['content']['application/json']; + +// @public (undocumented) +type I2faRegisterKeyResponse = operations['i/2fa/register-key']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type I2faRegisterRequest = operations['i/2fa/register']['requestBody']['content']['application/json']; + +// @public (undocumented) +type I2faRegisterResponse = operations['i/2fa/register']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type I2faRemoveKeyRequest = operations['i/2fa/remove-key']['requestBody']['content']['application/json']; + +// @public (undocumented) +type I2faUnregisterRequest = operations['i/2fa/unregister']['requestBody']['content']['application/json']; + +// @public (undocumented) +type I2faUpdateKeyRequest = operations['i/2fa/update-key']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IAppsRequest = operations['i/apps']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IAppsResponse = operations['i/apps']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type IAuthorizedAppsRequest = operations['i/authorized-apps']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IAuthorizedAppsResponse = operations['i/authorized-apps']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type IChangePasswordRequest = operations['i/change-password']['requestBody']['content']['application/json']; + // @public (undocumented) type IClaimAchievementRequest = operations['i/claim-achievement']['requestBody']['content']['application/json']; // @public (undocumented) type ID = string; +// @public (undocumented) +type IDeleteAccountRequest = operations['i/delete-account']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IExportFollowingRequest = operations['i/export-following']['requestBody']['content']['application/json']; + // @public (undocumented) type IFavoritesRequest = operations['i/favorites']['requestBody']['content']['application/json']; @@ -1890,6 +2078,27 @@ type IGalleryPostsRequest = operations['i/gallery/posts']['requestBody']['conten // @public (undocumented) type IGalleryPostsResponse = operations['i/gallery/posts']['responses']['200']['content']['application/json']; +// @public (undocumented) +type IImportAntennasRequest = operations['i/import-antennas']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IImportBlockingRequest = operations['i/import-blocking']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IImportFollowingRequest = operations['i/import-following']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IImportMutingRequest = operations['i/import-muting']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IImportUserListsRequest = operations['i/import-user-lists']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IMoveRequest = operations['i/move']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IMoveResponse = operations['i/move']['responses']['200']['content']['application/json']; + // @public (undocumented) type INotificationsGroupedRequest = operations['i/notifications-grouped']['requestBody']['content']['application/json']; @@ -1941,39 +2150,72 @@ type IPinResponse = operations['i/pin']['responses']['200']['content']['applicat // @public (undocumented) type IReadAnnouncementRequest = operations['i/read-announcement']['requestBody']['content']['application/json']; +// @public (undocumented) +type IRegenerateTokenRequest = operations['i/regenerate-token']['requestBody']['content']['application/json']; + // @public (undocumented) type IRegistryGetAllRequest = operations['i/registry/get-all']['requestBody']['content']['application/json']; +// @public (undocumented) +type IRegistryGetAllResponse = operations['i/registry/get-all']['responses']['200']['content']['application/json']; + // @public (undocumented) type IRegistryGetDetailRequest = operations['i/registry/get-detail']['requestBody']['content']['application/json']; +// @public (undocumented) +type IRegistryGetDetailResponse = operations['i/registry/get-detail']['responses']['200']['content']['application/json']; + // @public (undocumented) type IRegistryGetRequest = operations['i/registry/get']['requestBody']['content']['application/json']; +// @public (undocumented) +type IRegistryGetResponse = operations['i/registry/get']['responses']['200']['content']['application/json']; + // @public (undocumented) type IRegistryKeysRequest = operations['i/registry/keys']['requestBody']['content']['application/json']; // @public (undocumented) type IRegistryKeysWithTypeRequest = operations['i/registry/keys-with-type']['requestBody']['content']['application/json']; +// @public (undocumented) +type IRegistryKeysWithTypeResponse = operations['i/registry/keys-with-type']['responses']['200']['content']['application/json']; + // @public (undocumented) type IRegistryRemoveRequest = operations['i/registry/remove']['requestBody']['content']['application/json']; +// @public (undocumented) +type IRegistryScopesWithDomainResponse = operations['i/registry/scopes-with-domain']['responses']['200']['content']['application/json']; + // @public (undocumented) type IRegistrySetRequest = operations['i/registry/set']['requestBody']['content']['application/json']; // @public (undocumented) type IResponse = operations['i']['responses']['200']['content']['application/json']; +// @public (undocumented) +type IRevokeTokenRequest = operations['i/revoke-token']['requestBody']['content']['application/json']; + // @public (undocumented) function isAPIError(reason: any): reason is APIError; +// @public (undocumented) +type ISigninHistoryRequest = operations['i/signin-history']['requestBody']['content']['application/json']; + +// @public (undocumented) +type ISigninHistoryResponse = operations['i/signin-history']['responses']['200']['content']['application/json']; + // @public (undocumented) type IUnpinRequest = operations['i/unpin']['requestBody']['content']['application/json']; // @public (undocumented) type IUnpinResponse = operations['i/unpin']['responses']['200']['content']['application/json']; +// @public (undocumented) +type IUpdateEmailRequest = operations['i/update-email']['requestBody']['content']['application/json']; + +// @public (undocumented) +type IUpdateEmailResponse = operations['i/update-email']['responses']['200']['content']['application/json']; + // @public (undocumented) type IUpdateRequest = operations['i/update']['requestBody']['content']['application/json']; @@ -1989,12 +2231,21 @@ type IUserGroupInvitesResponse = operations['i/user-group-invites']['responses'] // @public (undocumented) type IWebhooksCreateRequest = operations['i/webhooks/create']['requestBody']['content']['application/json']; +// @public (undocumented) +type IWebhooksCreateResponse = operations['i/webhooks/create']['responses']['200']['content']['application/json']; + // @public (undocumented) type IWebhooksDeleteRequest = operations['i/webhooks/delete']['requestBody']['content']['application/json']; +// @public (undocumented) +type IWebhooksListResponse = operations['i/webhooks/list']['responses']['200']['content']['application/json']; + // @public (undocumented) type IWebhooksShowRequest = operations['i/webhooks/show']['requestBody']['content']['application/json']; +// @public (undocumented) +type IWebhooksShowResponse = operations['i/webhooks/show']['responses']['200']['content']['application/json']; + // @public (undocumented) type IWebhooksUpdateRequest = operations['i/webhooks/update']['requestBody']['content']['application/json']; @@ -2037,6 +2288,12 @@ type MetaRequest = operations['meta']['requestBody']['content']['application/jso // @public (undocumented) type MetaResponse = operations['meta']['responses']['200']['content']['application/json']; +// @public (undocumented) +type MiauthGenTokenRequest = operations['miauth/gen-token']['requestBody']['content']['application/json']; + +// @public (undocumented) +type MiauthGenTokenResponse = operations['miauth/gen-token']['responses']['200']['content']['application/json']; + // @public (undocumented) type ModerationLog = { id: ID; @@ -2364,7 +2621,7 @@ type Notification_2 = components['schemas']['Notification']; type NotificationsCreateRequest = operations['notifications/create']['requestBody']['content']['application/json']; // @public (undocumented) -export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "achievementEarned"]; +export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "achievementEarned"]; // @public (undocumented) type Page = components['schemas']['Page']; @@ -2378,6 +2635,9 @@ type PageEvent = { user: User; }; +// @public (undocumented) +type PagePushRequest = operations['page-push']['requestBody']['content']['application/json']; + // @public (undocumented) type PagesCreateRequest = operations['pages/create']['requestBody']['content']['application/json']; @@ -2409,7 +2669,7 @@ type PagesUpdateRequest = operations['pages/update']['requestBody']['content'][' function parse(acct: string): Acct; // @public (undocumented) -export const permissions: string[]; +export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "read:admin:show-users", "write:admin:suspend-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse"]; // @public (undocumented) type PingResponse = operations['ping']['responses']['200']['content']['application/json']; @@ -2440,7 +2700,7 @@ type QueueStats = { }; // @public (undocumented) -type QueueStatsLog = string[]; +type QueueStatsLog = QueueStats[]; // @public (undocumented) type RenoteMuteCreateRequest = operations['renote-mute/create']['requestBody']['content']['application/json']; @@ -2490,6 +2750,12 @@ type RolesShowResponse = operations['roles/show']['responses']['200']['content'] // @public (undocumented) type RolesUsersRequest = operations['roles/users']['requestBody']['content']['application/json']; +// @public (undocumented) +type RolesUsersResponse = operations['roles/users']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type ServerInfoResponse = operations['server-info']['responses']['200']['content']['application/json']; + // @public (undocumented) type ServerStats = { cpu: number; @@ -2508,11 +2774,52 @@ type ServerStats = { }; // @public (undocumented) -type ServerStatsLog = string[]; +type ServerStatsLog = ServerStats[]; // @public (undocumented) type Signin = components['schemas']['Signin']; +// @public (undocumented) +type SigninRequest = { + username: string; + password: string; + token?: string; +}; + +// @public (undocumented) +type SigninResponse = { + id: User['id']; + i: string; +}; + +// @public (undocumented) +type SignupPendingRequest = { + code: string; +}; + +// @public (undocumented) +type SignupPendingResponse = { + id: User['id']; + i: string; +}; + +// @public (undocumented) +type SignupRequest = { + username: string; + password: string; + host?: string; + invitationCode?: string; + emailAddress?: string; + 'hcaptcha-response'?: string | null; + 'g-recaptcha-response'?: string | null; + 'turnstile-response'?: string | null; +}; + +// @public (undocumented) +type SignupResponse = MeDetailed & { + token: string; +}; + // @public (undocumented) type StatsResponse = operations['stats']['responses']['200']['content']['application/json']; @@ -2586,6 +2893,9 @@ type SwUpdateRegistrationResponse = operations['sw/update-registration']['respon // @public (undocumented) type TestRequest = operations['test']['requestBody']['content']['application/json']; +// @public (undocumented) +type TestResponse = operations['test']['responses']['200']['content']['application/json']; + // @public (undocumented) function toString_2(acct: Acct): string; @@ -2619,6 +2929,9 @@ type UsernameAvailableResponse = operations['username/available']['responses'][' // @public (undocumented) type UsersAchievementsRequest = operations['users/achievements']['requestBody']['content']['application/json']; +// @public (undocumented) +type UsersAchievementsResponse = operations['users/achievements']['responses']['200']['content']['application/json']; + // @public (undocumented) type UsersClipsRequest = operations['users/clips']['requestBody']['content']['application/json']; @@ -2730,6 +3043,9 @@ type UsersListsFavoriteRequest = operations['users/lists/favorite']['requestBody // @public (undocumented) type UsersListsGetMembershipsRequest = operations['users/lists/get-memberships']['requestBody']['content']['application/json']; +// @public (undocumented) +type UsersListsGetMembershipsResponse = operations['users/lists/get-memberships']['responses']['200']['content']['application/json']; + // @public (undocumented) type UsersListsListRequest = operations['users/lists/list']['requestBody']['content']['application/json']; diff --git a/packages/cherrypick-js/generator/package.json b/packages/cherrypick-js/generator/package.json index c7a62d389c..bda56d0913 100644 --- a/packages/cherrypick-js/generator/package.json +++ b/packages/cherrypick-js/generator/package.json @@ -8,15 +8,16 @@ }, "devDependencies": { "@apidevtools/swagger-parser": "10.1.0", + "@misskey-dev/eslint-plugin": "^1.0.0", "@types/node": "20.9.1", "@typescript-eslint/eslint-plugin": "6.11.0", "@typescript-eslint/parser": "6.11.0", "eslint": "8.53.0", - "typescript": "5.3.2", - "tsx": "4.4.0", - "ts-case-convert": "2.0.2", "openapi-types": "12.1.3", - "openapi-typescript": "6.7.1" + "openapi-typescript": "6.7.1", + "ts-case-convert": "2.0.2", + "tsx": "4.4.0", + "typescript": "5.3.3" }, "files": [ "built" diff --git a/packages/cherrypick-js/generator/src/generator.ts b/packages/cherrypick-js/generator/src/generator.ts index 630c1e7e31..34c26f574b 100644 --- a/packages/cherrypick-js/generator/src/generator.ts +++ b/packages/cherrypick-js/generator/src/generator.ts @@ -160,6 +160,68 @@ async function generateEndpoints( await writeFile(endpointOutputPath, endpointOutputLine.join('\n')); } +async function generateApiClientJSDoc( + openApiDocs: OpenAPIV3.Document, + apiClientFileName: string, + endpointsFileName: string, + warningsOutputPath: string, +) { + const endpoints: { operationId: string; description: string; }[] = []; + + // cherrypick-jsはPOST固定で送っているので、こちらも決め打ちする。別メソッドに対応することがあればこちらも直す必要あり + const paths = openApiDocs.paths; + const postPathItems = Object.keys(paths) + .map(it => paths[it]?.post) + .filter(filterUndefined); + + for (const operation of postPathItems) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const operationId = operation.operationId!; + + if (operation.description) { + endpoints.push({ + operationId: operationId, + description: operation.description, + }); + } + } + + const endpointOutputLine: string[] = []; + + endpointOutputLine.push(generateVersionHeaderComment(openApiDocs)); + endpointOutputLine.push(''); + + endpointOutputLine.push(`import type { SwitchCaseResponseType } from '${toImportPath(apiClientFileName)}';`); + endpointOutputLine.push(`import type { Endpoints } from '${toImportPath(endpointsFileName)}';`); + endpointOutputLine.push(''); + + endpointOutputLine.push(`declare module '${toImportPath(apiClientFileName)}' {`); + endpointOutputLine.push(' export interface APIClient {'); + for (let i = 0; i < endpoints.length; i++) { + const endpoint = endpoints[i]; + + endpointOutputLine.push( + ' /**', + ` * ${endpoint.description.split('\n').join('\n * ')}`, + ' */', + ` request(`, + ' endpoint: E,', + ' params: P,', + ' credential?: string | null,', + ' ): Promise>;', + ); + + if (i < endpoints.length - 1) { + endpointOutputLine.push('\n'); + } + } + endpointOutputLine.push(' }'); + endpointOutputLine.push('}'); + endpointOutputLine.push(''); + + await writeFile(warningsOutputPath, endpointOutputLine.join('\n')); +} + function isRequestBodyObject(value: unknown): value is OpenAPIV3.RequestBodyObject { if (!value) { return false; @@ -280,6 +342,9 @@ async function main() { const entitiesFileName = `${generatePath}/entities.ts`; const endpointFileName = `${generatePath}/endpoint.ts`; await generateEndpoints(openApiDocs, typeFileName, entitiesFileName, endpointFileName); + + const apiClientWarningFileName = `${generatePath}/apiClientJSDoc.ts`; + await generateApiClientJSDoc(openApiDocs, '../api.ts', endpointFileName, apiClientWarningFileName); } main(); diff --git a/packages/cherrypick-js/package.json b/packages/cherrypick-js/package.json index d4690151ee..58ab00e0f3 100644 --- a/packages/cherrypick-js/package.json +++ b/packages/cherrypick-js/package.json @@ -6,6 +6,7 @@ "types": "./built/index.d.ts", "scripts": { "build": "tsc", + "watch": "nodemon -w src -e ts,js,cjs,mjs,json --exec \"pnpm run build\"", "tsd": "tsd", "api": "pnpm api-extractor run --local --verbose", "api-prod": "pnpm api-extractor run --verbose", @@ -21,20 +22,22 @@ "url": "git+https://github.com/misskey-dev/misskey.js.git" }, "devDependencies": { - "@microsoft/api-extractor": "7.38.3", + "@microsoft/api-extractor": "7.38.5", + "@misskey-dev/eslint-plugin": "^1.0.0", "@swc/jest": "0.2.29", - "@types/jest": "29.5.10", - "@types/node": "20.10.3", - "@typescript-eslint/eslint-plugin": "6.13.1", - "@typescript-eslint/parser": "6.13.1", - "eslint": "8.55.0", + "@types/jest": "29.5.11", + "@types/node": "20.10.5", + "@typescript-eslint/eslint-plugin": "6.14.0", + "@typescript-eslint/parser": "6.14.0", + "eslint": "8.56.0", "jest": "29.7.0", "jest-fetch-mock": "3.0.3", "jest-websocket-mock": "2.5.0", "mock-socket": "9.3.1", - "tsd": "0.29.0", - "typescript": "5.3.2", - "ncp": "2.0.0" + "ncp": "2.0.0", + "nodemon": "3.0.2", + "tsd": "0.30.0", + "typescript": "5.3.3" }, "files": [ "built" diff --git a/packages/cherrypick-js/src/api.ts b/packages/cherrypick-js/src/api.ts index c2fa4f1790..0d10faaada 100644 --- a/packages/cherrypick-js/src/api.ts +++ b/packages/cherrypick-js/src/api.ts @@ -1,3 +1,5 @@ +import './autogen/apiClientJSDoc'; + import { SwitchCaseResponseType } from './api.types'; import type { Endpoints } from './api.types'; diff --git a/packages/cherrypick-js/src/api.types.ts b/packages/cherrypick-js/src/api.types.ts index d97646b7cc..75ab7d91b1 100644 --- a/packages/cherrypick-js/src/api.types.ts +++ b/packages/cherrypick-js/src/api.types.ts @@ -1,6 +1,14 @@ import { Endpoints as Gen } from './autogen/endpoint'; import { UserDetailed } from './autogen/models'; import { UsersShowRequest } from './autogen/entities'; +import { + SigninRequest, + SigninResponse, + SignupPendingRequest, + SignupPendingResponse, + SignupRequest, + SignupResponse, +} from './entities'; type Overwrite = Omit< T, @@ -55,6 +63,21 @@ export type Endpoints = Overwrite< $default: UserDetailed; }; }; - } + }, + // api.jsonには載せないものなのでここで定義 + 'signup': { + req: SignupRequest; + res: SignupResponse; + }, + // api.jsonには載せないものなのでここで定義 + 'signup-pending': { + req: SignupPendingRequest; + res: SignupPendingResponse; + }, + // api.jsonには載せないものなのでここで定義 + 'signin': { + req: SigninRequest; + res: SigninResponse; + }, } > diff --git a/packages/cherrypick-js/src/autogen/apiClientJSDoc.ts b/packages/cherrypick-js/src/autogen/apiClientJSDoc.ts new file mode 100644 index 0000000000..6d589febbf --- /dev/null +++ b/packages/cherrypick-js/src/autogen/apiClientJSDoc.ts @@ -0,0 +1,4332 @@ +/* + * version: 4.6.0 + * basedMisskeyVersion: 2023.12.2 + * generatedAt: 2024-01-10T07:26:44.256Z + */ + +import type { SwitchCaseResponseType } from '../api.js'; +import type { Endpoints } from './endpoint.js'; + +declare module '../api.js' { + export interface APIClient { + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:meta* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-user-reports* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:ad* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:announcements* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:avatar-decorations* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:delete-all-files-of-a-user* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-avatar* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-banner* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:index-stats* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:table-stats* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:user-ips* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:invite-codes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:promo* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:queue* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:queue* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:queue* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:queue* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:relays* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:relays* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:relays* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:reset-password* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:send-email* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:server-info* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:show-moderation-log* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:show-user* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:show-users* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:suspend-user* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:unsuspend-user* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:meta* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:delete-account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:user-note* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* / **Permission**: *read:admin:roles* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:federation* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:blocks* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:blocks* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:blocks* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:channels* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:clip-favorite* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:clip-favorite* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:clip-favorite* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Find the notes to which the given file is attached. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Check if a given file exists. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Upload a new drive file. + * + * **Credential required**: *Yes* / **Permission**: *write:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Delete an existing drive file. + * + * **Credential required**: *Yes* / **Permission**: *write:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Search for a drive file by a hash of the contents. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Search for a drive file by the given parameters. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show the properties of a drive file. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Update the properties of a drive file. + * + * **Credential required**: *Yes* / **Permission**: *write:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Request the server to download a new drive file from the specified URL. + * + * **Credential required**: *Yes* / **Permission**: *write:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:following* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:gallery* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:gallery* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:gallery-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:gallery-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:gallery* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:favorites* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:gallery-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:gallery* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:notifications* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:notifications* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:page-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:pages* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:invite-codes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:invite-codes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:invite-codes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:invite-codes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:messaging* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:messaging* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:messaging* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:messaging* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:messaging* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:mutes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:mutes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:mutes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:mutes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:mutes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:mutes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:notes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:notes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:notes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:favorites* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:favorites* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:votes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:reactions* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:reactions* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:notes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:notifications* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:notifications* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:notifications* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:pages* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:pages* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:page-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:page-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:pages* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:flash* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:flash* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:flash-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:flash-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:flash* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:flash* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:flash-likes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Request a users password to be reset. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Only available when running with NODE_ENV=testing. Reset the database and flush Redis. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Complete the password reset that was previously requested. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Check push notification registration exists. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Update push notification registration. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Register to receive push notifications. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Unregister from receiving push notifications. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Endpoint for testing input validation. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show all clips this user owns. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show everyone that follows this user. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show everyone that this user is following. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show all gallery posts by the given user. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Get a list of other users that the specified user frequently replies to. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Create a new group. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Delete an existing group. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Invite a user to an existing group. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * List the groups that the authenticated user is a member of. + * + * **Credential required**: *Yes* / **Permission**: *read:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Leave a group. The owner of a group can not leave. They must transfer ownership or delete the group instead. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * List the groups that the authenticated user is the owner of. + * + * **Credential required**: *Yes* / **Permission**: *read:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Removes a specified user from a group. The owner can not be removed. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show the properties of a group. + * + * **Credential required**: *Yes* / **Permission**: *read:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Transfer ownership of a group from the authenticated user to another user. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Update the properties of a group. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Create a new list of users. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Delete an existing list of users. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show all lists that the authenticated user has created. + * + * **Credential required**: *No* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Remove a user from a list. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Add a user to an existing list. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show the properties of a list. + * + * **Credential required**: *No* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Update the properties of a list. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show all pages this user created. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show all flashs this user created. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show all reactions this user made. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show users that the authenticated user might be interested to follow. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show the different kinds of relations between the authenticated user and the specified user(s). + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * File a report. + * + * **Credential required**: *Yes* / **Permission**: *write:report-abuse* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Search for a user by username and/or host. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Search for users. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show the properties of a user. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * Show statistics about a user. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *No* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + } +} diff --git a/packages/cherrypick-js/src/autogen/endpoint.ts b/packages/cherrypick-js/src/autogen/endpoint.ts index 45add32c9a..3f1d6e1429 100644 --- a/packages/cherrypick-js/src/autogen/endpoint.ts +++ b/packages/cherrypick-js/src/autogen/endpoint.ts @@ -1,7 +1,7 @@ /* - * version: 4.6.0-beta.2 - * basedMisskeyVersion: 2023.12.0-beta.2 - * generatedAt: 2023-12-06T10:16:11.711Z + * version: 4.6.0 + * basedMisskeyVersion: 2023.12.2 + * generatedAt: 2024-01-10T07:26:44.254Z */ import type { @@ -20,9 +20,12 @@ import type { AdminAccountsCreateResponse, AdminAccountsDeleteRequest, AdminAccountsFindByEmailRequest, + AdminAccountsFindByEmailResponse, AdminAdCreateRequest, + AdminAdCreateResponse, AdminAdDeleteRequest, AdminAdListRequest, + AdminAdListResponse, AdminAdUpdateRequest, AdminAnnouncementsCreateRequest, AdminAnnouncementsCreateResponse, @@ -49,6 +52,7 @@ import type { AdminEmojiCopyResponse, AdminEmojiDeleteBulkRequest, AdminEmojiDeleteRequest, + AdminEmojiImportZipRequest, AdminEmojiListRemoteRequest, AdminEmojiListRemoteResponse, AdminEmojiListRequest, @@ -64,8 +68,10 @@ import type { AdminFederationRefreshRemoteInstanceMetadataRequest, AdminFederationRemoveAllFollowingRequest, AdminFederationUpdateInstanceRequest, + AdminGetIndexStatsResponse, AdminGetTableStatsResponse, AdminGetUserIpsRequest, + AdminGetUserIpsResponse, AdminInviteCreateRequest, AdminInviteCreateResponse, AdminInviteListRequest, @@ -107,6 +113,7 @@ import type { AdminRolesUnassignRequest, AdminRolesUpdateDefaultPoliciesRequest, AdminRolesUsersRequest, + AdminRolesUsersResponse, AnnouncementsRequest, AnnouncementsResponse, AntennasCreateRequest, @@ -127,6 +134,7 @@ import type { AppCreateResponse, AppShowRequest, AppShowResponse, + AuthAcceptRequest, AuthSessionGenerateRequest, AuthSessionGenerateResponse, AuthSessionShowRequest, @@ -233,6 +241,7 @@ import type { EmailAddressAvailableRequest, EmailAddressAvailableResponse, EndpointRequest, + EndpointResponse, EndpointsResponse, FederationFollowersRequest, FederationFollowersResponse, @@ -246,6 +255,7 @@ import type { FederationUsersRequest, FederationUsersResponse, FederationStatsRequest, + FederationStatsResponse, FollowingCreateRequest, FollowingCreateResponse, FollowingDeleteRequest, @@ -275,6 +285,7 @@ import type { GalleryPostsUnlikeRequest, GalleryPostsUpdateRequest, GalleryPostsUpdateResponse, + GetOnlineUsersCountResponse, GetAvatarDecorationsResponse, HashtagsListRequest, HashtagsListResponse, @@ -286,13 +297,36 @@ import type { HashtagsUsersRequest, HashtagsUsersResponse, IResponse, + I2faDoneRequest, + I2faKeyDoneRequest, + I2faKeyDoneResponse, + I2faPasswordLessRequest, + I2faRegisterKeyRequest, + I2faRegisterKeyResponse, + I2faRegisterRequest, + I2faRegisterResponse, + I2faUpdateKeyRequest, + I2faRemoveKeyRequest, + I2faUnregisterRequest, + IAppsRequest, + IAppsResponse, + IAuthorizedAppsRequest, + IAuthorizedAppsResponse, IClaimAchievementRequest, + IChangePasswordRequest, + IDeleteAccountRequest, + IExportFollowingRequest, IFavoritesRequest, IFavoritesResponse, IGalleryLikesRequest, IGalleryLikesResponse, IGalleryPostsRequest, IGalleryPostsResponse, + IImportBlockingRequest, + IImportFollowingRequest, + IImportMutingRequest, + IImportUserListsRequest, + IImportAntennasRequest, INotificationsRequest, INotificationsResponse, INotificationsGroupedRequest, @@ -304,21 +338,37 @@ import type { IPinRequest, IPinResponse, IReadAnnouncementRequest, + IRegenerateTokenRequest, IRegistryGetAllRequest, + IRegistryGetAllResponse, IRegistryGetDetailRequest, + IRegistryGetDetailResponse, IRegistryGetRequest, + IRegistryGetResponse, IRegistryKeysWithTypeRequest, + IRegistryKeysWithTypeResponse, IRegistryKeysRequest, IRegistryRemoveRequest, + IRegistryScopesWithDomainResponse, IRegistrySetRequest, + IRevokeTokenRequest, + ISigninHistoryRequest, + ISigninHistoryResponse, IUnpinRequest, IUnpinResponse, + IUpdateEmailRequest, + IUpdateEmailResponse, IUpdateRequest, IUpdateResponse, IUserGroupInvitesRequest, IUserGroupInvitesResponse, + IMoveRequest, + IMoveResponse, IWebhooksCreateRequest, + IWebhooksCreateResponse, + IWebhooksListResponse, IWebhooksShowRequest, + IWebhooksShowResponse, IWebhooksUpdateRequest, IWebhooksDeleteRequest, InviteCreateResponse, @@ -339,6 +389,8 @@ import type { EmojisResponse, EmojiRequest, EmojiResponse, + MiauthGenTokenRequest, + MiauthGenTokenResponse, MuteCreateRequest, MuteDeleteRequest, MuteListRequest, @@ -404,6 +456,7 @@ import type { NotesUserListTimelineRequest, NotesUserListTimelineResponse, NotificationsCreateRequest, + PagePushRequest, PagesCreateRequest, PagesCreateResponse, PagesDeleteRequest, @@ -414,8 +467,11 @@ import type { PagesUnlikeRequest, PagesUpdateRequest, FlashCreateRequest, + FlashCreateResponse, FlashDeleteRequest, FlashFeaturedResponse, + FlashGenTokenRequest, + FlashGenTokenResponse, FlashLikeRequest, FlashShowRequest, FlashShowResponse, @@ -432,10 +488,12 @@ import type { RolesShowRequest, RolesShowResponse, RolesUsersRequest, + RolesUsersResponse, RolesNotesRequest, RolesNotesResponse, RequestResetPasswordRequest, ResetPasswordRequest, + ServerInfoResponse, StatsResponse, SwShowRegistrationRequest, SwShowRegistrationResponse, @@ -445,6 +503,7 @@ import type { SwRegisterResponse, SwUnregisterRequest, TestRequest, + TestResponse, UsernameAvailableRequest, UsernameAvailableResponse, UsersRequest, @@ -494,6 +553,7 @@ import type { UsersListsCreateFromPublicResponse, UsersListsUpdateMembershipRequest, UsersListsGetMembershipsRequest, + UsersListsGetMembershipsResponse, UsersNotesRequest, UsersNotesResponse, UsersPagesRequest, @@ -516,11 +576,14 @@ import type { UsersStatsRequest, UsersStatsResponse, UsersAchievementsRequest, + UsersAchievementsResponse, UsersUpdateMemoRequest, UsersTranslateRequest, UsersTranslateResponse, FetchRssRequest, + FetchRssResponse, FetchExternalResourcesRequest, + FetchExternalResourcesResponse, RetentionResponse, } from './entities.js'; @@ -533,10 +596,10 @@ export type Endpoints = { 'admin/abuse-user-reports': { req: AdminAbuseUserReportsRequest; res: AdminAbuseUserReportsResponse }; 'admin/accounts/create': { req: AdminAccountsCreateRequest; res: AdminAccountsCreateResponse }; 'admin/accounts/delete': { req: AdminAccountsDeleteRequest; res: EmptyResponse }; - 'admin/accounts/find-by-email': { req: AdminAccountsFindByEmailRequest; res: EmptyResponse }; - 'admin/ad/create': { req: AdminAdCreateRequest; res: EmptyResponse }; + 'admin/accounts/find-by-email': { req: AdminAccountsFindByEmailRequest; res: AdminAccountsFindByEmailResponse }; + 'admin/ad/create': { req: AdminAdCreateRequest; res: AdminAdCreateResponse }; 'admin/ad/delete': { req: AdminAdDeleteRequest; res: EmptyResponse }; - 'admin/ad/list': { req: AdminAdListRequest; res: EmptyResponse }; + 'admin/ad/list': { req: AdminAdListRequest; res: AdminAdListResponse }; 'admin/ad/update': { req: AdminAdUpdateRequest; res: EmptyResponse }; 'admin/announcements/create': { req: AdminAnnouncementsCreateRequest; res: AdminAnnouncementsCreateResponse }; 'admin/announcements/delete': { req: AdminAnnouncementsDeleteRequest; res: EmptyResponse }; @@ -559,6 +622,7 @@ export type Endpoints = { 'admin/emoji/copy': { req: AdminEmojiCopyRequest; res: AdminEmojiCopyResponse }; 'admin/emoji/delete-bulk': { req: AdminEmojiDeleteBulkRequest; res: EmptyResponse }; 'admin/emoji/delete': { req: AdminEmojiDeleteRequest; res: EmptyResponse }; + 'admin/emoji/import-zip': { req: AdminEmojiImportZipRequest; res: EmptyResponse }; 'admin/emoji/list-remote': { req: AdminEmojiListRemoteRequest; res: AdminEmojiListRemoteResponse }; 'admin/emoji/list': { req: AdminEmojiListRequest; res: AdminEmojiListResponse }; 'admin/emoji/remove-aliases-bulk': { req: AdminEmojiRemoveAliasesBulkRequest; res: EmptyResponse }; @@ -571,9 +635,9 @@ export type Endpoints = { 'admin/federation/refresh-remote-instance-metadata': { req: AdminFederationRefreshRemoteInstanceMetadataRequest; res: EmptyResponse }; 'admin/federation/remove-all-following': { req: AdminFederationRemoveAllFollowingRequest; res: EmptyResponse }; 'admin/federation/update-instance': { req: AdminFederationUpdateInstanceRequest; res: EmptyResponse }; - 'admin/get-index-stats': { req: EmptyRequest; res: EmptyResponse }; + 'admin/get-index-stats': { req: EmptyRequest; res: AdminGetIndexStatsResponse }; 'admin/get-table-stats': { req: EmptyRequest; res: AdminGetTableStatsResponse }; - 'admin/get-user-ips': { req: AdminGetUserIpsRequest; res: EmptyResponse }; + 'admin/get-user-ips': { req: AdminGetUserIpsRequest; res: AdminGetUserIpsResponse }; 'admin/invite/create': { req: AdminInviteCreateRequest; res: AdminInviteCreateResponse }; 'admin/invite/list': { req: AdminInviteListRequest; res: AdminInviteListResponse }; 'admin/invite/revoke': { req: EmptyRequest; res: EmptyResponse }; @@ -606,7 +670,7 @@ export type Endpoints = { 'admin/roles/assign': { req: AdminRolesAssignRequest; res: EmptyResponse }; 'admin/roles/unassign': { req: AdminRolesUnassignRequest; res: EmptyResponse }; 'admin/roles/update-default-policies': { req: AdminRolesUpdateDefaultPoliciesRequest; res: EmptyResponse }; - 'admin/roles/users': { req: AdminRolesUsersRequest; res: EmptyResponse }; + 'admin/roles/users': { req: AdminRolesUsersRequest; res: AdminRolesUsersResponse }; 'announcements': { req: AnnouncementsRequest; res: AnnouncementsResponse }; 'antennas/create': { req: AntennasCreateRequest; res: AntennasCreateResponse }; 'antennas/delete': { req: AntennasDeleteRequest; res: EmptyResponse }; @@ -618,6 +682,7 @@ export type Endpoints = { 'ap/show': { req: ApShowRequest; res: ApShowResponse }; 'app/create': { req: AppCreateRequest; res: AppCreateResponse }; 'app/show': { req: AppShowRequest; res: AppShowResponse }; + 'auth/accept': { req: AuthAcceptRequest; res: EmptyResponse }; 'auth/session/generate': { req: AuthSessionGenerateRequest; res: AuthSessionGenerateResponse }; 'auth/session/show': { req: AuthSessionShowRequest; res: AuthSessionShowResponse }; 'auth/session/userkey': { req: AuthSessionUserkeyRequest; res: AuthSessionUserkeyResponse }; @@ -679,15 +744,16 @@ export type Endpoints = { 'drive/folders/update': { req: DriveFoldersUpdateRequest; res: DriveFoldersUpdateResponse }; 'drive/stream': { req: DriveStreamRequest; res: DriveStreamResponse }; 'email-address/available': { req: EmailAddressAvailableRequest; res: EmailAddressAvailableResponse }; - 'endpoint': { req: EndpointRequest; res: EmptyResponse }; + 'endpoint': { req: EndpointRequest; res: EndpointResponse }; 'endpoints': { req: EmptyRequest; res: EndpointsResponse }; + 'export-custom-emojis': { req: EmptyRequest; res: EmptyResponse }; 'federation/followers': { req: FederationFollowersRequest; res: FederationFollowersResponse }; 'federation/following': { req: FederationFollowingRequest; res: FederationFollowingResponse }; 'federation/instances': { req: FederationInstancesRequest; res: FederationInstancesResponse }; 'federation/show-instance': { req: FederationShowInstanceRequest; res: FederationShowInstanceResponse }; 'federation/update-remote-user': { req: FederationUpdateRemoteUserRequest; res: EmptyResponse }; 'federation/users': { req: FederationUsersRequest; res: FederationUsersResponse }; - 'federation/stats': { req: FederationStatsRequest; res: EmptyResponse }; + 'federation/stats': { req: FederationStatsRequest; res: FederationStatsResponse }; 'following/create': { req: FollowingCreateRequest; res: FollowingCreateResponse }; 'following/delete': { req: FollowingDeleteRequest; res: FollowingDeleteResponse }; 'following/update': { req: FollowingUpdateRequest; res: FollowingUpdateResponse }; @@ -706,7 +772,7 @@ export type Endpoints = { 'gallery/posts/show': { req: GalleryPostsShowRequest; res: GalleryPostsShowResponse }; 'gallery/posts/unlike': { req: GalleryPostsUnlikeRequest; res: EmptyResponse }; 'gallery/posts/update': { req: GalleryPostsUpdateRequest; res: GalleryPostsUpdateResponse }; - 'get-online-users-count': { req: EmptyRequest; res: EmptyResponse }; + 'get-online-users-count': { req: EmptyRequest; res: GetOnlineUsersCountResponse }; 'get-avatar-decorations': { req: EmptyRequest; res: GetAvatarDecorationsResponse }; 'hashtags/list': { req: HashtagsListRequest; res: HashtagsListResponse }; 'hashtags/search': { req: HashtagsSearchRequest; res: HashtagsSearchResponse }; @@ -714,10 +780,35 @@ export type Endpoints = { 'hashtags/trend': { req: EmptyRequest; res: HashtagsTrendResponse }; 'hashtags/users': { req: HashtagsUsersRequest; res: HashtagsUsersResponse }; 'i': { req: EmptyRequest; res: IResponse }; + 'i/2fa/done': { req: I2faDoneRequest; res: EmptyResponse }; + 'i/2fa/key-done': { req: I2faKeyDoneRequest; res: I2faKeyDoneResponse }; + 'i/2fa/password-less': { req: I2faPasswordLessRequest; res: EmptyResponse }; + 'i/2fa/register-key': { req: I2faRegisterKeyRequest; res: I2faRegisterKeyResponse }; + 'i/2fa/register': { req: I2faRegisterRequest; res: I2faRegisterResponse }; + 'i/2fa/update-key': { req: I2faUpdateKeyRequest; res: EmptyResponse }; + 'i/2fa/remove-key': { req: I2faRemoveKeyRequest; res: EmptyResponse }; + 'i/2fa/unregister': { req: I2faUnregisterRequest; res: EmptyResponse }; + 'i/apps': { req: IAppsRequest; res: IAppsResponse }; + 'i/authorized-apps': { req: IAuthorizedAppsRequest; res: IAuthorizedAppsResponse }; 'i/claim-achievement': { req: IClaimAchievementRequest; res: EmptyResponse }; + 'i/change-password': { req: IChangePasswordRequest; res: EmptyResponse }; + 'i/delete-account': { req: IDeleteAccountRequest; res: EmptyResponse }; + 'i/export-blocking': { req: EmptyRequest; res: EmptyResponse }; + 'i/export-following': { req: IExportFollowingRequest; res: EmptyResponse }; + 'i/export-mute': { req: EmptyRequest; res: EmptyResponse }; + 'i/export-notes': { req: EmptyRequest; res: EmptyResponse }; + 'i/export-clips': { req: EmptyRequest; res: EmptyResponse }; + 'i/export-favorites': { req: EmptyRequest; res: EmptyResponse }; + 'i/export-user-lists': { req: EmptyRequest; res: EmptyResponse }; + 'i/export-antennas': { req: EmptyRequest; res: EmptyResponse }; 'i/favorites': { req: IFavoritesRequest; res: IFavoritesResponse }; 'i/gallery/likes': { req: IGalleryLikesRequest; res: IGalleryLikesResponse }; 'i/gallery/posts': { req: IGalleryPostsRequest; res: IGalleryPostsResponse }; + 'i/import-blocking': { req: IImportBlockingRequest; res: EmptyResponse }; + 'i/import-following': { req: IImportFollowingRequest; res: EmptyResponse }; + 'i/import-muting': { req: IImportMutingRequest; res: EmptyResponse }; + 'i/import-user-lists': { req: IImportUserListsRequest; res: EmptyResponse }; + 'i/import-antennas': { req: IImportAntennasRequest; res: EmptyResponse }; 'i/notifications': { req: INotificationsRequest; res: INotificationsResponse }; 'i/notifications-grouped': { req: INotificationsGroupedRequest; res: INotificationsGroupedResponse }; 'i/page-likes': { req: IPageLikesRequest; res: IPageLikesResponse }; @@ -726,19 +817,25 @@ export type Endpoints = { 'i/read-all-messaging-messages': { req: EmptyRequest; res: EmptyResponse }; 'i/read-all-unread-notes': { req: EmptyRequest; res: EmptyResponse }; 'i/read-announcement': { req: IReadAnnouncementRequest; res: EmptyResponse }; - 'i/registry/get-all': { req: IRegistryGetAllRequest; res: EmptyResponse }; - 'i/registry/get-detail': { req: IRegistryGetDetailRequest; res: EmptyResponse }; - 'i/registry/get': { req: IRegistryGetRequest; res: EmptyResponse }; - 'i/registry/keys-with-type': { req: IRegistryKeysWithTypeRequest; res: EmptyResponse }; + 'i/regenerate-token': { req: IRegenerateTokenRequest; res: EmptyResponse }; + 'i/registry/get-all': { req: IRegistryGetAllRequest; res: IRegistryGetAllResponse }; + 'i/registry/get-detail': { req: IRegistryGetDetailRequest; res: IRegistryGetDetailResponse }; + 'i/registry/get': { req: IRegistryGetRequest; res: IRegistryGetResponse }; + 'i/registry/keys-with-type': { req: IRegistryKeysWithTypeRequest; res: IRegistryKeysWithTypeResponse }; 'i/registry/keys': { req: IRegistryKeysRequest; res: EmptyResponse }; 'i/registry/remove': { req: IRegistryRemoveRequest; res: EmptyResponse }; + 'i/registry/scopes-with-domain': { req: EmptyRequest; res: IRegistryScopesWithDomainResponse }; 'i/registry/set': { req: IRegistrySetRequest; res: EmptyResponse }; + 'i/revoke-token': { req: IRevokeTokenRequest; res: EmptyResponse }; + 'i/signin-history': { req: ISigninHistoryRequest; res: ISigninHistoryResponse }; 'i/unpin': { req: IUnpinRequest; res: IUnpinResponse }; + 'i/update-email': { req: IUpdateEmailRequest; res: IUpdateEmailResponse }; 'i/update': { req: IUpdateRequest; res: IUpdateResponse }; 'i/user-group-invites': { req: IUserGroupInvitesRequest; res: IUserGroupInvitesResponse }; - 'i/webhooks/create': { req: IWebhooksCreateRequest; res: EmptyResponse }; - 'i/webhooks/list': { req: EmptyRequest; res: EmptyResponse }; - 'i/webhooks/show': { req: IWebhooksShowRequest; res: EmptyResponse }; + 'i/move': { req: IMoveRequest; res: IMoveResponse }; + 'i/webhooks/create': { req: IWebhooksCreateRequest; res: IWebhooksCreateResponse }; + 'i/webhooks/list': { req: EmptyRequest; res: IWebhooksListResponse }; + 'i/webhooks/show': { req: IWebhooksShowRequest; res: IWebhooksShowResponse }; 'i/webhooks/update': { req: IWebhooksUpdateRequest; res: EmptyResponse }; 'i/webhooks/delete': { req: IWebhooksDeleteRequest; res: EmptyResponse }; 'invite/create': { req: EmptyRequest; res: InviteCreateResponse }; @@ -753,6 +850,7 @@ export type Endpoints = { 'meta': { req: MetaRequest; res: MetaResponse }; 'emojis': { req: EmptyRequest; res: EmojisResponse }; 'emoji': { req: EmojiRequest; res: EmojiResponse }; + 'miauth/gen-token': { req: MiauthGenTokenRequest; res: MiauthGenTokenResponse }; 'mute/create': { req: MuteCreateRequest; res: EmptyResponse }; 'mute/delete': { req: MuteDeleteRequest; res: EmptyResponse }; 'mute/list': { req: MuteListRequest; res: MuteListResponse }; @@ -795,6 +893,7 @@ export type Endpoints = { 'notifications/create': { req: NotificationsCreateRequest; res: EmptyResponse }; 'notifications/mark-all-as-read': { req: EmptyRequest; res: EmptyResponse }; 'notifications/test-notification': { req: EmptyRequest; res: EmptyResponse }; + 'page-push': { req: PagePushRequest; res: EmptyResponse }; 'pages/create': { req: PagesCreateRequest; res: PagesCreateResponse }; 'pages/delete': { req: PagesDeleteRequest; res: EmptyResponse }; 'pages/featured': { req: EmptyRequest; res: PagesFeaturedResponse }; @@ -802,9 +901,10 @@ export type Endpoints = { 'pages/show': { req: PagesShowRequest; res: PagesShowResponse }; 'pages/unlike': { req: PagesUnlikeRequest; res: EmptyResponse }; 'pages/update': { req: PagesUpdateRequest; res: EmptyResponse }; - 'flash/create': { req: FlashCreateRequest; res: EmptyResponse }; + 'flash/create': { req: FlashCreateRequest; res: FlashCreateResponse }; 'flash/delete': { req: FlashDeleteRequest; res: EmptyResponse }; 'flash/featured': { req: EmptyRequest; res: FlashFeaturedResponse }; + 'flash/gen-token': { req: FlashGenTokenRequest; res: FlashGenTokenResponse }; 'flash/like': { req: FlashLikeRequest; res: EmptyResponse }; 'flash/show': { req: FlashShowRequest; res: FlashShowResponse }; 'flash/unlike': { req: FlashUnlikeRequest; res: EmptyResponse }; @@ -816,18 +916,18 @@ export type Endpoints = { 'promo/read': { req: PromoReadRequest; res: EmptyResponse }; 'roles/list': { req: EmptyRequest; res: RolesListResponse }; 'roles/show': { req: RolesShowRequest; res: RolesShowResponse }; - 'roles/users': { req: RolesUsersRequest; res: EmptyResponse }; + 'roles/users': { req: RolesUsersRequest; res: RolesUsersResponse }; 'roles/notes': { req: RolesNotesRequest; res: RolesNotesResponse }; 'request-reset-password': { req: RequestResetPasswordRequest; res: EmptyResponse }; 'reset-db': { req: EmptyRequest; res: EmptyResponse }; 'reset-password': { req: ResetPasswordRequest; res: EmptyResponse }; - 'server-info': { req: EmptyRequest; res: EmptyResponse }; + 'server-info': { req: EmptyRequest; res: ServerInfoResponse }; 'stats': { req: EmptyRequest; res: StatsResponse }; 'sw/show-registration': { req: SwShowRegistrationRequest; res: SwShowRegistrationResponse }; 'sw/update-registration': { req: SwUpdateRegistrationRequest; res: SwUpdateRegistrationResponse }; 'sw/register': { req: SwRegisterRequest; res: SwRegisterResponse }; 'sw/unregister': { req: SwUnregisterRequest; res: EmptyResponse }; - 'test': { req: TestRequest; res: EmptyResponse }; + 'test': { req: TestRequest; res: TestResponse }; 'username/available': { req: UsernameAvailableRequest; res: UsernameAvailableResponse }; 'users': { req: UsersRequest; res: UsersResponse }; 'users/clips': { req: UsersClipsRequest; res: UsersClipsResponse }; @@ -859,7 +959,7 @@ export type Endpoints = { 'users/lists/update': { req: UsersListsUpdateRequest; res: UsersListsUpdateResponse }; 'users/lists/create-from-public': { req: UsersListsCreateFromPublicRequest; res: UsersListsCreateFromPublicResponse }; 'users/lists/update-membership': { req: UsersListsUpdateMembershipRequest; res: EmptyResponse }; - 'users/lists/get-memberships': { req: UsersListsGetMembershipsRequest; res: EmptyResponse }; + 'users/lists/get-memberships': { req: UsersListsGetMembershipsRequest; res: UsersListsGetMembershipsResponse }; 'users/notes': { req: UsersNotesRequest; res: UsersNotesResponse }; 'users/pages': { req: UsersPagesRequest; res: UsersPagesResponse }; 'users/flashs': { req: UsersFlashsRequest; res: UsersFlashsResponse }; @@ -871,10 +971,10 @@ export type Endpoints = { 'users/search': { req: UsersSearchRequest; res: UsersSearchResponse }; 'users/show': { req: UsersShowRequest; res: UsersShowResponse }; 'users/stats': { req: UsersStatsRequest; res: UsersStatsResponse }; - 'users/achievements': { req: UsersAchievementsRequest; res: EmptyResponse }; + 'users/achievements': { req: UsersAchievementsRequest; res: UsersAchievementsResponse }; 'users/update-memo': { req: UsersUpdateMemoRequest; res: EmptyResponse }; 'users/translate': { req: UsersTranslateRequest; res: UsersTranslateResponse }; - 'fetch-rss': { req: FetchRssRequest; res: EmptyResponse }; - 'fetch-external-resources': { req: FetchExternalResourcesRequest; res: EmptyResponse }; + 'fetch-rss': { req: FetchRssRequest; res: FetchRssResponse }; + 'fetch-external-resources': { req: FetchExternalResourcesRequest; res: FetchExternalResourcesResponse }; 'retention': { req: EmptyRequest; res: RetentionResponse }; } diff --git a/packages/cherrypick-js/src/autogen/entities.ts b/packages/cherrypick-js/src/autogen/entities.ts index 2e37ffac46..b4e7896b42 100644 --- a/packages/cherrypick-js/src/autogen/entities.ts +++ b/packages/cherrypick-js/src/autogen/entities.ts @@ -1,7 +1,7 @@ /* - * version: 4.6.0-beta.2 - * basedMisskeyVersion: 2023.12.0-beta.2 - * generatedAt: 2023-12-06T10:16:11.709Z + * version: 4.6.0 + * basedMisskeyVersion: 2023.12.2 + * generatedAt: 2024-01-10T07:26:44.252Z */ import { operations } from './types.js'; @@ -22,9 +22,12 @@ export type AdminAccountsCreateRequest = operations['admin/accounts/create']['re export type AdminAccountsCreateResponse = operations['admin/accounts/create']['responses']['200']['content']['application/json']; export type AdminAccountsDeleteRequest = operations['admin/accounts/delete']['requestBody']['content']['application/json']; export type AdminAccountsFindByEmailRequest = operations['admin/accounts/find-by-email']['requestBody']['content']['application/json']; +export type AdminAccountsFindByEmailResponse = operations['admin/accounts/find-by-email']['responses']['200']['content']['application/json']; export type AdminAdCreateRequest = operations['admin/ad/create']['requestBody']['content']['application/json']; +export type AdminAdCreateResponse = operations['admin/ad/create']['responses']['200']['content']['application/json']; export type AdminAdDeleteRequest = operations['admin/ad/delete']['requestBody']['content']['application/json']; export type AdminAdListRequest = operations['admin/ad/list']['requestBody']['content']['application/json']; +export type AdminAdListResponse = operations['admin/ad/list']['responses']['200']['content']['application/json']; export type AdminAdUpdateRequest = operations['admin/ad/update']['requestBody']['content']['application/json']; export type AdminAnnouncementsCreateRequest = operations['admin/announcements/create']['requestBody']['content']['application/json']; export type AdminAnnouncementsCreateResponse = operations['admin/announcements/create']['responses']['200']['content']['application/json']; @@ -51,6 +54,7 @@ export type AdminEmojiCopyRequest = operations['admin/emoji/copy']['requestBody' export type AdminEmojiCopyResponse = operations['admin/emoji/copy']['responses']['200']['content']['application/json']; export type AdminEmojiDeleteBulkRequest = operations['admin/emoji/delete-bulk']['requestBody']['content']['application/json']; export type AdminEmojiDeleteRequest = operations['admin/emoji/delete']['requestBody']['content']['application/json']; +export type AdminEmojiImportZipRequest = operations['admin/emoji/import-zip']['requestBody']['content']['application/json']; export type AdminEmojiListRemoteRequest = operations['admin/emoji/list-remote']['requestBody']['content']['application/json']; export type AdminEmojiListRemoteResponse = operations['admin/emoji/list-remote']['responses']['200']['content']['application/json']; export type AdminEmojiListRequest = operations['admin/emoji/list']['requestBody']['content']['application/json']; @@ -66,8 +70,10 @@ export type AdminFederationDeleteAllFilesRequest = operations['admin/federation/ export type AdminFederationRefreshRemoteInstanceMetadataRequest = operations['admin/federation/refresh-remote-instance-metadata']['requestBody']['content']['application/json']; export type AdminFederationRemoveAllFollowingRequest = operations['admin/federation/remove-all-following']['requestBody']['content']['application/json']; export type AdminFederationUpdateInstanceRequest = operations['admin/federation/update-instance']['requestBody']['content']['application/json']; +export type AdminGetIndexStatsResponse = operations['admin/get-index-stats']['responses']['200']['content']['application/json']; export type AdminGetTableStatsResponse = operations['admin/get-table-stats']['responses']['200']['content']['application/json']; export type AdminGetUserIpsRequest = operations['admin/get-user-ips']['requestBody']['content']['application/json']; +export type AdminGetUserIpsResponse = operations['admin/get-user-ips']['responses']['200']['content']['application/json']; export type AdminInviteCreateRequest = operations['admin/invite/create']['requestBody']['content']['application/json']; export type AdminInviteCreateResponse = operations['admin/invite/create']['responses']['200']['content']['application/json']; export type AdminInviteListRequest = operations['admin/invite/list']['requestBody']['content']['application/json']; @@ -109,6 +115,7 @@ export type AdminRolesAssignRequest = operations['admin/roles/assign']['requestB export type AdminRolesUnassignRequest = operations['admin/roles/unassign']['requestBody']['content']['application/json']; export type AdminRolesUpdateDefaultPoliciesRequest = operations['admin/roles/update-default-policies']['requestBody']['content']['application/json']; export type AdminRolesUsersRequest = operations['admin/roles/users']['requestBody']['content']['application/json']; +export type AdminRolesUsersResponse = operations['admin/roles/users']['responses']['200']['content']['application/json']; export type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json']; export type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json']; export type AntennasCreateRequest = operations['antennas/create']['requestBody']['content']['application/json']; @@ -129,6 +136,7 @@ export type AppCreateRequest = operations['app/create']['requestBody']['content' export type AppCreateResponse = operations['app/create']['responses']['200']['content']['application/json']; export type AppShowRequest = operations['app/show']['requestBody']['content']['application/json']; export type AppShowResponse = operations['app/show']['responses']['200']['content']['application/json']; +export type AuthAcceptRequest = operations['auth/accept']['requestBody']['content']['application/json']; export type AuthSessionGenerateRequest = operations['auth/session/generate']['requestBody']['content']['application/json']; export type AuthSessionGenerateResponse = operations['auth/session/generate']['responses']['200']['content']['application/json']; export type AuthSessionShowRequest = operations['auth/session/show']['requestBody']['content']['application/json']; @@ -235,6 +243,7 @@ export type DriveStreamResponse = operations['drive/stream']['responses']['200'] export type EmailAddressAvailableRequest = operations['email-address/available']['requestBody']['content']['application/json']; export type EmailAddressAvailableResponse = operations['email-address/available']['responses']['200']['content']['application/json']; export type EndpointRequest = operations['endpoint']['requestBody']['content']['application/json']; +export type EndpointResponse = operations['endpoint']['responses']['200']['content']['application/json']; export type EndpointsResponse = operations['endpoints']['responses']['200']['content']['application/json']; export type FederationFollowersRequest = operations['federation/followers']['requestBody']['content']['application/json']; export type FederationFollowersResponse = operations['federation/followers']['responses']['200']['content']['application/json']; @@ -248,6 +257,7 @@ export type FederationUpdateRemoteUserRequest = operations['federation/update-re export type FederationUsersRequest = operations['federation/users']['requestBody']['content']['application/json']; export type FederationUsersResponse = operations['federation/users']['responses']['200']['content']['application/json']; export type FederationStatsRequest = operations['federation/stats']['requestBody']['content']['application/json']; +export type FederationStatsResponse = operations['federation/stats']['responses']['200']['content']['application/json']; export type FollowingCreateRequest = operations['following/create']['requestBody']['content']['application/json']; export type FollowingCreateResponse = operations['following/create']['responses']['200']['content']['application/json']; export type FollowingDeleteRequest = operations['following/delete']['requestBody']['content']['application/json']; @@ -277,6 +287,7 @@ export type GalleryPostsShowResponse = operations['gallery/posts/show']['respons export type GalleryPostsUnlikeRequest = operations['gallery/posts/unlike']['requestBody']['content']['application/json']; export type GalleryPostsUpdateRequest = operations['gallery/posts/update']['requestBody']['content']['application/json']; export type GalleryPostsUpdateResponse = operations['gallery/posts/update']['responses']['200']['content']['application/json']; +export type GetOnlineUsersCountResponse = operations['get-online-users-count']['responses']['200']['content']['application/json']; export type GetAvatarDecorationsResponse = operations['get-avatar-decorations']['responses']['200']['content']['application/json']; export type HashtagsListRequest = operations['hashtags/list']['requestBody']['content']['application/json']; export type HashtagsListResponse = operations['hashtags/list']['responses']['200']['content']['application/json']; @@ -288,13 +299,36 @@ export type HashtagsTrendResponse = operations['hashtags/trend']['responses']['2 export type HashtagsUsersRequest = operations['hashtags/users']['requestBody']['content']['application/json']; export type HashtagsUsersResponse = operations['hashtags/users']['responses']['200']['content']['application/json']; export type IResponse = operations['i']['responses']['200']['content']['application/json']; +export type I2faDoneRequest = operations['i/2fa/done']['requestBody']['content']['application/json']; +export type I2faKeyDoneRequest = operations['i/2fa/key-done']['requestBody']['content']['application/json']; +export type I2faKeyDoneResponse = operations['i/2fa/key-done']['responses']['200']['content']['application/json']; +export type I2faPasswordLessRequest = operations['i/2fa/password-less']['requestBody']['content']['application/json']; +export type I2faRegisterKeyRequest = operations['i/2fa/register-key']['requestBody']['content']['application/json']; +export type I2faRegisterKeyResponse = operations['i/2fa/register-key']['responses']['200']['content']['application/json']; +export type I2faRegisterRequest = operations['i/2fa/register']['requestBody']['content']['application/json']; +export type I2faRegisterResponse = operations['i/2fa/register']['responses']['200']['content']['application/json']; +export type I2faUpdateKeyRequest = operations['i/2fa/update-key']['requestBody']['content']['application/json']; +export type I2faRemoveKeyRequest = operations['i/2fa/remove-key']['requestBody']['content']['application/json']; +export type I2faUnregisterRequest = operations['i/2fa/unregister']['requestBody']['content']['application/json']; +export type IAppsRequest = operations['i/apps']['requestBody']['content']['application/json']; +export type IAppsResponse = operations['i/apps']['responses']['200']['content']['application/json']; +export type IAuthorizedAppsRequest = operations['i/authorized-apps']['requestBody']['content']['application/json']; +export type IAuthorizedAppsResponse = operations['i/authorized-apps']['responses']['200']['content']['application/json']; export type IClaimAchievementRequest = operations['i/claim-achievement']['requestBody']['content']['application/json']; +export type IChangePasswordRequest = operations['i/change-password']['requestBody']['content']['application/json']; +export type IDeleteAccountRequest = operations['i/delete-account']['requestBody']['content']['application/json']; +export type IExportFollowingRequest = operations['i/export-following']['requestBody']['content']['application/json']; export type IFavoritesRequest = operations['i/favorites']['requestBody']['content']['application/json']; export type IFavoritesResponse = operations['i/favorites']['responses']['200']['content']['application/json']; export type IGalleryLikesRequest = operations['i/gallery/likes']['requestBody']['content']['application/json']; export type IGalleryLikesResponse = operations['i/gallery/likes']['responses']['200']['content']['application/json']; export type IGalleryPostsRequest = operations['i/gallery/posts']['requestBody']['content']['application/json']; export type IGalleryPostsResponse = operations['i/gallery/posts']['responses']['200']['content']['application/json']; +export type IImportBlockingRequest = operations['i/import-blocking']['requestBody']['content']['application/json']; +export type IImportFollowingRequest = operations['i/import-following']['requestBody']['content']['application/json']; +export type IImportMutingRequest = operations['i/import-muting']['requestBody']['content']['application/json']; +export type IImportUserListsRequest = operations['i/import-user-lists']['requestBody']['content']['application/json']; +export type IImportAntennasRequest = operations['i/import-antennas']['requestBody']['content']['application/json']; export type INotificationsRequest = operations['i/notifications']['requestBody']['content']['application/json']; export type INotificationsResponse = operations['i/notifications']['responses']['200']['content']['application/json']; export type INotificationsGroupedRequest = operations['i/notifications-grouped']['requestBody']['content']['application/json']; @@ -306,21 +340,37 @@ export type IPagesResponse = operations['i/pages']['responses']['200']['content' export type IPinRequest = operations['i/pin']['requestBody']['content']['application/json']; export type IPinResponse = operations['i/pin']['responses']['200']['content']['application/json']; export type IReadAnnouncementRequest = operations['i/read-announcement']['requestBody']['content']['application/json']; +export type IRegenerateTokenRequest = operations['i/regenerate-token']['requestBody']['content']['application/json']; export type IRegistryGetAllRequest = operations['i/registry/get-all']['requestBody']['content']['application/json']; +export type IRegistryGetAllResponse = operations['i/registry/get-all']['responses']['200']['content']['application/json']; export type IRegistryGetDetailRequest = operations['i/registry/get-detail']['requestBody']['content']['application/json']; +export type IRegistryGetDetailResponse = operations['i/registry/get-detail']['responses']['200']['content']['application/json']; export type IRegistryGetRequest = operations['i/registry/get']['requestBody']['content']['application/json']; +export type IRegistryGetResponse = operations['i/registry/get']['responses']['200']['content']['application/json']; export type IRegistryKeysWithTypeRequest = operations['i/registry/keys-with-type']['requestBody']['content']['application/json']; +export type IRegistryKeysWithTypeResponse = operations['i/registry/keys-with-type']['responses']['200']['content']['application/json']; export type IRegistryKeysRequest = operations['i/registry/keys']['requestBody']['content']['application/json']; export type IRegistryRemoveRequest = operations['i/registry/remove']['requestBody']['content']['application/json']; +export type IRegistryScopesWithDomainResponse = operations['i/registry/scopes-with-domain']['responses']['200']['content']['application/json']; export type IRegistrySetRequest = operations['i/registry/set']['requestBody']['content']['application/json']; +export type IRevokeTokenRequest = operations['i/revoke-token']['requestBody']['content']['application/json']; +export type ISigninHistoryRequest = operations['i/signin-history']['requestBody']['content']['application/json']; +export type ISigninHistoryResponse = operations['i/signin-history']['responses']['200']['content']['application/json']; export type IUnpinRequest = operations['i/unpin']['requestBody']['content']['application/json']; export type IUnpinResponse = operations['i/unpin']['responses']['200']['content']['application/json']; +export type IUpdateEmailRequest = operations['i/update-email']['requestBody']['content']['application/json']; +export type IUpdateEmailResponse = operations['i/update-email']['responses']['200']['content']['application/json']; export type IUpdateRequest = operations['i/update']['requestBody']['content']['application/json']; export type IUpdateResponse = operations['i/update']['responses']['200']['content']['application/json']; export type IUserGroupInvitesRequest = operations['i/user-group-invites']['requestBody']['content']['application/json']; export type IUserGroupInvitesResponse = operations['i/user-group-invites']['responses']['200']['content']['application/json']; +export type IMoveRequest = operations['i/move']['requestBody']['content']['application/json']; +export type IMoveResponse = operations['i/move']['responses']['200']['content']['application/json']; export type IWebhooksCreateRequest = operations['i/webhooks/create']['requestBody']['content']['application/json']; +export type IWebhooksCreateResponse = operations['i/webhooks/create']['responses']['200']['content']['application/json']; +export type IWebhooksListResponse = operations['i/webhooks/list']['responses']['200']['content']['application/json']; export type IWebhooksShowRequest = operations['i/webhooks/show']['requestBody']['content']['application/json']; +export type IWebhooksShowResponse = operations['i/webhooks/show']['responses']['200']['content']['application/json']; export type IWebhooksUpdateRequest = operations['i/webhooks/update']['requestBody']['content']['application/json']; export type IWebhooksDeleteRequest = operations['i/webhooks/delete']['requestBody']['content']['application/json']; export type InviteCreateResponse = operations['invite/create']['responses']['200']['content']['application/json']; @@ -341,6 +391,8 @@ export type MetaResponse = operations['meta']['responses']['200']['content']['ap export type EmojisResponse = operations['emojis']['responses']['200']['content']['application/json']; export type EmojiRequest = operations['emoji']['requestBody']['content']['application/json']; export type EmojiResponse = operations['emoji']['responses']['200']['content']['application/json']; +export type MiauthGenTokenRequest = operations['miauth/gen-token']['requestBody']['content']['application/json']; +export type MiauthGenTokenResponse = operations['miauth/gen-token']['responses']['200']['content']['application/json']; export type MuteCreateRequest = operations['mute/create']['requestBody']['content']['application/json']; export type MuteDeleteRequest = operations['mute/delete']['requestBody']['content']['application/json']; export type MuteListRequest = operations['mute/list']['requestBody']['content']['application/json']; @@ -406,6 +458,7 @@ export type NotesUnrenoteRequest = operations['notes/unrenote']['requestBody'][' export type NotesUserListTimelineRequest = operations['notes/user-list-timeline']['requestBody']['content']['application/json']; export type NotesUserListTimelineResponse = operations['notes/user-list-timeline']['responses']['200']['content']['application/json']; export type NotificationsCreateRequest = operations['notifications/create']['requestBody']['content']['application/json']; +export type PagePushRequest = operations['page-push']['requestBody']['content']['application/json']; export type PagesCreateRequest = operations['pages/create']['requestBody']['content']['application/json']; export type PagesCreateResponse = operations['pages/create']['responses']['200']['content']['application/json']; export type PagesDeleteRequest = operations['pages/delete']['requestBody']['content']['application/json']; @@ -416,8 +469,11 @@ export type PagesShowResponse = operations['pages/show']['responses']['200']['co export type PagesUnlikeRequest = operations['pages/unlike']['requestBody']['content']['application/json']; export type PagesUpdateRequest = operations['pages/update']['requestBody']['content']['application/json']; 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 FlashFeaturedResponse = operations['flash/featured']['responses']['200']['content']['application/json']; +export type FlashGenTokenRequest = operations['flash/gen-token']['requestBody']['content']['application/json']; +export type FlashGenTokenResponse = operations['flash/gen-token']['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']; export type FlashShowResponse = operations['flash/show']['responses']['200']['content']['application/json']; @@ -434,10 +490,12 @@ export type RolesListResponse = operations['roles/list']['responses']['200']['co export type RolesShowRequest = operations['roles/show']['requestBody']['content']['application/json']; export type RolesShowResponse = operations['roles/show']['responses']['200']['content']['application/json']; export type RolesUsersRequest = operations['roles/users']['requestBody']['content']['application/json']; +export type RolesUsersResponse = operations['roles/users']['responses']['200']['content']['application/json']; export type RolesNotesRequest = operations['roles/notes']['requestBody']['content']['application/json']; export type RolesNotesResponse = operations['roles/notes']['responses']['200']['content']['application/json']; export type RequestResetPasswordRequest = operations['request-reset-password']['requestBody']['content']['application/json']; export type ResetPasswordRequest = operations['reset-password']['requestBody']['content']['application/json']; +export type ServerInfoResponse = operations['server-info']['responses']['200']['content']['application/json']; export type StatsResponse = operations['stats']['responses']['200']['content']['application/json']; export type SwShowRegistrationRequest = operations['sw/show-registration']['requestBody']['content']['application/json']; export type SwShowRegistrationResponse = operations['sw/show-registration']['responses']['200']['content']['application/json']; @@ -447,6 +505,7 @@ export type SwRegisterRequest = operations['sw/register']['requestBody']['conten export type SwRegisterResponse = operations['sw/register']['responses']['200']['content']['application/json']; export type SwUnregisterRequest = operations['sw/unregister']['requestBody']['content']['application/json']; export type TestRequest = operations['test']['requestBody']['content']['application/json']; +export type TestResponse = operations['test']['responses']['200']['content']['application/json']; export type UsernameAvailableRequest = operations['username/available']['requestBody']['content']['application/json']; export type UsernameAvailableResponse = operations['username/available']['responses']['200']['content']['application/json']; export type UsersRequest = operations['users']['requestBody']['content']['application/json']; @@ -496,6 +555,7 @@ export type UsersListsCreateFromPublicRequest = operations['users/lists/create-f export type UsersListsCreateFromPublicResponse = operations['users/lists/create-from-public']['responses']['200']['content']['application/json']; export type UsersListsUpdateMembershipRequest = operations['users/lists/update-membership']['requestBody']['content']['application/json']; export type UsersListsGetMembershipsRequest = operations['users/lists/get-memberships']['requestBody']['content']['application/json']; +export type UsersListsGetMembershipsResponse = operations['users/lists/get-memberships']['responses']['200']['content']['application/json']; export type UsersNotesRequest = operations['users/notes']['requestBody']['content']['application/json']; export type UsersNotesResponse = operations['users/notes']['responses']['200']['content']['application/json']; export type UsersPagesRequest = operations['users/pages']['requestBody']['content']['application/json']; @@ -518,9 +578,12 @@ export type UsersShowResponse = operations['users/show']['responses']['200']['co export type UsersStatsRequest = operations['users/stats']['requestBody']['content']['application/json']; export type UsersStatsResponse = operations['users/stats']['responses']['200']['content']['application/json']; export type UsersAchievementsRequest = operations['users/achievements']['requestBody']['content']['application/json']; +export type UsersAchievementsResponse = operations['users/achievements']['responses']['200']['content']['application/json']; export type UsersUpdateMemoRequest = operations['users/update-memo']['requestBody']['content']['application/json']; export type UsersTranslateRequest = operations['users/translate']['requestBody']['content']['application/json']; export type UsersTranslateResponse = operations['users/translate']['responses']['200']['content']['application/json']; export type FetchRssRequest = operations['fetch-rss']['requestBody']['content']['application/json']; +export type FetchRssResponse = operations['fetch-rss']['responses']['200']['content']['application/json']; export type FetchExternalResourcesRequest = operations['fetch-external-resources']['requestBody']['content']['application/json']; +export type FetchExternalResourcesResponse = operations['fetch-external-resources']['responses']['200']['content']['application/json']; export type RetentionResponse = operations['retention']['responses']['200']['content']['application/json']; diff --git a/packages/cherrypick-js/src/autogen/models.ts b/packages/cherrypick-js/src/autogen/models.ts index 7c0b81b9d6..b1cd87fc86 100644 --- a/packages/cherrypick-js/src/autogen/models.ts +++ b/packages/cherrypick-js/src/autogen/models.ts @@ -1,7 +1,7 @@ /* - * version: 4.6.0-beta.2 - * basedMisskeyVersion: 2023.12.0-beta.2 - * generatedAt: 2023-12-06T10:16:11.709Z + * version: 4.6.0 + * basedMisskeyVersion: 2023.12.2 + * generatedAt: 2024-01-10T07:26:44.252Z */ import { components } from './types.js'; @@ -15,6 +15,7 @@ export type UserDetailed = components['schemas']['UserDetailed']; export type User = components['schemas']['User']; export type UserList = components['schemas']['UserList']; export type UserGroup = components['schemas']['UserGroup']; +export type Ad = components['schemas']['Ad']; export type Announcement = components['schemas']['Announcement']; export type App = components['schemas']['App']; export type MessagingMessage = components['schemas']['MessagingMessage']; diff --git a/packages/cherrypick-js/src/autogen/types.ts b/packages/cherrypick-js/src/autogen/types.ts index 478c897273..fd079b15b3 100644 --- a/packages/cherrypick-js/src/autogen/types.ts +++ b/packages/cherrypick-js/src/autogen/types.ts @@ -2,9 +2,9 @@ /* eslint @typescript-eslint/no-explicit-any: 0 */ /* - * version: 4.6.0-beta.2 - * basedMisskeyVersion: 2023.12.0-beta.2 - * generatedAt: 2023-12-06T10:16:11.638Z + * version: 4.6.0 + * basedMisskeyVersion: 2023.12.2 + * generatedAt: 2024-01-10T07:26:44.174Z */ /** @@ -23,7 +23,7 @@ export type paths = { * admin/meta * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:meta* */ post: operations['admin/meta']; }; @@ -68,7 +68,7 @@ export type paths = { * admin/abuse-user-reports * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-user-reports* */ post: operations['admin/abuse-user-reports']; }; @@ -86,7 +86,7 @@ export type paths = { * admin/accounts/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:account* */ post: operations['admin/accounts/delete']; }; @@ -95,7 +95,7 @@ export type paths = { * admin/accounts/find-by-email * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:account* */ post: operations['admin/accounts/find-by-email']; }; @@ -104,7 +104,7 @@ export type paths = { * admin/ad/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* */ post: operations['admin/ad/create']; }; @@ -113,7 +113,7 @@ export type paths = { * admin/ad/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* */ post: operations['admin/ad/delete']; }; @@ -122,7 +122,7 @@ export type paths = { * admin/ad/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:ad* */ post: operations['admin/ad/list']; }; @@ -131,7 +131,7 @@ export type paths = { * admin/ad/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* */ post: operations['admin/ad/update']; }; @@ -140,7 +140,7 @@ export type paths = { * admin/announcements/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* */ post: operations['admin/announcements/create']; }; @@ -149,7 +149,7 @@ export type paths = { * admin/announcements/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* */ post: operations['admin/announcements/delete']; }; @@ -158,7 +158,7 @@ export type paths = { * admin/announcements/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:announcements* */ post: operations['admin/announcements/list']; }; @@ -167,7 +167,7 @@ export type paths = { * admin/announcements/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* */ post: operations['admin/announcements/update']; }; @@ -176,7 +176,7 @@ export type paths = { * admin/avatar-decorations/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* */ post: operations['admin/avatar-decorations/create']; }; @@ -185,7 +185,7 @@ export type paths = { * admin/avatar-decorations/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* */ post: operations['admin/avatar-decorations/delete']; }; @@ -194,7 +194,7 @@ export type paths = { * admin/avatar-decorations/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:avatar-decorations* */ post: operations['admin/avatar-decorations/list']; }; @@ -203,7 +203,7 @@ export type paths = { * admin/avatar-decorations/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* */ post: operations['admin/avatar-decorations/update']; }; @@ -212,7 +212,7 @@ export type paths = { * admin/delete-all-files-of-a-user * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:delete-all-files-of-a-user* */ post: operations['admin/delete-all-files-of-a-user']; }; @@ -221,7 +221,7 @@ export type paths = { * admin/unset-user-avatar * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-avatar* */ post: operations['admin/unset-user-avatar']; }; @@ -230,7 +230,7 @@ export type paths = { * admin/unset-user-banner * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-banner* */ post: operations['admin/unset-user-banner']; }; @@ -239,7 +239,7 @@ export type paths = { * admin/drive/clean-remote-files * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:drive* */ post: operations['admin/drive/clean-remote-files']; }; @@ -248,7 +248,7 @@ export type paths = { * admin/drive/cleanup * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:drive* */ post: operations['admin/drive/cleanup']; }; @@ -257,7 +257,7 @@ export type paths = { * admin/drive/files * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:drive* */ post: operations['admin/drive/files']; }; @@ -266,7 +266,7 @@ export type paths = { * admin/drive/show-file * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:drive* */ post: operations['admin/drive/show-file']; }; @@ -275,7 +275,7 @@ export type paths = { * admin/emoji/add-aliases-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/add-aliases-bulk']; }; @@ -284,7 +284,7 @@ export type paths = { * admin/emoji/add * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/add']; }; @@ -293,7 +293,7 @@ export type paths = { * admin/emoji/adds * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/adds']; }; @@ -302,7 +302,7 @@ export type paths = { * admin/emoji/copy * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/copy']; }; @@ -311,7 +311,7 @@ export type paths = { * admin/emoji/delete-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/delete-bulk']; }; @@ -320,16 +320,26 @@ export type paths = { * admin/emoji/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/delete']; }; + '/admin/emoji/import-zip': { + /** + * admin/emoji/import-zip + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + post: operations['admin/emoji/import-zip']; + }; '/admin/emoji/list-remote': { /** * admin/emoji/list-remote * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ post: operations['admin/emoji/list-remote']; }; @@ -338,7 +348,7 @@ export type paths = { * admin/emoji/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ post: operations['admin/emoji/list']; }; @@ -347,7 +357,7 @@ export type paths = { * admin/emoji/remove-aliases-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/remove-aliases-bulk']; }; @@ -356,7 +366,7 @@ export type paths = { * admin/emoji/set-aliases-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/set-aliases-bulk']; }; @@ -365,7 +375,7 @@ export type paths = { * admin/emoji/set-category-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/set-category-bulk']; }; @@ -374,7 +384,7 @@ export type paths = { * admin/emoji/set-license-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/set-license-bulk']; }; @@ -383,7 +393,7 @@ export type paths = { * admin/emoji/steal * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/steal']; }; @@ -392,7 +402,7 @@ export type paths = { * admin/emoji/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ post: operations['admin/emoji/update']; }; @@ -401,7 +411,7 @@ export type paths = { * admin/federation/delete-all-files * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ post: operations['admin/federation/delete-all-files']; }; @@ -410,7 +420,7 @@ export type paths = { * admin/federation/refresh-remote-instance-metadata * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ post: operations['admin/federation/refresh-remote-instance-metadata']; }; @@ -419,7 +429,7 @@ export type paths = { * admin/federation/remove-all-following * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ post: operations['admin/federation/remove-all-following']; }; @@ -428,7 +438,7 @@ export type paths = { * admin/federation/update-instance * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ post: operations['admin/federation/update-instance']; }; @@ -437,7 +447,7 @@ export type paths = { * admin/get-index-stats * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:index-stats* */ post: operations['admin/get-index-stats']; }; @@ -446,7 +456,7 @@ export type paths = { * admin/get-table-stats * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:table-stats* */ post: operations['admin/get-table-stats']; }; @@ -455,7 +465,7 @@ export type paths = { * admin/get-user-ips * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:user-ips* */ post: operations['admin/get-user-ips']; }; @@ -464,7 +474,7 @@ export type paths = { * admin/invite/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes* */ post: operations['admin/invite/create']; }; @@ -473,7 +483,7 @@ export type paths = { * admin/invite/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:invite-codes* */ post: operations['admin/invite/list']; }; @@ -482,7 +492,7 @@ export type paths = { * admin/invite/revoke * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes* */ post: operations['admin/invite/revoke']; }; @@ -491,7 +501,7 @@ export type paths = { * admin/promo/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:promo* */ post: operations['admin/promo/create']; }; @@ -500,7 +510,7 @@ export type paths = { * admin/queue/clear * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:queue* */ post: operations['admin/queue/clear']; }; @@ -509,7 +519,7 @@ export type paths = { * admin/queue/deliver-delayed * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:queue* */ post: operations['admin/queue/deliver-delayed']; }; @@ -518,7 +528,7 @@ export type paths = { * admin/queue/inbox-delayed * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:queue* */ post: operations['admin/queue/inbox-delayed']; }; @@ -527,7 +537,7 @@ export type paths = { * admin/queue/promote * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:queue* */ post: operations['admin/queue/promote']; }; @@ -536,7 +546,7 @@ export type paths = { * admin/queue/stats * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ post: operations['admin/queue/stats']; }; @@ -545,7 +555,7 @@ export type paths = { * admin/relays/add * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:relays* */ post: operations['admin/relays/add']; }; @@ -554,7 +564,7 @@ export type paths = { * admin/relays/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:relays* */ post: operations['admin/relays/list']; }; @@ -563,7 +573,7 @@ export type paths = { * admin/relays/remove * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:relays* */ post: operations['admin/relays/remove']; }; @@ -572,7 +582,7 @@ export type paths = { * admin/reset-password * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:reset-password* */ post: operations['admin/reset-password']; }; @@ -581,7 +591,7 @@ export type paths = { * admin/resolve-abuse-user-report * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* */ post: operations['admin/resolve-abuse-user-report']; }; @@ -590,7 +600,7 @@ export type paths = { * admin/send-email * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:send-email* */ post: operations['admin/send-email']; }; @@ -599,7 +609,7 @@ export type paths = { * admin/server-info * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:server-info* */ post: operations['admin/server-info']; }; @@ -608,7 +618,7 @@ export type paths = { * admin/show-moderation-logs * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:show-moderation-log* */ post: operations['admin/show-moderation-logs']; }; @@ -617,7 +627,7 @@ export type paths = { * admin/show-user * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:show-user* */ post: operations['admin/show-user']; }; @@ -626,7 +636,7 @@ export type paths = { * admin/show-users * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:show-users* */ post: operations['admin/show-users']; }; @@ -635,7 +645,7 @@ export type paths = { * admin/suspend-user * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:suspend-user* */ post: operations['admin/suspend-user']; }; @@ -644,7 +654,7 @@ export type paths = { * admin/unsuspend-user * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:unsuspend-user* */ post: operations['admin/unsuspend-user']; }; @@ -653,7 +663,7 @@ export type paths = { * admin/update-meta * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:meta* */ post: operations['admin/update-meta']; }; @@ -662,7 +672,7 @@ export type paths = { * admin/delete-account * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:delete-account* */ post: operations['admin/delete-account']; }; @@ -671,7 +681,7 @@ export type paths = { * admin/update-user-note * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:user-note* */ post: operations['admin/update-user-note']; }; @@ -680,7 +690,7 @@ export type paths = { * admin/roles/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ post: operations['admin/roles/create']; }; @@ -689,7 +699,7 @@ export type paths = { * admin/roles/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ post: operations['admin/roles/delete']; }; @@ -698,7 +708,7 @@ export type paths = { * admin/roles/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:roles* */ post: operations['admin/roles/list']; }; @@ -707,7 +717,7 @@ export type paths = { * admin/roles/show * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:roles* */ post: operations['admin/roles/show']; }; @@ -716,7 +726,7 @@ export type paths = { * admin/roles/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ post: operations['admin/roles/update']; }; @@ -725,7 +735,7 @@ export type paths = { * admin/roles/assign * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ post: operations['admin/roles/assign']; }; @@ -734,7 +744,7 @@ export type paths = { * admin/roles/unassign * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ post: operations['admin/roles/unassign']; }; @@ -743,7 +753,7 @@ export type paths = { * admin/roles/update-default-policies * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ post: operations['admin/roles/update-default-policies']; }; @@ -752,7 +762,7 @@ export type paths = { * admin/roles/users * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *No* / **Permission**: *read:admin:roles* */ post: operations['admin/roles/users']; }; @@ -824,7 +834,7 @@ export type paths = { * ap/get * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:federation* */ post: operations['ap/get']; }; @@ -833,7 +843,7 @@ export type paths = { * ap/show * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ post: operations['ap/show']; }; @@ -855,6 +865,16 @@ export type paths = { */ post: operations['app/show']; }; + '/auth/accept': { + /** + * auth/accept + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + post: operations['auth/accept']; + }; '/auth/session/generate': { /** * auth/session/generate @@ -1506,6 +1526,16 @@ export type paths = { */ post: operations['endpoints']; }; + '/export-custom-emojis': { + /** + * export-custom-emojis + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + post: operations['export-custom-emojis']; + }; '/federation/followers': { /** * federation/followers @@ -1554,7 +1584,7 @@ export type paths = { * federation/update-remote-user * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ post: operations['federation/update-remote-user']; }; @@ -1827,1537 +1857,1881 @@ export type paths = { * i * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ post: operations['i']; }; - '/i/claim-achievement': { + '/i/2fa/done': { /** - * i/claim-achievement + * i/2fa/done * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['i/claim-achievement']; + post: operations['i/2fa/done']; }; - '/i/favorites': { + '/i/2fa/key-done': { /** - * i/favorites + * i/2fa/key-done * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:favorites* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/favorites']; + post: operations['i/2fa/key-done']; }; - '/i/gallery/likes': { + '/i/2fa/password-less': { /** - * i/gallery/likes + * i/2fa/password-less * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:gallery-likes* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/gallery/likes']; + post: operations['i/2fa/password-less']; }; - '/i/gallery/posts': { + '/i/2fa/register-key': { /** - * i/gallery/posts + * i/2fa/register-key * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:gallery* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/gallery/posts']; + post: operations['i/2fa/register-key']; }; - '/i/notifications': { + '/i/2fa/register': { /** - * i/notifications + * i/2fa/register * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:notifications* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/notifications']; + post: operations['i/2fa/register']; }; - '/i/notifications-grouped': { + '/i/2fa/update-key': { /** - * i/notifications-grouped + * i/2fa/update-key * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:notifications* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/notifications-grouped']; + post: operations['i/2fa/update-key']; }; - '/i/page-likes': { + '/i/2fa/remove-key': { /** - * i/page-likes + * i/2fa/remove-key * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:page-likes* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/page-likes']; + post: operations['i/2fa/remove-key']; }; - '/i/pages': { + '/i/2fa/unregister': { /** - * i/pages + * i/2fa/unregister * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:pages* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/pages']; + post: operations['i/2fa/unregister']; }; - '/i/pin': { + '/i/apps': { /** - * i/pin + * i/apps * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/pin']; + post: operations['i/apps']; }; - '/i/read-all-messaging-messages': { + '/i/authorized-apps': { /** - * i/read-all-messaging-messages + * i/authorized-apps * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/read-all-messaging-messages']; + post: operations['i/authorized-apps']; }; - '/i/read-all-unread-notes': { + '/i/claim-achievement': { /** - * i/read-all-unread-notes + * i/claim-achievement * @description No description provided. * * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['i/read-all-unread-notes']; + post: operations['i/claim-achievement']; }; - '/i/read-announcement': { + '/i/change-password': { /** - * i/read-announcement + * i/change-password * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/read-announcement']; + post: operations['i/change-password']; }; - '/i/registry/get-all': { + '/i/delete-account': { /** - * i/registry/get-all + * i/delete-account * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['i/registry/get-all']; + post: operations['i/delete-account']; }; - '/i/registry/get-detail': { + '/i/export-blocking': { /** - * i/registry/get-detail + * i/export-blocking * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['i/registry/get-detail']; + post: operations['i/export-blocking']; }; - '/i/registry/get': { + '/i/export-following': { /** - * i/registry/get + * i/export-following * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['i/registry/get']; + post: operations['i/export-following']; }; - '/i/registry/keys-with-type': { + '/i/export-mute': { /** - * i/registry/keys-with-type + * i/export-mute * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['i/registry/keys-with-type']; + post: operations['i/export-mute']; }; - '/i/registry/keys': { + '/i/export-notes': { /** - * i/registry/keys + * i/export-notes * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['i/registry/keys']; + post: operations['i/export-notes']; }; - '/i/registry/remove': { + '/i/export-clips': { /** - * i/registry/remove + * i/export-clips * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['i/registry/remove']; + post: operations['i/export-clips']; }; - '/i/registry/set': { + '/i/export-favorites': { /** - * i/registry/set + * i/export-favorites * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['i/registry/set']; + post: operations['i/export-favorites']; }; - '/i/unpin': { + '/i/export-user-lists': { /** - * i/unpin + * i/export-user-lists * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/unpin']; + post: operations['i/export-user-lists']; }; - '/i/update': { + '/i/export-antennas': { /** - * i/update + * i/export-antennas * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/update']; + post: operations['i/export-antennas']; }; - '/i/user-group-invites': { + '/i/favorites': { /** - * i/user-group-invites + * i/favorites * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:user-groups* + * **Credential required**: *Yes* / **Permission**: *read:favorites* */ - post: operations['i/user-group-invites']; + post: operations['i/favorites']; }; - '/i/webhooks/create': { + '/i/gallery/likes': { /** - * i/webhooks/create + * i/gallery/likes * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *Yes* / **Permission**: *read:gallery-likes* */ - post: operations['i/webhooks/create']; + post: operations['i/gallery/likes']; }; - '/i/webhooks/list': { + '/i/gallery/posts': { /** - * i/webhooks/list + * i/gallery/posts * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:account* + * **Credential required**: *Yes* / **Permission**: *read:gallery* */ - post: operations['i/webhooks/list']; + post: operations['i/gallery/posts']; }; - '/i/webhooks/show': { + '/i/import-blocking': { /** - * i/webhooks/show + * i/import-blocking * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/webhooks/show']; + post: operations['i/import-blocking']; }; - '/i/webhooks/update': { + '/i/import-following': { /** - * i/webhooks/update + * i/import-following * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/webhooks/update']; + post: operations['i/import-following']; }; - '/i/webhooks/delete': { + '/i/import-muting': { /** - * i/webhooks/delete + * i/import-muting * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['i/webhooks/delete']; + post: operations['i/import-muting']; }; - '/invite/create': { + '/i/import-user-lists': { /** - * invite/create + * i/import-user-lists * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['invite/create']; + post: operations['i/import-user-lists']; }; - '/invite/delete': { + '/i/import-antennas': { /** - * invite/delete + * i/import-antennas * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['invite/delete']; + post: operations['i/import-antennas']; }; - '/invite/list': { + '/i/notifications': { /** - * invite/list + * i/notifications * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:notifications* */ - post: operations['invite/list']; + post: operations['i/notifications']; }; - '/invite/limit': { + '/i/notifications-grouped': { /** - * invite/limit + * i/notifications-grouped * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:notifications* */ - post: operations['invite/limit']; + post: operations['i/notifications-grouped']; }; - '/messaging/history': { + '/i/page-likes': { /** - * messaging/history + * i/page-likes * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:messaging* + * **Credential required**: *Yes* / **Permission**: *read:page-likes* */ - post: operations['messaging/history']; + post: operations['i/page-likes']; }; - '/messaging/messages': { + '/i/pages': { /** - * messaging/messages + * i/pages * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:messaging* + * **Credential required**: *Yes* / **Permission**: *read:pages* */ - post: operations['messaging/messages']; + post: operations['i/pages']; }; - '/messaging/messages/create': { + '/i/pin': { /** - * messaging/messages/create + * i/pin * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:messaging* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['messaging/messages/create']; + post: operations['i/pin']; }; - '/messaging/messages/delete': { + '/i/read-all-messaging-messages': { /** - * messaging/messages/delete + * i/read-all-messaging-messages * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:messaging* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['messaging/messages/delete']; + post: operations['i/read-all-messaging-messages']; }; - '/messaging/messages/read': { + '/i/read-all-unread-notes': { /** - * messaging/messages/read + * i/read-all-unread-notes * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:messaging* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['messaging/messages/read']; + post: operations['i/read-all-unread-notes']; }; - '/meta': { + '/i/read-announcement': { /** - * meta + * i/read-announcement * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['meta']; + post: operations['i/read-announcement']; }; - '/emojis': { + '/i/regenerate-token': { /** - * emojis + * i/regenerate-token * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - get: operations['emojis']; + post: operations['i/regenerate-token']; + }; + '/i/registry/get-all': { /** - * emojis + * i/registry/get-all * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['emojis']; + post: operations['i/registry/get-all']; }; - '/emoji': { + '/i/registry/get-detail': { /** - * emoji + * i/registry/get-detail * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - get: operations['emoji']; + post: operations['i/registry/get-detail']; + }; + '/i/registry/get': { /** - * emoji + * i/registry/get * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['emoji']; + post: operations['i/registry/get']; }; - '/mute/create': { + '/i/registry/keys-with-type': { /** - * mute/create + * i/registry/keys-with-type * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:mutes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['mute/create']; + post: operations['i/registry/keys-with-type']; }; - '/mute/delete': { + '/i/registry/keys': { /** - * mute/delete + * i/registry/keys * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:mutes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['mute/delete']; + post: operations['i/registry/keys']; }; - '/mute/list': { + '/i/registry/remove': { /** - * mute/list + * i/registry/remove * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:mutes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['mute/list']; + post: operations['i/registry/remove']; }; - '/renote-mute/create': { + '/i/registry/scopes-with-domain': { /** - * renote-mute/create + * i/registry/scopes-with-domain * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:mutes* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['renote-mute/create']; + post: operations['i/registry/scopes-with-domain']; }; - '/renote-mute/delete': { + '/i/registry/set': { /** - * renote-mute/delete + * i/registry/set * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:mutes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['renote-mute/delete']; + post: operations['i/registry/set']; }; - '/renote-mute/list': { + '/i/revoke-token': { /** - * renote-mute/list + * i/revoke-token * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:mutes* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['renote-mute/list']; + post: operations['i/revoke-token']; }; - '/my/apps': { + '/i/signin-history': { /** - * my/apps + * i/signin-history * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['my/apps']; + post: operations['i/signin-history']; }; - '/notes': { + '/i/unpin': { /** - * notes + * i/unpin * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['notes']; + post: operations['i/unpin']; }; - '/notes/children': { + '/i/update-email': { /** - * notes/children + * i/update-email * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['notes/children']; + post: operations['i/update-email']; }; - '/notes/clips': { + '/i/update': { /** - * notes/clips + * i/update * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['notes/clips']; + post: operations['i/update']; }; - '/notes/conversation': { + '/i/user-group-invites': { /** - * notes/conversation + * i/user-group-invites * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:user-groups* */ - post: operations['notes/conversation']; + post: operations['i/user-group-invites']; }; - '/notes/create': { + '/i/move': { /** - * notes/create + * i/move * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:notes* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['notes/create']; + post: operations['i/move']; }; - '/notes/delete': { + '/i/webhooks/create': { /** - * notes/delete + * i/webhooks/create * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:notes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['notes/delete']; + post: operations['i/webhooks/create']; }; - '/notes/update': { + '/i/webhooks/list': { /** - * notes/update + * i/webhooks/list * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:notes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['notes/update']; + post: operations['i/webhooks/list']; }; - '/notes/favorites/create': { + '/i/webhooks/show': { /** - * notes/favorites/create + * i/webhooks/show * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:favorites* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['notes/favorites/create']; + post: operations['i/webhooks/show']; }; - '/notes/favorites/delete': { + '/i/webhooks/update': { /** - * notes/favorites/delete + * i/webhooks/update * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:favorites* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['notes/favorites/delete']; + post: operations['i/webhooks/update']; }; - '/notes/featured': { + '/i/webhooks/delete': { /** - * notes/featured + * i/webhooks/delete * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - get: operations['notes/featured']; + post: operations['i/webhooks/delete']; + }; + '/invite/create': { /** - * notes/featured + * invite/create * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:invite-codes* */ - post: operations['notes/featured']; + post: operations['invite/create']; }; - '/notes/global-timeline': { + '/invite/delete': { /** - * notes/global-timeline + * invite/delete * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:invite-codes* */ - post: operations['notes/global-timeline']; + post: operations['invite/delete']; }; - '/notes/hybrid-timeline': { + '/invite/list': { /** - * notes/hybrid-timeline + * invite/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:invite-codes* */ - post: operations['notes/hybrid-timeline']; + post: operations['invite/list']; }; - '/notes/local-timeline': { + '/invite/limit': { /** - * notes/local-timeline + * invite/limit * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:invite-codes* */ - post: operations['notes/local-timeline']; + post: operations['invite/limit']; }; - '/notes/mentions': { + '/messaging/history': { /** - * notes/mentions + * messaging/history * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:messaging* */ - post: operations['notes/mentions']; + post: operations['messaging/history']; }; - '/notes/polls/recommendation': { + '/messaging/messages': { /** - * notes/polls/recommendation + * messaging/messages * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:messaging* */ - post: operations['notes/polls/recommendation']; + post: operations['messaging/messages']; }; - '/notes/polls/vote': { + '/messaging/messages/create': { /** - * notes/polls/vote + * messaging/messages/create * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:votes* + * **Credential required**: *Yes* / **Permission**: *write:messaging* */ - post: operations['notes/polls/vote']; + post: operations['messaging/messages/create']; }; - '/notes/events/search': { + '/messaging/messages/delete': { /** - * notes/events/search + * messaging/messages/delete * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:messaging* */ - post: operations['notes/events/search']; + post: operations['messaging/messages/delete']; }; - '/notes/reactions': { + '/messaging/messages/read': { /** - * notes/reactions + * messaging/messages/read * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:messaging* */ - get: operations['notes/reactions']; + post: operations['messaging/messages/read']; + }; + '/meta': { /** - * notes/reactions + * meta * @description No description provided. * * **Credential required**: *No* */ - post: operations['notes/reactions']; + post: operations['meta']; }; - '/notes/reactions/create': { + '/emojis': { /** - * notes/reactions/create + * emojis * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:reactions* + * **Credential required**: *No* */ - post: operations['notes/reactions/create']; - }; - '/notes/reactions/delete': { + get: operations['emojis']; /** - * notes/reactions/delete + * emojis * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:reactions* + * **Credential required**: *No* */ - post: operations['notes/reactions/delete']; + post: operations['emojis']; }; - '/notes/renotes': { + '/emoji': { /** - * notes/renotes + * emoji * @description No description provided. * * **Credential required**: *No* */ - post: operations['notes/renotes']; - }; - '/notes/replies': { + get: operations['emoji']; /** - * notes/replies + * emoji * @description No description provided. * * **Credential required**: *No* */ - post: operations['notes/replies']; + post: operations['emoji']; }; - '/notes/search-by-tag': { + '/miauth/gen-token': { /** - * notes/search-by-tag + * miauth/gen-token * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['notes/search-by-tag']; + post: operations['miauth/gen-token']; }; - '/notes/search': { + '/mute/create': { /** - * notes/search + * mute/create * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:mutes* */ - post: operations['notes/search']; + post: operations['mute/create']; }; - '/notes/show': { + '/mute/delete': { /** - * notes/show + * mute/delete * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:mutes* */ - post: operations['notes/show']; + post: operations['mute/delete']; }; - '/notes/state': { + '/mute/list': { /** - * notes/state + * mute/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:mutes* */ - post: operations['notes/state']; + post: operations['mute/list']; }; - '/notes/thread-muting/create': { + '/renote-mute/create': { /** - * notes/thread-muting/create + * renote-mute/create * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *Yes* / **Permission**: *write:mutes* */ - post: operations['notes/thread-muting/create']; + post: operations['renote-mute/create']; }; - '/notes/thread-muting/delete': { + '/renote-mute/delete': { /** - * notes/thread-muting/delete + * renote-mute/delete * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *Yes* / **Permission**: *write:mutes* */ - post: operations['notes/thread-muting/delete']; + post: operations['renote-mute/delete']; }; - '/notes/timeline': { + '/renote-mute/list': { /** - * notes/timeline + * renote-mute/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:mutes* */ - post: operations['notes/timeline']; + post: operations['renote-mute/list']; }; - '/notes/translate': { + '/my/apps': { /** - * notes/translate + * my/apps * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['notes/translate']; + post: operations['my/apps']; }; - '/notes/unrenote': { + '/notes': { /** - * notes/unrenote + * notes * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:notes* + * **Credential required**: *No* */ - post: operations['notes/unrenote']; + post: operations['notes']; }; - '/notes/user-list-timeline': { + '/notes/children': { /** - * notes/user-list-timeline + * notes/children * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - post: operations['notes/user-list-timeline']; + post: operations['notes/children']; }; - '/notifications/create': { + '/notes/clips': { /** - * notifications/create + * notes/clips * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:notifications* + * **Credential required**: *No* */ - post: operations['notifications/create']; + post: operations['notes/clips']; }; - '/notifications/mark-all-as-read': { + '/notes/conversation': { /** - * notifications/mark-all-as-read + * notes/conversation * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:notifications* + * **Credential required**: *No* */ - post: operations['notifications/mark-all-as-read']; + post: operations['notes/conversation']; }; - '/notifications/test-notification': { + '/notes/create': { /** - * notifications/test-notification + * notes/create * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:notifications* + * **Credential required**: *Yes* / **Permission**: *write:notes* */ - post: operations['notifications/test-notification']; + post: operations['notes/create']; }; - '/pages/create': { + '/notes/delete': { /** - * pages/create + * notes/delete * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:pages* + * **Credential required**: *Yes* / **Permission**: *write:notes* */ - post: operations['pages/create']; + post: operations['notes/delete']; }; - '/pages/delete': { + '/notes/update': { /** - * pages/delete + * notes/update * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:pages* + * **Credential required**: *Yes* / **Permission**: *write:notes* */ - post: operations['pages/delete']; + post: operations['notes/update']; }; - '/pages/featured': { + '/notes/favorites/create': { /** - * pages/featured + * notes/favorites/create * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:favorites* */ - post: operations['pages/featured']; + post: operations['notes/favorites/create']; }; - '/pages/like': { + '/notes/favorites/delete': { /** - * pages/like + * notes/favorites/delete * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:page-likes* + * **Credential required**: *Yes* / **Permission**: *write:favorites* */ - post: operations['pages/like']; + post: operations['notes/favorites/delete']; }; - '/pages/show': { + '/notes/featured': { /** - * pages/show + * notes/featured * @description No description provided. * * **Credential required**: *No* */ - post: operations['pages/show']; - }; - '/pages/unlike': { + get: operations['notes/featured']; /** - * pages/unlike + * notes/featured * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:page-likes* + * **Credential required**: *No* */ - post: operations['pages/unlike']; + post: operations['notes/featured']; }; - '/pages/update': { + '/notes/global-timeline': { /** - * pages/update + * notes/global-timeline * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:pages* + * **Credential required**: *No* */ - post: operations['pages/update']; + post: operations['notes/global-timeline']; }; - '/flash/create': { + '/notes/hybrid-timeline': { /** - * flash/create + * notes/hybrid-timeline * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:flash* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['flash/create']; + post: operations['notes/hybrid-timeline']; }; - '/flash/delete': { + '/notes/local-timeline': { /** - * flash/delete + * notes/local-timeline * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:flash* + * **Credential required**: *No* */ - post: operations['flash/delete']; + post: operations['notes/local-timeline']; }; - '/flash/featured': { + '/notes/mentions': { /** - * flash/featured + * notes/mentions * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['flash/featured']; + post: operations['notes/mentions']; }; - '/flash/like': { + '/notes/polls/recommendation': { /** - * flash/like + * notes/polls/recommendation * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:flash-likes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['flash/like']; + post: operations['notes/polls/recommendation']; }; - '/flash/show': { + '/notes/polls/vote': { /** - * flash/show + * notes/polls/vote * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:votes* */ - post: operations['flash/show']; + post: operations['notes/polls/vote']; }; - '/flash/unlike': { + '/notes/events/search': { /** - * flash/unlike + * notes/events/search * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:flash-likes* + * **Credential required**: *No* */ - post: operations['flash/unlike']; + post: operations['notes/events/search']; }; - '/flash/update': { + '/notes/reactions': { /** - * flash/update + * notes/reactions * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:flash* + * **Credential required**: *No* */ - post: operations['flash/update']; - }; - '/flash/my': { + get: operations['notes/reactions']; /** - * flash/my + * notes/reactions * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:flash* + * **Credential required**: *No* */ - post: operations['flash/my']; + post: operations['notes/reactions']; }; - '/flash/my-likes': { + '/notes/reactions/create': { /** - * flash/my-likes + * notes/reactions/create * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:flash-likes* + * **Credential required**: *Yes* / **Permission**: *write:reactions* */ - post: operations['flash/my-likes']; + post: operations['notes/reactions/create']; }; - '/ping': { + '/notes/reactions/delete': { /** - * ping + * notes/reactions/delete * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:reactions* */ - post: operations['ping']; + post: operations['notes/reactions/delete']; }; - '/pinned-users': { + '/notes/renotes': { /** - * pinned-users + * notes/renotes * @description No description provided. * * **Credential required**: *No* */ - post: operations['pinned-users']; + post: operations['notes/renotes']; }; - '/promo/read': { + '/notes/replies': { /** - * promo/read + * notes/replies * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - post: operations['promo/read']; + post: operations['notes/replies']; }; - '/roles/list': { + '/notes/search-by-tag': { /** - * roles/list + * notes/search-by-tag * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - post: operations['roles/list']; + post: operations['notes/search-by-tag']; }; - '/roles/show': { + '/notes/search': { /** - * roles/show + * notes/search * @description No description provided. * * **Credential required**: *No* */ - post: operations['roles/show']; + post: operations['notes/search']; }; - '/roles/users': { + '/notes/show': { /** - * roles/users + * notes/show * @description No description provided. * * **Credential required**: *No* */ - post: operations['roles/users']; + post: operations['notes/show']; }; - '/roles/notes': { + '/notes/state': { /** - * roles/notes + * notes/state * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['roles/notes']; + post: operations['notes/state']; }; - '/request-reset-password': { + '/notes/thread-muting/create': { /** - * request-reset-password - * @description Request a users password to be reset. + * notes/thread-muting/create + * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['request-reset-password']; + post: operations['notes/thread-muting/create']; }; - '/reset-db': { + '/notes/thread-muting/delete': { /** - * reset-db - * @description Only available when running with NODE_ENV=testing. Reset the database and flush Redis. + * notes/thread-muting/delete + * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['reset-db']; + post: operations['notes/thread-muting/delete']; }; - '/reset-password': { + '/notes/timeline': { /** - * reset-password - * @description Complete the password reset that was previously requested. + * notes/timeline + * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['reset-password']; + post: operations['notes/timeline']; }; - '/server-info': { + '/notes/translate': { /** - * server-info + * notes/translate * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - get: operations['server-info']; + post: operations['notes/translate']; + }; + '/notes/unrenote': { /** - * server-info + * notes/unrenote * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:notes* */ - post: operations['server-info']; + post: operations['notes/unrenote']; }; - '/stats': { + '/notes/user-list-timeline': { /** - * stats + * notes/user-list-timeline * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['stats']; + post: operations['notes/user-list-timeline']; }; - '/sw/show-registration': { + '/notifications/create': { /** - * sw/show-registration - * @description Check push notification registration exists. + * notifications/create + * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:notifications* */ - post: operations['sw/show-registration']; + post: operations['notifications/create']; }; - '/sw/update-registration': { + '/notifications/mark-all-as-read': { /** - * sw/update-registration - * @description Update push notification registration. + * notifications/mark-all-as-read + * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:notifications* */ - post: operations['sw/update-registration']; + post: operations['notifications/mark-all-as-read']; }; - '/sw/register': { + '/notifications/test-notification': { /** - * sw/register - * @description Register to receive push notifications. + * notifications/test-notification + * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:notifications* */ - post: operations['sw/register']; + post: operations['notifications/test-notification']; }; - '/sw/unregister': { + '/page-push': { /** - * sw/unregister - * @description Unregister from receiving push notifications. + * page-push + * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['sw/unregister']; + post: operations['page-push']; }; - '/test': { + '/pages/create': { /** - * test - * @description Endpoint for testing input validation. + * pages/create + * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:pages* */ - post: operations['test']; + post: operations['pages/create']; }; - '/username/available': { + '/pages/delete': { /** - * username/available + * pages/delete * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:pages* */ - post: operations['username/available']; + post: operations['pages/delete']; }; - '/users': { + '/pages/featured': { /** - * users + * pages/featured * @description No description provided. * * **Credential required**: *No* */ - post: operations['users']; + post: operations['pages/featured']; }; - '/users/clips': { + '/pages/like': { /** - * users/clips - * @description Show all clips this user owns. + * pages/like + * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:page-likes* */ - post: operations['users/clips']; + post: operations['pages/like']; }; - '/users/followers': { + '/pages/show': { /** - * users/followers - * @description Show everyone that follows this user. + * pages/show + * @description No description provided. * * **Credential required**: *No* */ - post: operations['users/followers']; + post: operations['pages/show']; }; - '/users/following': { + '/pages/unlike': { /** - * users/following - * @description Show everyone that this user is following. + * pages/unlike + * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:page-likes* */ - post: operations['users/following']; + post: operations['pages/unlike']; }; - '/users/gallery/posts': { + '/pages/update': { /** - * users/gallery/posts - * @description Show all gallery posts by the given user. + * pages/update + * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:pages* */ - post: operations['users/gallery/posts']; + post: operations['pages/update']; }; - '/users/get-frequently-replied-users': { + '/flash/create': { /** - * users/get-frequently-replied-users - * @description Get a list of other users that the specified user frequently replies to. + * flash/create + * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:flash* */ - post: operations['users/get-frequently-replied-users']; + post: operations['flash/create']; }; - '/users/featured-notes': { + '/flash/delete': { /** - * users/featured-notes + * flash/delete * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:flash* */ - get: operations['users/featured-notes']; + post: operations['flash/delete']; + }; + '/flash/featured': { /** - * users/featured-notes + * flash/featured * @description No description provided. * * **Credential required**: *No* */ - post: operations['users/featured-notes']; + post: operations['flash/featured']; }; - '/users/groups/create': { + '/flash/gen-token': { /** - * users/groups/create - * @description Create a new group. + * flash/gen-token + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['users/groups/create']; + post: operations['flash/gen-token']; }; - '/users/groups/delete': { + '/flash/like': { /** - * users/groups/delete - * @description Delete an existing group. + * flash/like + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Credential required**: *Yes* / **Permission**: *write:flash-likes* */ - post: operations['users/groups/delete']; + post: operations['flash/like']; }; - '/users/groups/invitations/accept': { + '/flash/show': { /** - * users/groups/invitations/accept + * flash/show * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Credential required**: *No* */ - post: operations['users/groups/invitations/accept']; + post: operations['flash/show']; }; - '/users/groups/invitations/reject': { + '/flash/unlike': { /** - * users/groups/invitations/reject + * flash/unlike * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Credential required**: *Yes* / **Permission**: *write:flash-likes* */ - post: operations['users/groups/invitations/reject']; + post: operations['flash/unlike']; }; - '/users/groups/invite': { + '/flash/update': { /** - * users/groups/invite - * @description Invite a user to an existing group. + * flash/update + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Credential required**: *Yes* / **Permission**: *write:flash* */ - post: operations['users/groups/invite']; + post: operations['flash/update']; }; - '/users/groups/joined': { + '/flash/my': { /** - * users/groups/joined - * @description List the groups that the authenticated user is a member of. + * flash/my + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:user-groups* + * **Credential required**: *Yes* / **Permission**: *read:flash* */ - post: operations['users/groups/joined']; + post: operations['flash/my']; }; - '/users/groups/leave': { + '/flash/my-likes': { /** - * users/groups/leave - * @description Leave a group. The owner of a group can not leave. They must transfer ownership or delete the group instead. + * flash/my-likes + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Credential required**: *Yes* / **Permission**: *read:flash-likes* */ - post: operations['users/groups/leave']; + post: operations['flash/my-likes']; }; - '/users/groups/owned': { + '/ping': { /** - * users/groups/owned - * @description List the groups that the authenticated user is the owner of. + * ping + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:user-groups* + * **Credential required**: *No* */ - post: operations['users/groups/owned']; + post: operations['ping']; }; - '/users/groups/pull': { + '/pinned-users': { /** - * users/groups/pull - * @description Removes a specified user from a group. The owner can not be removed. + * pinned-users + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Credential required**: *No* */ - post: operations['users/groups/pull']; + post: operations['pinned-users']; }; - '/users/groups/show': { + '/promo/read': { /** - * users/groups/show - * @description Show the properties of a group. + * promo/read + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:user-groups* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['users/groups/show']; + post: operations['promo/read']; }; - '/users/groups/transfer': { + '/roles/list': { /** - * users/groups/transfer - * @description Transfer ownership of a group from the authenticated user to another user. + * roles/list + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['users/groups/transfer']; + post: operations['roles/list']; }; - '/users/groups/update': { + '/roles/show': { /** - * users/groups/update - * @description Update the properties of a group. + * roles/show + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:user-groups* + * **Credential required**: *No* */ - post: operations['users/groups/update']; + post: operations['roles/show']; }; - '/users/lists/create': { + '/roles/users': { /** - * users/lists/create - * @description Create a new list of users. + * roles/users + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - post: operations['users/lists/create']; + post: operations['roles/users']; }; - '/users/lists/delete': { + '/roles/notes': { /** - * users/lists/delete - * @description Delete an existing list of users. + * roles/notes + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - post: operations['users/lists/delete']; + post: operations['roles/notes']; }; - '/users/lists/list': { + '/request-reset-password': { /** - * users/lists/list - * @description Show all lists that the authenticated user has created. + * request-reset-password + * @description Request a users password to be reset. * - * **Credential required**: *No* / **Permission**: *read:account* + * **Credential required**: *No* */ - post: operations['users/lists/list']; + post: operations['request-reset-password']; }; - '/users/lists/pull': { + '/reset-db': { /** - * users/lists/pull - * @description Remove a user from a list. + * reset-db + * @description Only available when running with NODE_ENV=testing. Reset the database and flush Redis. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - post: operations['users/lists/pull']; + post: operations['reset-db']; }; - '/users/lists/push': { + '/reset-password': { /** - * users/lists/push - * @description Add a user to an existing list. + * reset-password + * @description Complete the password reset that was previously requested. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - post: operations['users/lists/push']; + post: operations['reset-password']; }; - '/users/lists/show': { + '/server-info': { /** - * users/lists/show - * @description Show the properties of a list. + * server-info + * @description No description provided. * - * **Credential required**: *No* / **Permission**: *read:account* + * **Credential required**: *No* */ - post: operations['users/lists/show']; - }; - '/users/lists/favorite': { + get: operations['server-info']; /** - * users/lists/favorite + * server-info * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - post: operations['users/lists/favorite']; + post: operations['server-info']; }; - '/users/lists/unfavorite': { + '/stats': { /** - * users/lists/unfavorite + * stats * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - post: operations['users/lists/unfavorite']; + post: operations['stats']; }; - '/users/lists/update': { + '/sw/show-registration': { /** - * users/lists/update - * @description Update the properties of a list. + * sw/show-registration + * @description Check push notification registration exists. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['users/lists/update']; + post: operations['sw/show-registration']; }; - '/users/lists/create-from-public': { + '/sw/update-registration': { /** - * users/lists/create-from-public - * @description No description provided. + * sw/update-registration + * @description Update push notification registration. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - post: operations['users/lists/create-from-public']; + post: operations['sw/update-registration']; }; - '/users/lists/update-membership': { + '/sw/register': { /** - * users/lists/update-membership - * @description No description provided. + * sw/register + * @description Register to receive push notifications. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - post: operations['users/lists/update-membership']; + post: operations['sw/register']; }; - '/users/lists/get-memberships': { + '/sw/unregister': { /** - * users/lists/get-memberships - * @description No description provided. + * sw/unregister + * @description Unregister from receiving push notifications. * - * **Credential required**: *No* / **Permission**: *read:account* + * **Credential required**: *No* */ - post: operations['users/lists/get-memberships']; + post: operations['sw/unregister']; }; - '/users/notes': { + '/test': { /** - * users/notes - * @description No description provided. + * test + * @description Endpoint for testing input validation. * * **Credential required**: *No* */ - post: operations['users/notes']; + post: operations['test']; }; - '/users/pages': { + '/username/available': { /** - * users/pages - * @description Show all pages this user created. + * username/available + * @description No description provided. * * **Credential required**: *No* */ - post: operations['users/pages']; + post: operations['username/available']; }; - '/users/flashs': { + '/users': { /** - * users/flashs - * @description Show all flashs this user created. + * users + * @description No description provided. * * **Credential required**: *No* */ - post: operations['users/flashs']; + post: operations['users']; }; - '/users/reactions': { + '/users/clips': { /** - * users/reactions - * @description Show all reactions this user made. + * users/clips + * @description Show all clips this user owns. * * **Credential required**: *No* */ - post: operations['users/reactions']; + post: operations['users/clips']; }; - '/users/recommendation': { + '/users/followers': { /** - * users/recommendation - * @description Show users that the authenticated user might be interested to follow. + * users/followers + * @description Show everyone that follows this user. * - * **Credential required**: *Yes* / **Permission**: *read:account* + * **Credential required**: *No* */ - post: operations['users/recommendation']; + post: operations['users/followers']; }; - '/users/relation': { + '/users/following': { /** - * users/relation - * @description Show the different kinds of relations between the authenticated user and the specified user(s). + * users/following + * @description Show everyone that this user is following. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - post: operations['users/relation']; + post: operations['users/following']; }; - '/users/report-abuse': { + '/users/gallery/posts': { /** - * users/report-abuse - * @description File a report. + * users/gallery/posts + * @description Show all gallery posts by the given user. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - post: operations['users/report-abuse']; + post: operations['users/gallery/posts']; }; - '/users/search-by-username-and-host': { + '/users/get-frequently-replied-users': { /** - * users/search-by-username-and-host - * @description Search for a user by username and/or host. + * users/get-frequently-replied-users + * @description Get a list of other users that the specified user frequently replies to. * * **Credential required**: *No* */ - post: operations['users/search-by-username-and-host']; + post: operations['users/get-frequently-replied-users']; }; - '/users/search': { + '/users/featured-notes': { /** - * users/search - * @description Search for users. + * users/featured-notes + * @description No description provided. * * **Credential required**: *No* */ - post: operations['users/search']; - }; - '/users/show': { + get: operations['users/featured-notes']; /** - * users/show - * @description Show the properties of a user. + * users/featured-notes + * @description No description provided. * * **Credential required**: *No* */ - post: operations['users/show']; + post: operations['users/featured-notes']; }; - '/users/stats': { + '/users/groups/create': { /** - * users/stats - * @description Show statistics about a user. + * users/groups/create + * @description Create a new group. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:user-groups* */ - post: operations['users/stats']; + post: operations['users/groups/create']; }; - '/users/achievements': { + '/users/groups/delete': { /** - * users/achievements + * users/groups/delete + * @description Delete an existing group. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + post: operations['users/groups/delete']; + }; + '/users/groups/invitations/accept': { + /** + * users/groups/invitations/accept * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:user-groups* */ - post: operations['users/achievements']; + post: operations['users/groups/invitations/accept']; }; - '/users/update-memo': { + '/users/groups/invitations/reject': { /** - * users/update-memo + * users/groups/invitations/reject * @description No description provided. * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + post: operations['users/groups/invitations/reject']; + }; + '/users/groups/invite': { + /** + * users/groups/invite + * @description Invite a user to an existing group. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + post: operations['users/groups/invite']; + }; + '/users/groups/joined': { + /** + * users/groups/joined + * @description List the groups that the authenticated user is a member of. + * + * **Credential required**: *Yes* / **Permission**: *read:user-groups* + */ + post: operations['users/groups/joined']; + }; + '/users/groups/leave': { + /** + * users/groups/leave + * @description Leave a group. The owner of a group can not leave. They must transfer ownership or delete the group instead. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + post: operations['users/groups/leave']; + }; + '/users/groups/owned': { + /** + * users/groups/owned + * @description List the groups that the authenticated user is the owner of. + * + * **Credential required**: *Yes* / **Permission**: *read:user-groups* + */ + post: operations['users/groups/owned']; + }; + '/users/groups/pull': { + /** + * users/groups/pull + * @description Removes a specified user from a group. The owner can not be removed. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + post: operations['users/groups/pull']; + }; + '/users/groups/show': { + /** + * users/groups/show + * @description Show the properties of a group. + * + * **Credential required**: *Yes* / **Permission**: *read:user-groups* + */ + post: operations['users/groups/show']; + }; + '/users/groups/transfer': { + /** + * users/groups/transfer + * @description Transfer ownership of a group from the authenticated user to another user. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + post: operations['users/groups/transfer']; + }; + '/users/groups/update': { + /** + * users/groups/update + * @description Update the properties of a group. + * + * **Credential required**: *Yes* / **Permission**: *write:user-groups* + */ + post: operations['users/groups/update']; + }; + '/users/lists/create': { + /** + * users/lists/create + * @description Create a new list of users. + * * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['users/update-memo']; + post: operations['users/lists/create']; }; - '/users/translate': { + '/users/lists/delete': { /** - * users/translate + * users/lists/delete + * @description Delete an existing list of users. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + post: operations['users/lists/delete']; + }; + '/users/lists/list': { + /** + * users/lists/list + * @description Show all lists that the authenticated user has created. + * + * **Credential required**: *No* / **Permission**: *read:account* + */ + post: operations['users/lists/list']; + }; + '/users/lists/pull': { + /** + * users/lists/pull + * @description Remove a user from a list. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + post: operations['users/lists/pull']; + }; + '/users/lists/push': { + /** + * users/lists/push + * @description Add a user to an existing list. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + post: operations['users/lists/push']; + }; + '/users/lists/show': { + /** + * users/lists/show + * @description Show the properties of a list. + * + * **Credential required**: *No* / **Permission**: *read:account* + */ + post: operations['users/lists/show']; + }; + '/users/lists/favorite': { + /** + * users/lists/favorite * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['users/translate']; + post: operations['users/lists/favorite']; }; - '/fetch-rss': { + '/users/lists/unfavorite': { /** - * fetch-rss + * users/lists/unfavorite * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - get: operations['fetch-rss']; + post: operations['users/lists/unfavorite']; + }; + '/users/lists/update': { /** - * fetch-rss + * users/lists/update + * @description Update the properties of a list. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + post: operations['users/lists/update']; + }; + '/users/lists/create-from-public': { + /** + * users/lists/create-from-public * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['fetch-rss']; + post: operations['users/lists/create-from-public']; }; - '/fetch-external-resources': { + '/users/lists/update-membership': { /** - * fetch-external-resources + * users/lists/update-membership * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - post: operations['fetch-external-resources']; + post: operations['users/lists/update-membership']; }; - '/retention': { + '/users/lists/get-memberships': { /** - * retention + * users/lists/get-memberships * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *No* / **Permission**: *read:account* */ - get: operations['retention']; + post: operations['users/lists/get-memberships']; + }; + '/users/notes': { /** - * retention + * users/notes * @description No description provided. * * **Credential required**: *No* */ - post: operations['retention']; + post: operations['users/notes']; }; -}; - -export type webhooks = Record; - + '/users/pages': { + /** + * users/pages + * @description Show all pages this user created. + * + * **Credential required**: *No* + */ + post: operations['users/pages']; + }; + '/users/flashs': { + /** + * users/flashs + * @description Show all flashs this user created. + * + * **Credential required**: *No* + */ + post: operations['users/flashs']; + }; + '/users/reactions': { + /** + * users/reactions + * @description Show all reactions this user made. + * + * **Credential required**: *No* + */ + post: operations['users/reactions']; + }; + '/users/recommendation': { + /** + * users/recommendation + * @description Show users that the authenticated user might be interested to follow. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + post: operations['users/recommendation']; + }; + '/users/relation': { + /** + * users/relation + * @description Show the different kinds of relations between the authenticated user and the specified user(s). + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + post: operations['users/relation']; + }; + '/users/report-abuse': { + /** + * users/report-abuse + * @description File a report. + * + * **Credential required**: *Yes* / **Permission**: *write:report-abuse* + */ + post: operations['users/report-abuse']; + }; + '/users/search-by-username-and-host': { + /** + * users/search-by-username-and-host + * @description Search for a user by username and/or host. + * + * **Credential required**: *No* + */ + post: operations['users/search-by-username-and-host']; + }; + '/users/search': { + /** + * users/search + * @description Search for users. + * + * **Credential required**: *No* + */ + post: operations['users/search']; + }; + '/users/show': { + /** + * users/show + * @description Show the properties of a user. + * + * **Credential required**: *No* + */ + post: operations['users/show']; + }; + '/users/stats': { + /** + * users/stats + * @description Show statistics about a user. + * + * **Credential required**: *No* + */ + post: operations['users/stats']; + }; + '/users/achievements': { + /** + * users/achievements + * @description No description provided. + * + * **Credential required**: *No* + */ + post: operations['users/achievements']; + }; + '/users/update-memo': { + /** + * users/update-memo + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + post: operations['users/update-memo']; + }; + '/users/translate': { + /** + * users/translate + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + post: operations['users/translate']; + }; + '/fetch-rss': { + /** + * fetch-rss + * @description No description provided. + * + * **Credential required**: *No* + */ + get: operations['fetch-rss']; + /** + * fetch-rss + * @description No description provided. + * + * **Credential required**: *No* + */ + post: operations['fetch-rss']; + }; + '/fetch-external-resources': { + /** + * fetch-external-resources + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + post: operations['fetch-external-resources']; + }; + '/retention': { + /** + * retention + * @description No description provided. + * + * **Credential required**: *No* + */ + get: operations['retention']; + /** + * retention + * @description No description provided. + * + * **Credential required**: *No* + */ + post: operations['retention']; + }; +}; + +export type webhooks = Record; + export type components = { schemas: { Error: { @@ -3397,9 +3771,9 @@ export type components = { id: string; angle?: number; flipH?: boolean; + offsetX?: number; + offsetY?: number; scale?: number; - moveX?: number; - moveY?: number; opacity?: number; /** Format: url */ url: string; @@ -3465,7 +3839,9 @@ export type components = { pinnedPage: components['schemas']['Page'] | null; publicReactions: boolean; /** @enum {string} */ - ffVisibility: 'public' | 'followers' | 'private'; + followingVisibility: 'public' | 'followers' | 'private'; + /** @enum {string} */ + followersVisibility: 'public' | 'followers' | 'private'; /** @default false */ twoFactorEnabled: boolean; /** @default false */ @@ -3553,18 +3929,10 @@ export type components = { /** @enum {string} */ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'list' | 'never'; }; - achievementEarned?: { - /** @enum {string} */ - type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'list' | 'never'; - }; receiveFollowRequest?: { /** @enum {string} */ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'list' | 'never'; }; - followRequestAccepted?: { - /** @enum {string} */ - type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'list' | 'never'; - }; groupInvited?: { /** @enum {string} */ type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'list' | 'never'; @@ -3600,6 +3968,7 @@ export type components = { userListLimit: number; userEachUserListsLimit: number; rateLimitFactor: number; + avatarDecorationLimit: number; }; email?: string | null; emailVerified?: boolean | null; @@ -3643,6 +4012,24 @@ export type components = { ownerId: string; userIds?: string[]; }; + Ad: { + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; + /** Format: date-time */ + expiresAt: string; + /** Format: date-time */ + startsAt: string; + place: string; + priority: string; + ratio: number; + url: string; + imageUrl: string; + memo: string; + dayOfWeek: number; + }; Announcement: { /** * Format: id @@ -3735,18 +4122,20 @@ export type components = { files?: components['schemas']['DriveFile'][]; tags?: string[]; poll?: Record | null; + event?: Record | null; /** * Format: id * @example xxxxxxxxxx */ channelId?: string | null; - channel?: { + channel?: ({ id: string; name: string; color: string; isSensitive: boolean; allowRenoteToExternal: boolean; - } | null; + userId: string | null; + }) | null; localOnly?: boolean; reactionAcceptance: string | null; reactions: Record; @@ -3787,7 +4176,7 @@ export type components = { /** Format: date-time */ createdAt: string; /** @enum {string} */ - type: 'note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped'; + type: 'note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped'; user?: components['schemas']['UserLite'] | null; /** Format: id */ userId?: string | null; @@ -4295,168 +4684,2175 @@ export type components = { priority: number; useDefault: boolean; }; - canManageCustomEmojis: { - value: number | boolean; - priority: number; - useDefault: boolean; + canManageCustomEmojis: { + value: number | boolean; + priority: number; + useDefault: boolean; + }; + userEachUserListsLimit: { + value: number | boolean; + priority: number; + useDefault: boolean; + }; + canManageAvatarDecorations: { + value: number | boolean; + priority: number; + useDefault: boolean; + }; + canUseTranslator: { + value: number | boolean; + priority: number; + useDefault: boolean; + }; + avatarDecorationLimit: { + value: number | boolean; + priority: number; + useDefault: boolean; + }; + }; + usersCount: number; + }); + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +}; + +export type $defs = Record; + +export type external = Record; + +export type operations = { + + /** + * admin/meta + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:meta* + */ + 'admin/meta': { + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + cacheRemoteFiles: boolean; + cacheRemoteSensitiveFiles: boolean; + emailRequiredForSignup: boolean; + enableHcaptcha: boolean; + hcaptchaSiteKey: string | null; + enableMcaptcha: boolean; + mcaptchaSiteKey: string | null; + mcaptchaInstanceUrl: string | null; + enableRecaptcha: boolean; + recaptchaSiteKey: string | null; + enableTurnstile: boolean; + turnstileSiteKey: string | null; + swPublickey: string | null; + /** @default /assets/ai.png */ + mascotImageUrl: string | null; + bannerUrl: string | null; + serverErrorImageUrl: string | null; + infoImageUrl: string | null; + notFoundImageUrl: string | null; + iconUrl: string | null; + app192IconUrl: string | null; + app512IconUrl: string | null; + enableEmail: boolean; + enableServiceWorker: boolean; + translatorAvailable: boolean; + translatorType: string | null; + silencedHosts?: string[]; + pinnedUsers: string[]; + hiddenTags: string[]; + blockedHosts: string[]; + sensitiveWords: string[]; + bannedEmailDomains?: string[]; + preservedUsernames: string[]; + hcaptchaSecretKey: string | null; + mcaptchaSecretKey: string | null; + recaptchaSecretKey: string | null; + turnstileSecretKey: string | null; + sensitiveMediaDetection: string; + sensitiveMediaDetectionSensitivity: string; + setSensitiveFlagAutomatically: boolean; + enableSensitiveMediaDetectionForVideos: boolean; + /** Format: id */ + proxyAccountId: string | null; + email: string | null; + smtpSecure: boolean; + smtpHost: string | null; + smtpPort: number | null; + smtpUser: string | null; + smtpPass: string | null; + swPrivateKey: string | null; + useObjectStorage: boolean; + objectStorageBaseUrl: string | null; + objectStorageBucket: string | null; + objectStoragePrefix: string | null; + objectStorageEndpoint: string | null; + objectStorageRegion: string | null; + objectStoragePort: number | null; + objectStorageAccessKey: string | null; + objectStorageSecretKey: string | null; + objectStorageUseSSL: boolean; + objectStorageUseProxy: boolean; + objectStorageSetPublicRead: boolean; + useObjectStorageRemote?: boolean; + objectStorageRemoteBaseUrl?: string | null; + objectStorageRemoteBucket?: string | null; + objectStorageRemotePrefix?: string | null; + objectStorageRemoteEndpoint?: string | null; + objectStorageRemoteRegion?: string | null; + objectStorageRemotePort?: number | null; + objectStorageRemoteAccessKey?: string | null; + objectStorageRemoteSecretKey?: string | null; + objectStorageRemoteUseSSL?: boolean; + objectStorageRemoteUseProxy?: boolean; + objectStorageRemoteSetPublicRead?: boolean; + enableIpLogging: boolean; + enableActiveEmailValidation: boolean; + enableVerifymailApi: boolean; + verifymailAuthKey: string | null; + enableTruemailApi: boolean; + truemailInstance: string | null; + truemailAuthKey: string | null; + enableChartsForRemoteUser: boolean; + enableChartsForFederatedInstances: boolean; + enableServerMachineStats: boolean; + enableIdenticonGeneration: boolean; + manifestJsonOverride: string; + policies: Record; + enableFanoutTimeline: boolean; + enableFanoutTimelineDbFallback: boolean; + perLocalUserUserTimelineCacheMax: number; + perRemoteUserUserTimelineCacheMax: number; + perUserHomeTimelineCacheMax: number; + perUserListTimelineCacheMax: number; + notesPerOneAd: number; + backgroundImageUrl: string | null; + deeplAuthKey: string | null; + deeplIsPro: boolean; + defaultDarkTheme: string | null; + defaultLightTheme: string | null; + description: string | null; + disableRegistration: boolean; + impressumUrl: string | null; + maintainerEmail: string | null; + maintainerName: string | null; + name: string | null; + shortName: string | null; + objectStorageS3ForcePathStyle: boolean; + objectStorageRemoteS3ForcePathStyle: boolean; + privacyPolicyUrl: string | null; + repositoryUrl: string; + summalyProxy: string | null; + themeColor: string | null; + tosUrl: string | null; + uri: string; + version: string; + doNotSendNotificationEmailsForAbuseReport: boolean; + emailToReceiveAbuseReport: string | null; + enableReceivePrerelease: boolean; + skipVersion: boolean; + skipCherryPickVersion?: string | null; + }; + }; + }; + /** @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/abuse-report-resolver/create + * @description No description provided. + * + * **Credential required**: *Yes* + */ + 'admin/abuse-report-resolver/create': { + requestBody: { + content: { + 'application/json': { + name: string; + targetUserPattern: string | null; + reporterPattern: string | null; + reportContentPattern: string | null; + /** @enum {string} */ + expiresAt: '1hour' | '12hours' | '1day' | '1week' | '1month' | '3months' | '6months' | '1year' | 'indefinitely'; + forward: boolean; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + name: string; + targetUserPattern: string | null; + reporterPattern: string | null; + reportContentPattern: string | null; + expiresAt: string; + forward: boolean; + }; + }; + }; + /** @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/abuse-report-resolver/list + * @description No description provided. + * + * **Credential required**: *Yes* + */ + 'admin/abuse-report-resolver/list': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ({ + name: string; + targetUserPattern: string | null; + reporterPattern: string | null; + reportContentPattern: string | null; + expiresAt: string; + forward: boolean; + })[]; + }; + }; + /** @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/abuse-report-resolver/delete + * @description No description provided. + * + * **Credential required**: *No* + */ + 'admin/abuse-report-resolver/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + resolverId: 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/abuse-report-resolver/update + * @description No description provided. + * + * **Credential required**: *Yes* + */ + 'admin/abuse-report-resolver/update': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + resolverId: string; + name?: string; + targetUserPattern?: string | null; + reporterPattern?: string | null; + reportContentPattern?: string | null; + /** @enum {string} */ + expiresAt?: '1hour' | '12hours' | '1day' | '1week' | '1month' | '3months' | '6months' | '1year' | 'indefinitely'; + forward?: boolean; + }; + }; + }; + 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/abuse-user-reports + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-user-reports* + */ + 'admin/abuse-user-reports': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default null */ + state?: string | null; + /** + * @default combined + * @enum {string} + */ + reporterOrigin?: 'combined' | 'local' | 'remote'; + /** + * @default combined + * @enum {string} + */ + targetUserOrigin?: 'combined' | 'local' | 'remote'; + /** @default false */ + forwarded?: boolean; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ({ + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; + /** Format: date-time */ + createdAt: string; + comment: string; + /** @example false */ + resolved: boolean; + /** Format: id */ + reporterId: string; + /** Format: id */ + targetUserId: string; + /** Format: id */ + assigneeId: string | null; + reporter: components['schemas']['User']; + targetUser: components['schemas']['User']; + assignee?: components['schemas']['User'] | null; + })[]; + }; + }; + /** @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/accounts/create + * @description No description provided. + * + * **Credential required**: *No* + */ + 'admin/accounts/create': { + requestBody: { + content: { + 'application/json': { + username: string; + password: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['User']; + }; + }; + /** @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/accounts/delete + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:account* + */ + 'admin/accounts/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + userId: 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/accounts/find-by-email + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:account* + */ + 'admin/accounts/find-by-email': { + requestBody: { + content: { + 'application/json': { + email: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['User']; + }; + }; + /** @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/ad/create + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* + */ + 'admin/ad/create': { + requestBody: { + content: { + 'application/json': { + url: string; + memo: string; + place: string; + priority: string; + ratio: number; + expiresAt: number; + startsAt: number; + imageUrl: string; + dayOfWeek: number; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Ad']; + }; + }; + /** @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/ad/delete + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* + */ + 'admin/ad/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: 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/ad/list + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:ad* + */ + 'admin/ad/list': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default null */ + publishing?: boolean | null; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Ad'][]; + }; + }; + /** @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/ad/update + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:ad* + */ + 'admin/ad/update': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + memo: string; + url: string; + imageUrl: string; + place: string; + priority: string; + ratio: number; + expiresAt: number; + startsAt: number; + dayOfWeek: number; + }; + }; + }; + 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/announcements/create + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* + */ + 'admin/announcements/create': { + requestBody: { + content: { + 'application/json': { + title: string; + text: string; + imageUrl: string | null; + /** + * @default info + * @enum {string} + */ + icon?: 'info' | 'warning' | 'error' | 'success'; + /** + * @default normal + * @enum {string} + */ + display?: 'normal' | 'banner' | 'dialog'; + /** @default false */ + forExistingUsers?: boolean; + /** @default false */ + silence?: boolean; + /** @default false */ + needConfirmationToRead?: boolean; + /** + * Format: misskey:id + * @default null + */ + userId?: string | null; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string | null; + title: string; + text: string; + imageUrl: string | null; + }; + }; + }; + /** @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/announcements/delete + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* + */ + 'admin/announcements/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: 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/announcements/list + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:announcements* + */ + 'admin/announcements/list': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** Format: misskey:id */ + userId?: string | null; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ({ + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string | null; + text: string; + title: string; + imageUrl: string | null; + reads: number; + })[]; + }; + }; + /** @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/announcements/update + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:announcements* + */ + 'admin/announcements/update': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + title?: string; + text?: string; + imageUrl?: string | null; + /** @enum {string} */ + icon?: 'info' | 'warning' | 'error' | 'success'; + /** @enum {string} */ + display?: 'normal' | 'banner' | 'dialog'; + forExistingUsers?: boolean; + silence?: boolean; + needConfirmationToRead?: boolean; + isActive?: boolean; + }; + }; + }; + 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/avatar-decorations/create + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* + */ + 'admin/avatar-decorations/create': { + requestBody: { + content: { + 'application/json': { + name: string; + description: string; + url: string; + roleIdsThatCanBeUsedThisDecoration?: 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/avatar-decorations/delete + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* + */ + 'admin/avatar-decorations/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: 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/avatar-decorations/list + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:avatar-decorations* + */ + 'admin/avatar-decorations/list': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** Format: misskey:id */ + userId?: string | null; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ({ + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string | null; + name: string; + description: string; + url: string; + roleIdsThatCanBeUsedThisDecoration: string[]; + })[]; + }; + }; + /** @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/avatar-decorations/update + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:avatar-decorations* + */ + 'admin/avatar-decorations/update': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + name?: string; + description?: string; + url?: string; + roleIdsThatCanBeUsedThisDecoration?: 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/delete-all-files-of-a-user + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:delete-all-files-of-a-user* + */ + 'admin/delete-all-files-of-a-user': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + userId: 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/unset-user-avatar + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-avatar* + */ + 'admin/unset-user-avatar': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + userId: 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/unset-user-banner + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:unset-user-banner* + */ + 'admin/unset-user-banner': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + userId: 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/drive/clean-remote-files + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:drive* + */ + 'admin/drive/clean-remote-files': { + 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/drive/cleanup + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:drive* + */ + 'admin/drive/cleanup': { + 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/drive/files + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:drive* + */ + 'admin/drive/files': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** Format: misskey:id */ + userId?: string | null; + type?: string | null; + /** + * @default local + * @enum {string} + */ + origin?: 'combined' | 'local' | 'remote'; + /** + * @description The local host is represented with `null`. + * @default null + */ + hostname?: string | null; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['DriveFile'][]; + }; + }; + /** @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/drive/show-file + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:drive* + */ + 'admin/drive/show-file': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + fileId?: string; + url?: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; + /** Format: date-time */ + createdAt: string; + /** + * Format: id + * @example xxxxxxxxxx + */ + userId: string | null; + /** @description The local host is represented with `null`. */ + userHost: string | null; + /** + * Format: md5 + * @example 15eca7fba0480996e2245f5185bf39f2 + */ + md5: string; + /** @example lenna.jpg */ + name: string; + /** @example image/jpeg */ + type: string; + /** @example 51469 */ + size: number; + comment: string | null; + blurhash: string | null; + properties: Record; + /** @example true */ + storedInternal: boolean | null; + /** Format: url */ + url: string | null; + /** Format: url */ + thumbnailUrl: string | null; + /** Format: url */ + webpublicUrl: string | null; + accessKey: string | null; + thumbnailAccessKey: string | null; + webpublicAccessKey: string | null; + uri: string | null; + src: string | null; + /** + * Format: id + * @example xxxxxxxxxx + */ + folderId: string | null; + isSensitive: boolean; + isLink: boolean; + }; + }; + }; + /** @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/emoji/add-aliases-bulk + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + 'admin/emoji/add-aliases-bulk': { + requestBody: { + content: { + 'application/json': { + ids: string[]; + aliases: 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/emoji/add + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + 'admin/emoji/add': { + requestBody: { + content: { + 'application/json': { + name: string; + /** Format: misskey:id */ + fileId: string; + /** @description Use `null` to reset the category. */ + category?: string | null; + aliases?: string[]; + license?: string | null; + isSensitive?: boolean; + localOnly?: boolean; + roleIdsThatCanBeUsedThisEmojiAsReaction?: 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/emoji/adds + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + 'admin/emoji/adds': { + requestBody: { + content: { + 'application/json': { + name?: string; + /** Format: misskey:id */ + fileId: string; + /** @description Use `null` to reset the category. */ + category?: string | null; + aliases?: string[]; + license?: string | null; + isSensitive?: boolean; + localOnly?: boolean; + roleIdsThatCanBeUsedThisEmojiAsReaction?: 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/emoji/copy + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + 'admin/emoji/copy': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + emojiId: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: id */ + id: string; + }; + }; + }; + /** @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/emoji/delete-bulk + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* + */ + 'admin/emoji/delete-bulk': { + requestBody: { + content: { + 'application/json': { + ids: 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']; }; - userEachUserListsLimit: { - value: number | boolean; - priority: number; - useDefault: boolean; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; }; - canManageAvatarDecorations: { - value: number | boolean; - priority: number; - useDefault: boolean; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; }; - canUseTranslator: { - value: number | boolean; - priority: number; - useDefault: boolean; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; }; }; - usersCount: number; - }); + }; }; - responses: never; - parameters: never; - requestBodies: never; - headers: never; - pathItems: never; -}; - -export type $defs = Record; - -export type external = Record; - -export type operations = { - /** - * admin/meta + * admin/emoji/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ - 'admin/meta': { - responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - cacheRemoteFiles: boolean; - cacheRemoteSensitiveFiles: boolean; - emailRequiredForSignup: boolean; - enableHcaptcha: boolean; - hcaptchaSiteKey: string | null; - enableRecaptcha: boolean; - recaptchaSiteKey: string | null; - enableTurnstile: boolean; - turnstileSiteKey: string | null; - swPublickey: string | null; - /** @default /assets/ai.png */ - mascotImageUrl: string | null; - bannerUrl: string | null; - serverErrorImageUrl: string | null; - infoImageUrl: string | null; - notFoundImageUrl: string | null; - iconUrl: string | null; - app192IconUrl: string | null; - app512IconUrl: string | null; - enableEmail: boolean; - enableServiceWorker: boolean; - translatorAvailable: boolean; - translatorType: string | null; - silencedHosts?: string[]; - pinnedUsers: string[]; - hiddenTags: string[]; - blockedHosts: string[]; - sensitiveWords: string[]; - preservedUsernames: string[]; - hcaptchaSecretKey: string | null; - recaptchaSecretKey: string | null; - turnstileSecretKey: string | null; - sensitiveMediaDetection: string; - sensitiveMediaDetectionSensitivity: string; - setSensitiveFlagAutomatically: boolean; - enableSensitiveMediaDetectionForVideos: boolean; - /** Format: id */ - proxyAccountId: string | null; - email: string | null; - smtpSecure: boolean; - smtpHost: string | null; - smtpPort: number | null; - smtpUser: string | null; - smtpPass: string | null; - swPrivateKey: string | null; - useObjectStorage: boolean; - objectStorageBaseUrl: string | null; - objectStorageBucket: string | null; - objectStoragePrefix: string | null; - objectStorageEndpoint: string | null; - objectStorageRegion: string | null; - objectStoragePort: number | null; - objectStorageAccessKey: string | null; - objectStorageSecretKey: string | null; - objectStorageUseSSL: boolean; - objectStorageUseProxy: boolean; - objectStorageSetPublicRead: boolean; - useObjectStorageRemote?: boolean; - objectStorageRemoteBaseUrl?: string | null; - objectStorageRemoteBucket?: string | null; - objectStorageRemotePrefix?: string | null; - objectStorageRemoteEndpoint?: string | null; - objectStorageRemoteRegion?: string | null; - objectStorageRemotePort?: number | null; - objectStorageRemoteAccessKey?: string | null; - objectStorageRemoteSecretKey?: string | null; - objectStorageRemoteUseSSL?: boolean; - objectStorageRemoteUseProxy?: boolean; - objectStorageRemoteSetPublicRead?: boolean; - enableIpLogging: boolean; - enableActiveEmailValidation: boolean; - enableVerifymailApi: boolean; - verifymailAuthKey: string | null; - enableChartsForRemoteUser: boolean; - enableChartsForFederatedInstances: boolean; - enableServerMachineStats: boolean; - enableIdenticonGeneration: boolean; - manifestJsonOverride: string; - doNotSendNotificationEmailsForAbuseReport: boolean; - emailToReceiveAbuseReport: string | null; - policies: Record; - enableFanoutTimeline: boolean; - enableFanoutTimelineDbFallback: boolean; - perLocalUserUserTimelineCacheMax: number; - perRemoteUserUserTimelineCacheMax: number; - perUserHomeTimelineCacheMax: number; - perUserListTimelineCacheMax: number; - notesPerOneAd: number; - backgroundImageUrl: string | null; - deeplAuthKey: string | null; - deeplIsPro: boolean; - defaultDarkTheme: string | null; - defaultLightTheme: string | null; - description: string | null; - disableRegistration: boolean; - impressumUrl: string | null; - maintainerEmail: string | null; - maintainerName: string | null; - name: string | null; - objectStorageS3ForcePathStyle: boolean; - privacyPolicyUrl: string | null; - repositoryUrl: string; - summalyProxy: string | null; - themeColor: string | null; - tosUrl: string | null; - uri: string; - version: string; - enableReceivePrerelease: boolean; - skipVersion: boolean; - skipCherryPickVersion?: string | null; - }; + 'admin/emoji/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; }; }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; /** @description Client error */ 400: { content: { @@ -4490,38 +6886,25 @@ export type operations = { }; }; /** - * admin/abuse-report-resolver/create + * admin/emoji/import-zip * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - 'admin/abuse-report-resolver/create': { + 'admin/emoji/import-zip': { requestBody: { content: { 'application/json': { - name: string; - targetUserPattern: string | null; - reporterPattern: string | null; - reportContentPattern: string | null; - /** @enum {string} */ - expiresAt: '1hour' | '12hours' | '1day' | '1week' | '1month' | '3months' | '6months' | '1year' | 'indefinitely'; - forward: boolean; + /** Format: misskey:id */ + fileId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - name: string; - targetUserPattern: string | null; - reporterPattern: string | null; - reportContentPattern: string | null; - expiresAt: string; - forward: boolean; - }; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -4556,15 +6939,22 @@ export type operations = { }; }; /** - * admin/abuse-report-resolver/list + * admin/emoji/list-remote * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ - 'admin/abuse-report-resolver/list': { + 'admin/emoji/list-remote': { requestBody: { content: { 'application/json': { + /** @default null */ + query?: string | null; + /** + * @description Use `null` to represent the local host. + * @default null + */ + host?: string | null; /** @default 10 */ limit?: number; /** Format: misskey:id */ @@ -4579,12 +6969,14 @@ export type operations = { 200: { content: { 'application/json': ({ + /** Format: id */ + id: string; + aliases: string[]; name: string; - targetUserPattern: string | null; - reporterPattern: string | null; - reportContentPattern: string | null; - expiresAt: string; - forward: boolean; + category: string | null; + /** @description The local host is represented with `null`. */ + host: string | null; + url: string; })[]; }; }; @@ -4621,24 +7013,41 @@ export type operations = { }; }; /** - * admin/abuse-report-resolver/delete + * admin/emoji/list * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ - 'admin/abuse-report-resolver/delete': { + 'admin/emoji/list': { requestBody: { content: { 'application/json': { + /** @default null */ + query?: string | null; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; /** Format: misskey:id */ - resolverId: string; + untilId?: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ({ + /** Format: id */ + id: string; + aliases: string[]; + name: string; + category: string | null; + /** @description The local host is represented with `null`. The field exists for compatibility with other API endpoints that return files. */ + host: string | null; + url: string; + })[]; + }; }; /** @description Client error */ 400: { @@ -4673,24 +7082,17 @@ export type operations = { }; }; /** - * admin/abuse-report-resolver/update + * admin/emoji/remove-aliases-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ - 'admin/abuse-report-resolver/update': { + 'admin/emoji/remove-aliases-bulk': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - resolverId: string; - name?: string; - targetUserPattern?: string | null; - reporterPattern?: string | null; - reportContentPattern?: string | null; - /** @enum {string} */ - expiresAt?: '1hour' | '12hours' | '1day' | '1week' | '1month' | '3months' | '6months' | '1year' | 'indefinitely'; - forward?: boolean; + ids: string[]; + aliases: string[]; }; }; }; @@ -4732,64 +7134,24 @@ export type operations = { }; }; /** - * admin/abuse-user-reports + * admin/emoji/set-aliases-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ - 'admin/abuse-user-reports': { + 'admin/emoji/set-aliases-bulk': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default null */ - state?: string | null; - /** - * @default combined - * @enum {string} - */ - reporterOrigin?: 'combined' | 'local' | 'remote'; - /** - * @default combined - * @enum {string} - */ - targetUserOrigin?: 'combined' | 'local' | 'remote'; - /** @default false */ - forwarded?: boolean; + ids: string[]; + aliases: string[]; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': ({ - /** - * Format: id - * @example xxxxxxxxxx - */ - id: string; - /** Format: date-time */ - createdAt: string; - comment: string; - /** @example false */ - resolved: boolean; - /** Format: id */ - reporterId: string; - /** Format: id */ - targetUserId: string; - /** Format: id */ - assigneeId: string | null; - reporter: components['schemas']['User']; - targetUser: components['schemas']['User']; - assignee?: components['schemas']['User'] | null; - })[]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -4824,26 +7186,25 @@ export type operations = { }; }; /** - * admin/accounts/create + * admin/emoji/set-category-bulk * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ - 'admin/accounts/create': { + 'admin/emoji/set-category-bulk': { requestBody: { content: { 'application/json': { - username: string; - password: string; + ids: string[]; + /** @description Use `null` to reset the category. */ + category?: string | null; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['User']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -4878,17 +7239,18 @@ export type operations = { }; }; /** - * admin/accounts/delete + * admin/emoji/set-license-bulk * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ - 'admin/accounts/delete': { + 'admin/emoji/set-license-bulk': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + ids: string[]; + /** @description Use `null` to reset the license. */ + license?: string | null; }; }; }; @@ -4930,23 +7292,29 @@ export type operations = { }; }; /** - * admin/accounts/find-by-email + * admin/emoji/steal * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ - 'admin/accounts/find-by-email': { + 'admin/emoji/steal': { requestBody: { content: { 'application/json': { - email: string; + name: string; + host: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: id */ + id: string; + }; + }; }; /** @description Client error */ 400: { @@ -4981,24 +7349,27 @@ export type operations = { }; }; /** - * admin/ad/create + * admin/emoji/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:emoji* */ - 'admin/ad/create': { + 'admin/emoji/update': { requestBody: { content: { 'application/json': { - url: string; - memo: string; - place: string; - priority: string; - ratio: number; - expiresAt: number; - startsAt: number; - imageUrl: string; - dayOfWeek: number; + /** Format: misskey:id */ + id: string; + name: string; + /** Format: misskey:id */ + fileId?: string; + /** @description Use `null` to reset the category. */ + category?: string | null; + aliases: string[]; + license?: string | null; + isSensitive?: boolean; + localOnly?: boolean; + roleIdsThatCanBeUsedThisEmojiAsReaction?: string[]; }; }; }; @@ -5040,17 +7411,16 @@ export type operations = { }; }; /** - * admin/ad/delete + * admin/federation/delete-all-files * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ - 'admin/ad/delete': { + 'admin/federation/delete-all-files': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - id: string; + host: string; }; }; }; @@ -5092,23 +7462,16 @@ export type operations = { }; }; /** - * admin/ad/list + * admin/federation/refresh-remote-instance-metadata * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ - 'admin/ad/list': { + 'admin/federation/refresh-remote-instance-metadata': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default null */ - publishing?: boolean | null; + host: string; }; }; }; @@ -5150,26 +7513,16 @@ export type operations = { }; }; /** - * admin/ad/update + * admin/federation/remove-all-following * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* */ - 'admin/ad/update': { + 'admin/federation/remove-all-following': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - id: string; - memo: string; - url: string; - imageUrl: string; - place: string; - priority: string; - ratio: number; - expiresAt: number; - startsAt: number; - dayOfWeek: number; + host: string; }; }; }; @@ -5211,62 +7564,25 @@ export type operations = { }; }; /** - * admin/announcements/create - * @description No description provided. - * - * **Credential required**: *Yes* - */ - 'admin/announcements/create': { - requestBody: { - content: { - 'application/json': { - title: string; - text: string; - imageUrl: string | null; - /** - * @default info - * @enum {string} - */ - icon?: 'info' | 'warning' | 'error' | 'success'; - /** - * @default normal - * @enum {string} - */ - display?: 'normal' | 'banner' | 'dialog'; - /** @default false */ - forExistingUsers?: boolean; - /** @default false */ - silence?: boolean; - /** @default false */ - needConfirmationToRead?: boolean; - /** - * Format: misskey:id - * @default null - */ - userId?: string | null; - }; - }; - }; - responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - /** - * Format: id - * @example xxxxxxxxxx - */ - id: string; - /** Format: date-time */ - createdAt: string; - /** Format: date-time */ - updatedAt: string | null; - title: string; - text: string; - imageUrl: string | null; - }; + * admin/federation/update-instance + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:federation* + */ + 'admin/federation/update-instance': { + requestBody: { + content: { + 'application/json': { + host: string; + isSuspended: boolean; }; }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; /** @description Client error */ 400: { content: { @@ -5300,24 +7616,21 @@ export type operations = { }; }; /** - * admin/announcements/delete + * admin/get-index-stats * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:index-stats* */ - 'admin/announcements/delete': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - id: string; - }; - }; - }; + 'admin/get-index-stats': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + tablename: string; + indexname: string; + }[]; + }; }; /** @description Client error */ 400: { @@ -5352,45 +7665,17 @@ export type operations = { }; }; /** - * admin/announcements/list + * admin/get-table-stats * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:table-stats* */ - 'admin/announcements/list': { - requestBody: { - content: { - 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** Format: misskey:id */ - userId?: string | null; - }; - }; - }; + 'admin/get-table-stats': { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': ({ - /** - * Format: id - * @example xxxxxxxxxx - */ - id: string; - /** Format: date-time */ - createdAt: string; - /** Format: date-time */ - updatedAt: string | null; - text: string; - title: string; - imageUrl: string | null; - reads: number; - })[]; + 'application/json': Record; }; }; /** @description Client error */ @@ -5426,35 +7711,30 @@ export type operations = { }; }; /** - * admin/announcements/update + * admin/get-user-ips * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:user-ips* */ - 'admin/announcements/update': { + 'admin/get-user-ips': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - id: string; - title?: string; - text?: string; - imageUrl?: string | null; - /** @enum {string} */ - icon?: 'info' | 'warning' | 'error' | 'success'; - /** @enum {string} */ - display?: 'normal' | 'banner' | 'dialog'; - forExistingUsers?: boolean; - silence?: boolean; - needConfirmationToRead?: boolean; - isActive?: boolean; + userId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + ip: string; + /** Format: date-time */ + createdAt: string; + }[]; + }; }; /** @description Client error */ 400: { @@ -5489,26 +7769,27 @@ export type operations = { }; }; /** - * admin/avatar-decorations/create + * admin/invite/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes* */ - 'admin/avatar-decorations/create': { + 'admin/invite/create': { requestBody: { content: { 'application/json': { - name: string; - description: string; - url: string; - roleIdsThatCanBeUsedThisDecoration?: string[]; + /** @default 1 */ + count?: number; + expiresAt?: string | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['InviteCode'][]; + }; }; /** @description Client error */ 400: { @@ -5543,24 +7824,35 @@ export type operations = { }; }; /** - * admin/avatar-decorations/delete + * admin/invite/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:invite-codes* */ - 'admin/avatar-decorations/delete': { + 'admin/invite/list': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - id: string; + /** @default 30 */ + limit?: number; + /** @default 0 */ + offset?: number; + /** + * @default all + * @enum {string} + */ + type?: 'unused' | 'used' | 'expired' | 'all'; + /** @enum {string} */ + sort?: '+createdAt' | '-createdAt' | '+usedAt' | '-usedAt'; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['InviteCode'][]; + }; }; /** @description Client error */ 400: { @@ -5595,46 +7887,16 @@ export type operations = { }; }; /** - * admin/avatar-decorations/list + * admin/invite/revoke * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:invite-codes* */ - 'admin/avatar-decorations/list': { - requestBody: { - content: { - 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** Format: misskey:id */ - userId?: string | null; - }; - }; - }; + 'admin/invite/revoke': { responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': ({ - /** - * Format: id - * @example xxxxxxxxxx - */ - id: string; - /** Format: date-time */ - createdAt: string; - /** Format: date-time */ - updatedAt: string | null; - name: string; - description: string; - url: string; - roleIdsThatCanBeUsedThisDecoration: string[]; - })[]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -5669,21 +7931,18 @@ export type operations = { }; }; /** - * admin/avatar-decorations/update + * admin/promo/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:promo* */ - 'admin/avatar-decorations/update': { + 'admin/promo/create': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - id: string; - name?: string; - description?: string; - url?: string; - roleIdsThatCanBeUsedThisDecoration?: string[]; + noteId: string; + expiresAt: number; }; }; }; @@ -5725,20 +7984,12 @@ export type operations = { }; }; /** - * admin/delete-all-files-of-a-user + * admin/queue/clear * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:queue* */ - 'admin/delete-all-files-of-a-user': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - userId: string; - }; - }; - }; + 'admin/queue/clear': { responses: { /** @description OK (without any results) */ 204: { @@ -5777,24 +8028,64 @@ export type operations = { }; }; /** - * admin/unset-user-avatar + * admin/queue/deliver-delayed * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:queue* */ - 'admin/unset-user-avatar': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - userId: string; + 'admin/queue/deliver-delayed': { + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ((string | number)[])[]; + }; + }; + /** @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/queue/inbox-delayed + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:admin:queue* + */ + 'admin/queue/inbox-delayed': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ((string | number)[])[]; + }; }; /** @description Client error */ 400: { @@ -5829,17 +8120,17 @@ export type operations = { }; }; /** - * admin/unset-user-banner + * admin/queue/promote * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:queue* */ - 'admin/unset-user-banner': { + 'admin/queue/promote': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + /** @enum {string} */ + type: 'deliver' | 'inbox'; }; }; }; @@ -5881,16 +8172,23 @@ export type operations = { }; }; /** - * admin/drive/clean-remote-files + * admin/queue/stats * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:emoji* */ - 'admin/drive/clean-remote-files': { + 'admin/queue/stats': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + deliver: components['schemas']['QueueCount']; + inbox: components['schemas']['QueueCount']; + db: components['schemas']['QueueCount']; + objectStorage: components['schemas']['QueueCount']; + }; + }; }; /** @description Client error */ 400: { @@ -5925,16 +8223,35 @@ export type operations = { }; }; /** - * admin/drive/cleanup + * admin/relays/add * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:relays* */ - 'admin/drive/cleanup': { + 'admin/relays/add': { + requestBody: { + content: { + 'application/json': { + inbox: string; + }; + }; + }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: id */ + id: string; + /** Format: url */ + inbox: string; + /** + * @default requesting + * @enum {string} + */ + status: 'requesting' | 'accepted' | 'rejected'; + }; + }; }; /** @description Client error */ 400: { @@ -5969,42 +8286,27 @@ export type operations = { }; }; /** - * admin/drive/files + * admin/relays/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:relays* */ - 'admin/drive/files': { - requestBody: { - content: { - 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** Format: misskey:id */ - userId?: string | null; - type?: string | null; - /** - * @default local - * @enum {string} - */ - origin?: 'combined' | 'local' | 'remote'; - /** - * @description The local host is represented with `null`. - * @default null - */ - hostname?: string | null; - }; - }; - }; + 'admin/relays/list': { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFile'][]; + 'application/json': ({ + /** Format: id */ + id: string; + /** Format: url */ + inbox: string; + /** + * @default requesting + * @enum {string} + */ + status: 'requesting' | 'accepted' | 'rejected'; + })[]; }; }; /** @description Client error */ @@ -6040,76 +8342,23 @@ export type operations = { }; }; /** - * admin/drive/show-file + * admin/relays/remove * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:relays* */ - 'admin/drive/show-file': { + 'admin/relays/remove': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - fileId?: string; - url?: string; + inbox: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - /** - * Format: id - * @example xxxxxxxxxx - */ - id: string; - /** Format: date-time */ - createdAt: string; - /** - * Format: id - * @example xxxxxxxxxx - */ - userId: string | null; - /** @description The local host is represented with `null`. */ - userHost: string | null; - /** - * Format: md5 - * @example 15eca7fba0480996e2245f5185bf39f2 - */ - md5: string; - /** @example lenna.jpg */ - name: string; - /** @example image/jpeg */ - type: string; - /** @example 51469 */ - size: number; - comment: string | null; - blurhash: string | null; - properties: Record; - /** @example true */ - storedInternal: boolean | null; - /** Format: url */ - url: string | null; - /** Format: url */ - thumbnailUrl: string | null; - /** Format: url */ - webpublicUrl: string | null; - accessKey: string | null; - thumbnailAccessKey: string | null; - webpublicAccessKey: string | null; - uri: string | null; - src: string | null; - /** - * Format: id - * @example xxxxxxxxxx - */ - folderId: string | null; - isSensitive: boolean; - isLink: boolean; - }; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -6144,24 +8393,28 @@ export type operations = { }; }; /** - * admin/emoji/add-aliases-bulk + * admin/reset-password * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:reset-password* */ - 'admin/emoji/add-aliases-bulk': { + 'admin/reset-password': { requestBody: { content: { 'application/json': { - ids: string[]; - aliases: string[]; + /** Format: misskey:id */ + userId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + password: string; + }; + }; }; /** @description Client error */ 400: { @@ -6196,25 +8449,19 @@ export type operations = { }; }; /** - * admin/emoji/add + * admin/resolve-abuse-user-report * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:resolve-abuse-user-report* */ - 'admin/emoji/add': { + 'admin/resolve-abuse-user-report': { requestBody: { content: { 'application/json': { - name: string; /** Format: misskey:id */ - fileId: string; - /** @description Use `null` to reset the category. */ - category?: string | null; - aliases?: string[]; - license?: string | null; - isSensitive?: boolean; - localOnly?: boolean; - roleIdsThatCanBeUsedThisEmojiAsReaction?: string[]; + reportId: string; + /** @default false */ + forward?: boolean; }; }; }; @@ -6256,25 +8503,18 @@ export type operations = { }; }; /** - * admin/emoji/adds + * admin/send-email * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:send-email* */ - 'admin/emoji/adds': { + 'admin/send-email': { requestBody: { content: { 'application/json': { - name?: string; - /** Format: misskey:id */ - fileId: string; - /** @description Use `null` to reset the category. */ - category?: string | null; - aliases?: string[]; - license?: string | null; - isSensitive?: boolean; - localOnly?: boolean; - roleIdsThatCanBeUsedThisEmojiAsReaction?: string[]; + to: string; + subject: string; + text: string; }; }; }; @@ -6316,27 +8556,40 @@ export type operations = { }; }; /** - * admin/emoji/copy + * admin/server-info * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:server-info* */ - 'admin/emoji/copy': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - emojiId: string; - }; - }; - }; + 'admin/server-info': { responses: { /** @description OK (with results) */ 200: { content: { 'application/json': { - /** Format: id */ - id: string; + machine: string; + /** @example linux */ + os: string; + node: string; + psql: string; + cpu: { + model: string; + cores: number; + }; + mem: { + /** Format: bytes */ + total: number; + }; + fs: { + /** Format: bytes */ + total: number; + /** Format: bytes */ + used: number; + }; + net: { + /** @example eth0 */ + interface: string; + }; }; }; }; @@ -6373,23 +8626,43 @@ export type operations = { }; }; /** - * admin/emoji/delete-bulk + * admin/show-moderation-logs * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:show-moderation-log* */ - 'admin/emoji/delete-bulk': { + 'admin/show-moderation-logs': { requestBody: { content: { 'application/json': { - ids: string[]; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + type?: string | null; + /** Format: misskey:id */ + userId?: string | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: id */ + id: string; + /** Format: date-time */ + createdAt: string; + type: string; + info: Record; + /** Format: id */ + userId: string; + user: components['schemas']['UserDetailed']; + }[]; + }; }; /** @description Client error */ 400: { @@ -6424,24 +8697,26 @@ export type operations = { }; }; /** - * admin/emoji/delete + * admin/show-user * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:show-user* */ - 'admin/emoji/delete': { + 'admin/show-user': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - id: string; + userId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': Record; + }; }; /** @description Client error */ 400: { @@ -6476,28 +8751,38 @@ export type operations = { }; }; /** - * admin/emoji/list-remote + * admin/show-users * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:show-users* */ - 'admin/emoji/list-remote': { + 'admin/show-users': { requestBody: { content: { 'application/json': { + /** @default 10 */ + limit?: number; + /** @default 0 */ + offset?: number; + /** @enum {string} */ + sort?: '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+updatedAt' | '-updatedAt' | '+lastActiveDate' | '-lastActiveDate'; + /** + * @default all + * @enum {string} + */ + state?: 'all' | 'alive' | 'available' | 'admin' | 'moderator' | 'adminOrModerator' | 'suspended'; + /** + * @default combined + * @enum {string} + */ + origin?: 'combined' | 'local' | 'remote'; /** @default null */ - query?: string | null; + username?: string | null; /** - * @description Use `null` to represent the local host. + * @description The local host is represented with `null`. * @default null */ - host?: string | null; - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; + hostname?: string | null; }; }; }; @@ -6505,16 +8790,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': ({ - /** Format: id */ - id: string; - aliases: string[]; - name: string; - category: string | null; - /** @description The local host is represented with `null`. */ - host: string | null; - url: string; - })[]; + 'application/json': components['schemas']['UserDetailed'][]; }; }; /** @description Client error */ @@ -6550,41 +8826,24 @@ export type operations = { }; }; /** - * admin/emoji/list + * admin/suspend-user * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:suspend-user* */ - 'admin/emoji/list': { + 'admin/suspend-user': { requestBody: { content: { 'application/json': { - /** @default null */ - query?: string | null; - /** @default 10 */ - limit?: number; /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; + userId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': ({ - /** Format: id */ - id: string; - aliases: string[]; - name: string; - category: string | null; - /** @description The local host is represented with `null`. The field exists for compatibility with other API endpoints that return files. */ - host: string | null; - url: string; - })[]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -6619,17 +8878,17 @@ export type operations = { }; }; /** - * admin/emoji/remove-aliases-bulk + * admin/unsuspend-user * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:unsuspend-user* */ - 'admin/emoji/remove-aliases-bulk': { + 'admin/unsuspend-user': { requestBody: { content: { 'application/json': { - ids: string[]; - aliases: string[]; + /** Format: misskey:id */ + userId: string; }; }; }; @@ -6671,17 +8930,141 @@ export type operations = { }; }; /** - * admin/emoji/set-aliases-bulk + * admin/update-meta * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:meta* */ - 'admin/emoji/set-aliases-bulk': { + 'admin/update-meta': { requestBody: { content: { 'application/json': { - ids: string[]; - aliases: string[]; + disableRegistration?: boolean | null; + pinnedUsers?: string[] | null; + hiddenTags?: string[] | null; + blockedHosts?: string[] | null; + sensitiveWords?: string[] | null; + themeColor?: string | null; + mascotImageUrl?: string | null; + bannerUrl?: string | null; + serverErrorImageUrl?: string | null; + infoImageUrl?: string | null; + notFoundImageUrl?: string | null; + iconUrl?: string | null; + app192IconUrl?: string | null; + app512IconUrl?: string | null; + backgroundImageUrl?: string | null; + logoImageUrl?: string | null; + name?: string | null; + shortName?: string | null; + description?: string | null; + defaultLightTheme?: string | null; + defaultDarkTheme?: string | null; + cacheRemoteFiles?: boolean; + cacheRemoteSensitiveFiles?: boolean; + emailRequiredForSignup?: boolean; + enableHcaptcha?: boolean; + hcaptchaSiteKey?: string | null; + hcaptchaSecretKey?: string | null; + enableMcaptcha?: boolean; + mcaptchaSiteKey?: string | null; + mcaptchaInstanceUrl?: string | null; + mcaptchaSecretKey?: string | null; + enableRecaptcha?: boolean; + recaptchaSiteKey?: string | null; + recaptchaSecretKey?: string | null; + enableTurnstile?: boolean; + turnstileSiteKey?: string | null; + turnstileSecretKey?: string | null; + /** @enum {string} */ + sensitiveMediaDetection?: 'none' | 'all' | 'local' | 'remote'; + /** @enum {string} */ + sensitiveMediaDetectionSensitivity?: 'medium' | 'low' | 'high' | 'veryLow' | 'veryHigh'; + setSensitiveFlagAutomatically?: boolean; + enableSensitiveMediaDetectionForVideos?: boolean; + /** Format: misskey:id */ + proxyAccountId?: string | null; + maintainerName?: string | null; + maintainerEmail?: string | null; + langs?: string[]; + summalyProxy?: string | null; + translatorType?: string | null; + deeplAuthKey?: string | null; + deeplIsPro?: boolean; + ctav3SaKey?: string | null; + ctav3ProjectId?: string | null; + ctav3Location?: string | null; + ctav3Model?: string | null; + ctav3Glossary?: string | null; + enableEmail?: boolean; + email?: string | null; + smtpSecure?: boolean; + smtpHost?: string | null; + smtpPort?: number | null; + smtpUser?: string | null; + smtpPass?: string | null; + enableServiceWorker?: boolean; + swPublicKey?: string | null; + swPrivateKey?: string | null; + tosUrl?: string | null; + repositoryUrl?: string; + feedbackUrl?: string; + impressumUrl?: string | null; + privacyPolicyUrl?: string | null; + useObjectStorage?: boolean; + objectStorageBaseUrl?: string | null; + objectStorageBucket?: string | null; + objectStoragePrefix?: string | null; + objectStorageEndpoint?: string | null; + objectStorageRegion?: string | null; + objectStoragePort?: number | null; + objectStorageAccessKey?: string | null; + objectStorageSecretKey?: string | null; + objectStorageUseSSL?: boolean; + objectStorageUseProxy?: boolean; + objectStorageSetPublicRead?: boolean; + objectStorageS3ForcePathStyle?: boolean; + useObjectStorageRemote?: boolean; + objectStorageRemoteBaseUrl?: string | null; + objectStorageRemoteBucket?: string | null; + objectStorageRemotePrefix?: string | null; + objectStorageRemoteEndpoint?: string | null; + objectStorageRemoteRegion?: string | null; + objectStorageRemotePort?: number | null; + objectStorageRemoteAccessKey?: string | null; + objectStorageRemoteSecretKey?: string | null; + objectStorageRemoteUseSSL?: boolean; + objectStorageRemoteUseProxy?: boolean; + objectStorageRemoteSetPublicRead?: boolean; + objectStorageRemoteS3ForcePathStyle?: boolean; + enableIpLogging?: boolean; + enableActiveEmailValidation?: boolean; + enableVerifymailApi?: boolean; + verifymailAuthKey?: string | null; + enableTruemailApi?: boolean; + truemailInstance?: string | null; + truemailAuthKey?: string | null; + enableChartsForRemoteUser?: boolean; + enableChartsForFederatedInstances?: boolean; + enableServerMachineStats?: boolean; + enableIdenticonGeneration?: boolean; + serverRules?: string[]; + bannedEmailDomains?: string[]; + preservedUsernames?: string[]; + manifestJsonOverride?: string; + enableFanoutTimeline?: boolean; + enableFanoutTimelineDbFallback?: boolean; + perLocalUserUserTimelineCacheMax?: number; + perRemoteUserUserTimelineCacheMax?: number; + perUserHomeTimelineCacheMax?: number; + perUserListTimelineCacheMax?: number; + notesPerOneAd?: number; + silencedHosts?: string[] | null; + doNotSendNotificationEmailsForAbuseReport?: boolean; + emailToReceiveAbuseReport?: string | null; + enableReceivePrerelease?: boolean; + skipVersion?: boolean; + skipCherryPickVersion?: string | null; }; }; }; @@ -6723,25 +9106,26 @@ export type operations = { }; }; /** - * admin/emoji/set-category-bulk + * admin/delete-account * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:delete-account* */ - 'admin/emoji/set-category-bulk': { + 'admin/delete-account': { requestBody: { content: { 'application/json': { - ids: string[]; - /** @description Use `null` to reset the category. */ - category?: string | null; + /** Format: misskey:id */ + userId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': unknown; + }; }; /** @description Client error */ 400: { @@ -6776,18 +9160,18 @@ export type operations = { }; }; /** - * admin/emoji/set-license-bulk + * admin/update-user-note * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:user-note* */ - 'admin/emoji/set-license-bulk': { + 'admin/update-user-note': { requestBody: { content: { 'application/json': { - ids: string[]; - /** @description Use `null` to reset the license. */ - license?: string | null; + /** Format: misskey:id */ + userId: string; + text: string; }; }; }; @@ -6829,17 +9213,31 @@ export type operations = { }; }; /** - * admin/emoji/steal + * admin/roles/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ - 'admin/emoji/steal': { + 'admin/roles/create': { requestBody: { content: { 'application/json': { name: string; - host: string; + description: string; + color: string | null; + iconUrl: string | null; + /** @enum {string} */ + target: 'manual' | 'conditional'; + condFormula: Record; + isPublic: boolean; + isModerator: boolean; + isAdministrator: boolean; + /** @default false */ + isExplorable?: boolean; + asBadge: boolean; + canEditMembersByModerator: boolean; + displayOrder: number; + policies: Record; }; }; }; @@ -6847,10 +9245,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - /** Format: id */ - id: string; - }; + 'application/json': components['schemas']['Role']; }; }; /** @description Client error */ @@ -6886,27 +9281,17 @@ export type operations = { }; }; /** - * admin/emoji/update + * admin/roles/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ - 'admin/emoji/update': { + 'admin/roles/delete': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - id: string; - name: string; - /** Format: misskey:id */ - fileId?: string; - /** @description Use `null` to reset the category. */ - category?: string | null; - aliases: string[]; - license?: string | null; - isSensitive?: boolean; - localOnly?: boolean; - roleIdsThatCanBeUsedThisEmojiAsReaction?: string[]; + roleId: string; }; }; }; @@ -6948,23 +9333,18 @@ export type operations = { }; }; /** - * admin/federation/delete-all-files + * admin/roles/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:roles* */ - 'admin/federation/delete-all-files': { - requestBody: { - content: { - 'application/json': { - host: string; - }; - }; - }; + 'admin/roles/list': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Role'][]; + }; }; /** @description Client error */ 400: { @@ -6999,23 +9379,26 @@ export type operations = { }; }; /** - * admin/federation/refresh-remote-instance-metadata + * admin/roles/show * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:admin:roles* */ - 'admin/federation/refresh-remote-instance-metadata': { + 'admin/roles/show': { requestBody: { content: { 'application/json': { - host: string; + /** Format: misskey:id */ + roleId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Role']; + }; }; /** @description Client error */ 400: { @@ -7050,16 +9433,32 @@ export type operations = { }; }; /** - * admin/federation/remove-all-following + * admin/roles/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ - 'admin/federation/remove-all-following': { + 'admin/roles/update': { requestBody: { content: { 'application/json': { - host: string; + /** Format: misskey:id */ + roleId: string; + name: string; + description: string; + color: string | null; + iconUrl: string | null; + /** @enum {string} */ + target: 'manual' | 'conditional'; + condFormula: Record; + isPublic: boolean; + isModerator: boolean; + isAdministrator: boolean; + isExplorable?: boolean; + asBadge: boolean; + canEditMembersByModerator: boolean; + displayOrder: number; + policies: Record; }; }; }; @@ -7101,114 +9500,27 @@ export type operations = { }; }; /** - * admin/federation/update-instance + * admin/roles/assign * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ - 'admin/federation/update-instance': { + 'admin/roles/assign': { requestBody: { content: { 'application/json': { - host: string; - isSuspended: boolean; - }; - }; - }; - 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/get-index-stats - * @description No description provided. - * - * **Credential required**: *Yes* - */ - 'admin/get-index-stats': { - 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']; + /** Format: misskey:id */ + roleId: string; + /** Format: misskey:id */ + userId: string; + expiresAt?: number | null; }; }; }; - }; - /** - * admin/get-table-stats - * @description No description provided. - * - * **Credential required**: *Yes* - */ - 'admin/get-table-stats': { - responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': Record; - }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -7243,15 +9555,17 @@ export type operations = { }; }; /** - * admin/get-user-ips + * admin/roles/unassign * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ - 'admin/get-user-ips': { + 'admin/roles/unassign': { requestBody: { content: { 'application/json': { + /** Format: misskey:id */ + roleId: string; /** Format: misskey:id */ userId: string; }; @@ -7295,27 +9609,23 @@ export type operations = { }; }; /** - * admin/invite/create + * admin/roles/update-default-policies * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:admin:roles* */ - 'admin/invite/create': { + 'admin/roles/update-default-policies': { requestBody: { content: { 'application/json': { - /** @default 1 */ - count?: number; - expiresAt?: string | null; + policies: Record; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['InviteCode'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -7350,26 +9660,23 @@ export type operations = { }; }; /** - * admin/invite/list + * admin/roles/users * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* / **Permission**: *read:admin:roles* */ - 'admin/invite/list': { + 'admin/roles/users': { requestBody: { content: { 'application/json': { - /** @default 30 */ + /** Format: misskey:id */ + roleId: string; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default 10 */ limit?: number; - /** @default 0 */ - offset?: number; - /** - * @default all - * @enum {string} - */ - type?: 'unused' | 'used' | 'expired' | 'all'; - /** @enum {string} */ - sort?: '+createdAt' | '-createdAt' | '+usedAt' | '-usedAt'; }; }; }; @@ -7377,7 +9684,15 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['InviteCode'][]; + 'application/json': ({ + /** Format: misskey:id */ + id: string; + /** Format: date-time */ + createdAt: string; + user: components['schemas']['UserDetailed']; + /** Format: date-time */ + expiresAt: string | null; + })[]; }; }; /** @description Client error */ @@ -7413,16 +9728,32 @@ export type operations = { }; }; /** - * admin/invite/revoke + * announcements * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/invite/revoke': { + announcements: { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default true */ + isActive?: boolean; + }; + }; + }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Announcement'][]; + }; }; /** @description Client error */ 400: { @@ -7457,25 +9788,39 @@ export type operations = { }; }; /** - * admin/promo/create + * antennas/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'admin/promo/create': { + 'antennas/create': { requestBody: { content: { 'application/json': { + name: string; + /** @enum {string} */ + src: 'home' | 'all' | 'users' | 'list' | 'group' | 'users_blacklist'; /** Format: misskey:id */ - noteId: string; - expiresAt: number; + userListId?: string | null; + /** Format: misskey:id */ + userGroupId?: string | null; + keywords: string[][]; + excludeKeywords: string[][]; + users: string[]; + caseSensitive: boolean; + localOnly?: boolean; + withReplies: boolean; + withFile: boolean; + notify: boolean; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Antenna']; + }; }; /** @description Client error */ 400: { @@ -7510,12 +9855,20 @@ export type operations = { }; }; /** - * admin/queue/clear + * antennas/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'admin/queue/clear': { + 'antennas/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + antennaId: string; + }; + }; + }; responses: { /** @description OK (without any results) */ 204: { @@ -7554,17 +9907,17 @@ export type operations = { }; }; /** - * admin/queue/deliver-delayed + * antennas/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'admin/queue/deliver-delayed': { + 'antennas/list': { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': ((string | number)[])[]; + 'application/json': components['schemas']['Antenna'][]; }; }; /** @description Client error */ @@ -7600,17 +9953,33 @@ export type operations = { }; }; /** - * admin/queue/inbox-delayed + * antennas/notes * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'admin/queue/inbox-delayed': { + 'antennas/notes': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + antennaId: string; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + sinceDate?: number; + untilDate?: number; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': ((string | number)[])[]; + 'application/json': components['schemas']['Note'][]; }; }; /** @description Client error */ @@ -7646,24 +10015,26 @@ export type operations = { }; }; /** - * admin/queue/promote + * antennas/show * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'admin/queue/promote': { + 'antennas/show': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - type: 'deliver' | 'inbox'; + /** Format: misskey:id */ + antennaId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Antenna']; + }; }; /** @description Client error */ 400: { @@ -7698,22 +10069,40 @@ export type operations = { }; }; /** - * admin/queue/stats + * antennas/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'admin/queue/stats': { + 'antennas/update': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + antennaId: string; + name: string; + /** @enum {string} */ + src: 'home' | 'all' | 'users' | 'list' | 'group' | 'users_blacklist'; + /** Format: misskey:id */ + userListId?: string | null; + /** Format: misskey:id */ + userGroupId?: string | null; + keywords: string[][]; + excludeKeywords: string[][]; + users: string[]; + caseSensitive: boolean; + localOnly?: boolean; + withReplies: boolean; + withFile: boolean; + notify: boolean; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': { - deliver: components['schemas']['QueueCount']; - inbox: components['schemas']['QueueCount']; - db: components['schemas']['QueueCount']; - objectStorage: components['schemas']['QueueCount']; - }; + 'application/json': components['schemas']['Antenna']; }; }; /** @description Client error */ @@ -7749,16 +10138,16 @@ export type operations = { }; }; /** - * admin/relays/add + * ap/get * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:federation* */ - 'admin/relays/add': { + 'ap/get': { requestBody: { content: { 'application/json': { - inbox: string; + uri: string; }; }; }; @@ -7766,17 +10155,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - /** Format: id */ - id: string; - /** Format: url */ - inbox: string; - /** - * @default requesting - * @enum {string} - */ - status: 'requesting' | 'accepted' | 'rejected'; - }; + 'application/json': Record; }; }; /** @description Client error */ @@ -7803,6 +10182,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -7810,29 +10195,34 @@ export type operations = { }; }; }; - }; - /** - * admin/relays/list - * @description No description provided. - * - * **Credential required**: *Yes* - */ - 'admin/relays/list': { + }; + /** + * ap/show + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + 'ap/show': { + requestBody: { + content: { + 'application/json': { + uri: string; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': ({ - /** Format: id */ - id: string; - /** Format: url */ - inbox: string; - /** - * @default requesting - * @enum {string} - */ - status: 'requesting' | 'accepted' | 'rejected'; - })[]; + 'application/json': OneOf<[{ + /** @enum {string} */ + type: 'User'; + object: components['schemas']['UserDetailedNotMe']; + }, { + /** @enum {string} */ + type: 'Note'; + object: components['schemas']['Note']; + }]>; }; }; /** @description Client error */ @@ -7859,6 +10249,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -7868,23 +10264,28 @@ export type operations = { }; }; /** - * admin/relays/remove + * app/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/relays/remove': { + 'app/create': { requestBody: { content: { 'application/json': { - inbox: string; + name: string; + description: string; + permission: string[]; + callbackUrl?: string | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['App']; + }; }; /** @description Client error */ 400: { @@ -7919,17 +10320,17 @@ export type operations = { }; }; /** - * admin/reset-password + * app/show * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/reset-password': { + 'app/show': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - userId: string; + appId: string; }; }; }; @@ -7937,9 +10338,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - password: string; - }; + 'application/json': components['schemas']['App']; }; }; /** @description Client error */ @@ -7975,19 +10374,17 @@ export type operations = { }; }; /** - * admin/resolve-abuse-user-report + * auth/accept * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - 'admin/resolve-abuse-user-report': { + 'auth/accept': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - reportId: string; - /** @default false */ - forward?: boolean; + token: string; }; }; }; @@ -8029,25 +10426,29 @@ export type operations = { }; }; /** - * admin/send-email + * auth/session/generate * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/send-email': { + 'auth/session/generate': { requestBody: { content: { 'application/json': { - to: string; - subject: string; - text: string; + appSecret: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + token: string; + /** Format: url */ + url: string; + }; + }; }; /** @description Client error */ 400: { @@ -8082,40 +10483,28 @@ export type operations = { }; }; /** - * admin/server-info + * auth/session/show * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/server-info': { + 'auth/session/show': { + requestBody: { + content: { + 'application/json': { + token: string; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { 'application/json': { - machine: string; - /** @example linux */ - os: string; - node: string; - psql: string; - cpu: { - model: string; - cores: number; - }; - mem: { - /** Format: bytes */ - total: number; - }; - fs: { - /** Format: bytes */ - total: number; - /** Format: bytes */ - used: number; - }; - net: { - /** @example eth0 */ - interface: string; - }; + /** Format: id */ + id: string; + app: components['schemas']['App']; + token: string; }; }; }; @@ -8152,24 +10541,17 @@ export type operations = { }; }; /** - * admin/show-moderation-logs + * auth/session/userkey * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/show-moderation-logs': { + 'auth/session/userkey': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - type?: string | null; - /** Format: misskey:id */ - userId?: string | null; + appSecret: string; + token: string; }; }; }; @@ -8178,16 +10560,9 @@ export type operations = { 200: { content: { 'application/json': { - /** Format: id */ - id: string; - /** Format: date-time */ - createdAt: string; - type: string; - info: Record; - /** Format: id */ - userId: string; - user: components['schemas']['UserDetailed']; - }[]; + accessToken: string; + user: components['schemas']['UserDetailedNotMe']; + }; }; }; /** @description Client error */ @@ -8223,12 +10598,12 @@ export type operations = { }; }; /** - * admin/show-user + * blocking/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:blocks* */ - 'admin/show-user': { + 'blocking/create': { requestBody: { content: { 'application/json': { @@ -8241,7 +10616,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': Record; + 'application/json': components['schemas']['UserDetailedNotMe']; }; }; /** @description Client error */ @@ -8268,6 +10643,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -8277,38 +10658,17 @@ export type operations = { }; }; /** - * admin/show-users + * blocking/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:blocks* */ - 'admin/show-users': { + 'blocking/delete': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** @default 0 */ - offset?: number; - /** @enum {string} */ - sort?: '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+updatedAt' | '-updatedAt' | '+lastActiveDate' | '-lastActiveDate'; - /** - * @default all - * @enum {string} - */ - state?: 'all' | 'alive' | 'available' | 'admin' | 'moderator' | 'adminOrModerator' | 'suspended'; - /** - * @default combined - * @enum {string} - */ - origin?: 'combined' | 'local' | 'remote'; - /** @default null */ - username?: string | null; - /** - * @description The local host is represented with `null`. - * @default null - */ - hostname?: string | null; + /** Format: misskey:id */ + userId: string; }; }; }; @@ -8316,7 +10676,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['UserDetailed'][]; + 'application/json': components['schemas']['UserDetailedNotMe']; }; }; /** @description Client error */ @@ -8343,6 +10703,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -8352,24 +10718,30 @@ export type operations = { }; }; /** - * admin/suspend-user + * blocking/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:blocks* */ - 'admin/suspend-user': { + 'blocking/list': { requestBody: { content: { 'application/json': { + /** @default 30 */ + limit?: number; /** Format: misskey:id */ - userId: string; + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Blocking'][]; + }; }; /** @description Client error */ 400: { @@ -8404,24 +10776,31 @@ export type operations = { }; }; /** - * admin/unsuspend-user + * channels/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:channels* */ - 'admin/unsuspend-user': { + 'channels/create': { requestBody: { content: { 'application/json': { + name: string; + description?: string | null; /** Format: misskey:id */ - userId: string; + bannerId?: string | null; + color?: string; + isSensitive?: boolean | null; + allowRenoteToExternal?: boolean | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Channel']; + }; }; /** @description Client error */ 400: { @@ -8447,6 +10826,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -8456,140 +10841,18 @@ export type operations = { }; }; /** - * admin/update-meta + * channels/featured * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/update-meta': { - requestBody: { - content: { - 'application/json': { - disableRegistration?: boolean | null; - pinnedUsers?: string[] | null; - hiddenTags?: string[] | null; - blockedHosts?: string[] | null; - sensitiveWords?: string[] | null; - themeColor?: string | null; - mascotImageUrl?: string | null; - bannerUrl?: string | null; - serverErrorImageUrl?: string | null; - infoImageUrl?: string | null; - notFoundImageUrl?: string | null; - iconUrl?: string | null; - app192IconUrl?: string | null; - app512IconUrl?: string | null; - backgroundImageUrl?: string | null; - logoImageUrl?: string | null; - name?: string | null; - shortName?: string | null; - description?: string | null; - defaultLightTheme?: string | null; - defaultDarkTheme?: string | null; - cacheRemoteFiles?: boolean; - cacheRemoteSensitiveFiles?: boolean; - emailRequiredForSignup?: boolean; - enableHcaptcha?: boolean; - hcaptchaSiteKey?: string | null; - hcaptchaSecretKey?: string | null; - enableRecaptcha?: boolean; - recaptchaSiteKey?: string | null; - recaptchaSecretKey?: string | null; - enableTurnstile?: boolean; - turnstileSiteKey?: string | null; - turnstileSecretKey?: string | null; - /** @enum {string} */ - sensitiveMediaDetection?: 'none' | 'all' | 'local' | 'remote'; - /** @enum {string} */ - sensitiveMediaDetectionSensitivity?: 'medium' | 'low' | 'high' | 'veryLow' | 'veryHigh'; - setSensitiveFlagAutomatically?: boolean; - enableSensitiveMediaDetectionForVideos?: boolean; - /** Format: misskey:id */ - proxyAccountId?: string | null; - maintainerName?: string | null; - maintainerEmail?: string | null; - langs?: string[]; - summalyProxy?: string | null; - translatorType?: string | null; - deeplAuthKey?: string | null; - deeplIsPro?: boolean; - ctav3SaKey?: string | null; - ctav3ProjectId?: string | null; - ctav3Location?: string | null; - ctav3Model?: string | null; - ctav3Glossary?: string | null; - enableEmail?: boolean; - email?: string | null; - smtpSecure?: boolean; - smtpHost?: string | null; - smtpPort?: number | null; - smtpUser?: string | null; - smtpPass?: string | null; - enableServiceWorker?: boolean; - swPublicKey?: string | null; - swPrivateKey?: string | null; - tosUrl?: string | null; - repositoryUrl?: string; - feedbackUrl?: string; - impressumUrl?: string | null; - privacyPolicyUrl?: string | null; - useObjectStorage?: boolean; - objectStorageBaseUrl?: string | null; - objectStorageBucket?: string | null; - objectStoragePrefix?: string | null; - objectStorageEndpoint?: string | null; - objectStorageRegion?: string | null; - objectStoragePort?: number | null; - objectStorageAccessKey?: string | null; - objectStorageSecretKey?: string | null; - objectStorageUseSSL?: boolean; - objectStorageUseProxy?: boolean; - objectStorageSetPublicRead?: boolean; - objectStorageS3ForcePathStyle?: boolean; - useObjectStorageRemote?: boolean; - objectStorageRemoteBaseUrl?: string | null; - objectStorageRemoteBucket?: string | null; - objectStorageRemotePrefix?: string | null; - objectStorageRemoteEndpoint?: string | null; - objectStorageRemoteRegion?: string | null; - objectStorageRemotePort?: number | null; - objectStorageRemoteAccessKey?: string | null; - objectStorageRemoteSecretKey?: string | null; - objectStorageRemoteUseSSL?: boolean; - objectStorageRemoteUseProxy?: boolean; - objectStorageRemoteSetPublicRead?: boolean; - objectStorageRemoteS3ForcePathStyle?: boolean; - enableIpLogging?: boolean; - enableActiveEmailValidation?: boolean; - enableVerifymailApi?: boolean; - verifymailAuthKey?: string | null; - enableChartsForRemoteUser?: boolean; - enableChartsForFederatedInstances?: boolean; - enableServerMachineStats?: boolean; - enableIdenticonGeneration?: boolean; - doNotSendNotificationEmailsForAbuseReport?: boolean; - emailToReceiveAbuseReport?: string | null; - serverRules?: string[]; - preservedUsernames?: string[]; - manifestJsonOverride?: string; - enableFanoutTimeline?: boolean; - enableFanoutTimelineDbFallback?: boolean; - perLocalUserUserTimelineCacheMax?: number; - perRemoteUserUserTimelineCacheMax?: number; - perUserHomeTimelineCacheMax?: number; - perUserListTimelineCacheMax?: number; - notesPerOneAd?: number; - silencedHosts?: string[] | null; - enableReceivePrerelease?: boolean; - skipVersion?: boolean; - skipCherryPickVersion?: string | null; - }; - }; - }; + 'channels/featured': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Channel'][]; + }; }; /** @description Client error */ 400: { @@ -8624,26 +10887,24 @@ export type operations = { }; }; /** - * admin/delete-account + * channels/follow * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:channels* */ - 'admin/delete-account': { + 'channels/follow': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - userId: string; + channelId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -8678,25 +10939,30 @@ export type operations = { }; }; /** - * admin/update-user-note + * channels/followed * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:channels* */ - 'admin/update-user-note': { + 'channels/followed': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - userId: string; - text: string; + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default 5 */ + limit?: number; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Channel'][]; + }; }; /** @description Client error */ 400: { @@ -8731,31 +10997,21 @@ export type operations = { }; }; /** - * admin/roles/create + * channels/owned * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:channels* */ - 'admin/roles/create': { + 'channels/owned': { requestBody: { content: { 'application/json': { - name: string; - description: string; - color: string | null; - iconUrl: string | null; - /** @enum {string} */ - target: 'manual' | 'conditional'; - condFormula: Record; - isPublic: boolean; - isModerator: boolean; - isAdministrator: boolean; - /** @default false */ - isExplorable?: boolean; - asBadge: boolean; - canEditMembersByModerator: boolean; - displayOrder: number; - policies: Record; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default 5 */ + limit?: number; }; }; }; @@ -8763,7 +11019,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Role']; + 'application/json': components['schemas']['Channel'][]; }; }; /** @description Client error */ @@ -8799,24 +11055,26 @@ export type operations = { }; }; /** - * admin/roles/delete + * channels/show * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/roles/delete': { + 'channels/show': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - roleId: string; + channelId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Channel']; + }; }; /** @description Client error */ 400: { @@ -8851,17 +11109,35 @@ export type operations = { }; }; /** - * admin/roles/list + * channels/timeline * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'admin/roles/list': { + 'channels/timeline': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + channelId: string; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + sinceDate?: number; + untilDate?: number; + /** @default false */ + allowPartial?: boolean; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Role'][]; + 'application/json': components['schemas']['Note'][]; }; }; /** @description Client error */ @@ -8897,26 +11173,24 @@ export type operations = { }; }; /** - * admin/roles/show + * channels/unfollow * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:channels* */ - 'admin/roles/show': { + 'channels/unfollow': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - roleId: string; + channelId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Role']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -8951,39 +11225,35 @@ export type operations = { }; }; /** - * admin/roles/update + * channels/update * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:channels* */ - 'admin/roles/update': { + 'channels/update': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - roleId: string; - name: string; - description: string; - color: string | null; - iconUrl: string | null; - /** @enum {string} */ - target: 'manual' | 'conditional'; - condFormula: Record; - isPublic: boolean; - isModerator: boolean; - isAdministrator: boolean; - isExplorable?: boolean; - asBadge: boolean; - canEditMembersByModerator: boolean; - displayOrder: number; - policies: Record; + channelId: string; + name?: string; + description?: string | null; + /** Format: misskey:id */ + bannerId?: string | null; + isArchived?: boolean | null; + pinnedNoteIds?: string[]; + color?: string; + isSensitive?: boolean | null; + allowRenoteToExternal?: boolean | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Channel']; + }; }; /** @description Client error */ 400: { @@ -9018,20 +11288,17 @@ export type operations = { }; }; /** - * admin/roles/assign + * channels/favorite * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:channels* */ - 'admin/roles/assign': { + 'channels/favorite': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - roleId: string; - /** Format: misskey:id */ - userId: string; - expiresAt?: number | null; + channelId: string; }; }; }; @@ -9073,19 +11340,17 @@ export type operations = { }; }; /** - * admin/roles/unassign + * channels/unfavorite * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:channels* */ - 'admin/roles/unassign': { + 'channels/unfavorite': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - roleId: string; - /** Format: misskey:id */ - userId: string; + channelId: string; }; }; }; @@ -9127,23 +11392,18 @@ export type operations = { }; }; /** - * admin/roles/update-default-policies + * channels/my-favorites * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:channels* */ - 'admin/roles/update-default-policies': { - requestBody: { - content: { - 'application/json': { - policies: Record; - }; - }; - }; + 'channels/my-favorites': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Channel'][]; + }; }; /** @description Client error */ 400: { @@ -9178,30 +11438,36 @@ export type operations = { }; }; /** - * admin/roles/users + * channels/search * @description No description provided. * * **Credential required**: *No* */ - 'admin/roles/users': { + 'channels/search': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - roleId: string; + query: string; + /** + * @default nameAndDescription + * @enum {string} + */ + type?: 'nameAndDescription' | 'nameOnly'; /** Format: misskey:id */ sinceId?: string; /** Format: misskey:id */ untilId?: string; - /** @default 10 */ + /** @default 5 */ limit?: number; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Channel'][]; + }; }; /** @description Client error */ 400: { @@ -9236,23 +11502,21 @@ export type operations = { }; }; /** - * announcements + * charts/active-users * @description No description provided. * * **Credential required**: *No* */ - announcements: { + 'charts/active-users': { requestBody: { content: { 'application/json': { - /** @default 10 */ + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default true */ - isActive?: boolean; + /** @default null */ + offset?: number | null; }; }; }; @@ -9260,7 +11524,17 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Announcement'][]; + 'application/json': { + readWrite: number[]; + read: number[]; + write: number[]; + registeredWithinWeek: number[]; + registeredWithinMonth: number[]; + registeredWithinYear: number[]; + registeredOutsideWeek: number[]; + registeredOutsideMonth: number[]; + registeredOutsideYear: number[]; + }; }; }; /** @description Client error */ @@ -9296,30 +11570,21 @@ export type operations = { }; }; /** - * antennas/create + * charts/ap-request * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - 'antennas/create': { + 'charts/ap-request': { requestBody: { content: { 'application/json': { - name: string; /** @enum {string} */ - src: 'home' | 'all' | 'users' | 'list' | 'group' | 'users_blacklist'; - /** Format: misskey:id */ - userListId?: string | null; - /** Format: misskey:id */ - userGroupId?: string | null; - keywords: string[][]; - excludeKeywords: string[][]; - users: string[]; - caseSensitive: boolean; - localOnly?: boolean; - withReplies: boolean; - withFile: boolean; - notify: boolean; + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; }; }; }; @@ -9327,7 +11592,11 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Antenna']; + 'application/json': { + deliverFailed: number[]; + deliverSucceeded: number[]; + inboxReceived: number[]; + }; }; }; /** @description Client error */ @@ -9363,24 +11632,39 @@ export type operations = { }; }; /** - * antennas/delete + * charts/drive * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - 'antennas/delete': { + 'charts/drive': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - antennaId: string; + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + 'local.incCount': number[]; + 'local.incSize': number[]; + 'local.decCount': number[]; + 'local.decSize': number[]; + 'remote.incCount': number[]; + 'remote.incSize': number[]; + 'remote.decCount': number[]; + 'remote.decSize': number[]; + }; + }; }; /** @description Client error */ 400: { @@ -9415,17 +11699,38 @@ export type operations = { }; }; /** - * antennas/list + * charts/federation * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:account* + * **Credential required**: *No* */ - 'antennas/list': { + 'charts/federation': { + requestBody: { + content: { + 'application/json': { + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Antenna'][]; + 'application/json': { + deliveredInstances: number[]; + inboxInstances: number[]; + stalled: number[]; + sub: number[]; + pub: number[]; + pubsub: number[]; + subActive: number[]; + pubActive: number[]; + }; }; }; /** @description Client error */ @@ -9461,25 +11766,22 @@ export type operations = { }; }; /** - * antennas/notes + * charts/instance * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:account* + * **Credential required**: *No* */ - 'antennas/notes': { + 'charts/instance': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - antennaId: string; - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - sinceDate?: number; - untilDate?: number; + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; + host: string; }; }; }; @@ -9487,7 +11789,32 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Note'][]; + 'application/json': { + 'requests.failed': number[]; + 'requests.succeeded': number[]; + 'requests.received': number[]; + 'notes.total': number[]; + 'notes.inc': number[]; + 'notes.dec': number[]; + 'notes.diffs.normal': number[]; + 'notes.diffs.reply': number[]; + 'notes.diffs.renote': number[]; + 'notes.diffs.withFile': number[]; + 'users.total': number[]; + 'users.inc': number[]; + 'users.dec': number[]; + 'following.total': number[]; + 'following.inc': number[]; + 'following.dec': number[]; + 'followers.total': number[]; + 'followers.inc': number[]; + 'followers.dec': number[]; + 'drive.totalFiles': number[]; + 'drive.incFiles': number[]; + 'drive.decFiles': number[]; + 'drive.incUsage': number[]; + 'drive.decUsage': number[]; + }; }; }; /** @description Client error */ @@ -9523,17 +11850,21 @@ export type operations = { }; }; /** - * antennas/show + * charts/notes * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:account* + * **Credential required**: *No* */ - 'antennas/show': { + 'charts/notes': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - antennaId: string; + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; }; }; }; @@ -9541,7 +11872,22 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Antenna']; + 'application/json': { + 'local.total': number[]; + 'local.inc': number[]; + 'local.dec': number[]; + 'local.diffs.normal': number[]; + 'local.diffs.reply': number[]; + 'local.diffs.renote': number[]; + 'local.diffs.withFile': number[]; + 'remote.total': number[]; + 'remote.inc': number[]; + 'remote.dec': number[]; + 'remote.diffs.normal': number[]; + 'remote.diffs.reply': number[]; + 'remote.diffs.renote': number[]; + 'remote.diffs.withFile': number[]; + }; }; }; /** @description Client error */ @@ -9577,32 +11923,23 @@ export type operations = { }; }; /** - * antennas/update + * charts/user/drive * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - 'antennas/update': { + 'charts/user/drive': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - antennaId: string; - name: string; /** @enum {string} */ - src: 'home' | 'all' | 'users' | 'list' | 'group' | 'users_blacklist'; - /** Format: misskey:id */ - userListId?: string | null; + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; /** Format: misskey:id */ - userGroupId?: string | null; - keywords: string[][]; - excludeKeywords: string[][]; - users: string[]; - caseSensitive: boolean; - localOnly?: boolean; - withReplies: boolean; - withFile: boolean; - notify: boolean; + userId: string; }; }; }; @@ -9610,7 +11947,14 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Antenna']; + 'application/json': { + totalCount: number[]; + totalSize: number[]; + incCount: number[]; + incSize: number[]; + decCount: number[]; + decSize: number[]; + }; }; }; /** @description Client error */ @@ -9646,16 +11990,23 @@ export type operations = { }; }; /** - * ap/get + * charts/user/following * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'ap/get': { + 'charts/user/following': { requestBody: { content: { 'application/json': { - uri: string; + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; + /** Format: misskey:id */ + userId: string; }; }; }; @@ -9663,7 +12014,20 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': Record; + 'application/json': { + 'local.followings.total': number[]; + 'local.followings.inc': number[]; + 'local.followings.dec': number[]; + 'local.followers.total': number[]; + 'local.followers.inc': number[]; + 'local.followers.dec': number[]; + 'remote.followings.total': number[]; + 'remote.followings.inc': number[]; + 'remote.followings.dec': number[]; + 'remote.followers.total': number[]; + 'remote.followers.inc': number[]; + 'remote.followers.dec': number[]; + }; }; }; /** @description Client error */ @@ -9690,12 +12054,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -9705,16 +12063,23 @@ export type operations = { }; }; /** - * ap/show + * charts/user/notes * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ - 'ap/show': { + 'charts/user/notes': { requestBody: { content: { 'application/json': { - uri: string; + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; + /** Format: misskey:id */ + userId: string; }; }; }; @@ -9722,15 +12087,15 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': OneOf<[{ - /** @enum {string} */ - type: 'User'; - object: components['schemas']['UserDetailedNotMe']; - }, { - /** @enum {string} */ - type: 'Note'; - object: components['schemas']['Note']; - }]>; + 'application/json': { + total: number[]; + inc: number[]; + dec: number[]; + 'diffs.normal': number[]; + 'diffs.reply': number[]; + 'diffs.renote': number[]; + 'diffs.withFile': number[]; + }; }; }; /** @description Client error */ @@ -9757,12 +12122,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -9772,19 +12131,23 @@ export type operations = { }; }; /** - * app/create + * charts/user/pv * @description No description provided. * * **Credential required**: *No* */ - 'app/create': { + 'charts/user/pv': { requestBody: { content: { 'application/json': { - name: string; - description: string; - permission: string[]; - callbackUrl?: string | null; + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; + /** Format: misskey:id */ + userId: string; }; }; }; @@ -9792,7 +12155,12 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['App']; + 'application/json': { + 'upv.user': number[]; + 'pv.user': number[]; + 'upv.visitor': number[]; + 'pv.visitor': number[]; + }; }; }; /** @description Client error */ @@ -9828,17 +12196,23 @@ export type operations = { }; }; /** - * app/show + * charts/user/reactions * @description No description provided. * * **Credential required**: *No* */ - 'app/show': { + 'charts/user/reactions': { requestBody: { content: { 'application/json': { + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; /** Format: misskey:id */ - appId: string; + userId: string; }; }; }; @@ -9846,7 +12220,10 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['App']; + 'application/json': { + 'local.count': number[]; + 'remote.count': number[]; + }; }; }; /** @description Client error */ @@ -9882,16 +12259,21 @@ export type operations = { }; }; /** - * auth/session/generate + * charts/users * @description No description provided. * * **Credential required**: *No* */ - 'auth/session/generate': { + 'charts/users': { requestBody: { content: { 'application/json': { - appSecret: string; + /** @enum {string} */ + span: 'day' | 'hour'; + /** @default 30 */ + limit?: number; + /** @default null */ + offset?: number | null; }; }; }; @@ -9900,9 +12282,12 @@ export type operations = { 200: { content: { 'application/json': { - token: string; - /** Format: url */ - url: string; + 'local.total': number[]; + 'local.inc': number[]; + 'local.dec': number[]; + 'remote.total': number[]; + 'remote.inc': number[]; + 'remote.dec': number[]; }; }; }; @@ -9939,31 +12324,27 @@ export type operations = { }; }; /** - * auth/session/show + * clips/add-note * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'auth/session/show': { + 'clips/add-note': { requestBody: { content: { - 'application/json': { - token: string; - }; - }; - }; - responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - /** Format: id */ - id: string; - app: components['schemas']['App']; - token: string; - }; + 'application/json': { + /** Format: misskey:id */ + clipId: string; + /** Format: misskey:id */ + noteId: string; }; }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; /** @description Client error */ 400: { content: { @@ -9988,6 +12369,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -9997,29 +12384,26 @@ export type operations = { }; }; /** - * auth/session/userkey + * clips/remove-note * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'auth/session/userkey': { + 'clips/remove-note': { requestBody: { content: { 'application/json': { - appSecret: string; - token: string; + /** Format: misskey:id */ + clipId: string; + /** Format: misskey:id */ + noteId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - accessToken: string; - user: components['schemas']['UserDetailedNotMe']; - }; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -10054,17 +12438,19 @@ export type operations = { }; }; /** - * blocking/create + * clips/create * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:blocks* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'blocking/create': { + 'clips/create': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + name: string; + /** @default false */ + isPublic?: boolean; + description?: string | null; }; }; }; @@ -10072,7 +12458,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['UserDetailedNotMe']; + 'application/json': components['schemas']['Clip']; }; }; /** @description Client error */ @@ -10099,12 +12485,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -10114,26 +12494,24 @@ export type operations = { }; }; /** - * blocking/delete + * clips/delete * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:blocks* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'blocking/delete': { + 'clips/delete': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - userId: string; + clipId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['UserDetailedNotMe']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -10159,12 +12537,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -10174,29 +12546,17 @@ export type operations = { }; }; /** - * blocking/list + * clips/list * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:blocks* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'blocking/list': { - requestBody: { - content: { - 'application/json': { - /** @default 30 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - }; - }; - }; + 'clips/list': { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Blocking'][]; + 'application/json': components['schemas']['Clip'][]; }; }; /** @description Client error */ @@ -10232,22 +12592,23 @@ export type operations = { }; }; /** - * channels/create + * clips/notes * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:channels* + * **Credential required**: *No* / **Permission**: *read:account* */ - 'channels/create': { + 'clips/notes': { requestBody: { content: { 'application/json': { - name: string; - description?: string | null; /** Format: misskey:id */ - bannerId?: string | null; - color?: string; - isSensitive?: boolean | null; - allowRenoteToExternal?: boolean | null; + clipId: string; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; }; }; }; @@ -10255,7 +12616,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Channel']; + 'application/json': components['schemas']['Note'][]; }; }; /** @description Client error */ @@ -10282,12 +12643,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -10297,17 +12652,25 @@ export type operations = { }; }; /** - * channels/featured + * clips/show * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *No* / **Permission**: *read:account* */ - 'channels/featured': { + 'clips/show': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + clipId: string; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Channel'][]; + 'application/json': components['schemas']['Clip']; }; }; /** @description Client error */ @@ -10343,24 +12706,29 @@ export type operations = { }; }; /** - * channels/follow + * clips/update * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:channels* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'channels/follow': { + 'clips/update': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - channelId: string; + clipId: string; + name: string; + isPublic?: boolean; + description?: string | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Clip']; + }; }; /** @description Client error */ 400: { @@ -10395,30 +12763,24 @@ export type operations = { }; }; /** - * channels/followed + * clips/favorite * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:channels* + * **Credential required**: *Yes* / **Permission**: *write:clip-favorite* */ - 'channels/followed': { + 'clips/favorite': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default 5 */ - limit?: number; + clipId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Channel'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -10453,30 +12815,24 @@ export type operations = { }; }; /** - * channels/owned + * clips/unfavorite * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:channels* + * **Credential required**: *Yes* / **Permission**: *write:clip-favorite* */ - 'channels/owned': { + 'clips/unfavorite': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default 5 */ - limit?: number; + clipId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Channel'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -10511,25 +12867,17 @@ export type operations = { }; }; /** - * channels/show + * clips/my-favorites * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:clip-favorite* */ - 'channels/show': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - channelId: string; - }; - }; - }; + 'clips/my-favorites': { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Channel']; + 'application/json': components['schemas']['Clip'][]; }; }; /** @description Client error */ @@ -10550,50 +12898,35 @@ export type operations = { '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']; - }; - }; - }; - }; - /** - * channels/timeline - * @description No description provided. - * - * **Credential required**: *No* - */ - 'channels/timeline': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - channelId: string; - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - sinceDate?: number; - untilDate?: number; - /** @default false */ - allowPartial?: boolean; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; }; }; }; + }; + /** + * drive + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:drive* + */ + drive: { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Note'][]; + 'application/json': { + capacity: number; + usage: number; + }; }; }; /** @description Client error */ @@ -10629,24 +12962,38 @@ export type operations = { }; }; /** - * channels/unfollow + * drive/files * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:channels* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'channels/unfollow': { + 'drive/files': { requestBody: { content: { 'application/json': { + /** @default 10 */ + limit?: number; /** Format: misskey:id */ - channelId: string; + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** + * Format: misskey:id + * @default null + */ + folderId?: string | null; + type?: string | null; + /** @enum {string|null} */ + sort?: '+createdAt' | '-createdAt' | '+name' | '-name' | '+size' | '-size' | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['DriveFile'][]; + }; }; /** @description Client error */ 400: { @@ -10681,26 +13028,23 @@ export type operations = { }; }; /** - * channels/update - * @description No description provided. + * drive/files/attached-notes + * @description Find the notes to which the given file is attached. * - * **Credential required**: *Yes* / **Permission**: *write:channels* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'channels/update': { + 'drive/files/attached-notes': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - channelId: string; - name?: string; - description?: string | null; + sinceId?: string; /** Format: misskey:id */ - bannerId?: string | null; - isArchived?: boolean | null; - pinnedNoteIds?: string[]; - color?: string; - isSensitive?: boolean | null; - allowRenoteToExternal?: boolean | null; + untilId?: string; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + fileId: string; }; }; }; @@ -10708,7 +13052,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Channel']; + 'application/json': components['schemas']['Note'][]; }; }; /** @description Client error */ @@ -10744,24 +13088,25 @@ export type operations = { }; }; /** - * channels/favorite - * @description No description provided. + * drive/files/check-existence + * @description Check if a given file exists. * - * **Credential required**: *Yes* / **Permission**: *write:channels* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'channels/favorite': { + 'drive/files/check-existence': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - channelId: string; + md5: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': boolean; + }; }; /** @description Client error */ 400: { @@ -10796,24 +13141,42 @@ export type operations = { }; }; /** - * channels/unfavorite - * @description No description provided. + * drive/files/create + * @description Upload a new drive file. * - * **Credential required**: *Yes* / **Permission**: *write:channels* + * **Credential required**: *Yes* / **Permission**: *write:drive* */ - 'channels/unfavorite': { + 'drive/files/create': { requestBody: { content: { - 'application/json': { - /** Format: misskey:id */ - channelId: string; + 'multipart/form-data': { + /** + * Format: misskey:id + * @default null + */ + folderId?: string | null; + /** @default null */ + name?: string | null; + /** @default null */ + comment?: string | null; + /** @default false */ + isSensitive?: boolean; + /** @default false */ + force?: boolean; + /** + * Format: binary + * @description The file contents. + */ + file: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['DriveFile']; + }; }; /** @description Client error */ 400: { @@ -10839,6 +13202,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -10848,19 +13217,25 @@ export type operations = { }; }; /** - * channels/my-favorites - * @description No description provided. + * drive/files/delete + * @description Delete an existing drive file. * - * **Credential required**: *Yes* / **Permission**: *read:channels* + * **Credential required**: *Yes* / **Permission**: *write:drive* */ - 'channels/my-favorites': { - responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Channel'][]; + 'drive/files/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + fileId: string; }; }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; /** @description Client error */ 400: { content: { @@ -10894,27 +13269,16 @@ export type operations = { }; }; /** - * channels/search - * @description No description provided. + * drive/files/find-by-hash + * @description Search for a drive file by a hash of the contents. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'channels/search': { + 'drive/files/find-by-hash': { requestBody: { content: { 'application/json': { - query: string; - /** - * @default nameAndDescription - * @enum {string} - */ - type?: 'nameAndDescription' | 'nameOnly'; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default 5 */ - limit?: number; + md5: string; }; }; }; @@ -10922,7 +13286,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Channel'][]; + 'application/json': components['schemas']['DriveFile'][]; }; }; /** @description Client error */ @@ -10958,21 +13322,21 @@ export type operations = { }; }; /** - * charts/active-users - * @description No description provided. + * drive/files/find + * @description Search for a drive file by the given parameters. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'charts/active-users': { + 'drive/files/find': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; + name: string; + /** + * Format: misskey:id + * @default null + */ + folderId?: string | null; }; }; }; @@ -10980,17 +13344,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - readWrite: number[]; - read: number[]; - write: number[]; - registeredWithinWeek: number[]; - registeredWithinMonth: number[]; - registeredWithinYear: number[]; - registeredOutsideWeek: number[]; - registeredOutsideMonth: number[]; - registeredOutsideYear: number[]; - }; + 'application/json': components['schemas']['DriveFile'][]; }; }; /** @description Client error */ @@ -11026,21 +13380,18 @@ export type operations = { }; }; /** - * charts/ap-request - * @description No description provided. + * drive/files/show + * @description Show the properties of a drive file. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'charts/ap-request': { + 'drive/files/show': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; + /** Format: misskey:id */ + fileId?: string; + url?: string; }; }; }; @@ -11048,11 +13399,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - deliverFailed: number[]; - deliverSucceeded: number[]; - inboxReceived: number[]; - }; + 'application/json': components['schemas']['DriveFile']; }; }; /** @description Client error */ @@ -11088,21 +13435,22 @@ export type operations = { }; }; /** - * charts/drive - * @description No description provided. + * drive/files/update + * @description Update the properties of a drive file. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:drive* */ - 'charts/drive': { + 'drive/files/update': { requestBody: { content: { - 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; + 'application/json': { + /** Format: misskey:id */ + fileId: string; + /** Format: misskey:id */ + folderId?: string | null; + name?: string; + isSensitive?: boolean; + comment?: string | null; }; }; }; @@ -11110,16 +13458,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - 'local.incCount': number[]; - 'local.incSize': number[]; - 'local.decCount': number[]; - 'local.decSize': number[]; - 'remote.incCount': number[]; - 'remote.incSize': number[]; - 'remote.decCount': number[]; - 'remote.decSize': number[]; - }; + 'application/json': components['schemas']['DriveFile']; }; }; /** @description Client error */ @@ -11155,39 +13494,36 @@ export type operations = { }; }; /** - * charts/federation - * @description No description provided. + * drive/files/upload-from-url + * @description Request the server to download a new drive file from the specified URL. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:drive* */ - 'charts/federation': { + 'drive/files/upload-from-url': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; + url: string; + /** + * Format: misskey:id + * @default null + */ + folderId?: string | null; + /** @default false */ + isSensitive?: boolean; /** @default null */ - offset?: number | null; + comment?: string | null; + /** @default null */ + marker?: string | null; + /** @default false */ + force?: boolean; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - deliveredInstances: number[]; - inboxInstances: number[]; - stalled: number[]; - sub: number[]; - pub: number[]; - pubsub: number[]; - subActive: number[]; - pubActive: number[]; - }; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -11213,6 +13549,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -11222,22 +13564,26 @@ export type operations = { }; }; /** - * charts/instance + * drive/folders * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'charts/instance': { + 'drive/folders': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ + /** @default 10 */ limit?: number; - /** @default null */ - offset?: number | null; - host: string; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** + * Format: misskey:id + * @default null + */ + folderId?: string | null; }; }; }; @@ -11245,32 +13591,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - 'requests.failed': number[]; - 'requests.succeeded': number[]; - 'requests.received': number[]; - 'notes.total': number[]; - 'notes.inc': number[]; - 'notes.dec': number[]; - 'notes.diffs.normal': number[]; - 'notes.diffs.reply': number[]; - 'notes.diffs.renote': number[]; - 'notes.diffs.withFile': number[]; - 'users.total': number[]; - 'users.inc': number[]; - 'users.dec': number[]; - 'following.total': number[]; - 'following.inc': number[]; - 'following.dec': number[]; - 'followers.total': number[]; - 'followers.inc': number[]; - 'followers.dec': number[]; - 'drive.totalFiles': number[]; - 'drive.incFiles': number[]; - 'drive.decFiles': number[]; - 'drive.incUsage': number[]; - 'drive.decUsage': number[]; - }; + 'application/json': components['schemas']['DriveFolder'][]; }; }; /** @description Client error */ @@ -11306,21 +13627,19 @@ export type operations = { }; }; /** - * charts/notes + * drive/folders/create * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:drive* */ - 'charts/notes': { + 'drive/folders/create': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; + /** @default Untitled */ + name?: string; + /** Format: misskey:id */ + parentId?: string | null; }; }; }; @@ -11328,22 +13647,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - 'local.total': number[]; - 'local.inc': number[]; - 'local.dec': number[]; - 'local.diffs.normal': number[]; - 'local.diffs.reply': number[]; - 'local.diffs.renote': number[]; - 'local.diffs.withFile': number[]; - 'remote.total': number[]; - 'remote.inc': number[]; - 'remote.dec': number[]; - 'remote.diffs.normal': number[]; - 'remote.diffs.reply': number[]; - 'remote.diffs.renote': number[]; - 'remote.diffs.withFile': number[]; - }; + 'application/json': components['schemas']['DriveFolder']; }; }; /** @description Client error */ @@ -11370,6 +13674,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -11379,39 +13689,24 @@ export type operations = { }; }; /** - * charts/user/drive + * drive/folders/delete * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:drive* */ - 'charts/user/drive': { + 'drive/folders/delete': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; /** Format: misskey:id */ - userId: string; + folderId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - totalCount: number[]; - totalSize: number[]; - incCount: number[]; - incSize: number[]; - decCount: number[]; - decSize: number[]; - }; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -11446,23 +13741,21 @@ export type operations = { }; }; /** - * charts/user/following + * drive/folders/find * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'charts/user/following': { + 'drive/folders/find': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; - /** Format: misskey:id */ - userId: string; + name: string; + /** + * Format: misskey:id + * @default null + */ + parentId?: string | null; }; }; }; @@ -11470,20 +13763,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - 'local.followings.total': number[]; - 'local.followings.inc': number[]; - 'local.followings.dec': number[]; - 'local.followers.total': number[]; - 'local.followers.inc': number[]; - 'local.followers.dec': number[]; - 'remote.followings.total': number[]; - 'remote.followings.inc': number[]; - 'remote.followings.dec': number[]; - 'remote.followers.total': number[]; - 'remote.followers.inc': number[]; - 'remote.followers.dec': number[]; - }; + 'application/json': components['schemas']['DriveFolder'][]; }; }; /** @description Client error */ @@ -11519,23 +13799,17 @@ export type operations = { }; }; /** - * charts/user/notes + * drive/folders/show * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'charts/user/notes': { + 'drive/folders/show': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; /** Format: misskey:id */ - userId: string; + folderId: string; }; }; }; @@ -11543,15 +13817,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - total: number[]; - inc: number[]; - dec: number[]; - 'diffs.normal': number[]; - 'diffs.reply': number[]; - 'diffs.renote': number[]; - 'diffs.withFile': number[]; - }; + 'application/json': components['schemas']['DriveFolder']; }; }; /** @description Client error */ @@ -11587,23 +13853,20 @@ export type operations = { }; }; /** - * charts/user/pv + * drive/folders/update * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *write:drive* */ - 'charts/user/pv': { + 'drive/folders/update': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; /** Format: misskey:id */ - userId: string; + folderId: string; + name?: string; + /** Format: misskey:id */ + parentId?: string | null; }; }; }; @@ -11611,12 +13874,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - 'upv.user': number[]; - 'pv.user': number[]; - 'upv.visitor': number[]; - 'pv.visitor': number[]; - }; + 'application/json': components['schemas']['DriveFolder']; }; }; /** @description Client error */ @@ -11652,23 +13910,22 @@ export type operations = { }; }; /** - * charts/user/reactions + * drive/stream * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:drive* */ - 'charts/user/reactions': { + 'drive/stream': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ + /** @default 10 */ limit?: number; - /** @default null */ - offset?: number | null; /** Format: misskey:id */ - userId: string; + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + type?: string; }; }; }; @@ -11676,10 +13933,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': { - 'local.count': number[]; - 'remote.count': number[]; - }; + 'application/json': components['schemas']['DriveFile'][]; }; }; /** @description Client error */ @@ -11715,21 +13969,16 @@ export type operations = { }; }; /** - * charts/users + * email-address/available * @description No description provided. * * **Credential required**: *No* */ - 'charts/users': { + 'email-address/available': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - span: 'day' | 'hour'; - /** @default 30 */ - limit?: number; - /** @default null */ - offset?: number | null; + emailAddress: string; }; }; }; @@ -11738,12 +13987,8 @@ export type operations = { 200: { content: { 'application/json': { - 'local.total': number[]; - 'local.inc': number[]; - 'local.dec': number[]; - 'remote.total': number[]; - 'remote.inc': number[]; - 'remote.dec': number[]; + available: boolean; + reason: string | null; }; }; }; @@ -11780,23 +14025,31 @@ export type operations = { }; }; /** - * clips/add-note + * endpoint * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - 'clips/add-note': { + endpoint: { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - clipId: string; - /** Format: misskey:id */ - noteId: string; + endpoint: string; }; }; }; responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + params: { + name: string; + type: string; + }[]; + } | null; + }; + }; /** @description OK (without any results) */ 204: { content: never; @@ -11825,12 +14078,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -11840,26 +14087,18 @@ export type operations = { }; }; /** - * clips/remove-note + * endpoints * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - 'clips/remove-note': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - clipId: string; - /** Format: misskey:id */ - noteId: string; - }; - }; - }; + endpoints: { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': string[]; + }; }; /** @description Client error */ 400: { @@ -11894,28 +14133,17 @@ export type operations = { }; }; /** - * clips/create + * export-custom-emojis * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'clips/create': { - requestBody: { - content: { - 'application/json': { - name: string; - /** @default false */ - isPublic?: boolean; - description?: string | null; - }; - }; - }; + 'export-custom-emojis': { responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Clip']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -11941,6 +14169,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -11950,24 +14184,31 @@ export type operations = { }; }; /** - * clips/delete + * federation/followers * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - 'clips/delete': { + 'federation/followers': { requestBody: { content: { 'application/json': { + host: string; /** Format: misskey:id */ - clipId: string; + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default 10 */ + limit?: number; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Following'][]; + }; }; /** @description Client error */ 400: { @@ -12002,17 +14243,30 @@ export type operations = { }; }; /** - * clips/list + * federation/following * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:account* + * **Credential required**: *No* */ - 'clips/list': { + 'federation/following': { + requestBody: { + content: { + 'application/json': { + host: string; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default 10 */ + limit?: number; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Clip'][]; + 'application/json': components['schemas']['Following'][]; }; }; /** @description Client error */ @@ -12048,23 +14302,30 @@ export type operations = { }; }; /** - * clips/notes + * federation/instances * @description No description provided. * - * **Credential required**: *No* / **Permission**: *read:account* + * **Credential required**: *No* */ - 'clips/notes': { + 'federation/instances': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - clipId: string; - /** @default 10 */ + /** @description Omit or use `null` to not filter by host. */ + host?: string | null; + blocked?: boolean | null; + notResponding?: boolean | null; + suspended?: boolean | null; + silenced?: boolean | null; + federating?: boolean | null; + subscribing?: boolean | null; + publishing?: boolean | null; + /** @default 30 */ limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; + /** @default 0 */ + offset?: number; + /** @enum {string|null} */ + sort?: '+pubSub' | '-pubSub' | '+notes' | '-notes' | '+users' | '-users' | '+following' | '-following' | '+followers' | '-followers' | '+firstRetrievedAt' | '-firstRetrievedAt' | '+latestRequestReceivedAt' | '-latestRequestReceivedAt' | null; }; }; }; @@ -12072,7 +14333,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Note'][]; + 'application/json': components['schemas']['FederationInstance'][]; }; }; /** @description Client error */ @@ -12108,17 +14369,16 @@ export type operations = { }; }; /** - * clips/show + * federation/show-instance * @description No description provided. * - * **Credential required**: *No* / **Permission**: *read:account* + * **Credential required**: *No* */ - 'clips/show': { + 'federation/show-instance': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - clipId: string; + host: string; }; }; }; @@ -12126,9 +14386,13 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Clip']; + 'application/json': components['schemas']['FederationInstance'] | null; }; }; + /** @description OK (without any results) */ + 204: { + content: never; + }; /** @description Client error */ 400: { content: { @@ -12162,29 +14426,24 @@ export type operations = { }; }; /** - * clips/update + * federation/update-remote-user * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *No* */ - 'clips/update': { + 'federation/update-remote-user': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - clipId: string; - name: string; - isPublic?: boolean; - description?: string | null; + userId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Clip']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -12219,25 +14478,32 @@ export type operations = { }; }; /** - * clips/favorite + * federation/users * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:clip-favorite* + * **Credential required**: *No* */ - 'clips/favorite': { + 'federation/users': { requestBody: { content: { 'application/json': { + host: string; /** Format: misskey:id */ - clipId: string; + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default 10 */ + limit?: number; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['UserDetailedNotMe'][]; }; }; - }; - responses: { - /** @description OK (without any results) */ - 204: { - content: never; - }; /** @description Client error */ 400: { content: { @@ -12271,24 +14537,31 @@ export type operations = { }; }; /** - * clips/unfavorite + * federation/stats * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:clip-favorite* + * **Credential required**: *No* */ - 'clips/unfavorite': { + 'federation/stats': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - clipId: string; + /** @default 10 */ + limit?: number; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + topSubInstances: components['schemas']['FederationInstance'][]; + otherFollowersCount: number; + topPubInstances: components['schemas']['FederationInstance'][]; + otherFollowingCount: number; + }; + }; }; /** @description Client error */ 400: { @@ -12323,17 +14596,26 @@ export type operations = { }; }; /** - * clips/my-favorites + * following/create * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:clip-favorite* + * **Credential required**: *Yes* / **Permission**: *write:following* */ - 'clips/my-favorites': { + 'following/create': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + userId: string; + withReplies?: boolean; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Clip'][]; + 'application/json': components['schemas']['UserLite']; }; }; /** @description Client error */ @@ -12360,6 +14642,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -12369,20 +14657,25 @@ export type operations = { }; }; /** - * drive + * following/delete * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *Yes* / **Permission**: *write:following* */ - drive: { + 'following/delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + userId: string; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': { - capacity: number; - usage: number; - }; + 'application/json': components['schemas']['UserLite']; }; }; /** @description Client error */ @@ -12409,6 +14702,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -12418,29 +14717,20 @@ export type operations = { }; }; /** - * drive/files + * following/update * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *Yes* / **Permission**: *write:following* */ - 'drive/files': { + 'following/update': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; /** Format: misskey:id */ - untilId?: string; - /** - * Format: misskey:id - * @default null - */ - folderId?: string | null; - type?: string | null; - /** @enum {string|null} */ - sort?: '+createdAt' | '-createdAt' | '+name' | '-name' | '+size' | '-size' | null; + userId: string; + /** @enum {string} */ + notify?: 'normal' | 'none'; + withReplies?: boolean; }; }; }; @@ -12448,7 +14738,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFile'][]; + 'application/json': components['schemas']['UserLite']; }; }; /** @description Client error */ @@ -12475,6 +14765,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -12484,32 +14780,25 @@ export type operations = { }; }; /** - * drive/files/attached-notes - * @description Find the notes to which the given file is attached. + * following/update-all + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *Yes* / **Permission**: *write:following* */ - 'drive/files/attached-notes': { + 'following/update-all': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - fileId: string; + /** @enum {string} */ + notify?: 'normal' | 'none'; + withReplies?: boolean; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Note'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -12535,6 +14824,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -12544,16 +14839,17 @@ export type operations = { }; }; /** - * drive/files/check-existence - * @description Check if a given file exists. + * following/invalidate + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *Yes* / **Permission**: *write:following* */ - 'drive/files/check-existence': { + 'following/invalidate': { requestBody: { content: { 'application/json': { - md5: string; + /** Format: misskey:id */ + userId: string; }; }; }; @@ -12561,7 +14857,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': boolean; + 'application/json': components['schemas']['UserLite']; }; }; /** @description Client error */ @@ -12588,6 +14884,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -12597,42 +14899,24 @@ export type operations = { }; }; /** - * drive/files/create - * @description Upload a new drive file. + * following/requests/accept + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:drive* + * **Credential required**: *Yes* / **Permission**: *write:following* */ - 'drive/files/create': { + 'following/requests/accept': { requestBody: { content: { - 'multipart/form-data': { - /** - * Format: misskey:id - * @default null - */ - folderId?: string | null; - /** @default null */ - name?: string | null; - /** @default null */ - comment?: string | null; - /** @default false */ - isSensitive?: boolean; - /** @default false */ - force?: boolean; - /** - * Format: binary - * @description The file contents. - */ - file: string; + 'application/json': { + /** Format: misskey:id */ + userId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['DriveFile']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -12658,12 +14942,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -12673,24 +14951,26 @@ export type operations = { }; }; /** - * drive/files/delete - * @description Delete an existing drive file. + * following/requests/cancel + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:drive* + * **Credential required**: *Yes* / **Permission**: *write:following* */ - 'drive/files/delete': { + 'following/requests/cancel': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - fileId: string; + userId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['UserLite']; + }; }; /** @description Client error */ 400: { @@ -12725,16 +15005,21 @@ export type operations = { }; }; /** - * drive/files/find-by-hash - * @description Search for a drive file by a hash of the contents. + * following/requests/list + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *Yes* / **Permission**: *read:following* */ - 'drive/files/find-by-hash': { + 'following/requests/list': { requestBody: { content: { 'application/json': { - md5: string; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default 10 */ + limit?: number; }; }; }; @@ -12742,7 +15027,12 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFile'][]; + 'application/json': { + /** Format: id */ + id: string; + follower: components['schemas']['UserLite']; + followee: components['schemas']['UserLite']; + }[]; }; }; /** @description Client error */ @@ -12778,30 +15068,24 @@ export type operations = { }; }; /** - * drive/files/find - * @description Search for a drive file by the given parameters. + * following/requests/reject + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *Yes* / **Permission**: *write:following* */ - 'drive/files/find': { + 'following/requests/reject': { requestBody: { - content: { - 'application/json': { - name: string; - /** - * Format: misskey:id - * @default null - */ - folderId?: string | null; + content: { + 'application/json': { + /** Format: misskey:id */ + userId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['DriveFile'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -12836,18 +15120,19 @@ export type operations = { }; }; /** - * drive/files/show - * @description Show the properties of a drive file. + * gallery/featured + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *No* */ - 'drive/files/show': { + 'gallery/featured': { requestBody: { content: { 'application/json': { + /** @default 10 */ + limit?: number; /** Format: misskey:id */ - fileId?: string; - url?: string; + untilId?: string; }; }; }; @@ -12855,7 +15140,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFile']; + 'application/json': components['schemas']['GalleryPost'][]; }; }; /** @description Client error */ @@ -12891,30 +15176,17 @@ export type operations = { }; }; /** - * drive/files/update - * @description Update the properties of a drive file. + * gallery/popular + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:drive* + * **Credential required**: *No* */ - 'drive/files/update': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - fileId: string; - /** Format: misskey:id */ - folderId?: string | null; - name?: string; - isSensitive?: boolean; - comment?: string | null; - }; - }; - }; + 'gallery/popular': { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFile']; + 'application/json': components['schemas']['GalleryPost'][]; }; }; /** @description Client error */ @@ -12950,36 +15222,30 @@ export type operations = { }; }; /** - * drive/files/upload-from-url - * @description Request the server to download a new drive file from the specified URL. + * gallery/posts + * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:drive* + * **Credential required**: *No* */ - 'drive/files/upload-from-url': { + 'gallery/posts': { requestBody: { content: { 'application/json': { - url: string; - /** - * Format: misskey:id - * @default null - */ - folderId?: string | null; - /** @default false */ - isSensitive?: boolean; - /** @default null */ - comment?: string | null; - /** @default null */ - marker?: string | null; - /** @default false */ - force?: boolean; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['GalleryPost'][]; + }; }; /** @description Client error */ 400: { @@ -13005,12 +15271,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -13020,26 +15280,20 @@ export type operations = { }; }; /** - * drive/folders + * gallery/posts/create * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *Yes* / **Permission**: *write:gallery* */ - 'drive/folders': { + 'gallery/posts/create': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** - * Format: misskey:id - * @default null - */ - folderId?: string | null; + title: string; + description?: string | null; + fileIds: string[]; + /** @default false */ + isSensitive?: boolean; }; }; }; @@ -13047,7 +15301,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFolder'][]; + 'application/json': components['schemas']['GalleryPost']; }; }; /** @description Client error */ @@ -13074,6 +15328,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -13083,28 +15343,24 @@ export type operations = { }; }; /** - * drive/folders/create + * gallery/posts/delete * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:drive* + * **Credential required**: *Yes* / **Permission**: *write:gallery* */ - 'drive/folders/create': { + 'gallery/posts/delete': { requestBody: { content: { 'application/json': { - /** @default Untitled */ - name?: string; /** Format: misskey:id */ - parentId?: string | null; + postId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['DriveFolder']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -13130,12 +15386,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -13145,17 +15395,17 @@ export type operations = { }; }; /** - * drive/folders/delete + * gallery/posts/like * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:drive* + * **Credential required**: *Yes* / **Permission**: *write:gallery-likes* */ - 'drive/folders/delete': { + 'gallery/posts/like': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - folderId: string; + postId: string; }; }; }; @@ -13197,21 +15447,17 @@ export type operations = { }; }; /** - * drive/folders/find + * gallery/posts/show * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *No* */ - 'drive/folders/find': { + 'gallery/posts/show': { requestBody: { content: { 'application/json': { - name: string; - /** - * Format: misskey:id - * @default null - */ - parentId?: string | null; + /** Format: misskey:id */ + postId: string; }; }; }; @@ -13219,7 +15465,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFolder'][]; + 'application/json': components['schemas']['GalleryPost']; }; }; /** @description Client error */ @@ -13255,26 +15501,24 @@ export type operations = { }; }; /** - * drive/folders/show + * gallery/posts/unlike * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *Yes* / **Permission**: *write:gallery-likes* */ - 'drive/folders/show': { + 'gallery/posts/unlike': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - folderId: string; + postId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['DriveFolder']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -13309,20 +15553,22 @@ export type operations = { }; }; /** - * drive/folders/update + * gallery/posts/update * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:drive* + * **Credential required**: *Yes* / **Permission**: *write:gallery* */ - 'drive/folders/update': { + 'gallery/posts/update': { requestBody: { content: { 'application/json': { /** Format: misskey:id */ - folderId: string; - name?: string; - /** Format: misskey:id */ - parentId?: string | null; + postId: string; + title: string; + description?: string | null; + fileIds: string[]; + /** @default false */ + isSensitive?: boolean; }; }; }; @@ -13330,7 +15576,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFolder']; + 'application/json': components['schemas']['GalleryPost']; }; }; /** @description Client error */ @@ -13357,6 +15603,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -13366,30 +15618,19 @@ export type operations = { }; }; /** - * drive/stream + * get-online-users-count * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:drive* + * **Credential required**: *No* */ - 'drive/stream': { - requestBody: { - content: { - 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - type?: string; - }; - }; - }; + 'get-online-users-count': { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['DriveFile'][]; + 'application/json': { + count: number; + }; }; }; /** @description Client error */ @@ -13425,27 +15666,27 @@ export type operations = { }; }; /** - * email-address/available + * get-avatar-decorations * @description No description provided. * * **Credential required**: *No* */ - 'email-address/available': { - requestBody: { - content: { - 'application/json': { - emailAddress: string; - }; - }; - }; + 'get-avatar-decorations': { responses: { /** @description OK (with results) */ 200: { content: { 'application/json': { - available: boolean; - reason: string | null; - }; + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; + name: string; + description: string; + url: string; + roleIdsThatCanBeUsedThisDecoration: string[]; + }[]; }; }; /** @description Client error */ @@ -13481,23 +15722,34 @@ export type operations = { }; }; /** - * endpoint + * hashtags/list * @description No description provided. * * **Credential required**: *No* */ - endpoint: { + 'hashtags/list': { requestBody: { content: { 'application/json': { - endpoint: string; + /** @default 10 */ + limit?: number; + /** @default false */ + attachedToUserOnly?: boolean; + /** @default false */ + attachedToLocalUserOnly?: boolean; + /** @default false */ + attachedToRemoteUserOnly?: boolean; + /** @enum {string} */ + sort: '+mentionedUsers' | '-mentionedUsers' | '+mentionedLocalUsers' | '-mentionedLocalUsers' | '+mentionedRemoteUsers' | '-mentionedRemoteUsers' | '+attachedUsers' | '-attachedUsers' | '+attachedLocalUsers' | '-attachedLocalUsers' | '+attachedRemoteUsers' | '-attachedRemoteUsers'; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Hashtag'][]; + }; }; /** @description Client error */ 400: { @@ -13532,12 +15784,23 @@ export type operations = { }; }; /** - * endpoints + * hashtags/search * @description No description provided. * * **Credential required**: *No* */ - endpoints: { + 'hashtags/search': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + query: string; + /** @default 0 */ + offset?: number; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { @@ -13578,22 +15841,16 @@ export type operations = { }; }; /** - * federation/followers + * hashtags/show * @description No description provided. * * **Credential required**: *No* */ - 'federation/followers': { + 'hashtags/show': { requestBody: { content: { 'application/json': { - host: string; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default 10 */ - limit?: number; + tag: string; }; }; }; @@ -13601,7 +15858,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Following'][]; + 'application/json': components['schemas']['Hashtag']; }; }; /** @description Client error */ @@ -13637,30 +15894,21 @@ export type operations = { }; }; /** - * federation/following + * hashtags/trend * @description No description provided. * * **Credential required**: *No* */ - 'federation/following': { - requestBody: { - content: { - 'application/json': { - host: string; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default 10 */ - limit?: number; - }; - }; - }; + 'hashtags/trend': { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Following'][]; + 'application/json': { + tag: string; + chart: number[]; + usersCount: number; + }[]; }; }; /** @description Client error */ @@ -13696,30 +15944,30 @@ export type operations = { }; }; /** - * federation/instances + * hashtags/users * @description No description provided. * * **Credential required**: *No* */ - 'federation/instances': { + 'hashtags/users': { requestBody: { content: { 'application/json': { - /** @description Omit or use `null` to not filter by host. */ - host?: string | null; - blocked?: boolean | null; - notResponding?: boolean | null; - suspended?: boolean | null; - silenced?: boolean | null; - federating?: boolean | null; - subscribing?: boolean | null; - publishing?: boolean | null; - /** @default 30 */ + tag: string; + /** @default 10 */ limit?: number; - /** @default 0 */ - offset?: number; - /** @enum {string|null} */ - sort?: '+pubSub' | '-pubSub' | '+notes' | '-notes' | '+users' | '-users' | '+following' | '-following' | '+followers' | '-followers' | '+firstRetrievedAt' | '-firstRetrievedAt' | '+latestRequestReceivedAt' | '-latestRequestReceivedAt' | null; + /** @enum {string} */ + sort: '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+updatedAt' | '-updatedAt'; + /** + * @default all + * @enum {string} + */ + state?: 'all' | 'alive'; + /** + * @default local + * @enum {string} + */ + origin?: 'combined' | 'local' | 'remote'; }; }; }; @@ -13727,7 +15975,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['FederationInstance'][]; + 'application/json': components['schemas']['UserDetailed'][]; }; }; /** @description Client error */ @@ -13763,30 +16011,19 @@ export type operations = { }; }; /** - * federation/show-instance + * i * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'federation/show-instance': { - requestBody: { - content: { - 'application/json': { - host: string; - }; - }; - }; + i: { responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['FederationInstance'] | null; + 'application/json': components['schemas']['MeDetailed']; }; }; - /** @description OK (without any results) */ - 204: { - content: never; - }; /** @description Client error */ 400: { content: { @@ -13820,17 +16057,17 @@ export type operations = { }; }; /** - * federation/update-remote-user + * i/2fa/done * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - 'federation/update-remote-user': { + 'i/2fa/done': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + token: string; }; }; }; @@ -13872,22 +16109,20 @@ export type operations = { }; }; /** - * federation/users + * i/2fa/key-done * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'federation/users': { + 'i/2fa/key-done': { requestBody: { content: { 'application/json': { - host: string; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default 10 */ - limit?: number; + password: string; + token?: string | null; + name: string; + credential: Record; }; }; }; @@ -13895,7 +16130,10 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['UserDetailedNotMe'][]; + 'application/json': { + id: string; + name: string; + }; }; }; /** @description Client error */ @@ -13931,17 +16169,17 @@ export type operations = { }; }; /** - * federation/stats + * i/2fa/password-less * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'federation/stats': { + 'i/2fa/password-less': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; + value: boolean; }; }; }; @@ -13983,18 +16221,18 @@ export type operations = { }; }; /** - * following/create + * i/2fa/register-key * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:following* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'following/create': { + 'i/2fa/register-key': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; - withReplies?: boolean; + password: string; + token?: string | null; }; }; }; @@ -14002,7 +16240,41 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['UserLite']; + 'application/json': { + rp: { + id: string | null; + }; + user: { + id: string; + name: string; + displayName: string; + }; + challenge: string; + pubKeyCredParams: { + type: string; + alg: number; + }[]; + timeout: number | null; + excludeCredentials: (({ + id: string; + type: string; + transports: ('ble' | 'cable' | 'hybrid' | 'internal' | 'nfc' | 'smart-card' | 'usb')[]; + })[]) | null; + authenticatorSelection: ({ + /** @enum {string} */ + authenticatorAttachment: 'cross-platform' | 'platform'; + requireResidentKey: boolean; + /** @enum {string} */ + userVerification: 'discouraged' | 'preferred' | 'required'; + }) | null; + /** @enum {string|null} */ + attestation: 'direct' | 'enterprise' | 'indirect' | 'none' | null; + extensions: ({ + appid: string | null; + credProps: boolean | null; + hmacCreateSecret: boolean | null; + }) | null; + }; }; }; /** @description Client error */ @@ -14029,12 +16301,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -14044,17 +16310,18 @@ export type operations = { }; }; /** - * following/delete + * i/2fa/register * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:following* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'following/delete': { + 'i/2fa/register': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + password: string; + token?: string | null; }; }; }; @@ -14062,7 +16329,13 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['UserLite']; + 'application/json': { + qr: string; + url: string; + secret: string; + label: string; + issuer: string; + }; }; }; /** @description Client error */ @@ -14089,12 +16362,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -14104,29 +16371,25 @@ export type operations = { }; }; /** - * following/update + * i/2fa/update-key * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:following* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'following/update': { + 'i/2fa/update-key': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; - /** @enum {string} */ - notify?: 'normal' | 'none'; - withReplies?: boolean; + name: string; + credentialId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['UserLite']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14152,12 +16415,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -14167,18 +16424,19 @@ export type operations = { }; }; /** - * following/update-all + * i/2fa/remove-key * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:following* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'following/update-all': { + 'i/2fa/remove-key': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - notify?: 'normal' | 'none'; - withReplies?: boolean; + password: string; + token?: string | null; + credentialId: string; }; }; }; @@ -14211,12 +16469,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -14226,26 +16478,25 @@ export type operations = { }; }; /** - * following/invalidate + * i/2fa/unregister * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:following* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'following/invalidate': { + 'i/2fa/unregister': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + password: string; + token?: string | null; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['UserLite']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14266,13 +16517,7 @@ export type operations = { }; }; /** @description I'm Ai */ - 418: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; - /** @description To many requests */ - 429: { + 418: { content: { 'application/json': components['schemas']['Error']; }; @@ -14286,24 +16531,36 @@ export type operations = { }; }; /** - * following/requests/accept + * i/apps * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:following* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'following/requests/accept': { + 'i/apps': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + /** @enum {string} */ + sort?: '+createdAt' | '-createdAt' | '+lastUsedAt' | '-lastUsedAt'; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + name: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + lastUsedAt: string; + permission: string[]; + }[]; + }; }; /** @description Client error */ 400: { @@ -14338,17 +16595,25 @@ export type operations = { }; }; /** - * following/requests/cancel + * i/authorized-apps * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:following* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'following/requests/cancel': { + 'i/authorized-apps': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + /** @default 10 */ + limit?: number; + /** @default 0 */ + offset?: number; + /** + * @default desc + * @enum {string} + */ + sort?: 'desc' | 'asc'; }; }; }; @@ -14356,7 +16621,14 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['UserLite']; + 'application/json': ({ + /** Format: misskey:id */ + id: string; + name: string; + callbackUrl: string | null; + permission: string[]; + isAuthorized: boolean; + })[]; }; }; /** @description Client error */ @@ -14392,35 +16664,24 @@ export type operations = { }; }; /** - * following/requests/list + * i/claim-achievement * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:following* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'following/requests/list': { + 'i/claim-achievement': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default 10 */ - limit?: number; + /** @enum {string} */ + name: 'notes1' | 'notes10' | 'notes100' | 'notes500' | 'notes1000' | 'notes5000' | 'notes10000' | 'notes20000' | 'notes30000' | 'notes40000' | 'notes50000' | 'notes60000' | 'notes70000' | 'notes80000' | 'notes90000' | 'notes100000' | 'login3' | 'login7' | 'login15' | 'login30' | 'login60' | 'login100' | 'login200' | 'login300' | 'login400' | 'login500' | 'login600' | 'login700' | 'login800' | 'login900' | 'login1000' | 'passedSinceAccountCreated1' | 'passedSinceAccountCreated2' | 'passedSinceAccountCreated3' | 'loggedInOnBirthday' | 'loggedInOnNewYearsDay' | 'noteClipped1' | 'noteFavorited1' | 'myNoteFavorited1' | 'profileFilled' | 'markedAsCat' | 'following1' | 'following10' | 'following50' | 'following100' | 'following300' | 'followers1' | 'followers10' | 'followers50' | 'followers100' | 'followers300' | 'followers500' | 'followers1000' | 'collectAchievements30' | 'viewAchievements3min' | 'iLoveCherryPick' | 'foundTreasure' | 'client30min' | 'client60min' | 'noteDeletedWithin1min' | 'postedAtLateNight' | 'postedAt0min0sec' | 'selfQuote' | 'htl20npm' | 'viewInstanceChart' | 'outputHelloWorldOnScratchpad' | 'open3windows' | 'driveFolderCircularReference' | 'reactWithoutRead' | 'clickedClickHere' | 'justPlainLucky' | 'setNameToSyuilo' | 'setNameToNoriDev' | 'cookieClicked' | 'brainDiver' | 'smashTestNotificationButton' | 'tutorialCompleted' | 'bubbleGameExplodingHead' | 'bubbleGameDoubleExplodingHead'; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - /** Format: id */ - id: string; - follower: components['schemas']['UserLite']; - followee: components['schemas']['UserLite']; - }[]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14455,17 +16716,19 @@ export type operations = { }; }; /** - * following/requests/reject + * i/change-password * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:following* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'following/requests/reject': { + 'i/change-password': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - userId: string; + currentPassword: string; + newPassword: string; + token?: string | null; }; }; }; @@ -14507,28 +16770,25 @@ export type operations = { }; }; /** - * gallery/featured + * i/delete-account * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'gallery/featured': { + 'i/delete-account': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - untilId?: string; + password: string; + token?: string | null; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['GalleryPost'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14563,18 +16823,17 @@ export type operations = { }; }; /** - * gallery/popular + * i/export-blocking * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'gallery/popular': { + 'i/export-blocking': { responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['GalleryPost'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14600,6 +16859,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -14609,30 +16874,27 @@ export type operations = { }; }; /** - * gallery/posts + * i/export-following * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'gallery/posts': { + 'i/export-following': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; + /** @default false */ + excludeMuting?: boolean; + /** @default false */ + excludeInactive?: boolean; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['GalleryPost'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14658,6 +16920,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -14667,29 +16935,17 @@ export type operations = { }; }; /** - * gallery/posts/create + * i/export-mute * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:gallery* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'gallery/posts/create': { - requestBody: { - content: { - 'application/json': { - title: string; - description?: string | null; - fileIds: string[]; - /** @default false */ - isSensitive?: boolean; - }; - }; - }; + 'i/export-mute': { responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['GalleryPost']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14730,20 +16986,13 @@ export type operations = { }; }; /** - * gallery/posts/delete + * i/export-notes * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:gallery* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'gallery/posts/delete': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - postId: string; - }; - }; - }; + 'i/export-notes': { responses: { /** @description OK (without any results) */ 204: { @@ -14773,6 +17022,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -14782,20 +17037,13 @@ export type operations = { }; }; /** - * gallery/posts/like + * i/export-clips * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:gallery-likes* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'gallery/posts/like': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - postId: string; - }; - }; - }; + 'i/export-clips': { responses: { /** @description OK (without any results) */ 204: { @@ -14825,6 +17073,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -14834,26 +17088,17 @@ export type operations = { }; }; /** - * gallery/posts/show + * i/export-favorites * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'gallery/posts/show': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - postId: string; - }; - }; - }; + 'i/export-favorites': { responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['GalleryPost']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14879,6 +17124,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -14888,20 +17139,13 @@ export type operations = { }; }; /** - * gallery/posts/unlike + * i/export-user-lists * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:gallery-likes* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'gallery/posts/unlike': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - postId: string; - }; - }; - }; + 'i/export-user-lists': { responses: { /** @description OK (without any results) */ 204: { @@ -14931,40 +17175,32 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description Internal server error */ - 500: { + /** @description To many requests */ + 429: { content: { 'application/json': components['schemas']['Error']; }; }; - }; - }; - /** - * gallery/posts/update - * @description No description provided. - * - * **Credential required**: *Yes* / **Permission**: *write:gallery* - */ - 'gallery/posts/update': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - postId: string; - title: string; - description?: string | null; - fileIds: string[]; - /** @default false */ - isSensitive?: boolean; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; }; }; }; + }; + /** + * i/export-antennas + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + 'i/export-antennas': { responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['GalleryPost']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15005,16 +17241,30 @@ export type operations = { }; }; /** - * get-online-users-count + * i/favorites * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:favorites* */ - 'get-online-users-count': { + 'i/favorites': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + }; + }; + }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['NoteFavorite'][]; + }; }; /** @description Client error */ 400: { @@ -15049,26 +17299,32 @@ export type operations = { }; }; /** - * get-avatar-decorations + * i/gallery/likes * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:gallery-likes* */ - 'get-avatar-decorations': { + 'i/gallery/likes': { + requestBody: { + content: { + 'application/json': { + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { content: { 'application/json': { - /** - * Format: id - * @example xxxxxxxxxx - */ + /** Format: id */ id: string; - name: string; - description: string; - url: string; - roleIdsThatCanBeUsedThisDecoration: string[]; + post: components['schemas']['GalleryPost']; }[]; }; }; @@ -15105,25 +17361,21 @@ export type operations = { }; }; /** - * hashtags/list + * i/gallery/posts * @description No description provided. * - * **Credential required**: *No* + * **Credential required**: *Yes* / **Permission**: *read:gallery* */ - 'hashtags/list': { + 'i/gallery/posts': { requestBody: { content: { 'application/json': { /** @default 10 */ limit?: number; - /** @default false */ - attachedToUserOnly?: boolean; - /** @default false */ - attachedToLocalUserOnly?: boolean; - /** @default false */ - attachedToRemoteUserOnly?: boolean; - /** @enum {string} */ - sort: '+mentionedUsers' | '-mentionedUsers' | '+mentionedLocalUsers' | '-mentionedLocalUsers' | '+mentionedRemoteUsers' | '-mentionedRemoteUsers' | '+attachedUsers' | '-attachedUsers' | '+attachedLocalUsers' | '-attachedLocalUsers' | '+attachedRemoteUsers' | '-attachedRemoteUsers'; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; }; }; }; @@ -15131,7 +17383,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Hashtag'][]; + 'application/json': components['schemas']['GalleryPost'][]; }; }; /** @description Client error */ @@ -15167,29 +17419,25 @@ export type operations = { }; }; /** - * hashtags/search + * i/import-blocking * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'hashtags/search': { + 'i/import-blocking': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - query: string; - /** @default 0 */ - offset?: number; + /** Format: misskey:id */ + fileId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': string[]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15215,6 +17463,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -15224,25 +17478,26 @@ export type operations = { }; }; /** - * hashtags/show + * i/import-following * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'hashtags/show': { + 'i/import-following': { requestBody: { content: { 'application/json': { - tag: string; + /** Format: misskey:id */ + fileId: string; + withReplies?: boolean; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Hashtag']; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15268,6 +17523,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -15277,23 +17538,26 @@ export type operations = { }; }; /** - * hashtags/trend + * i/import-muting * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'hashtags/trend': { - responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - tag: string; - chart: number[]; - usersCount: number; - }[]; + 'i/import-muting': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + fileId: string; }; }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; /** @description Client error */ 400: { content: { @@ -15318,6 +17582,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -15327,39 +17597,25 @@ export type operations = { }; }; /** - * hashtags/users + * i/import-user-lists * @description No description provided. * - * **Credential required**: *No* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'hashtags/users': { + 'i/import-user-lists': { requestBody: { content: { 'application/json': { - tag: string; - /** @default 10 */ - limit?: number; - /** @enum {string} */ - sort: '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+updatedAt' | '-updatedAt'; - /** - * @default all - * @enum {string} - */ - state?: 'all' | 'alive'; - /** - * @default local - * @enum {string} - */ - origin?: 'combined' | 'local' | 'remote'; + /** Format: misskey:id */ + fileId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['UserDetailed'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15385,6 +17641,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -15394,19 +17656,26 @@ export type operations = { }; }; /** - * i + * i/import-antennas * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - i: { - responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['MeDetailed']; + 'i/import-antennas': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + fileId: string; }; }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; /** @description Client error */ 400: { content: { @@ -15431,6 +17700,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -15440,24 +17715,34 @@ export type operations = { }; }; /** - * i/claim-achievement + * i/notifications * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:notifications* */ - 'i/claim-achievement': { + 'i/notifications': { requestBody: { content: { 'application/json': { - /** @enum {string} */ - name: 'notes1' | 'notes10' | 'notes100' | 'notes500' | 'notes1000' | 'notes5000' | 'notes10000' | 'notes20000' | 'notes30000' | 'notes40000' | 'notes50000' | 'notes60000' | 'notes70000' | 'notes80000' | 'notes90000' | 'notes100000' | 'login3' | 'login7' | 'login15' | 'login30' | 'login60' | 'login100' | 'login200' | 'login300' | 'login400' | 'login500' | 'login600' | 'login700' | 'login800' | 'login900' | 'login1000' | 'passedSinceAccountCreated1' | 'passedSinceAccountCreated2' | 'passedSinceAccountCreated3' | 'loggedInOnBirthday' | 'loggedInOnNewYearsDay' | 'noteClipped1' | 'noteFavorited1' | 'myNoteFavorited1' | 'profileFilled' | 'markedAsCat' | 'following1' | 'following10' | 'following50' | 'following100' | 'following300' | 'followers1' | 'followers10' | 'followers50' | 'followers100' | 'followers300' | 'followers500' | 'followers1000' | 'collectAchievements30' | 'viewAchievements3min' | 'iLoveCherryPick' | 'foundTreasure' | 'client30min' | 'client60min' | 'noteDeletedWithin1min' | 'postedAtLateNight' | 'postedAt0min0sec' | 'selfQuote' | 'htl20npm' | 'viewInstanceChart' | 'outputHelloWorldOnScratchpad' | 'open3windows' | 'driveFolderCircularReference' | 'reactWithoutRead' | 'clickedClickHere' | 'justPlainLucky' | 'setNameToSyuilo' | 'cookieClicked' | 'brainDiver' | 'smashTestNotificationButton' | 'tutorialCompleted'; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + /** @default true */ + markAsRead?: boolean; + includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; + excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Notification'][]; + }; }; /** @description Client error */ 400: { @@ -15477,8 +17762,14 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description I'm Ai */ - 418: { + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description To many requests */ + 429: { content: { 'application/json': components['schemas']['Error']; }; @@ -15492,12 +17783,12 @@ export type operations = { }; }; /** - * i/favorites + * i/notifications-grouped * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:favorites* + * **Credential required**: *Yes* / **Permission**: *read:notifications* */ - 'i/favorites': { + 'i/notifications-grouped': { requestBody: { content: { 'application/json': { @@ -15507,6 +17798,10 @@ export type operations = { sinceId?: string; /** Format: misskey:id */ untilId?: string; + /** @default true */ + markAsRead?: boolean; + includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; + excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; }; }; }; @@ -15514,7 +17809,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['NoteFavorite'][]; + 'application/json': components['schemas']['Notification'][]; }; }; /** @description Client error */ @@ -15541,6 +17836,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -15550,12 +17851,12 @@ export type operations = { }; }; /** - * i/gallery/likes + * i/page-likes * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:gallery-likes* + * **Credential required**: *Yes* / **Permission**: *read:page-likes* */ - 'i/gallery/likes': { + 'i/page-likes': { requestBody: { content: { 'application/json': { @@ -15575,7 +17876,7 @@ export type operations = { 'application/json': { /** Format: id */ id: string; - post: components['schemas']['GalleryPost']; + page: components['schemas']['Page']; }[]; }; }; @@ -15612,12 +17913,12 @@ export type operations = { }; }; /** - * i/gallery/posts + * i/pages * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:gallery* + * **Credential required**: *Yes* / **Permission**: *read:pages* */ - 'i/gallery/posts': { + 'i/pages': { requestBody: { content: { 'application/json': { @@ -15634,7 +17935,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['GalleryPost'][]; + 'application/json': components['schemas']['Page'][]; }; }; /** @description Client error */ @@ -15670,25 +17971,17 @@ export type operations = { }; }; /** - * i/notifications + * i/pin * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:notifications* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'i/notifications': { + 'i/pin': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default true */ - markAsRead?: boolean; - includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; - excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; + noteId: string; }; }; }; @@ -15696,7 +17989,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['Notification'][]; + 'application/json': components['schemas']['MeDetailed']; }; }; /** @description Client error */ @@ -15723,12 +18016,6 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { - content: { - 'application/json': components['schemas']['Error']; - }; - }; /** @description Internal server error */ 500: { content: { @@ -15738,34 +18025,16 @@ export type operations = { }; }; /** - * i/notifications-grouped + * i/read-all-messaging-messages * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:notifications* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'i/notifications-grouped': { - requestBody: { - content: { - 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; - /** @default true */ - markAsRead?: boolean; - includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; - excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'groupInvited' | 'achievementEarned' | 'app' | 'test' | 'pollVote')[]; - }; - }; - }; + 'i/read-all-messaging-messages': { responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Notification'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15791,8 +18060,46 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; - /** @description To many requests */ - 429: { + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * i/read-all-unread-notes + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + 'i/read-all-unread-notes': { + 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']; }; @@ -15806,34 +18113,24 @@ export type operations = { }; }; /** - * i/page-likes + * i/read-announcement * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:page-likes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'i/page-likes': { + 'i/read-announcement': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; + announcementId: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': { - /** Format: id */ - id: string; - page: components['schemas']['Page']; - }[]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15868,30 +18165,24 @@ export type operations = { }; }; /** - * i/pages + * i/regenerate-token * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *read:pages* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'i/pages': { + 'i/regenerate-token': { requestBody: { content: { 'application/json': { - /** @default 10 */ - limit?: number; - /** Format: misskey:id */ - sinceId?: string; - /** Format: misskey:id */ - untilId?: string; + password: string; }; }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': components['schemas']['Page'][]; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15926,17 +18217,18 @@ export type operations = { }; }; /** - * i/pin + * i/registry/get-all * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'i/pin': { + 'i/registry/get-all': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - noteId: string; + /** @default [] */ + scope: string[]; + domain?: string | null; }; }; }; @@ -15944,7 +18236,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['MeDetailed']; + 'application/json': Record; }; }; /** @description Client error */ @@ -15980,16 +18272,28 @@ export type operations = { }; }; /** - * i/read-all-messaging-messages + * i/registry/get-detail * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'i/read-all-messaging-messages': { + 'i/registry/get-detail': { + requestBody: { + content: { + 'application/json': { + key: string; + /** @default [] */ + scope: string[]; + domain?: string | null; + }; + }; + }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': Record; + }; }; /** @description Client error */ 400: { @@ -16024,16 +18328,28 @@ export type operations = { }; }; /** - * i/read-all-unread-notes + * i/registry/get * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'i/read-all-unread-notes': { + 'i/registry/get': { + requestBody: { + content: { + 'application/json': { + key: string; + /** @default [] */ + scope: string[]; + domain?: string | null; + }; + }; + }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': Record; + }; }; /** @description Client error */ 400: { @@ -16068,24 +18384,27 @@ export type operations = { }; }; /** - * i/read-announcement + * i/registry/keys-with-type * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'i/read-announcement': { + 'i/registry/keys-with-type': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - announcementId: string; + /** @default [] */ + scope: string[]; + domain?: string | null; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': Record; + }; }; /** @description Client error */ 400: { @@ -16120,12 +18439,12 @@ export type operations = { }; }; /** - * i/registry/get-all + * i/registry/keys * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ - 'i/registry/get-all': { + 'i/registry/keys': { requestBody: { content: { 'application/json': { @@ -16173,12 +18492,12 @@ export type operations = { }; }; /** - * i/registry/get-detail + * i/registry/remove * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'i/registry/get-detail': { + 'i/registry/remove': { requestBody: { content: { 'application/json': { @@ -16227,26 +18546,22 @@ export type operations = { }; }; /** - * i/registry/get + * i/registry/scopes-with-domain * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - 'i/registry/get': { - requestBody: { - content: { - 'application/json': { - key: string; - /** @default [] */ - scope: string[]; - domain?: string | null; - }; - }; - }; + 'i/registry/scopes-with-domain': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ({ + scopes: string[][]; + domain: string | null; + })[]; + }; }; /** @description Client error */ 400: { @@ -16281,15 +18596,17 @@ export type operations = { }; }; /** - * i/registry/keys-with-type + * i/registry/set * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'i/registry/keys-with-type': { + 'i/registry/set': { requestBody: { content: { 'application/json': { + key: string; + value: unknown; /** @default [] */ scope: string[]; domain?: string | null; @@ -16334,18 +18651,19 @@ export type operations = { }; }; /** - * i/registry/keys + * i/revoke-token * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - 'i/registry/keys': { + 'i/revoke-token': { requestBody: { content: { 'application/json': { - /** @default [] */ - scope: string[]; - domain?: string | null; + /** Format: misskey:id */ + tokenId?: string; + token?: string | null; }; }; }; @@ -16387,26 +18705,31 @@ export type operations = { }; }; /** - * i/registry/remove + * i/signin-history * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ - 'i/registry/remove': { + 'i/signin-history': { requestBody: { content: { 'application/json': { - key: string; - /** @default [] */ - scope: string[]; - domain?: string | null; + /** @default 10 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Signin'][]; + }; }; /** @description Client error */ 400: { @@ -16441,27 +18764,26 @@ export type operations = { }; }; /** - * i/registry/set + * i/unpin * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ - 'i/registry/set': { + 'i/unpin': { requestBody: { content: { 'application/json': { - key: string; - value: unknown; - /** @default [] */ - scope: string[]; - domain?: string | null; + /** Format: misskey:id */ + noteId: string; }; }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['MeDetailed']; + }; }; /** @description Client error */ 400: { @@ -16496,17 +18818,19 @@ export type operations = { }; }; /** - * i/unpin + * i/update-email * @description No description provided. * - * **Credential required**: *Yes* / **Permission**: *write:account* + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* */ - 'i/unpin': { + 'i/update-email': { requestBody: { content: { 'application/json': { - /** Format: misskey:id */ - noteId: string; + password: string; + email?: string | null; + token?: string | null; }; }; }; @@ -16514,7 +18838,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['MeDetailed']; + 'application/json': components['schemas']['UserDetailed']; }; }; /** @description Client error */ @@ -16541,6 +18865,12 @@ export type operations = { 'application/json': components['schemas']['Error']; }; }; + /** @description To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; /** @description Internal server error */ 500: { content: { @@ -16572,9 +18902,9 @@ export type operations = { id: string; angle?: number | null; flipH?: boolean | null; + offsetX?: number | null; + offsetY?: number | null; scale?: number | null; - moveX?: number | null; - moveY?: number | null; opacity?: number | null; })[]; /** Format: misskey:id */ @@ -16598,7 +18928,9 @@ export type operations = { alwaysMarkNsfw?: boolean; autoSensitive?: boolean; /** @enum {string} */ - ffVisibility?: 'public' | 'followers' | 'private'; + followingVisibility?: 'public' | 'followers' | 'private'; + /** @enum {string} */ + followersVisibility?: 'public' | 'followers' | 'private'; /** Format: misskey:id */ pinnedPageId?: string | null; mutedWords?: (string[] | string)[]; @@ -16717,6 +19049,66 @@ export type operations = { }; }; }; + /** + * i/move + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + 'i/move': { + requestBody: { + content: { + 'application/json': { + moveToAccount: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': Record; + }; + }; + /** @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 To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; /** * i/webhooks/create * @description No description provided. @@ -16736,9 +19128,24 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + /** Format: misskey:id */ + userId: string; + name: string; + on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[]; + url: string; + secret: string; + active: boolean; + /** Format: date-time */ + latestSentAt: string | null; + latestStatus: number | null; + }; + }; }; /** @description Client error */ 400: { @@ -16780,9 +19187,24 @@ export type operations = { */ 'i/webhooks/list': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': ({ + /** Format: misskey:id */ + id: string; + /** Format: misskey:id */ + userId: string; + name: string; + on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[]; + url: string; + secret: string; + active: boolean; + /** Format: date-time */ + latestSentAt: string | null; + latestStatus: number | null; + })[]; + }; }; /** @description Client error */ 400: { @@ -16832,9 +19254,24 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + /** Format: misskey:id */ + userId: string; + name: string; + on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[]; + url: string; + secret: string; + active: boolean; + /** Format: date-time */ + latestSentAt: string | null; + latestStatus: number | null; + }; + }; }; /** @description Client error */ 400: { @@ -16982,7 +19419,7 @@ export type operations = { * invite/create * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:invite-codes* */ 'invite/create': { responses: { @@ -17028,7 +19465,7 @@ export type operations = { * invite/delete * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:invite-codes* */ 'invite/delete': { requestBody: { @@ -17080,7 +19517,7 @@ export type operations = { * invite/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:invite-codes* */ 'invite/list': { requestBody: { @@ -17138,7 +19575,7 @@ export type operations = { * invite/limit * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:invite-codes* */ 'invite/limit': { responses: { @@ -17523,6 +19960,9 @@ export type operations = { emailRequiredForSignup: boolean; enableHcaptcha: boolean; hcaptchaSiteKey: string | null; + enableMcaptcha: boolean; + mcaptchaSiteKey: string | null; + mcaptchaInstanceUrl: string | null; enableRecaptcha: boolean; recaptchaSiteKey: string | null; enableTurnstile: boolean; @@ -17537,11 +19977,18 @@ export type operations = { iconUrl: string | null; maxNoteTextLength: number; ads: { - place: string; + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; /** Format: url */ url: string; + place: string; + ratio: number; /** Format: url */ imageUrl: string; + dayOfWeek: number; }[]; /** @default 0 */ notesPerOneAd: number; @@ -17658,11 +20105,69 @@ export type operations = { * * **Credential required**: *No* */ - emoji: { + emoji: { + requestBody: { + content: { + 'application/json': { + name: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['EmojiDetailed']; + }; + }; + /** @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']; + }; + }; + }; + }; + /** + * miauth/gen-token + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + 'miauth/gen-token': { requestBody: { content: { 'application/json': { - name: string; + session: string | null; + name?: string | null; + description?: string | null; + iconUrl?: string | null; + permission: string[]; }; }; }; @@ -17670,7 +20175,9 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['EmojiDetailed']; + 'application/json': { + token: string; + }; }; }; /** @description Client error */ @@ -18047,7 +20554,7 @@ export type operations = { * my/apps * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'my/apps': { requestBody: { @@ -18115,6 +20622,7 @@ export type operations = { renote?: boolean; withFiles?: boolean; poll?: boolean; + event?: boolean; /** @default 10 */ limit?: number; /** Format: misskey:id */ @@ -18804,7 +21312,7 @@ export type operations = { * notes/hybrid-timeline * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'notes/hybrid-timeline': { requestBody: { @@ -18950,7 +21458,7 @@ export type operations = { * notes/mentions * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'notes/mentions': { requestBody: { @@ -19011,7 +21519,7 @@ export type operations = { * notes/polls/recommendation * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'notes/polls/recommendation': { requestBody: { @@ -19697,7 +22205,7 @@ export type operations = { * notes/state * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'notes/state': { requestBody: { @@ -19864,7 +22372,7 @@ export type operations = { * notes/timeline * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'notes/timeline': { requestBody: { @@ -19938,7 +22446,7 @@ export type operations = { * notes/translate * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'notes/translate': { requestBody: { @@ -19954,7 +22462,10 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': Record; + 'application/json': { + sourceLang: string; + text: string; + }; }; }; /** @description Client error */ @@ -20051,7 +22562,7 @@ export type operations = { * notes/user-list-timeline * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'notes/user-list-timeline': { requestBody: { @@ -20279,6 +22790,61 @@ export type operations = { }; }; }; + /** + * page-push + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + 'page-push': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + pageId: string; + event: string; + var?: unknown; + }; + }; + }; + 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']; + }; + }; + }; + }; /** * pages/create * @description No description provided. @@ -20708,9 +23274,11 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['Flash']; + }; }; /** @description Client error */ 400: { @@ -20848,6 +23416,68 @@ export type operations = { }; }; }; + /** + * flash/gen-token + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* + */ + 'flash/gen-token': { + requestBody: { + content: { + 'application/json': { + permissions: string[]; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + token: string; + }; + }; + }; + /** @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 To many requests */ + 429: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; /** * flash/like * @description No description provided. @@ -21288,7 +23918,7 @@ export type operations = { * promo/read * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ 'promo/read': { requestBody: { @@ -21340,7 +23970,7 @@ export type operations = { * roles/list * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'roles/list': { responses: { @@ -21458,9 +24088,15 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + user: components['schemas']['User']; + }[]; + }; }; /** @description Client error */ 400: { @@ -21498,7 +24134,7 @@ export type operations = { * roles/notes * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'roles/notes': { requestBody: { @@ -21718,9 +24354,24 @@ export type operations = { */ 'server-info': { responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + machine: string; + cpu: { + model: string; + cores: number; + }; + mem: { + total: number; + }; + fs: { + total: number; + used: number; + }; + }; + }; }; /** @description Client error */ 400: { @@ -21812,6 +24463,7 @@ export type operations = { * sw/show-registration * @description Check push notification registration exists. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ 'sw/show-registration': { @@ -21873,6 +24525,7 @@ export type operations = { * sw/update-registration * @description Update push notification registration. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ 'sw/update-registration': { @@ -21931,6 +24584,7 @@ export type operations = { * sw/register * @description Register to receive push notifications. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ 'sw/register': { @@ -22064,9 +24718,19 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + required: boolean; + string: string; + default: string; + /** @default hello */ + nullableDefault: string | null; + }; + }; }; /** @description Client error */ 400: { @@ -23557,7 +26221,7 @@ export type operations = { * users/lists/favorite * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ 'users/lists/favorite': { requestBody: { @@ -23609,7 +26273,7 @@ export type operations = { * users/lists/unfavorite * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ 'users/lists/unfavorite': { requestBody: { @@ -23717,7 +26381,7 @@ export type operations = { * users/lists/create-from-public * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:account* */ 'users/lists/create-from-public': { requestBody: { @@ -23847,9 +26511,20 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + /** Format: date-time */ + createdAt: string; + /** Format: misskey:id */ + userId: string; + user: components['schemas']['User']; + withReplies: boolean; + }[]; + }; }; /** @description Client error */ 400: { @@ -24199,7 +26874,7 @@ export type operations = { * users/relation * @description Show the different kinds of relations between the authenticated user and the specified user(s). * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'users/relation': { requestBody: { @@ -24274,7 +26949,7 @@ export type operations = { * users/report-abuse * @description File a report. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *write:report-abuse* */ 'users/report-abuse': { requestBody: { @@ -24583,7 +27258,7 @@ export type operations = { * users/achievements * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *No* */ 'users/achievements': { requestBody: { @@ -24595,9 +27270,14 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + name: string; + unlockedAt: number; + }[]; + }; }; /** @description Client error */ 400: { @@ -24689,7 +27369,7 @@ export type operations = { * users/translate * @description No description provided. * - * **Credential required**: *Yes* + * **Credential required**: *Yes* / **Permission**: *read:account* */ 'users/translate': { requestBody: { @@ -24705,7 +27385,10 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': Record; + 'application/json': { + sourceLang: string; + text: string; + }; }; }; /** @description Client error */ @@ -24755,9 +27438,13 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + items: Record[]; + }; + }; }; /** @description Client error */ 400: { @@ -24795,6 +27482,7 @@ export type operations = { * fetch-external-resources * @description No description provided. * + * **Internal Endpoint**: This endpoint is an API for the cherrypick mainframe and is not intended for use by third parties. * **Credential required**: *Yes* */ 'fetch-external-resources': { @@ -24807,9 +27495,14 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + type: string; + data: string; + }; + }; }; /** @description Client error */ 400: { diff --git a/packages/cherrypick-js/src/consts.ts b/packages/cherrypick-js/src/consts.ts index a8f0b96d5d..0e446c1215 100644 --- a/packages/cherrypick-js/src/consts.ts +++ b/packages/cherrypick-js/src/consts.ts @@ -1,10 +1,12 @@ -export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'achievementEarned'] as const; +export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const; export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; export const mutedNoteReasons = ['word', 'manual', 'spam', 'other'] as const; -export const ffVisibility = ['public', 'followers', 'private'] as const; +export const followingVisibilities = ['public', 'followers', 'private'] as const; + +export const followersVisibilities = ['public', 'followers', 'private'] as const; export const permissions = [ 'read:account', @@ -43,7 +45,55 @@ export const permissions = [ 'write:flash', 'read:flash-likes', 'write:flash-likes', -]; + 'read:admin:abuse-user-reports', + 'write:admin:delete-account', + 'write:admin:delete-all-files-of-a-user', + 'read:admin:index-stats', + 'read:admin:table-stats', + 'read:admin:user-ips', + 'read:admin:meta', + 'write:admin:reset-password', + 'write:admin:resolve-abuse-user-report', + 'write:admin:send-email', + 'read:admin:server-info', + 'read:admin:show-moderation-log', + 'read:admin:show-user', + 'read:admin:show-users', + 'write:admin:suspend-user', + 'write:admin:unset-user-avatar', + 'write:admin:unset-user-banner', + 'write:admin:unsuspend-user', + 'write:admin:meta', + 'write:admin:user-note', + 'write:admin:roles', + 'read:admin:roles', + 'write:admin:relays', + 'read:admin:relays', + 'write:admin:invite-codes', + 'read:admin:invite-codes', + 'write:admin:announcements', + 'read:admin:announcements', + 'write:admin:avatar-decorations', + 'read:admin:avatar-decorations', + 'write:admin:federation', + 'write:admin:account', + 'read:admin:account', + 'write:admin:emoji', + 'read:admin:emoji', + 'write:admin:queue', + 'read:admin:queue', + 'write:admin:promo', + 'write:admin:drive', + 'read:admin:drive', + 'write:admin:ad', + 'read:admin:ad', + 'write:invite-codes', + 'read:invite-codes', + 'write:clip-favorite', + 'read:clip-favorite', + 'read:federation', + 'write:report-abuse', +] as const; export const moderationLogTypes = [ 'updateServerSettings', diff --git a/packages/cherrypick-js/src/entities.ts b/packages/cherrypick-js/src/entities.ts index 99f433cc02..9ee55fc884 100644 --- a/packages/cherrypick-js/src/entities.ts +++ b/packages/cherrypick-js/src/entities.ts @@ -1,5 +1,5 @@ import { ModerationLogPayloads } from './consts.js'; -import { Announcement, EmojiDetailed, Page, User, UserDetailed } from './autogen/models'; +import { Announcement, EmojiDetailed, MeDetailed, Page, User, UserDetailed } from './autogen/models'; export * from './autogen/entities'; export * from './autogen/models'; @@ -149,7 +149,7 @@ export type ServerStats = { } }; -export type ServerStatsLog = string[]; +export type ServerStatsLog = ServerStats[]; export type QueueStats = { deliver: { @@ -166,7 +166,7 @@ export type QueueStats = { }; }; -export type QueueStatsLog = string[]; +export type QueueStatsLog = QueueStats[]; export type EmojiAdded = { emoji: EmojiDetailed @@ -183,3 +183,38 @@ export type EmojiDeleted = { export type AnnouncementCreated = { announcement: Announcement; }; + +export type SignupRequest = { + username: string; + password: string; + host?: string; + invitationCode?: string; + emailAddress?: string; + 'hcaptcha-response'?: string | null; + 'g-recaptcha-response'?: string | null; + 'turnstile-response'?: string | null; +} + +export type SignupResponse = MeDetailed & { + token: string; +} + +export type SignupPendingRequest = { + code: string; +}; + +export type SignupPendingResponse = { + id: User['id'], + i: string, +}; + +export type SigninRequest = { + username: string; + password: string; + token?: string; +}; + +export type SigninResponse = { + id: User['id'], + i: string, +}; diff --git a/packages/cherrypick-js/src/index.ts b/packages/cherrypick-js/src/index.ts index e78501fdfd..54cae8ec03 100644 --- a/packages/cherrypick-js/src/index.ts +++ b/packages/cherrypick-js/src/index.ts @@ -16,7 +16,8 @@ export const permissions = consts.permissions; export const notificationTypes = consts.notificationTypes; export const noteVisibilities = consts.noteVisibilities; export const mutedNoteReasons = consts.mutedNoteReasons; -export const ffVisibility = consts.ffVisibility; +export const followingVisibilities = consts.followingVisibilities; +export const followersVisibilities = consts.followersVisibilities; export const moderationLogTypes = consts.moderationLogTypes; // api extractor not supported yet diff --git a/packages/frontend/.eslintrc.cjs b/packages/frontend/.eslintrc.cjs index 6b297fbbf6..d4cbb3a95b 100644 --- a/packages/frontend/.eslintrc.cjs +++ b/packages/frontend/.eslintrc.cjs @@ -70,12 +70,6 @@ module.exports = { 'require': false, '__dirname': false, - // Vue - '$$': false, - '$ref': false, - '$shallowRef': false, - '$computed': false, - // CherryPick '_DEV_': false, '_LANGS_': false, diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts index 6c082d9d52..98cb8aa8af 100644 --- a/packages/frontend/.storybook/fakes.ts +++ b/packages/frontend/.storybook/fakes.ts @@ -82,7 +82,8 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi birthday: '2014-06-20', createdAt: '2016-12-28T22:49:51.000Z', description: 'I am a cool user!', - ffVisibility: 'public', + followingVisibility: 'public', + followersVisibility: 'public', roles: [], fields: [ { diff --git a/packages/frontend/.storybook/mocks.ts b/packages/frontend/.storybook/mocks.ts index 1a17454836..fea11bc015 100644 --- a/packages/frontend/.storybook/mocks.ts +++ b/packages/frontend/.storybook/mocks.ts @@ -25,7 +25,7 @@ export const commonHandlers = [ }), rest.get('/twemoji/:codepoints.svg', async (req, res, ctx) => { const { codepoints } = req.params; - const value = await fetch(`https://unpkg.com/@discordapp/twemoji@14.1.2/dist/svg/${codepoints}.svg`).then((response) => response.blob()); + const value = await fetch(`https://unpkg.com/@discordapp/twemoji@15.0.2/dist/svg/${codepoints}.svg`).then((response) => response.blob()); return res(ctx.set('Content-Type', 'image/svg+xml'), ctx.body(value)); }), ]; diff --git a/packages/frontend/.storybook/preview-head.html b/packages/frontend/.storybook/preview-head.html index 1fd749b7fc..537ccf971a 100644 --- a/packages/frontend/.storybook/preview-head.html +++ b/packages/frontend/.storybook/preview-head.html @@ -1,6 +1,6 @@ - + diff --git a/packages/frontend/src/components/MkChart.vue b/packages/frontend/src/components/MkChart.vue index 0d5e1975b8..09fad93d1e 100644 --- a/packages/frontend/src/components/MkChart.vue +++ b/packages/frontend/src/components/MkChart.vue @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { onMounted, ref, shallowRef, watch, PropType } from 'vue'; import { Chart } from 'chart.js'; import gradient from 'chartjs-plugin-gradient'; -import * as os from '@/os.js'; +import { misskeyApiGet } from '@/scripts/misskey-api.js'; import { defaultStore } from '@/store.js'; import { useChartTooltip } from '@/scripts/use-chart-tooltip.js'; import { chartVLine } from '@/scripts/chart-vline.js'; @@ -74,7 +74,7 @@ const props = defineProps({ }, }); -let legendEl = $shallowRef>(); +const legendEl = shallowRef>(); const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); const negate = arr => arr.map(x => -x); @@ -268,7 +268,7 @@ const render = () => { gradient, }, }, - plugins: [chartVLine(vLineColor), ...(props.detailed ? [chartLegend(legendEl)] : [])], + plugins: [chartVLine(vLineColor), ...(props.detailed ? [chartLegend(legendEl.value)] : [])], }); }; @@ -277,7 +277,7 @@ const exportData = () => { }; const fetchFederationChart = async (): Promise => { - const raw = await os.apiGet('charts/federation', { limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/federation', { limit: props.limit, span: props.span }); return { series: [{ name: 'Received', @@ -327,7 +327,7 @@ const fetchFederationChart = async (): Promise => { }; const fetchApRequestChart = async (): Promise => { - const raw = await os.apiGet('charts/ap-request', { limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/ap-request', { limit: props.limit, span: props.span }); return { series: [{ name: 'In', @@ -349,7 +349,7 @@ const fetchApRequestChart = async (): Promise => { }; const fetchNotesChart = async (type: string): Promise => { - const raw = await os.apiGet('charts/notes', { limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/notes', { limit: props.limit, span: props.span }); return { series: [{ name: 'All', @@ -396,7 +396,7 @@ const fetchNotesChart = async (type: string): Promise => { }; const fetchNotesTotalChart = async (): Promise => { - const raw = await os.apiGet('charts/notes', { limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/notes', { limit: props.limit, span: props.span }); return { series: [{ name: 'Combined', @@ -415,7 +415,7 @@ const fetchNotesTotalChart = async (): Promise => { }; const fetchUsersChart = async (total: boolean): Promise => { - const raw = await os.apiGet('charts/users', { limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/users', { limit: props.limit, span: props.span }); return { series: [{ name: 'Combined', @@ -443,7 +443,7 @@ const fetchUsersChart = async (total: boolean): Promise => { }; const fetchActiveUsersChart = async (): Promise => { - const raw = await os.apiGet('charts/active-users', { limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/active-users', { limit: props.limit, span: props.span }); return { series: [{ name: 'Read & Write', @@ -495,7 +495,7 @@ const fetchActiveUsersChart = async (): Promise => { }; const fetchDriveChart = async (): Promise => { - const raw = await os.apiGet('charts/drive', { limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/drive', { limit: props.limit, span: props.span }); return { bytes: true, series: [{ @@ -531,7 +531,7 @@ const fetchDriveChart = async (): Promise => { }; const fetchDriveFilesChart = async (): Promise => { - const raw = await os.apiGet('charts/drive', { limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/drive', { limit: props.limit, span: props.span }); return { series: [{ name: 'All', @@ -566,7 +566,7 @@ const fetchDriveFilesChart = async (): Promise => { }; const fetchInstanceRequestsChart = async (): Promise => { - const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); return { series: [{ name: 'In', @@ -588,7 +588,7 @@ const fetchInstanceRequestsChart = async (): Promise => { }; const fetchInstanceUsersChart = async (total: boolean): Promise => { - const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); return { series: [{ name: 'Users', @@ -603,7 +603,7 @@ const fetchInstanceUsersChart = async (total: boolean): Promise => { - const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); return { series: [{ name: 'Notes', @@ -618,7 +618,7 @@ const fetchInstanceNotesChart = async (total: boolean): Promise => { - const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); return { series: [{ name: 'Following', @@ -641,7 +641,7 @@ const fetchInstanceFfChart = async (total: boolean): Promise = }; const fetchInstanceDriveUsageChart = async (total: boolean): Promise => { - const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); return { bytes: true, series: [{ @@ -657,7 +657,7 @@ const fetchInstanceDriveUsageChart = async (total: boolean): Promise => { - const raw = await os.apiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/instance', { host: props.args.host, limit: props.limit, span: props.span }); return { series: [{ name: 'Drive files', @@ -672,7 +672,7 @@ const fetchInstanceDriveFilesChart = async (total: boolean): Promise => { - const raw = await os.apiGet('charts/user/notes', { userId: props.args.user.id, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/user/notes', { userId: props.args.user.id, limit: props.limit, span: props.span }); return { series: [...(props.args.withoutAll ? [] : [{ name: 'All', @@ -704,7 +704,7 @@ const fetchPerUserNotesChart = async (): Promise => { }; const fetchPerUserPvChart = async (): Promise => { - const raw = await os.apiGet('charts/user/pv', { userId: props.args.user.id, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/user/pv', { userId: props.args.user.id, limit: props.limit, span: props.span }); return { series: [{ name: 'Unique PV (user)', @@ -731,7 +731,7 @@ const fetchPerUserPvChart = async (): Promise => { }; const fetchPerUserFollowingChart = async (): Promise => { - const raw = await os.apiGet('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span }); return { series: [{ name: 'Local', @@ -746,7 +746,7 @@ const fetchPerUserFollowingChart = async (): Promise => { }; const fetchPerUserFollowersChart = async (): Promise => { - const raw = await os.apiGet('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span }); return { series: [{ name: 'Local', @@ -761,7 +761,7 @@ const fetchPerUserFollowersChart = async (): Promise => { }; const fetchPerUserDriveChart = async (): Promise => { - const raw = await os.apiGet('charts/user/drive', { userId: props.args.user.id, limit: props.limit, span: props.span }); + const raw = await misskeyApiGet('charts/user/drive', { userId: props.args.user.id, limit: props.limit, span: props.span }); return { series: [{ name: 'Inc', diff --git a/packages/frontend/src/components/MkChartLegend.vue b/packages/frontend/src/components/MkChartLegend.vue index b594d85cc8..6127b37859 100644 --- a/packages/frontend/src/components/MkChartLegend.vue +++ b/packages/frontend/src/components/MkChartLegend.vue @@ -13,29 +13,30 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -78,7 +82,6 @@ function isMe(message) { > header { display: flex; - align-items: center; margin-bottom: 2px; white-space: nowrap; overflow: hidden; @@ -91,11 +94,12 @@ function isMe(message) { } .indicator { - position: absolute; - top: 41px; - left: 12px; + position: relative; + top: 25px; + left: -12px; color: var(--indicator); font-size: 9px; + float: left; } .name { @@ -103,10 +107,11 @@ function isMe(message) { padding: 0; font-weight: bold; transition: all 0.1s ease; + overflow: hidden; + text-overflow: ellipsis; } .username { - margin: 0 8px; overflow: hidden; text-overflow: ellipsis; } @@ -118,15 +123,15 @@ function isMe(message) { .avatar { float: left; - width: 42px; - height: 42px; + width: 52px; + height: 52px; margin: 0 16px 0 0; border-radius: 8px; transition: all 0.1s ease; } .text { - display: block; + display: -webkit-box; margin: 0 0 0 0; padding: 0; overflow: hidden; @@ -134,6 +139,8 @@ function isMe(message) { line-height: 1.35; max-height: 4.05em; color: var(--faceText); + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; } .me { @@ -160,7 +167,7 @@ function isMe(message) { } .avatar { - margin: 0 12px 0 0; + margin: 0 8px; } } diff --git a/packages/frontend/src/components/MkClickerGame.vue b/packages/frontend/src/components/MkClickerGame.vue index 9ad13fcb8a..f6bf33ae64 100644 --- a/packages/frontend/src/components/MkClickerGame.vue +++ b/packages/frontend/src/components/MkClickerGame.vue @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkMiniChart.vue b/packages/frontend/src/components/MkMiniChart.vue index 08cfff5285..c3ea92bd3f 100644 --- a/packages/frontend/src/components/MkMiniChart.vue +++ b/packages/frontend/src/components/MkMiniChart.vue @@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -101,7 +99,7 @@ function showOnRemote() { display: block; margin: 0 .5em 0 0; padding: 0; - overflow: scroll; + overflow: hidden; overflow-wrap: anywhere; font-size: 1em; font-weight: bold; @@ -132,7 +130,7 @@ function showOnRemote() { .username { flex-shrink: 9999999; margin: 0 .5em 0 0; - overflow: scroll; + overflow: hidden; text-overflow: ellipsis; font-size: .95em; max-width: 300px; diff --git a/packages/frontend/src/components/MkNotePreview.vue b/packages/frontend/src/components/MkNotePreview.vue index 0de34b00b1..1d41a178b0 100644 --- a/packages/frontend/src/components/MkNotePreview.vue +++ b/packages/frontend/src/components/MkNotePreview.vue @@ -17,7 +17,6 @@ SPDX-License-Identifier: AGPL-3.0-only

-
@@ -27,10 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index ba0a3a01fb..97f1882ea3 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+
@@ -38,6 +39,7 @@ SPDX-License-Identifier: AGPL-3.0-only + {{ i18n.ts._notification.pollEnded }} {{ i18n.ts._notification.newNote }}: + {{ i18n.ts._notification.roleAssigned }} {{ i18n.ts._notification.achievementEarned }} {{ i18n.ts._notification.testNotification }} @@ -88,6 +91,9 @@ SPDX-License-Identifier: AGPL-3.0-only +
+ {{ notification.role.name }} +
{{ i18n.ts._achievements._types['_' + notification.achievement].title }} @@ -139,7 +145,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkPlusOneEffect.vue b/packages/frontend/src/components/MkPlusOneEffect.vue index 472eae32c6..ebd288aa55 100644 --- a/packages/frontend/src/components/MkPlusOneEffect.vue +++ b/packages/frontend/src/components/MkPlusOneEffect.vue @@ -5,31 +5,33 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index da68b11edf..b746be963f 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -52,9 +52,9 @@ SPDX-License-Identifier: AGPL-3.0-only
- - -
{{ i18n.ts.quoteAttached }}
+ + +
{{ i18n.ts.quoteAttached }}
{{ i18n.ts.recipient }} @@ -69,6 +69,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.notSpecifiedMentionWarning }} -
+
+ +
+ +
{{ i18n.ts.save }}
@@ -194,4 +223,12 @@ onMounted(() => { .save { margin: 8px 0 0 0; } + +.mfmPreview { + padding: 12px; + border-radius: var(--radius); + box-sizing: border-box; + min-height: 130px; + pointer-events: none; +} diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index be21188d6b..240d04b94c 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -11,13 +11,13 @@ SPDX-License-Identifier: AGPL-3.0-only :pagination="paginationQuery" :noGap="!defaultStore.state.showGapBetweenNotesInTimeline" @queue="emit('queue', $event)" - @status="prComponent.setDisabled($event)" + @status="prComponent?.setDisabled($event)" /> diff --git a/packages/frontend/src/components/MkTokenGenerateWindow.vue b/packages/frontend/src/components/MkTokenGenerateWindow.vue index feed1e6ba0..13fc1f7a7f 100644 --- a/packages/frontend/src/components/MkTokenGenerateWindow.vue +++ b/packages/frontend/src/components/MkTokenGenerateWindow.vue @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only :withOkButton="true" :okButtonDisabled="false" :canClose="false" - @close="dialog.close()" + @close="dialog?.close()" @closed="$emit('closed')" @ok="ok()" > @@ -33,7 +33,13 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.enableAll }}
- {{ i18n.t(`_permissions.${kind}`) }} + {{ i18n.t(`_permissions.${kind}`) }} +
+
+
{{ i18n.ts.adminPermission }}
+
+ {{ i18n.t(`_permissions.${kind}`) }} +
@@ -41,7 +47,7 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/components/MkTooltip.vue b/packages/frontend/src/components/MkTooltip.vue index d606cf62f9..59f41f0f99 100644 --- a/packages/frontend/src/components/MkTooltip.vue +++ b/packages/frontend/src/components/MkTooltip.vue @@ -13,8 +13,10 @@ SPDX-License-Identifier: AGPL-3.0-only >
- - {{ text }} +
@@ -53,6 +55,7 @@ const el = shallowRef(); const zIndex = os.claimZIndex('high'); function setPosition() { + if (!el.value || !props.targetElement) return; const data = calcPopupPosition(el.value, { anchorElement: props.targetElement, direction: props.direction, diff --git a/packages/frontend/src/components/MkTutorialDialog.Timeline.vue b/packages/frontend/src/components/MkTutorialDialog.Timeline.vue index fa689ac445..f1801c1aa1 100644 --- a/packages/frontend/src/components/MkTutorialDialog.Timeline.vue +++ b/packages/frontend/src/components/MkTutorialDialog.Timeline.vue @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
diff --git a/packages/frontend/src/components/MkTutorialDialog.vue b/packages/frontend/src/components/MkTutorialDialog.vue index 88533deadc..d938b6c61d 100644 --- a/packages/frontend/src/components/MkTutorialDialog.vue +++ b/packages/frontend/src/components/MkTutorialDialog.vue @@ -130,7 +130,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts._initialTutorial._done.title }}
{{ i18n.t('_initialAccountSetting.haveFun', { name: instance.name ?? host }) }}
diff --git a/packages/frontend/src/components/MkUpdated.vue b/packages/frontend/src/components/MkUpdated.vue index 86c9cdf21f..88fb9eb7eb 100644 --- a/packages/frontend/src/components/MkUpdated.vue +++ b/packages/frontend/src/components/MkUpdated.vue @@ -6,12 +6,18 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue b/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue index f494ccd112..da3cfd6a3b 100644 --- a/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue +++ b/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue @@ -50,12 +50,13 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkUserCardMini.vue b/packages/frontend/src/components/MkUserCardMini.vue index d7d03efa09..eabc894323 100644 --- a/packages/frontend/src/components/MkUserCardMini.vue +++ b/packages/frontend/src/components/MkUserCardMini.vue @@ -16,9 +16,9 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue index e329f1aa44..88b87b7bf1 100644 --- a/packages/frontend/src/components/MkUserSelectDialog.vue +++ b/packages/frontend/src/components/MkUserSelectDialog.vue @@ -61,12 +61,12 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/form/suspense.vue b/packages/frontend/src/components/form/suspense.vue index 17ab881c08..e072b2ee8a 100644 --- a/packages/frontend/src/components/form/suspense.vue +++ b/packages/frontend/src/components/form/suspense.vue @@ -21,7 +21,6 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts index 279e4fb28c..0a9f091f00 100644 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts @@ -7,7 +7,7 @@ import { StoryObj } from '@storybook/vue3'; import { within } from '@storybook/testing-library'; import { expect } from '@storybook/jest'; -import MkMisskeyFlavoredMarkdown from './MkMisskeyFlavoredMarkdown.ts'; +import MkMisskeyFlavoredMarkdown from './MkMisskeyFlavoredMarkdown.js'; export const Default = { render(args) { return { diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts index b27d921136..885d64169c 100644 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { VNode, h } from 'vue'; +import { VNode, h, SetupContext } from 'vue'; import * as mfm from 'cherrypick-mfm-js'; import * as Misskey from 'cherrypick-js'; import temml from 'temml/dist/temml.mjs'; @@ -38,14 +38,18 @@ type MfmProps = { isNote?: boolean; emojiUrls?: string[]; rootScale?: number; - nyaize: boolean | 'respect'; + nyaize?: boolean | 'respect'; parsedNodes?: mfm.MfmNode[] | null; enableEmojiMenu?: boolean; enableEmojiMenuReaction?: boolean; }; +type MfmEvents = { + clickEv(id: string): void; +}; + // eslint-disable-next-line import/no-default-export -export default function(props: MfmProps) { +export default function(props: MfmProps, context: SetupContext) { const isNote = props.isNote ?? true; const shouldNyaize = props.nyaize ? props.nyaize === 'respect' ? props.author?.isCat : false : false; @@ -108,22 +112,26 @@ export default function(props: MfmProps) { switch (token.props.name) { case 'tada': { const speed = validTime(token.props.args.speed) ?? '1s'; - style = 'font-size: 150%;' + (useAnim ? `animation: tada ${speed} linear infinite both;` : ''); + const delay = validTime(token.props.args.delay) ?? '0s'; + style = 'font-size: 150%;' + (useAnim ? `animation: tada ${speed} linear infinite both; animation-delay: ${delay};` : ''); break; } case 'jelly': { const speed = validTime(token.props.args.speed) ?? '1s'; - style = (useAnim ? `animation: mfm-rubberBand ${speed} linear infinite both;` : ''); + const delay = validTime(token.props.args.delay) ?? '0s'; + style = (useAnim ? `animation: mfm-rubberBand ${speed} linear infinite both; animation-delay: ${delay};` : ''); break; } case 'twitch': { const speed = validTime(token.props.args.speed) ?? '0.5s'; - style = useAnim ? `animation: mfm-twitch ${speed} ease infinite;` : ''; + const delay = validTime(token.props.args.delay) ?? '0s'; + style = useAnim ? `animation: mfm-twitch ${speed} ease infinite; animation-delay: ${delay};` : ''; break; } case 'shake': { const speed = validTime(token.props.args.speed) ?? '0.5s'; - style = useAnim ? `animation: mfm-shake ${speed} ease infinite;` : ''; + const delay = validTime(token.props.args.delay) ?? '0s'; + style = useAnim ? `animation: mfm-shake ${speed} ease infinite; animation-delay: ${delay};` : ''; break; } case 'spin': { @@ -136,17 +144,20 @@ export default function(props: MfmProps) { token.props.args.y ? 'mfm-spinY' : 'mfm-spin'; const speed = validTime(token.props.args.speed) ?? '1.5s'; - style = useAnim ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : ''; + const delay = validTime(token.props.args.delay) ?? '0s'; + style = useAnim ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction}; animation-delay: ${delay};` : ''; break; } case 'jump': { const speed = validTime(token.props.args.speed) ?? '0.75s'; - style = useAnim ? `animation: mfm-jump ${speed} linear infinite;` : ''; + const delay = validTime(token.props.args.delay) ?? '0s'; + style = useAnim ? `animation: mfm-jump ${speed} linear infinite; animation-delay: ${delay};` : ''; break; } case 'bounce': { const speed = validTime(token.props.args.speed) ?? '0.75s'; - style = useAnim ? `animation: mfm-bounce ${speed} linear infinite; transform-origin: center bottom;` : ''; + const delay = validTime(token.props.args.delay) ?? '0s'; + style = useAnim ? `animation: mfm-bounce ${speed} linear infinite; transform-origin: center bottom; animation-delay: ${delay};` : ''; break; } case 'flip': { @@ -196,7 +207,8 @@ export default function(props: MfmProps) { }, genEl(token.children, scale)); } const speed = validTime(token.props.args.speed) ?? '1s'; - style = `animation: mfm-rainbow ${speed} linear infinite;`; + const delay = validTime(token.props.args.delay) ?? '0s'; + style = `animation: mfm-rainbow ${speed} linear infinite; animation-delay: ${delay};`; break; } case 'sparkle': { @@ -210,7 +222,8 @@ export default function(props: MfmProps) { return genEl(token.children, scale); } const speed = validTime(token.props.args.speed) ?? '4s'; - style = `animation: mfm-fade ${speed} linear infinite;`; + const delay = validTime(token.props.args.delay) ?? '0s'; + style = `animation: mfm-fade ${speed} linear infinite; animation-delay: ${delay};`; break; } case 'rotate': { @@ -239,13 +252,13 @@ export default function(props: MfmProps) { case 'fg': { let color = token.props.args.color; if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00'; - style = `color: #${color};`; + style = `color: #${color}; overflow-wrap: anywhere;`; break; } case 'bg': { let color = token.props.args.color; if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00'; - style = `background-color: #${color};`; + style = `background-color: #${color}; overflow-wrap: anywhere;`; break; } case 'ruby': { @@ -282,6 +295,13 @@ export default function(props: MfmProps) { }), ]); } + case 'clickable': { + return h('span', { onClick(ev: MouseEvent): void { + ev.stopPropagation(); + ev.preventDefault(); + context.emit('clickEv', token.props.args.ev ?? ''); + } }, genEl(token.children, scale)); + } } if (style === undefined) { return h('span', {}, ['$[', token.props.name, ' ', ...genEl(token.children, scale), ']']); diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 0088603d35..23cc2a386d 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -15,8 +15,12 @@ SPDX-License-Identifier: AGPL-3.0-only
+
+
+
+
@@ -51,7 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
@@ -62,7 +66,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue index 8f4d76f9dd..9e2c8858f1 100644 --- a/packages/frontend/src/components/global/MkTime.vue +++ b/packages/frontend/src/components/global/MkTime.vue @@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts index 9127b84691..961204b560 100644 --- a/packages/frontend/src/instance.ts +++ b/packages/frontend/src/instance.ts @@ -5,7 +5,7 @@ import { computed, reactive } from 'vue'; import * as Misskey from 'cherrypick-js'; -import { api } from '@/os.js'; +import { misskeyApi } from '@/scripts/misskey-api.js'; import { miLocalStorage } from '@/local-storage.js'; import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERROR_IMAGE_URL } from '@/const.js'; @@ -26,7 +26,7 @@ export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL); export async function fetchInstance() { - const meta = await api('meta', { + const meta = await misskeyApi('meta', { detail: false, }); diff --git a/packages/frontend/src/local-storage.ts b/packages/frontend/src/local-storage.ts index f9cb6c2b5d..16385b9614 100644 --- a/packages/frontend/src/local-storage.ts +++ b/packages/frontend/src/local-storage.ts @@ -39,7 +39,9 @@ type Keys = `aiscriptSecure:${string}` | 'lastEmojisFetchedAt' | // DEPRECATED, stored in indexeddb (13.9.0~) 'emojis' | // DEPRECATED, stored in indexeddb (13.9.0~); - 'neverShowNoteEditInfo' + `channelLastReadedAt:${string}` | + 'neverShowNoteEditInfo' | + 'showPushNotificationDialog' export const miLocalStorage = { getItem: (key: Keys): string | null => window.localStorage.getItem(key), diff --git a/packages/frontend/src/nirax.ts b/packages/frontend/src/nirax.ts index 93ebca5756..ffa8d993ff 100644 --- a/packages/frontend/src/nirax.ts +++ b/packages/frontend/src/nirax.ts @@ -5,11 +5,11 @@ // NIRAX --- A lightweight router -import { EventEmitter } from 'eventemitter3'; import { Component, onMounted, shallowRef, ShallowRef } from 'vue'; +import { EventEmitter } from 'eventemitter3'; import { safeURIDecode } from '@/scripts/safe-uri-decode.js'; -type RouteDef = { +export type RouteDef = { path: string; component: Component; query?: Record; @@ -27,6 +27,27 @@ type ParsedPath = (string | { optional?: boolean; })[]; +export type RouterEvent = { + change: (ctx: { + beforePath: string; + path: string; + resolved: Resolved; + key: string; + }) => void; + replace: (ctx: { + path: string; + key: string; + }) => void; + push: (ctx: { + beforePath: string; + path: string; + route: RouteDef | null; + props: Map | null; + key: string; + }) => void; + same: () => void; +} + export type Resolved = { route: RouteDef; props: Map; child?: Resolved; }; function parsePath(path: string): ParsedPath { @@ -54,26 +75,85 @@ function parsePath(path: string): ParsedPath { return res; } -export class Router extends EventEmitter<{ - change: (ctx: { - beforePath: string; - path: string; - resolved: Resolved; - key: string; - }) => void; - replace: (ctx: { - path: string; - key: string; - }) => void; - push: (ctx: { - beforePath: string; - path: string; - route: RouteDef | null; - props: Map | null; - key: string; - }) => void; - same: () => void; -}> { +export interface IRouter extends EventEmitter { + current: Resolved; + currentRef: ShallowRef; + currentRoute: ShallowRef; + navHook: ((path: string, flag?: any) => boolean) | null; + + resolve(path: string): Resolved | null; + + getCurrentPath(): any; + + getCurrentKey(): string; + + push(path: string, flag?: any): void; + + replace(path: string, key?: string | null): void; + + /** @see EventEmitter */ + eventNames(): Array>; + + /** @see EventEmitter */ + listeners>( + event: T + ): Array>; + + /** @see EventEmitter */ + listenerCount( + event: EventEmitter.EventNames + ): number; + + /** @see EventEmitter */ + emit>( + event: T, + ...args: EventEmitter.EventArgs + ): boolean; + + /** @see EventEmitter */ + on>( + event: T, + fn: EventEmitter.EventListener, + context?: any + ): this; + + /** @see EventEmitter */ + addListener>( + event: T, + fn: EventEmitter.EventListener, + context?: any + ): this; + + /** @see EventEmitter */ + once>( + event: T, + fn: EventEmitter.EventListener, + context?: any + ): this; + + /** @see EventEmitter */ + removeListener>( + event: T, + fn?: EventEmitter.EventListener, + context?: any, + once?: boolean | undefined + ): this; + + /** @see EventEmitter */ + off>( + event: T, + fn?: EventEmitter.EventListener, + context?: any, + once?: boolean | undefined + ): this; + + /** @see EventEmitter */ + removeAllListeners( + event?: EventEmitter.EventNames + ): this; +} + +export class Router extends EventEmitter implements IRouter { private routes: RouteDef[]; public current: Resolved; public currentRef: ShallowRef = shallowRef(); @@ -277,7 +357,7 @@ export class Router extends EventEmitter<{ } } -export function useScrollPositionManager(getScrollContainer: () => HTMLElement, router: Router) { +export function useScrollPositionManager(getScrollContainer: () => HTMLElement, router: IRouter) { const scrollPosStore = new Map(); onMounted(() => { diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index 9ba2979c6e..726e36e468 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -5,18 +5,16 @@ // TODO: なんでもかんでもos.tsに突っ込むのやめたいのでよしなに分割する -import { pendingApiRequestsCount, api, apiExternal, apiGet } from '@/scripts/api.js'; -export { pendingApiRequestsCount, api, apiExternal, apiGet }; import { Component, markRaw, Ref, ref, defineAsyncComponent } from 'vue'; import { EventEmitter } from 'eventemitter3'; import insertTextAtCursor from 'insert-text-at-cursor'; import * as Misskey from 'cherrypick-js'; +import { misskeyApi } from '@/scripts/misskey-api.js'; import { i18n } from '@/i18n.js'; import MkPostFormDialog from '@/components/MkPostFormDialog.vue'; import MkWaitingDialog from '@/components/MkWaitingDialog.vue'; import MkPageWindow from '@/components/MkPageWindow.vue'; import MkToast from '@/components/MkToast.vue'; -import MkNoteToast from '@/components/MkNoteToast.vue'; import MkWelcomeToast from '@/components/MkWelcomeToast.vue'; import MkDialog from '@/components/MkDialog.vue'; import MkPasswordDialog from '@/components/MkPasswordDialog.vue'; @@ -35,7 +33,7 @@ export const apiWithDialog = (( data: Record = {}, token?: string | null | undefined, ) => { - const promise = api(endpoint, data, token); + const promise = misskeyApi(endpoint, data, token); promiseDialog(promise, null, async (err) => { let title = null; let text = err.message + '\n' + (err as any).id; @@ -85,7 +83,7 @@ export const apiWithDialog = (( }); return promise; -}) as typeof api; +}) as typeof misskeyApi; export function promiseDialog>( promise: T, @@ -179,15 +177,9 @@ export function pageWindow(path: string) { }, {}, 'closed'); } -export function toast(message: string) { +export function toast(message: string, icon?: string) { popup(MkToast, { message, - }, {}, 'closed'); -} - -export function noteToast(message: string, icon: string) { - popup(MkNoteToast, { - message, icon, }, {}, 'closed'); } @@ -563,7 +555,7 @@ export async function openEmojiPicker(src?: HTMLElement, opts, initialTextarea: }); } -export function popupMenu(items: MenuItem[] | Ref, src?: HTMLElement, options?: { +export function popupMenu(items: MenuItem[] | Ref, src?: HTMLElement | EventTarget | null, options?: { align?: string; width?: number; viaKeyboard?: boolean; @@ -638,7 +630,7 @@ export function checkExistence(fileData: ArrayBuffer): Promise { const data = new FormData(); data.append('md5', getMD5(fileData)); - os.api('drive/files/find-by-hash', { + api('drive/files/find-by-hash', { md5: getMD5(fileData) }).then(resp => { resolve(resp.length > 0 ? resp[0] : null); diff --git a/packages/frontend/src/pages/_error_.vue b/packages/frontend/src/pages/_error_.vue index 1a87720389..f3a73959df 100644 --- a/packages/frontend/src/pages/_error_.vue +++ b/packages/frontend/src/pages/_error_.vue @@ -25,11 +25,11 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/about.federation.vue b/packages/frontend/src/pages/about.federation.vue index 49d33d3863..8263fc137e 100644 --- a/packages/frontend/src/pages/about.federation.vue +++ b/packages/frontend/src/pages/about.federation.vue @@ -51,7 +51,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 4b58adb2db..457417799a 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -132,10 +132,10 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.assign }} -
+
- +
@@ -201,7 +201,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -624,9 +625,6 @@ definePageMetadata(computed(() => ({ } } -.roleItem { -} - .roleItemMain { display: flex; } diff --git a/packages/frontend/src/pages/admin/_header_.vue b/packages/frontend/src/pages/admin/_header_.vue index fe8ffc1bf4..3de304b871 100644 --- a/packages/frontend/src/pages/admin/_header_.vue +++ b/packages/frontend/src/pages/admin/_header_.vue @@ -81,8 +81,8 @@ const metadata = injectPageMetadata(); const el = shallowRef(null); const tabRefs = {}; -const tabHighlightEl = $shallowRef(null); -const bg = ref(null); +const tabHighlightEl = shallowRef(null); +const bg = ref(null); const height = ref(0); const hasTabs = computed(() => { return props.tabs && props.tabs.length > 0; @@ -148,13 +148,13 @@ onMounted(() => { watch(() => [props.tab, props.tabs], () => { nextTick(() => { const tabEl = tabRefs[props.tab]; - if (tabEl && tabHighlightEl) { + if (tabEl && tabHighlightEl.value) { // offsetWidth や offsetLeft は少数を丸めてしまうため getBoundingClientRect を使う必要がある // https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/offsetWidth#%E5%80%A4 const parentRect = tabEl.parentElement.getBoundingClientRect(); const rect = tabEl.getBoundingClientRect(); - tabHighlightEl.style.width = rect.width + 'px'; - tabHighlightEl.style.left = (rect.left - parentRect.left) + 'px'; + tabHighlightEl.value.style.width = rect.width + 'px'; + tabHighlightEl.value.style.left = (rect.left - parentRect.left) + 'px'; } }); }, { diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index 773ab7f751..d7826c5757 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/drop-and-fusion.vue b/packages/frontend/src/pages/drop-and-fusion.vue new file mode 100644 index 0000000000..3609950de7 --- /dev/null +++ b/packages/frontend/src/pages/drop-and-fusion.vue @@ -0,0 +1,152 @@ + + + + + + + diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue index e82ba48a6d..f6675c2389 100644 --- a/packages/frontend/src/pages/emoji-edit-dialog.vue +++ b/packages/frontend/src/pages/emoji-edit-dialog.vue @@ -39,7 +39,10 @@ SPDX-License-Identifier: AGPL-3.0-only - + @@ -74,7 +77,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/emojis.emoji.vue b/packages/frontend/src/pages/emojis.emoji.vue index 1af5c9f4b1..64362d4a01 100644 --- a/packages/frontend/src/pages/emojis.emoji.vue +++ b/packages/frontend/src/pages/emojis.emoji.vue @@ -16,6 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/explore.roles.vue b/packages/frontend/src/pages/explore.roles.vue index baf943f514..029c5dcfab 100644 --- a/packages/frontend/src/pages/explore.roles.vue +++ b/packages/frontend/src/pages/explore.roles.vue @@ -12,14 +12,15 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/explore.users.vue b/packages/frontend/src/pages/explore.users.vue index 5e218cb22a..3b83f280fd 100644 --- a/packages/frontend/src/pages/explore.users.vue +++ b/packages/frontend/src/pages/explore.users.vue @@ -63,27 +63,28 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/explore.vue b/packages/frontend/src/pages/explore.vue index ee0ef8b5a9..81384fc930 100644 --- a/packages/frontend/src/pages/explore.vue +++ b/packages/frontend/src/pages/explore.vue @@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -281,6 +271,11 @@ definePageMetadata(computed(() => flash ? { } } } + +.button { + min-width: 48px; + min-height: 48px; +} diff --git a/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue b/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue new file mode 100644 index 0000000000..c3c0128822 --- /dev/null +++ b/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue @@ -0,0 +1,174 @@ + + + + + + + diff --git a/packages/frontend/src/pages/settings/avatar-decoration.vue b/packages/frontend/src/pages/settings/avatar-decoration.vue new file mode 100644 index 0000000000..0f67fdcd7f --- /dev/null +++ b/packages/frontend/src/pages/settings/avatar-decoration.vue @@ -0,0 +1,161 @@ + + + + + + + diff --git a/packages/frontend/src/pages/settings/cherrypick.vue b/packages/frontend/src/pages/settings/cherrypick.vue index 72defb3186..0933c9d18f 100644 --- a/packages/frontend/src/pages/settings/cherrypick.vue +++ b/packages/frontend/src/pages/settings/cherrypick.vue @@ -7,9 +7,8 @@ SPDX-License-Identifier: AGPL-3.0-only
+
-
{{ i18n.ts._cherrypick.functionDescription }}
- {{ i18n.ts._cherrypick.nickname }} @@ -50,9 +49,8 @@ SPDX-License-Identifier: AGPL-3.0-only +
-
{{ i18n.ts._cherrypick.patchDescription }}
- {{ i18n.ts._cherrypick.reactableRemoteReaction }} {{ i18n.ts._cherrypick.showFollowingMessageInsteadOfButton }} {{ i18n.ts._cherrypick.mobileHeaderChange }} @@ -68,10 +66,20 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.friendlyEnableNotifications }} {{ i18n.ts.friendlyEnableWidgets }} - {{ i18n.ts._cherrypick.enableLongPressOpenAccountMenu }} + + + + {{ i18n.ts._cherrypick.friendlyShowAvatarDecorationsInNavBtn }}
+ + + + +
+
+
@@ -128,9 +136,9 @@ watch([ await reloadAsk(); }); -const headerActions = $computed(() => []); +const headerActions = computed(() => []); -const headerTabs = $computed(() => []); +const headerTabs = computed(() => []); definePageMetadata({ title: 'CherryPick', diff --git a/packages/frontend/src/pages/settings/custom-css.vue b/packages/frontend/src/pages/settings/custom-css.vue index 268af5e792..2132974d35 100644 --- a/packages/frontend/src/pages/settings/custom-css.vue +++ b/packages/frontend/src/pages/settings/custom-css.vue @@ -7,15 +7,15 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.customCssWarn }} - + - +
+ + diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 3c945ac5cb..87bcf9eda3 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -58,6 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+ {{ i18n.ts.enableQuickAddMfmFunction }} {{ i18n.ts.showGapBetweenNotesInTimeline }} {{ i18n.ts.loadRawImages }} @@ -74,6 +75,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.infoButtonForNoteActions }} CherryPick {{ i18n.ts.showReplyInNotification }} CherryPick {{ i18n.ts.renoteQuoteButtonSeparation }} CherryPick + {{ i18n.ts.showRenoteVisibilitySelector }} CherryPick {{ i18n.ts.showFixedPostFormInReplies }} CherryPick {{ i18n.ts.allMediaNoteCollapse }} CherryPick
@@ -154,6 +156,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.useSystemFont }} {{ i18n.ts.disableDrawer }} {{ i18n.ts.forceShowAds }} + {{ i18n.ts.seasonalScreenEffect }} {{ i18n.ts.showUnreadNotificationsCount }}
@@ -338,6 +341,7 @@ import MkInfo from '@/components/MkInfo.vue'; import { langs } from '@/config.js'; import { defaultStore } from '@/store.js'; import * as os from '@/os.js'; +import { misskeyApi } from '@/scripts/misskey-api.js'; import { unisonReload } from '@/scripts/unison-reload.js'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; @@ -387,6 +391,7 @@ const removeModalBgColorForBlur = computed(defaultStore.makeGetterSetter('remove const showGapBetweenNotesInTimeline = computed(defaultStore.makeGetterSetter('showGapBetweenNotesInTimeline')); const animatedMfm = computed(defaultStore.makeGetterSetter('animatedMfm')); const advancedMfm = computed(defaultStore.makeGetterSetter('advancedMfm')); +const enableQuickAddMfmFunction = computed(defaultStore.makeGetterSetter('enableQuickAddMfmFunction')); const emojiStyle = computed(defaultStore.makeGetterSetter('emojiStyle')); const disableDrawer = computed(defaultStore.makeGetterSetter('disableDrawer')); const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages')); @@ -409,6 +414,7 @@ const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificati const keepScreenOn = computed(defaultStore.makeGetterSetter('keepScreenOn')); const disableStreamingTimeline = computed(defaultStore.makeGetterSetter('disableStreamingTimeline')); const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroupedNotifications')); +const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enableSeasonalScreenEffect')); const showUnreadNotificationsCount = computed(defaultStore.makeGetterSetter('showUnreadNotificationsCount')); const newNoteReceivedNotificationBehavior = computed(defaultStore.makeGetterSetter('newNoteReceivedNotificationBehavior')); const fontSize = computed(defaultStore.makeGetterSetter('fontSize')); @@ -426,10 +432,12 @@ const showFixedPostFormInReplies = computed(defaultStore.makeGetterSetter('showF const showingAnimatedImages = computed(defaultStore.makeGetterSetter('showingAnimatedImages')); const allMediaNoteCollapse = computed(defaultStore.makeGetterSetter('allMediaNoteCollapse')); const nsfwOpenBehavior = computed(defaultStore.makeGetterSetter('nsfwOpenBehavior')); +const renoteVisibilitySelection = computed(defaultStore.makeGetterSetter('renoteVisibilitySelection')); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); miLocalStorage.removeItem('locale'); + miLocalStorage.removeItem('localeVersion'); }); watch(fontSize, () => { @@ -472,25 +480,37 @@ watch([ showUnreadNotificationsCount, showFixedPostFormInReplies, showingAnimatedImages, + enableSeasonalScreenEffect, ], async () => { await reloadAsk(); }); watch([ - enableInfiniteScroll, + collapseDefault, hideAvatarsInNote, showNoteActionsOnlyHover, + showClipButtonInNoteFooter, instanceTicker, mediaListWithOneImageAppearance, reactionsDisplaySize, limitWidthOfReaction, highlightSensitiveMedia, + showReplyInNotification, + showTranslateButtonInNote, enableAbsoluteTime, enableMarkByDate, showSubNoteFooterButton, infoButtonForNoteActionsEnabled, renoteQuoteButtonSeparation, allMediaNoteCollapse, +], () => { + reloadTimeline(); + reloadNotification(); +}); + +watch([ + collapseRenotes, + enableInfiniteScroll, ], () => { reloadTimeline(); }); @@ -532,7 +552,7 @@ function removeEmojiIndex(lang: string) { } async function setPinnedList() { - const lists = await os.api('users/lists/list'); + const lists = await misskeyApi('users/lists/list'); const { canceled, result: list } = await os.select({ title: i18n.ts.selectList, items: lists.map(x => ({ @@ -599,9 +619,9 @@ onMounted(() => { } }); -const headerActions = $computed(() => []); +const headerActions = computed(() => []); -const headerTabs = $computed(() => []); +const headerTabs = computed(() => []); definePageMetadata({ title: i18n.ts.general, diff --git a/packages/frontend/src/pages/settings/import-export.vue b/packages/frontend/src/pages/settings/import-export.vue index d7bc044bf6..40e5fd3ab7 100644 --- a/packages/frontend/src/pages/settings/import-export.vue +++ b/packages/frontend/src/pages/settings/import-export.vue @@ -21,6 +21,14 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.export }} + + + + + + {{ i18n.ts.export }} + +
@@ -111,12 +119,13 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue index 96c98f1684..1820f53726 100644 --- a/packages/frontend/src/pages/settings/notifications.vue +++ b/packages/frontend/src/pages/settings/notifications.vue @@ -56,25 +56,28 @@ SPDX-License-Identifier: AGPL-3.0-only - - diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index b183bd0a9b..ebccf94694 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -5,19 +5,24 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/settings/reaction.vue b/packages/frontend/src/pages/settings/reaction.vue deleted file mode 100644 index a84cf2e397..0000000000 --- a/packages/frontend/src/pages/settings/reaction.vue +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - diff --git a/packages/frontend/src/pages/settings/roles.vue b/packages/frontend/src/pages/settings/roles.vue index 9434bfde49..17d0414dbe 100644 --- a/packages/frontend/src/pages/settings/roles.vue +++ b/packages/frontend/src/pages/settings/roles.vue @@ -23,32 +23,18 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/user-list-timeline.vue b/packages/frontend/src/pages/user-list-timeline.vue index 77786a04d8..c43875596c 100644 --- a/packages/frontend/src/pages/user-list-timeline.vue +++ b/packages/frontend/src/pages/user-list-timeline.vue @@ -24,13 +24,14 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/user-tag.vue b/packages/frontend/src/pages/user-tag.vue index 2a25da0edd..ab38aca802 100644 --- a/packages/frontend/src/pages/user-tag.vue +++ b/packages/frontend/src/pages/user-tag.vue @@ -16,8 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/user/following.vue b/packages/frontend/src/pages/user/following.vue index f1f7e96bc1..28f5964122 100644 --- a/packages/frontend/src/pages/user/following.vue +++ b/packages/frontend/src/pages/user/following.vue @@ -19,10 +19,10 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/user/home.stories.impl.ts b/packages/frontend/src/pages/user/home.stories.impl.ts index f484aaf235..ad1f50a7bd 100644 --- a/packages/frontend/src/pages/user/home.stories.impl.ts +++ b/packages/frontend/src/pages/user/home.stories.impl.ts @@ -6,8 +6,8 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; import { rest } from 'msw'; -import { userDetailed } from '../../../.storybook/fakes'; -import { commonHandlers } from '../../../.storybook/mocks'; +import { userDetailed } from '../../../.storybook/fakes.js'; +import { commonHandlers } from '../../../.storybook/mocks.js'; import home_ from './home.vue'; export const Default = { render(args) { diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index 998c21c32e..d4e134439a 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -127,11 +127,11 @@ SPDX-License-Identifier: AGPL-3.0-only {{ number(user.notesCount) }} {{ i18n.ts.notes }} - + {{ number(user.followingCount) }} {{ i18n.ts.following }} - + {{ number(user.followersCount) }} {{ i18n.ts.followers }} @@ -145,10 +145,18 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.userPagePinTip }} - +
+ + + +
@@ -160,7 +168,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/ui/minimum.vue b/packages/frontend/src/ui/minimum.vue index 10ca85fb6d..a706b4c2eb 100644 --- a/packages/frontend/src/ui/minimum.vue +++ b/packages/frontend/src/ui/minimum.vue @@ -14,19 +14,19 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/ui/zen.vue b/packages/frontend/src/ui/zen.vue index 70006503c6..9c8ad365b9 100644 --- a/packages/frontend/src/ui/zen.vue +++ b/packages/frontend/src/ui/zen.vue @@ -22,23 +22,23 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/widgets/WidgetActivity.vue b/packages/frontend/src/widgets/WidgetActivity.vue index ec1457f7aa..ae05a3c7e9 100644 --- a/packages/frontend/src/widgets/WidgetActivity.vue +++ b/packages/frontend/src/widgets/WidgetActivity.vue @@ -12,8 +12,8 @@ SPDX-License-Identifier: AGPL-3.0-only
@@ -21,11 +21,11 @@ SPDX-License-Identifier: AGPL-3.0-only