Compare commits

...

139 commits

Author SHA1 Message Date
takaion
047773341d
fix(frontend): エラー画像が横に引き伸ばされてしまう問題に対応 (#16502)
* fix(frontend): エラー画像が横に引き伸ばされてしまう問題に対応

Fix misskey-dev#15982

* Update CHANGELOG.md
2025-09-02 16:40:57 +09:00
yukineko
842670e100
fix(frontend): RSSティッカーウィジェットが正しく動作しない問題を修正 (#16498)
* fix: RSSティッカーウィジェットが正しく機能しない問題を修正

* chore: update CHANGELOG.md
2025-09-02 10:29:25 +09:00
anatawa12
ffc481a994
fix: 「自動でもっと見る」の設定ができない問題 (#16500) 2025-09-02 10:11:50 +09:00
syuilo
2ccf4f94cb refactor 2025-09-01 16:51:58 +09:00
syuilo
3566bc207f refactor 2025-09-01 16:36:15 +09:00
syuilo
4a0e968662 refactor 2025-09-01 16:23:05 +09:00
syuilo
b1479ab1d8 Update misskey-js.api.md 2025-09-01 14:07:24 +09:00
syuilo
18a9ccf7af pnpm dedupe 2025-09-01 14:07:14 +09:00
syuilo
959e72b2b3 refactor 2025-09-01 14:02:14 +09:00
syuilo
a3d78b2f08 refactor 2025-09-01 13:41:40 +09:00
syuilo
3c998e1f48 refactor 2025-09-01 12:59:53 +09:00
syuilo
782c9f9852 refactor 2025-09-01 12:33:44 +09:00
syuilo
d27c740ab0 refactor 2025-09-01 12:31:27 +09:00
syuilo
08ecf7ca79 refactor 2025-09-01 10:19:14 +09:00
syuilo
bdec4bf87a refactor 2025-09-01 10:16:33 +09:00
syuilo
7000095b44 refactor 2025-09-01 10:01:03 +09:00
syuilo
18e42cc83d refactoe 2025-09-01 09:53:38 +09:00
syuilo
11204eeb43 refactor 2025-09-01 09:50:36 +09:00
かっこかり
c95092903a
refactor(frontend): フロントエンドの型エラー解消(途中まで) (#16477)
* refactor(frontend): フロントエンドの型エラー解消

* fix

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-08-31 19:53:38 +09:00
github-actions[bot]
21b2b9e5f8 [skip ci] Update CHANGELOG.md (prepend template) 2025-08-31 08:42:45 +00:00
github-actions[bot]
665ec2c43c Release: 2025.8.0 2025-08-31 08:42:39 +00:00
syuilo
34bd840525 Update CHANGELOG.md 2025-08-31 15:56:07 +09:00
syuilo
3d1cbcf094 Update CHANGELOG.md 2025-08-31 15:29:22 +09:00
github-actions[bot]
5f5d88036f Bump version to 2025.8.0-rc.0 2025-08-31 01:32:06 +00:00
syuilo
24739cd040
New Crowdin updates (#16483)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Italian)
2025-08-31 10:24:41 +09:00
syuilo
b491432daa fix(frontend): タッチ操作時にマウスホバー時のユーザープレビューが開くことがある問題を修正
Fix #16464
2025-08-31 10:23:29 +09:00
syuilo
ebe029458e enhance(frontend): アイコンのスクロール追従を無効化する際の適用範囲を強化
Resolve #16485
2025-08-31 10:18:48 +09:00
syuilo
d127d82c5b Update CHANGELOG.md 2025-08-30 19:17:11 +09:00
syuilo
aabda5a956 clean up 2025-08-30 19:15:52 +09:00
syuilo
bd5b38c9d9 Update CHANGELOG.md 2025-08-30 19:12:53 +09:00
syuilo
647e03bf34 update locale 2025-08-30 19:10:19 +09:00
syuilo
d16db7f311
New translations ja-jp.yml (English) (#16472) 2025-08-30 16:11:27 +09:00
github-actions[bot]
ec4731dee4 Bump version to 2025.8.0-beta.6 2025-08-29 07:38:45 +00:00
syuilo
65a4d77a7f fix(backend): タイムラインAPIの withRenotes: false 時のレスポンスを修正 2025-08-29 16:03:03 +09:00
かっこかり
328301ffc2
fix(misskey-js): run api extractor (#16476) 2025-08-29 13:37:17 +09:00
syuilo
def148d7a6 refactor 2025-08-28 20:02:28 +09:00
syuilo
aa85d701b9 refactor 2025-08-28 19:53:10 +09:00
syuilo
f0833cffe9 refactor 2025-08-28 19:47:58 +09:00
github-actions[bot]
9cd918f12b Bump version to 2025.8.0-beta.5 2025-08-28 05:33:23 +00:00
syuilo
195a80622b
New Crowdin updates (#16457)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (English)
2025-08-28 13:31:05 +09:00
syuilo
8b347e23e3 refactor 2025-08-28 13:30:52 +09:00
syuilo
bca3602da2 refactor 2025-08-28 13:24:25 +09:00
syuilo
cfd4d7c57b refactor 2025-08-28 13:20:11 +09:00
tamaina
084ccf5c9a
build-misskey-js-with-types (#16471)
* build-misskey-js-with-types

* build-misskey-js-with-types
2025-08-28 11:45:46 +09:00
syuilo
fc1693f768 そもそもnullになることはあり得なかった 2025-08-28 11:39:54 +09:00
syuilo
ff6f115976 refactor 2025-08-28 11:30:03 +09:00
syuilo
8c2b96ad37 lint 2025-08-28 11:16:40 +09:00
syuilo
3e24419981 refactor 2025-08-28 11:15:17 +09:00
tamaina
25c2007f59
build-misskey-js-with-types (#16470) 2025-08-28 10:39:39 +09:00
syuilo
2e4c4dd555 refactor 2025-08-28 08:59:13 +09:00
taiy
653cb116ea
fix(build): run build-misskey-js-with-types (#16468) 2025-08-27 19:11:05 +09:00
syuilo
c9f363b215 fix i/apps schema 2025-08-27 17:21:24 +09:00
syuilo
e72da587e4 型の漏れを修正 2025-08-27 17:05:29 +09:00
syuilo
439337a108 json schemaに誤りがあるのを修正 2025-08-27 17:01:02 +09:00
syuilo
5fef2332f4 refactor 2025-08-27 17:00:58 +09:00
syuilo
40a325cbe7 userのjson schemaに誤りがあるのを修正 2025-08-27 16:55:07 +09:00
syuilo
5eff31383f refactor 2025-08-27 16:52:58 +09:00
syuilo
575379a683 refactor 2025-08-27 16:48:32 +09:00
syuilo
bf82b49633 refactor 2025-08-27 16:27:16 +09:00
syuilo
87d09f255d refactor 2025-08-27 15:59:39 +09:00
syuilo
98e07c3bd1 perf(frontend): use WeakMap 2025-08-27 12:41:24 +09:00
syuilo
c5bb881438 refactor 2025-08-27 12:40:11 +09:00
syuilo
ee96f77ef2 refactor 2025-08-27 12:09:19 +09:00
syuilo
55eb18f5a6
Update CHANGELOG.md 2025-08-27 10:29:45 +09:00
syuilo
aa8daca914 chore(frontend): skip typecheck for auto-generated files 2025-08-27 10:23:41 +09:00
syuilo
3e9118af3d fix(frontend): lookupページでリモートURLを指定した際に正しく動作しない問題を修正 2025-08-27 10:15:11 +09:00
syuilo
25df56dfd0 refactor 2025-08-27 10:14:17 +09:00
syuilo
231ccae006 tweak locale 2025-08-27 09:57:33 +09:00
syuilo
2e0a34300a refactor 2025-08-27 09:46:31 +09:00
syuilo
d2fd7460ed
Update CHANGELOG.md
#16465
2025-08-27 00:41:11 +09:00
syuilo
5e3d8fc9b8 refactor 2025-08-26 20:17:25 +09:00
syuilo
b186c67767 refactor 2025-08-26 20:04:59 +09:00
syuilo
ac7c60d102 refactor and fix 2025-08-26 19:06:15 +09:00
syuilo
b9dbd58a1c refactor 2025-08-26 18:54:54 +09:00
syuilo
69bbac013a refactor 2025-08-26 17:31:36 +09:00
syuilo
203296b9cb chore(frontend): tweak MkServerSetupWizard 2025-08-26 15:02:12 +09:00
syuilo
689d70ffae refactor 2025-08-26 14:38:42 +09:00
syuilo
d5475d1ff6 refactor 2025-08-26 14:22:53 +09:00
syuilo
05cc8047fa refactor 2025-08-26 13:58:57 +09:00
syuilo
d6a1046361 refactor 2025-08-26 13:34:41 +09:00
syuilo
eb9915baf8 refactor and fix 2025-08-26 10:56:09 +09:00
syuilo
dbb6c71c5c refactor 2025-08-26 09:39:23 +09:00
syuilo
9e5c8d94bf refactor 2025-08-26 09:08:00 +09:00
syuilo
120af977a9 refactoe 2025-08-26 08:57:36 +09:00
syuilo
506c8a259b refactor 2025-08-26 08:50:34 +09:00
syuilo
0c8545ec1c
Update CHANGELOG.md 2025-08-26 07:44:26 +09:00
tamaina
7e7dc03796
fix(frontend): ap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正 (#16460) 2025-08-26 07:43:59 +09:00
syuilo
a874def344 remove unused file 2025-08-25 20:32:07 +09:00
syuilo
44ac51f64f refactor: ReloadSuggest -> ReloadSuggestion 2025-08-25 20:31:22 +09:00
syuilo
3b65be8b91 clean up 2025-08-25 20:29:26 +09:00
syuilo
76beac41d2 refactor 2025-08-25 20:07:33 +09:00
syuilo
69cdc73f5a refactor 2025-08-25 19:55:42 +09:00
syuilo
1c966db324 refactor 2025-08-25 17:12:11 +09:00
syuilo
692284886b refactor 2025-08-25 17:04:49 +09:00
syuilo
0121d19645 refactor 2025-08-25 16:56:10 +09:00
syuilo
bf8636e516 refactor 2025-08-25 16:56:05 +09:00
syuilo
d336a1fb1c refactor 2025-08-25 13:51:52 +09:00
syuilo
7c761e7017 refactor 2025-08-25 13:48:09 +09:00
syuilo
7924daf7f8 refactor 2025-08-25 13:46:22 +09:00
syuilo
2b9706a68b refactor 2025-08-25 13:40:41 +09:00
syuilo
f2d15f9240 refactor 2025-08-25 13:36:38 +09:00
syuilo
caf6a3ab81 refactor 2025-08-25 13:34:17 +09:00
syuilo
f4baa973bf refactor 2025-08-25 13:26:41 +09:00
syuilo
3741fa4b49 refactor 2025-08-25 13:25:05 +09:00
syuilo
27df7f643e fix typo
Fix #16452
2025-08-25 10:07:42 +09:00
syuilo
30987b6f1f
Update CHANGELOG.md 2025-08-25 10:05:15 +09:00
anatawa12
41b5677f01
fix: Pages will be deleted when eye-catching image is moved (#16455) 2025-08-25 10:04:35 +09:00
github-actions[bot]
47d83e8930 Bump version to 2025.8.0-beta.4 2025-08-24 09:29:08 +00:00
renovate[bot]
61ff1f313b
fix(deps): update [backend] update dependencies (#16450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 18:27:14 +09:00
renovate[bot]
637ad3d479
chore(deps): update [misskey-js] update dependencies (#16448)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 16:05:06 +09:00
syuilo
2dd8c2a355
New Crowdin updates (#16442)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Turkish)
2025-08-24 12:02:36 +09:00
renovate[bot]
857a87d4b6
chore(deps): update [github actions] update dependencies (#16447)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 11:53:23 +09:00
renovate[bot]
8b4cea5c86
fix(deps): update [root] update dependencies (#16449)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 11:53:10 +09:00
renovate[bot]
9f25d96ec3
fix(deps): update [frontend] update dependencies (#16387)
* fix(deps): update [frontend] update dependencies

* fix build error

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-08-24 09:13:04 +09:00
syuilo
bd0730e5e8 fix(backend): 削除されたユーザーがチャットメッセージにリアクションしている場合chat/historyなどでエラーになる問題を修正
Fix #16445
2025-08-23 17:37:15 +09:00
syuilo
07ccb82691
Update CHANGELOG with recent feature and fix entries 2025-08-22 19:40:15 +09:00
github-actions[bot]
16030c6381 Bump version to 2025.8.0-beta.3 2025-08-22 10:39:14 +00:00
syuilo
1f6716d69b
New Crowdin updates (#16436)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Italian)
2025-08-22 19:37:20 +09:00
かっこかり
ade603ff7a
fix(frontend): ページネーションの進行方向を指定できるように (#16433)
* fix(frontend): ページネーションの進行方向を指定できるように

* Update Changelog

* fix lint

* fix: directionをMkPaginationに移動

* fix

* fix

* fix

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-08-22 19:34:20 +09:00
かっこかり
4d215bde10
fix(frontend): follow-up of #16380 2025-08-22 19:31:27 +09:00
かっこかり
20d81696e1
fix(backend): fix test (#16441)
* fix(backend): fix test

* fix

* fix
2025-08-22 18:26:19 +09:00
syuilo
8cbbb80e3f fix(backend): notes/mentions で場合によっては並び順が正しく返されない問題を修正
Fix #16398
2025-08-21 19:10:16 +09:00
かっこかり
1eabb21d69
fix(backend): クリップ一覧APIをページネーションに対応させる (#16434)
* fix(backend): クリップ一覧APIをページネーションに対応させる

* Update Changelog
2025-08-21 19:02:21 +09:00
かっこかり
7f6ba2e501
enhance: verify-emailにフロントエンドUIを実装 (#16431)
* enhance: メールのverifyをAPIに変更

* enhance(frontend): メールのVerifyページを追加

* fix

* 🎨

* 🎨

* Update Changelog

* lint
2025-08-21 16:52:30 +09:00
github-actions[bot]
8c433d2706 Bump version to 2025.8.0-beta.2 2025-08-20 07:41:12 +00:00
syuilo
3a856b785d
New Crowdin updates (#16416)
* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)
2025-08-20 16:35:50 +09:00
syuilo
b07bf838e3
サーバー管理コマンド (#15882)
* wip

* Update cli.ts

* Update cli.ts

* wip

* Update CHANGELOG.md

* Delete cli.mjs
2025-08-20 16:35:26 +09:00
syuilo
bdfe709319 fix(frontend): 読み込み直後にプラグインによるノートの書き換えが行われない問題を修正
ブート時にプラグインがロードされるまで待機
Fix #16428
2025-08-20 15:57:20 +09:00
github-actions[bot]
4190c6cb8e Bump version to 2025.8.0-beta.1 2025-08-19 05:24:14 +00:00
renovate[bot]
44a2d531b3
fix(deps): update dependency tmp to v0.2.4 [security] (#16374)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 14:20:53 +09:00
syuilo
a17271a5c4
Update CHANGELOG.md 2025-08-19 14:19:54 +09:00
syuilo
3980172243 feat: 非ログイン時に表示されるトップページのスタイルを選択できるように 2025-08-19 14:15:19 +09:00
syuilo
3b4879133c 🎨 2025-08-18 18:06:32 +09:00
syuilo
a1232cbae3
Update CHANGELOG.md 2025-08-18 14:47:35 +09:00
github-actions[bot]
ebb014da4c Bump version to 2025.8.0-beta.0 2025-08-18 05:41:44 +00:00
syuilo
7786761d76 chore(frontend): more haptic 2025-08-18 14:24:14 +09:00
Souma
ff334fe9d7
enhance(frontend): Add an option to customize Lockdown duration (#16405)
* chore(locales): Add "setManually" and "_time.month"

Add Japanese locales to auto-generate other languages.

* feat(frontend): Add text fields to set lockdown duration manually

Choose from presets or set it manually.

* refactor(frontend): Make objects contains option's values and labels

When adding a new option, it needed to write two times.

* docs(changelog): Add a description about this change

Users can notice what's changed by this PR.

* refactor(frontend): Manage state by MkSelect

The functions only initialize the values.

* refactor(frontend): Make the custom input as writable computed

Clean up the MkInput components.

* chore(locales): Switch to "custom"

A single word is better than sentence on this situation.

* refactor(frontend): Insert the custom button to presets

Users don't need to click multiple times to use prests.
2025-08-18 14:11:48 +09:00
syuilo
ba40cb750b Update about-misskey.vue 2025-08-18 10:59:31 +09:00
syuilo
fcde6789ff feat(frontend): introduce haptic feedback as experimental feature
#16410
2025-08-18 10:49:27 +09:00
353 changed files with 4886 additions and 3430 deletions

View file

@ -16,7 +16,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4.1.0 uses: pnpm/action-setup@v4.1.0

View file

@ -12,7 +12,7 @@ jobs:
steps: steps:
- name: Checkout head - name: Checkout head
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4.4.0 uses: actions/setup-node@v4.4.0
with: with:

View file

@ -18,7 +18,7 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }} if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
persist-credentials: false persist-credentials: false
@ -66,7 +66,7 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }} if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
persist-credentials: false persist-credentials: false

View file

@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
- name: Check version - name: Check version
run: | run: |
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then

View file

@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
- name: Check - name: Check
run: | run: |
counter=0 counter=0

View file

@ -10,7 +10,7 @@ jobs:
check_copyright_year: check_copyright_year:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
- run: | - run: |
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
echo "Please change copyright year!" echo "Please change copyright year!"

View file

@ -28,7 +28,7 @@ jobs:
wait_time: ${{ steps.get-wait-time.outputs.wait_time }} wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
- name: Check allowed users - name: Check allowed users
id: check-allowed-users id: check-allowed-users

View file

@ -27,7 +27,7 @@ jobs:
platform=${{ matrix.platform }} platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub - name: Log in to Docker Hub

View file

@ -32,7 +32,7 @@ jobs:
platform=${{ matrix.platform }} platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Docker meta - name: Docker meta

View file

@ -15,7 +15,7 @@ jobs:
DOCKER_CONTENT_TRUST: 1 DOCKER_CONTENT_TRUST: 1
DOCKLE_VERSION: 0.4.14 DOCKLE_VERSION: 0.4.14
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
- name: Download and install dockle v${{ env.DOCKLE_VERSION }} - name: Download and install dockle v${{ env.DOCKLE_VERSION }}
run: | run: |
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb" curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"

View file

@ -25,7 +25,7 @@ jobs:
ref: refs/pull/${{ github.event.number }}/merge ref: refs/pull/${{ github.event.number }}/merge
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
ref: ${{ matrix.ref }} ref: ${{ matrix.ref }}
submodules: true submodules: true

View file

@ -36,7 +36,7 @@ jobs:
pnpm_install: pnpm_install:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
@ -69,7 +69,7 @@ jobs:
eslint-cache-version: v1 eslint-cache-version: v1
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }} eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
@ -81,7 +81,7 @@ jobs:
cache: 'pnpm' cache: 'pnpm'
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Restore eslint cache - name: Restore eslint cache
uses: actions/cache@v4.2.3 uses: actions/cache@v4.2.4
with: with:
path: ${{ env.eslint-cache-path }} path: ${{ env.eslint-cache-path }}
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }} key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
@ -99,7 +99,7 @@ jobs:
- sw - sw
- misskey-js - misskey-js
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true

View file

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
continue-on-error: true continue-on-error: true
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true

View file

@ -16,7 +16,7 @@ jobs:
id-token: write id-token: write
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
- name: Setup pnpm - name: Setup pnpm

View file

@ -22,12 +22,12 @@ jobs:
NODE_OPTIONS: "--max_old_space_size=7168" NODE_OPTIONS: "--max_old_space_size=7168"
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
if: github.event_name != 'pull_request_target' if: github.event_name != 'pull_request_target'
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
if: github.event_name == 'pull_request_target' if: github.event_name == 'pull_request_target'
with: with:
fetch-depth: 0 fetch-depth: 0

View file

@ -50,7 +50,7 @@ jobs:
- 56312:6379 - 56312:6379
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
- name: Setup pnpm - name: Setup pnpm
@ -129,7 +129,7 @@ jobs:
- 56312:6379 - 56312:6379
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
- name: Setup pnpm - name: Setup pnpm
@ -173,7 +173,7 @@ jobs:
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
- name: Setup pnpm - name: Setup pnpm

View file

@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
- name: Setup pnpm - name: Setup pnpm
@ -76,7 +76,7 @@ jobs:
- 56312:6379 - 56312:6379
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150 # https://github.com/cypress-io/cypress-docker-images/issues/150

View file

@ -22,7 +22,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.3.0
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4.1.0 uses: pnpm/action-setup@v4.1.0

View file

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
- name: Setup pnpm - name: Setup pnpm

View file

@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.3.0
with: with:
submodules: true submodules: true
- name: Setup pnpm - name: Setup pnpm

View file

@ -1,3 +1,16 @@
## Unreleased
### General
-
### Client
- Fix: RSSティッカーウィジェットが正しく動作しない問題を修正
- Fix: エラー画像が横に引き伸ばされてしまう問題に対応
### Server
-
## 2025.8.0 ## 2025.8.0
### Note ### Note
@ -6,15 +19,17 @@
### General ### General
- ノートを削除した際、関連するノートが同時に削除されないようになりました - ノートを削除した際、関連するノートが同時に削除されないようになりました
- APIで、「replyIdが存在しているのにreplyがnull」や「renoteIdが存在しているのにrenoteがnull」であるという、今までにはなかったパターンが表れることになります - APIで、「replyIdが存在しているのにreplyがnull」や「renoteIdが存在しているのにrenoteがnull」であるという、今までにはなかったパターンが表れることになります
- 定期的に参照されていない古いリモートの投稿を削除する機能が実装されました(コントロールパネル→パフォーマンス→Remote Notes Cleaning) - 定期的に古いリモートの投稿を削除する機能が実装されました
- 既存のサーバーでは**デフォルトでオフ**、新規サーバーでは**デフォルトでオン**になります - コントロールパネル→パフォーマンス→Remote Notes Cleaning で有効化できます
- データベースの肥大化を防止することが可能です - データベースの肥大化を防止することが可能です
- 既存のサーバーで当機能を有効化した場合は、処理量が多くなるため、一時的にストレージ使用量が増加する可能性があります。 - 既存のサーバーで当機能を有効化した場合は、処理量が多くなるため、一時的にストレージ使用量が増加する可能性があります。
- 増加量を抑えるには、最大処理継続時間をデフォルトより短くしてください。 - 増加量を抑えるには、最大処理継続時間をデフォルトより短くしてください。
- データベースサイズへの効果が見られない場合はautovacuumが有効になっているか確認してください
- サーバーの初期設定が完了するまでは連合がオンにならないようになりました - サーバーの初期設定が完了するまでは連合がオンにならないようになりました
- 日本語における公開範囲名称の「ダイレクト」が「指名」に改称されました - 日本語における公開範囲名称の「ダイレクト」が「指名」に改称されました
- 実際の動作に即した名称になり、馴染みのない人でも理解しやすくなりました - 実際の動作に即した名称になり、馴染みのない人でも理解しやすくなりました
- 他サービスにおける「ダイレクトメッセージ」に相当するMisskeyの機能は「チャット」ですが、「ダイレクト投稿」という名称の機能が存在するとそちらがダイレクトメッセージ機能であるような誤解を生んでいました - 他サービスにおける「ダイレクトメッセージ」に相当するMisskeyの機能は「チャット」ですが(過去のバージョンのMisskeyでも、当該機能は「チャット」ではなく「ダイレクトメッセージ」でした)、「ダイレクト投稿」という名称の機能が存在するとそちらがダイレクトメッセージ機能であるような誤解を生んでいました
- 今後、「チャット」の名称を「ダイレクトメッセージ」に戻す可能性があります
- mfm.jsをアップデートしました - mfm.jsをアップデートしました
- Enhance: Unicode 15.1 および 16.0 に収録されている絵文字に対応 - Enhance: Unicode 15.1 および 16.0 に収録されている絵文字に対応
- Enhance: acctに `.` が入っているユーザーのメンションに対応 - Enhance: acctに `.` が入っているユーザーのメンションに対応
@ -24,20 +39,28 @@
### Client ### Client
- Feat: AiScriptが1.1.0に更新されました - Feat: AiScriptが1.1.0に更新されました
- プラグインは1.xに対応したものが必要です - プラグインは1.xに対応したものが必要です
- Playはそのまま動作しますが、新規に作られるプリセットは1.0になります - Playはそのまま動作しますが、新規に作られるプリセットは1.xになります
- 以前のバージョンから無効化されていた note_view_interruptor が有効になりました - 以前のバージョンから無効化されていた note_view_interruptor が有効になりました
- ハンドラは同期的である必要があります
- Feat: セーフモード - Feat: セーフモード
- プラグイン・テーマ・カスタムCSSの使用でクライアントの起動に問題が発生した際に、これらを無効にして起動できます - プラグイン・テーマ・カスタムCSSの使用でクライアントの起動に問題が発生した際に、これらを無効にして起動できます
- 以下の方法でセーフモードを起動できます - 以下の方法でセーフモードを起動できます
- `g` キーを連打する - `g` キーを連打する
- URLに`?safemode=true`を付ける - URLに`?safemode=true`を付ける
- PWAのショートカットで Safemode を選択して起動する - PWAのショートカットで Safemode を選択して起動する
- Feat: 非ログイン時に表示されるトップページのスタイルを選択できるように
- コントロールパネル→ブランディング→エントランスページのスタイル
- Feat: ページのタブバーを下部に表示できるように - Feat: ページのタブバーを下部に表示できるように
- Feat: (実験的)iOSでの触覚フィードバックを有効にできるように
- Feat: コントロールパネルを検索できるように
- Enhance: 「自動でもっと見る」オプションが有効になり、安定性が向上しました - Enhance: 「自動でもっと見る」オプションが有効になり、安定性が向上しました
- Enhance: コントロールパネルを検索できるように
- Enhance: トルコ語 (tr-TR) に対応 - Enhance: トルコ語 (tr-TR) に対応
- Enhance: 不必要な翻訳データを読み込まなくなり、パフォーマンスが向上しました - Enhance: 不必要な翻訳データを読み込まなくなり、パフォーマンスが向上しました
- Enhance: 画像エフェクトのパラメータ名の多言語対応 - Enhance: 画像エフェクトのパラメータ名の多言語対応
- Enhance: ートを非表示にする相対期間を1ヶ月単位で自由に指定できるように
- Enhance: メールアドレス確認画面のUIを改善
- Enhance: アイコンのスクロール追従を無効化する際の適用範囲を強化
- Enhance: レンダリングパフォーマンスの向上
- Enhance: 依存ソフトウェアの更新 - Enhance: 依存ソフトウェアの更新
- Fix: 投稿フォームでファイルのアップロードが中止または失敗した際のハンドリングを修正 - Fix: 投稿フォームでファイルのアップロードが中止または失敗した際のハンドリングを修正
- Fix: 一部の設定検索結果が存在しないパスになる問題を修正 - Fix: 一部の設定検索結果が存在しないパスになる問題を修正
@ -47,12 +70,27 @@
- Fix: カラムの名前が正しくリスト/チャンネルの名前にならない問題を修正 - Fix: カラムの名前が正しくリスト/チャンネルの名前にならない問題を修正
- Fix: 複数のメンションを1行に記述した場合に、サジェストが正しく表示されない問題を修正 - Fix: 複数のメンションを1行に記述した場合に、サジェストが正しく表示されない問題を修正
- Fix: メンションとしての条件を満たしていても、特定の条件(`-`が含まれる場合など)で正しくサジェストされない問題を一部修正 - Fix: メンションとしての条件を満たしていても、特定の条件(`-`が含まれる場合など)で正しくサジェストされない問題を一部修正
- Fix: ユーザーの前後ノートを閲覧する機能が動作しない問題を修正
- Fix: 照会ダイアログでap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正
- Fix: アイコンのデコレーションを付ける際にデコレーションが表示されなくなる問題を修正
- Fix: タッチ操作時にマウスホバー時のユーザープレビューが開くことがある問題を修正
- Fix: 管理中アカウント一覧で正しい表示が行われない問題を修正
- Fix: lookupページでリモートURLを指定した際に正しく動作しない問題を修正
### Server ### Server
- Feat: サーバー管理コマンド
- `pnpm cli foo` の形式で実行可能です
- 現在以下のコマンドが利用可能です
- `reset-captcha` - CAPTCHA設定をリセットします
- Enhance: ノートの削除処理の効率化 - Enhance: ノートの削除処理の効率化
- Enhance: 全体的なパフォーマンスの向上 - Enhance: 全体的なパフォーマンスの向上
- Enhance: 依存ソフトウェアの更新 - Enhance: 依存ソフトウェアの更新
- Enhance: `clips/list` APIがページネーションに対応しました
- Fix: `notes/mentions` で場合によっては並び順が正しく返されない問題を修正
- Fix: SystemWebhook設定でsecretを空に出来ない問題を修正 - Fix: SystemWebhook設定でsecretを空に出来ない問題を修正
- Fix: 削除されたユーザーがチャットメッセージにリアクションしている場合`chat/history`などでエラーになる問題を修正
- Fix: Pageのアイキャッチ画像をドライブから消してもPageごと消えないように
- Fix: タイムラインAPIの withRenotes: false 時のレスポンスを修正
## 2025.7.0 ## 2025.7.0

View file

@ -4,8 +4,8 @@
*/ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable @typescript-eslint/explicit-function-return-type */
import { action } from '@storybook/addon-actions'; import { action } from 'storybook/actions';
import { StoryObj } from '@storybook/vue3'; import type { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw'; import { HttpResponse, http } from 'msw';
import { abuseUserReport } from '../packages/frontend/.storybook/fakes.js'; import { abuseUserReport } from '../packages/frontend/.storybook/fakes.js';
import { commonHandlers } from '../packages/frontend/.storybook/mocks.js'; import { commonHandlers } from '../packages/frontend/.storybook/mocks.js';

View file

@ -1054,6 +1054,7 @@ permissionDeniedError: "Operació no permesa "
permissionDeniedErrorDescription: "Aquest compte no té suficients permisos per dur a terme aquesta acció " permissionDeniedErrorDescription: "Aquest compte no té suficients permisos per dur a terme aquesta acció "
preset: "Predefinit" preset: "Predefinit"
selectFromPresets: "Escull des dels predefinits" selectFromPresets: "Escull des dels predefinits"
custom: "Personalitzat"
achievements: "Assoliments" achievements: "Assoliments"
gotInvalidResponseError: "Resposta del servidor invàlida " gotInvalidResponseError: "Resposta del servidor invàlida "
gotInvalidResponseErrorDescription: "No es pot contactar amb el servidor o potser es troba fora de línia per manteniment. Provar-ho de nou més tard." gotInvalidResponseErrorDescription: "No es pot contactar amb el servidor o potser es troba fora de línia per manteniment. Provar-ho de nou més tard."
@ -1244,7 +1245,7 @@ releaseToRefresh: "Deixar anar per actualitzar"
refreshing: "Recarregant..." refreshing: "Recarregant..."
pullDownToRefresh: "Llisca cap a baix per recarregar" pullDownToRefresh: "Llisca cap a baix per recarregar"
useGroupedNotifications: "Mostrar les notificacions agrupades " useGroupedNotifications: "Mostrar les notificacions agrupades "
signupPendingError: "Hi ha hagut un problema verificant l'adreça de correu electrònic. L'enllaç pot haver caducat." emailVerificationFailedError: "Hem tingut un problema en verificar la teva adreça de correu electrònic. És probable que l'enllaç estigui caducat."
cwNotationRequired: "Si està activat \"Amagar contingut\" s'ha d'escriure una descripció " cwNotationRequired: "Si està activat \"Amagar contingut\" s'ha d'escriure una descripció "
doReaction: "Afegeix una reacció " doReaction: "Afegeix una reacció "
code: "Codi" code: "Codi"
@ -1375,6 +1376,7 @@ safeModeEnabled: "Mode segur activat"
pluginsAreDisabledBecauseSafeMode: "Els afegits no estan activats perquè el mode segur està activat." pluginsAreDisabledBecauseSafeMode: "Els afegits no estan activats perquè el mode segur està activat."
customCssIsDisabledBecauseSafeMode: "El CSS personalitzat no s'aplica perquè el mode segur es troba activat." customCssIsDisabledBecauseSafeMode: "El CSS personalitzat no s'aplica perquè el mode segur es troba activat."
themeIsDefaultBecauseSafeMode: "El tema predeterminat es farà servir mentre el mode segur estigui activat. Una vegada es desactivi el mode segur es restablirà el tema escollit." themeIsDefaultBecauseSafeMode: "El tema predeterminat es farà servir mentre el mode segur estigui activat. Una vegada es desactivi el mode segur es restablirà el tema escollit."
thankYouForTestingBeta: "Gràcies per ajudar-nos a provar la versió beta!"
_order: _order:
newest: "Més recent" newest: "Més recent"
oldest: "Antigues primer" oldest: "Antigues primer"
@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "La publicació incondicional de tots els continguts del servidor a internet, incloent-hi els continguts remots rebuts pel servidor, comporta riscos. Això és extremadament important per els espectadors que desconeixen el caràcter descentralitzat dels continguts, ja que poden percebre erroneament els continguts remots com contingut generat per el propi servidor." userGeneratedContentsVisibilityForVisitor_description2: "La publicació incondicional de tots els continguts del servidor a internet, incloent-hi els continguts remots rebuts pel servidor, comporta riscos. Això és extremadament important per els espectadors que desconeixen el caràcter descentralitzat dels continguts, ja que poden percebre erroneament els continguts remots com contingut generat per el propi servidor."
restartServerSetupWizardConfirm_title: "Vols tornar a executar l'assistent de configuració inicial del servidor?" restartServerSetupWizardConfirm_title: "Vols tornar a executar l'assistent de configuració inicial del servidor?"
restartServerSetupWizardConfirm_text: "Algunes configuracions actuals seran restablertes." restartServerSetupWizardConfirm_text: "Algunes configuracions actuals seran restablertes."
entrancePageStyle: "Estil de la pàgina d'inici"
showTimelineForVisitor: "Mostrar la línia de temps"
showActivitiesForVisitor: "Mostrar activitat"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "Tot obert al públic " all: "Tot obert al públic "
localOnly: "Només es publiquen els continguts locals, el contingut remot es manté privat" localOnly: "Només es publiquen els continguts locals, el contingut remot es manté privat"
@ -2273,6 +2278,7 @@ _time:
minute: "Minut(s)" minute: "Minut(s)"
hour: "Hor(a)(es)" hour: "Hor(a)(es)"
day: "Di(a)(es)" day: "Di(a)(es)"
month: "Mes(os)"
_2fa: _2fa:
alreadyRegistered: "J has registrat un dispositiu d'autenticació de doble factor." alreadyRegistered: "J has registrat un dispositiu d'autenticació de doble factor."
registerTOTP: "Registrar una aplicació autenticadora" registerTOTP: "Registrar una aplicació autenticadora"

View file

@ -1243,7 +1243,6 @@ releaseToRefresh: "Zum Aktualisieren loslassen"
refreshing: "Wird aktualisiert..." refreshing: "Wird aktualisiert..."
pullDownToRefresh: "Zum Aktualisieren ziehen" pullDownToRefresh: "Zum Aktualisieren ziehen"
useGroupedNotifications: "Benachrichtigungen gruppieren" 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." cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden."
doReaction: "Reagieren" doReaction: "Reagieren"
code: "Code" code: "Code"

View file

@ -1054,6 +1054,7 @@ permissionDeniedError: "Operation denied"
permissionDeniedErrorDescription: "This account does not have the permission to perform this action." permissionDeniedErrorDescription: "This account does not have the permission to perform this action."
preset: "Preset" preset: "Preset"
selectFromPresets: "Choose from presets" selectFromPresets: "Choose from presets"
custom: "Custom"
achievements: "Achievements" achievements: "Achievements"
gotInvalidResponseError: "Invalid server response" gotInvalidResponseError: "Invalid server response"
gotInvalidResponseErrorDescription: "The server may be unreachable or undergoing maintenance. Please try again later." gotInvalidResponseErrorDescription: "The server may be unreachable or undergoing maintenance. Please try again later."
@ -1217,8 +1218,8 @@ showRepliesToOthersInTimeline: "Show replies to others in timeline"
hideRepliesToOthersInTimeline: "Hide replies to others from timeline" hideRepliesToOthersInTimeline: "Hide replies to others from timeline"
showRepliesToOthersInTimelineAll: "Show replies to others from everyone you follow in timeline" showRepliesToOthersInTimelineAll: "Show replies to others from everyone you follow in timeline"
hideRepliesToOthersInTimelineAll: "Hide replies to others from everyone you follow in timeline" hideRepliesToOthersInTimelineAll: "Hide replies to others from everyone you follow in timeline"
confirmShowRepliesAll: "This operation is irreversible. Would you really like to show replies to others from everyone you follow in your timeline?" confirmShowRepliesAll: "Are you sure you want to show replies from everyone you follow in your timeline? This action is irreversible."
confirmHideRepliesAll: "This operation is irreversible. Would you really like to hide replies to others from everyone you follow in your timeline?" confirmHideRepliesAll: "Are you sure you want to hide replies from everyone you follow in your timeline? This action is irreversible."
externalServices: "External Services" externalServices: "External Services"
sourceCode: "Source code" sourceCode: "Source code"
sourceCodeIsNotYetProvided: "Source code is not yet available. Contact the administrator to fix this problem." sourceCodeIsNotYetProvided: "Source code is not yet available. Contact the administrator to fix this problem."
@ -1244,7 +1245,7 @@ releaseToRefresh: "Release to refresh"
refreshing: "Refreshing..." refreshing: "Refreshing..."
pullDownToRefresh: "Pull down to refresh" pullDownToRefresh: "Pull down to refresh"
useGroupedNotifications: "Display grouped notifications" useGroupedNotifications: "Display grouped notifications"
signupPendingError: "There was a problem verifying the email address. The link may have expired." emailVerificationFailedError: "A problem occurred while verifying your email address. The link may have expired."
cwNotationRequired: "If \"Hide content\" is enabled, a description must be provided." cwNotationRequired: "If \"Hide content\" is enabled, a description must be provided."
doReaction: "Add reaction" doReaction: "Add reaction"
code: "Code" code: "Code"
@ -1375,6 +1376,7 @@ safeModeEnabled: "Safe mode is enabled"
pluginsAreDisabledBecauseSafeMode: "All plugins are disabled because safe mode is enabled." pluginsAreDisabledBecauseSafeMode: "All plugins are disabled because safe mode is enabled."
customCssIsDisabledBecauseSafeMode: "Custom CSS is not applied because safe mode is enabled." customCssIsDisabledBecauseSafeMode: "Custom CSS is not applied because safe mode is enabled."
themeIsDefaultBecauseSafeMode: "While safe mode is active, the default theme is used. Disabling safe mode will revert these changes." themeIsDefaultBecauseSafeMode: "While safe mode is active, the default theme is used. Disabling safe mode will revert these changes."
thankYouForTestingBeta: "Thank you for helping us test the beta version!"
_order: _order:
newest: "Newest First" newest: "Newest First"
oldest: "Oldest First" oldest: "Oldest First"
@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Unconditionally publishing all content on the server to the Internet, including remote content received by the server is risky. This is especially important for guests who are unaware of the distributed nature of the content, as they may mistakenly believe that even remote content is content created by users on the server." userGeneratedContentsVisibilityForVisitor_description2: "Unconditionally publishing all content on the server to the Internet, including remote content received by the server is risky. This is especially important for guests who are unaware of the distributed nature of the content, as they may mistakenly believe that even remote content is content created by users on the server."
restartServerSetupWizardConfirm_title: "Restart server setup wizard?" restartServerSetupWizardConfirm_title: "Restart server setup wizard?"
restartServerSetupWizardConfirm_text: "Some current settings will be reset." restartServerSetupWizardConfirm_text: "Some current settings will be reset."
entrancePageStyle: "Entrance page style"
showTimelineForVisitor: "Show timeline"
showActivitiesForVisitor: "Show activities"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "Everything is public" all: "Everything is public"
localOnly: "Only local content is published, remote content is kept private" localOnly: "Only local content is published, remote content is kept private"
@ -2273,6 +2278,7 @@ _time:
minute: "Minute(s)" minute: "Minute(s)"
hour: "Hour(s)" hour: "Hour(s)"
day: "Day(s)" day: "Day(s)"
month: "Month(s)"
_2fa: _2fa:
alreadyRegistered: "You have already registered a 2-factor authentication device." alreadyRegistered: "You have already registered a 2-factor authentication device."
registerTOTP: "Register authenticator app" registerTOTP: "Register authenticator app"

View file

@ -1054,6 +1054,7 @@ permissionDeniedError: "Operación denegada"
permissionDeniedErrorDescription: "Esta cuenta no tiene permisos para hacer esa acción." permissionDeniedErrorDescription: "Esta cuenta no tiene permisos para hacer esa acción."
preset: "Predefinido" preset: "Predefinido"
selectFromPresets: "Escoger desde predefinidos" selectFromPresets: "Escoger desde predefinidos"
custom: "Personalizado"
achievements: "Logros" achievements: "Logros"
gotInvalidResponseError: "Respuesta del servidor inválida" gotInvalidResponseError: "Respuesta del servidor inválida"
gotInvalidResponseErrorDescription: "Puede que el servidor esté caído o en mantenimiento. Favor de intentar más tarde" gotInvalidResponseErrorDescription: "Puede que el servidor esté caído o en mantenimiento. Favor de intentar más tarde"
@ -1244,7 +1245,7 @@ releaseToRefresh: "Soltar para recargar"
refreshing: "Recargando..." refreshing: "Recargando..."
pullDownToRefresh: "Tira hacia abajo para recargar" pullDownToRefresh: "Tira hacia abajo para recargar"
useGroupedNotifications: "Mostrar notificaciones agrupadas" 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." emailVerificationFailedError: "Se ha producido un error al confirmar 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." cwNotationRequired: "Si se ha activado \"ocultar contenido\", es necesario proporcionar una descripción."
doReaction: "Añadir reacción" doReaction: "Añadir reacción"
code: "Código" code: "Código"
@ -1375,6 +1376,7 @@ safeModeEnabled: "El modo seguro está activado"
pluginsAreDisabledBecauseSafeMode: "El modo seguro está activado, por lo que todos los plugins están desactivados." pluginsAreDisabledBecauseSafeMode: "El modo seguro está activado, por lo que todos los plugins están desactivados."
customCssIsDisabledBecauseSafeMode: "El modo seguro está activado, por lo que no se aplica el CSS personalizado." customCssIsDisabledBecauseSafeMode: "El modo seguro está activado, por lo que no se aplica el CSS personalizado."
themeIsDefaultBecauseSafeMode: "Mientras el modo seguro esté activado, se utilizará el tema predeterminado. Cuando se desactive el modo seguro, se volverá al tema original." themeIsDefaultBecauseSafeMode: "Mientras el modo seguro esté activado, se utilizará el tema predeterminado. Cuando se desactive el modo seguro, se volverá al tema original."
thankYouForTestingBeta: "¡Gracias por tu colaboración en la prueba de la versión beta!"
_order: _order:
newest: "Los más recientes primero" newest: "Los más recientes primero"
oldest: "Los más antiguos primero" oldest: "Los más antiguos primero"
@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Publicar incondicionalmente todo el contenido del servidor en Internet, incluido el contenido remoto recibido por el servidor, es arriesgado. Esto es especialmente importante para los invitados que desconocen la naturaleza distribuida del contenido, ya que pueden creer erróneamente que incluso el contenido remoto es contenido creado por usuarios en el servidor." userGeneratedContentsVisibilityForVisitor_description2: "Publicar incondicionalmente todo el contenido del servidor en Internet, incluido el contenido remoto recibido por el servidor, es arriesgado. Esto es especialmente importante para los invitados que desconocen la naturaleza distribuida del contenido, ya que pueden creer erróneamente que incluso el contenido remoto es contenido creado por usuarios en el servidor."
restartServerSetupWizardConfirm_title: "¿Reiniciar el asistente de configuración del servidor?" restartServerSetupWizardConfirm_title: "¿Reiniciar el asistente de configuración del servidor?"
restartServerSetupWizardConfirm_text: "Algunas configuraciones actuales se restablecerán" restartServerSetupWizardConfirm_text: "Algunas configuraciones actuales se restablecerán"
entrancePageStyle: "Estilo de la página de inicio"
showTimelineForVisitor: "Mostrar la línea de tiempo"
showActivitiesForVisitor: "Mostrar actividades"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "Todo es público." all: "Todo es público."
localOnly: "Sólo se publica el contenido local, el remoto se mantiene privado" localOnly: "Sólo se publica el contenido local, el remoto se mantiene privado"
@ -2273,6 +2278,7 @@ _time:
minute: "Minutos" minute: "Minutos"
hour: "Horas" hour: "Horas"
day: "Días" day: "Días"
month: "Mes(es)"
_2fa: _2fa:
alreadyRegistered: "Ya has completado la configuración." alreadyRegistered: "Ya has completado la configuración."
registerTOTP: "Registrar aplicación autenticadora" registerTOTP: "Registrar aplicación autenticadora"

View file

@ -1208,7 +1208,6 @@ releaseToRefresh: "Relâcher pour rafraîchir"
refreshing: "Rafraîchissement..." refreshing: "Rafraîchissement..."
pullDownToRefresh: "Tirer vers le bas pour rafraîchir" pullDownToRefresh: "Tirer vers le bas pour rafraîchir"
useGroupedNotifications: "Grouper les notifications" 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." cwNotationRequired: "Si « Masquer le contenu » est activé, une description doit être fournie."
doReaction: "Réagir" doReaction: "Réagir"
code: "Code" code: "Code"

View file

@ -1212,7 +1212,6 @@ releaseToRefresh: "Lepaskan untuk memuat ulang"
refreshing: "Sedang memuat ulang..." refreshing: "Sedang memuat ulang..."
pullDownToRefresh: "Tarik ke bawah untuk memuat ulang" pullDownToRefresh: "Tarik ke bawah untuk memuat ulang"
useGroupedNotifications: "Tampilkan notifikasi secara dikelompokkan" useGroupedNotifications: "Tampilkan notifikasi secara dikelompokkan"
signupPendingError: "Terdapat masalah ketika memverifikasi alamat surel. Tautan kemungkinan telah kedaluwarsa."
cwNotationRequired: "Jika \"Sembunyikan konten\" diaktifkan, deskripsi harus disediakan." cwNotationRequired: "Jika \"Sembunyikan konten\" diaktifkan, deskripsi harus disediakan."
doReaction: "Tambahkan reaksi" doReaction: "Tambahkan reaksi"
code: "Kode" code: "Kode"

32
locales/index.d.ts vendored
View file

@ -4234,6 +4234,10 @@ export interface Locale extends ILocale {
* *
*/ */
"selectFromPresets": string; "selectFromPresets": string;
/**
*
*/
"custom": string;
/** /**
* *
*/ */
@ -4997,7 +5001,7 @@ export interface Locale extends ILocale {
/** /**
* *
*/ */
"signupPendingError": string; "emailVerificationFailedError": string;
/** /**
* *
*/ */
@ -5521,6 +5525,10 @@ export interface Locale extends ILocale {
* 使 * 使
*/ */
"themeIsDefaultBecauseSafeMode": string; "themeIsDefaultBecauseSafeMode": string;
/**
*
*/
"thankYouForTestingBeta": string;
"_order": { "_order": {
/** /**
* *
@ -6523,7 +6531,7 @@ export interface Locale extends ILocale {
*/ */
"remoteNotesCleaning": string; "remoteNotesCleaning": string;
/** /**
* 稿 * 稿
*/ */
"remoteNotesCleaning_description": string; "remoteNotesCleaning_description": string;
/** /**
@ -6614,6 +6622,18 @@ export interface Locale extends ILocale {
* *
*/ */
"restartServerSetupWizardConfirm_text": string; "restartServerSetupWizardConfirm_text": string;
/**
*
*/
"entrancePageStyle": string;
/**
*
*/
"showTimelineForVisitor": string;
/**
*
*/
"showActivitiesForVisitor": string;
"_userGeneratedContentsVisibilityForVisitor": { "_userGeneratedContentsVisibilityForVisitor": {
/** /**
* *
@ -8836,6 +8856,10 @@ export interface Locale extends ILocale {
* *
*/ */
"day": string; "day": string;
/**
*
*/
"month": string;
}; };
"_2fa": { "_2fa": {
/** /**
@ -12008,11 +12032,11 @@ export interface Locale extends ILocale {
*/ */
"youCanConfigureMoreFederationSettingsLater": string; "youCanConfigureMoreFederationSettingsLater": string;
/** /**
* *
*/ */
"remoteContentsCleaning": string; "remoteContentsCleaning": string;
/** /**
* *
*/ */
"remoteContentsCleaning_description": string; "remoteContentsCleaning_description": string;
/** /**

View file

@ -139,7 +139,7 @@ overwriteFromPinnedEmojis: "Sovrascrivi con le impostazioni globali"
reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere." reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere."
rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note" rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note"
attachCancel: "Rimuovi allegato" attachCancel: "Rimuovi allegato"
deleteFile: "File da Drive eliminato" deleteFile: "Elimina un file dal Drive"
markAsSensitive: "Segna come esplicito" markAsSensitive: "Segna come esplicito"
unmarkAsSensitive: "Non segnare come esplicito " unmarkAsSensitive: "Non segnare come esplicito "
enterFileName: "Nome del file" enterFileName: "Nome del file"
@ -1054,6 +1054,7 @@ permissionDeniedError: "Errore, attività non autorizzata"
permissionDeniedErrorDescription: "Non si dispone dell'autorizzazione per eseguire questa operazione." permissionDeniedErrorDescription: "Non si dispone dell'autorizzazione per eseguire questa operazione."
preset: "Preimpostato" preset: "Preimpostato"
selectFromPresets: "Seleziona preimpostato" selectFromPresets: "Seleziona preimpostato"
custom: "Personalizzato"
achievements: "Conquiste" achievements: "Conquiste"
gotInvalidResponseError: "Risposta del server non valida" gotInvalidResponseError: "Risposta del server non valida"
gotInvalidResponseErrorDescription: "Il server potrebbe essere irraggiungibile o in manutenzione. Riprova più tardi." gotInvalidResponseErrorDescription: "Il server potrebbe essere irraggiungibile o in manutenzione. Riprova più tardi."
@ -1244,7 +1245,7 @@ releaseToRefresh: "Rilascia per aggiornare"
refreshing: "Aggiornamento..." refreshing: "Aggiornamento..."
pullDownToRefresh: "Trascinare per aggiornare" pullDownToRefresh: "Trascinare per aggiornare"
useGroupedNotifications: "Mostra le notifiche raggruppate" useGroupedNotifications: "Mostra le notifiche raggruppate"
signupPendingError: "Si è verificato un problema durante la verifica del tuo indirizzo email. Potrebbe essere scaduto il collegamento temporaneo." emailVerificationFailedError: "La verifica dell'indirizzo e-mail non è andata a buon fine. Il link potrebbe essere scaduto."
cwNotationRequired: "Devi indicare perché il contenuto è indicato come esplicito." cwNotationRequired: "Devi indicare perché il contenuto è indicato come esplicito."
doReaction: "Reagisci" doReaction: "Reagisci"
code: "Codice" code: "Codice"
@ -1375,6 +1376,7 @@ safeModeEnabled: "La modalità sicura è attiva"
pluginsAreDisabledBecauseSafeMode: "Tutti i plugin sono disattivati, poiché la modalità sicura è attiva." pluginsAreDisabledBecauseSafeMode: "Tutti i plugin sono disattivati, poiché la modalità sicura è attiva."
customCssIsDisabledBecauseSafeMode: "Il CSS personalizzato non è stato applicato, poiché la modalità sicura è attiva." customCssIsDisabledBecauseSafeMode: "Il CSS personalizzato non è stato applicato, poiché la modalità sicura è attiva."
themeIsDefaultBecauseSafeMode: "Quando la modalità sicura è attiva, viene utilizzato il tema predefinito. Quando la modalità sicura viene disattivata, il tema torna a essere quello precedente." themeIsDefaultBecauseSafeMode: "Quando la modalità sicura è attiva, viene utilizzato il tema predefinito. Quando la modalità sicura viene disattivata, il tema torna a essere quello precedente."
thankYouForTestingBeta: "Grazie per la tua collaborazione nella verifica delle versioni beta!"
_order: _order:
newest: "Prima i più recenti" newest: "Prima i più recenti"
oldest: "Meno recenti prima" oldest: "Meno recenti prima"
@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Esistono dei rischi nell'esporre incondizionatamente su internet tutto il contenuto del tuo server, incluso il contenuto remoto ricevuto da altri server. In particolare, occorre prestare attenzione, perché le persone non consapevoli della federazione potrebbero erroneamente credere che il contenuto remoto sia stato invece creato all'interno del proprio server." userGeneratedContentsVisibilityForVisitor_description2: "Esistono dei rischi nell'esporre incondizionatamente su internet tutto il contenuto del tuo server, incluso il contenuto remoto ricevuto da altri server. In particolare, occorre prestare attenzione, perché le persone non consapevoli della federazione potrebbero erroneamente credere che il contenuto remoto sia stato invece creato all'interno del proprio server."
restartServerSetupWizardConfirm_title: "Vuoi ripetere la procedura guidata di configurazione iniziale del server?" restartServerSetupWizardConfirm_title: "Vuoi ripetere la procedura guidata di configurazione iniziale del server?"
restartServerSetupWizardConfirm_text: "Verranno ripristinate alcune tue impostazioni personalizzate." restartServerSetupWizardConfirm_text: "Verranno ripristinate alcune tue impostazioni personalizzate."
entrancePageStyle: "Stile della pagina di ingresso"
showTimelineForVisitor: "Mostra la Timeline a visitatori non autenticati"
showActivitiesForVisitor: "Mostrare la propria attività"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "Tutto pubblico" all: "Tutto pubblico"
localOnly: "Pubblica solo contenuti locali, mantieni privati i contenuti remoti" localOnly: "Pubblica solo contenuti locali, mantieni privati i contenuti remoti"
@ -2217,7 +2222,7 @@ _theme:
hashtag: "Hashtag" hashtag: "Hashtag"
mention: "Menzioni" mention: "Menzioni"
mentionMe: "Menzioni (di me)" mentionMe: "Menzioni (di me)"
renote: "Renota" renote: "Rinota"
modalBg: "Sfondo modale." modalBg: "Sfondo modale."
divider: "Interruzione di linea" divider: "Interruzione di linea"
scrollbarHandle: "Maniglie della barra di scorrimento" scrollbarHandle: "Maniglie della barra di scorrimento"
@ -2273,6 +2278,7 @@ _time:
minute: "min" minute: "min"
hour: "ore" hour: "ore"
day: "giorni" day: "giorni"
month: "Mese"
_2fa: _2fa:
alreadyRegistered: "La configurazione è stata già completata." alreadyRegistered: "La configurazione è stata già completata."
registerTOTP: "Registra una App di autenticazione a due fattori (2FA/MFA)" registerTOTP: "Registra una App di autenticazione a due fattori (2FA/MFA)"
@ -2657,7 +2663,7 @@ _notification:
createToken: "È stato creato un token di accesso" createToken: "È stato creato un token di accesso"
createTokenDescription: "In caso contrario, eliminare il token di accesso tramite ({text})." createTokenDescription: "In caso contrario, eliminare il token di accesso tramite ({text})."
_types: _types:
all: "Tutto" all: "Tutte"
note: "Nuove Note" note: "Nuove Note"
follow: "Follower" follow: "Follower"
mention: "Menzioni" mention: "Menzioni"
@ -2665,7 +2671,7 @@ _notification:
renote: "Rinota" renote: "Rinota"
quote: "Cita" quote: "Cita"
reaction: "Reazioni" reaction: "Reazioni"
pollEnded: "Sondaggio chiuso." pollEnded: "Sondaggio terminato"
receiveFollowRequest: "Richieste di follow in arrivo" receiveFollowRequest: "Richieste di follow in arrivo"
followRequestAccepted: "Richieste di follow accettate" followRequestAccepted: "Richieste di follow accettate"
roleAssigned: "Ruolo concesso" roleAssigned: "Ruolo concesso"
@ -2673,7 +2679,7 @@ _notification:
achievementEarned: "Risultato raggiunto" achievementEarned: "Risultato raggiunto"
exportCompleted: "Esportazione completata" exportCompleted: "Esportazione completata"
login: "Accessi" login: "Accessi"
createToken: "Creare un token di accesso" createToken: "Aggiunto un token di accesso"
test: "Notifiche di test" test: "Notifiche di test"
app: "Notifiche da applicazioni" app: "Notifiche da applicazioni"
_actions: _actions:
@ -2765,56 +2771,56 @@ _abuseReport:
notifiedWebhook: "Webhook da usare" notifiedWebhook: "Webhook da usare"
deleteConfirm: "Vuoi davvero rimuovere il destinatario della notifica?" deleteConfirm: "Vuoi davvero rimuovere il destinatario della notifica?"
_moderationLogTypes: _moderationLogTypes:
createRole: "Ruolo creato" createRole: "Crea un Ruolo"
deleteRole: "Ruolo eliminato" deleteRole: "Elimina un Ruolo"
updateRole: "Ruolo aggiornato" updateRole: "Modifica un ruolo"
assignRole: "Ruolo assegnato" assignRole: "Assegna un Ruolo"
unassignRole: "Ruolo disassegnato" unassignRole: "Toglie un Ruolo al Profilo"
suspend: "Sospensione" suspend: "Sospende"
unsuspend: "Sospensione rimossa" unsuspend: "Solleva la sospensione"
addCustomEmoji: "Emoji personalizzata aggiunta" addCustomEmoji: "Aggiunge Emoji personalizzata"
updateCustomEmoji: "Emoji personalizzata aggiornata" updateCustomEmoji: "Modifica Emoji personalizzata"
deleteCustomEmoji: "Emoji personalizzata eliminata" deleteCustomEmoji: "Elimina Emoji personalizzata"
updateServerSettings: "Impostazioni del server aggiornate" updateServerSettings: "Modifica le impostazioni del server"
updateUserNote: "Promemoria di moderazione aggiornato" updateUserNote: "Modifica un promemoria di moderazione"
deleteDriveFile: "File da Drive eliminato" deleteDriveFile: "Elimina un file dal Drive"
deleteNote: "Nota eliminata" deleteNote: "Elimina una Nota"
createGlobalAnnouncement: "Annuncio globale creato" createGlobalAnnouncement: "Crea un annuncio globale"
createUserAnnouncement: "Annuncio ai profili iscritti creato" createUserAnnouncement: "Crea un annuncio ai profili già iscritti"
updateGlobalAnnouncement: "Annuncio globale aggiornato" updateGlobalAnnouncement: "Modifica un annuncio globale"
updateUserAnnouncement: "Annuncio ai profili iscritti aggiornato" updateUserAnnouncement: "Modifica un annuncio ai profili già iscritti"
deleteGlobalAnnouncement: "Annuncio globale eliminato" deleteGlobalAnnouncement: "Elimina un annuncio globale"
deleteUserAnnouncement: "Annuncio ai profili iscritti eliminato" deleteUserAnnouncement: "Elimina un annuncio ai profili già iscritti"
resetPassword: "Password azzerata" resetPassword: "Azzera la password"
suspendRemoteInstance: "Istanza remota sospesa" suspendRemoteInstance: "Sospende una istanza remota"
unsuspendRemoteInstance: "Istanza remota riattivata" unsuspendRemoteInstance: "Riattiva una istanza remota"
updateRemoteInstanceNote: "Aggiornamento del promemoria di moderazione per il server remoto" updateRemoteInstanceNote: "Modifica il promemoria di moderazione per il server remoto"
markSensitiveDriveFile: "File nel Drive segnato come esplicito" markSensitiveDriveFile: "Aggiunge NSFW a un file nel Drive"
unmarkSensitiveDriveFile: "File nel Drive segnato come non esplicito" unmarkSensitiveDriveFile: "Toglie NSFW da un file nel Drive"
resolveAbuseReport: "Segnalazione risolta" resolveAbuseReport: "Risolve una segnalazione"
forwardAbuseReport: "Segnalazione inoltrata" forwardAbuseReport: "Inoltra una segnalazione"
updateAbuseReportNote: "Ha aggiornato la segnalazione" updateAbuseReportNote: "Modifica una segnalazione"
createInvitation: "Genera codice di invito" createInvitation: "Genera un codice di invito"
createAd: "Banner creato" createAd: "Aggiunge un Banner"
deleteAd: "Banner eliminato" deleteAd: "Elimina un Banner"
updateAd: "Banner aggiornato" updateAd: "Modifica un Banner"
createAvatarDecoration: "Creazione decorazione della foto profilo" createAvatarDecoration: "Crea una decorazione della foto profilo"
updateAvatarDecoration: "Aggiornamento decorazione foto profilo" updateAvatarDecoration: "Modifica una decorazione della foto profilo"
deleteAvatarDecoration: "Eliminazione decorazione della foto profilo" deleteAvatarDecoration: "Elimina una decorazione della foto profilo"
unsetUserAvatar: "Rimossa foto profilo" unsetUserAvatar: "Toglie una foto profilo"
unsetUserBanner: "Rimossa intestazione profilo" unsetUserBanner: "Toglie una immagine di intestazione profilo"
createSystemWebhook: "Crea un SystemWebhook" createSystemWebhook: "Aggiunge un System Webhook"
updateSystemWebhook: "Modifica SystemWebhook" updateSystemWebhook: "Modifica un System Webhook"
deleteSystemWebhook: "Elimina SystemWebhook" deleteSystemWebhook: "Elimina un System Webhook"
createAbuseReportNotificationRecipient: "Crea destinatario per le notifiche di segnalazioni" createAbuseReportNotificationRecipient: "Crea destinatario per le notifiche di segnalazioni"
updateAbuseReportNotificationRecipient: "Aggiorna destinatario notifiche di segnalazioni" updateAbuseReportNotificationRecipient: "Modifica un destinatario per le notifiche di segnalazioni"
deleteAbuseReportNotificationRecipient: "Elimina destinatario notifiche di segnalazioni" deleteAbuseReportNotificationRecipient: "Elimina un destinatario per le notifiche di segnalazioni"
deleteAccount: "Quando viene eliminato un profilo" deleteAccount: "Elimina un profilo"
deletePage: "Pagina eliminata" deletePage: "Elimina una Pagina"
deleteFlash: "Play eliminato" deleteFlash: "Elimina un Play"
deleteGalleryPost: "Eliminazione pubblicazione nella Galleria" deleteGalleryPost: "Elimina pubblicazione nella Galleria"
deleteChatRoom: "Elimina chat" deleteChatRoom: "Elimina una Chat"
updateProxyAccountDescription: "Aggiornata la descrizione del profilo proxy" updateProxyAccountDescription: "Aggiorna la descrizione del profilo proxy"
_fileViewer: _fileViewer:
title: "Dettagli del file" title: "Dettagli del file"
type: "Tipo di file" type: "Tipo di file"
@ -3231,7 +3237,7 @@ _imageEffector:
zoomLinesThreshold: "Limite delle linee zoom" zoomLinesThreshold: "Limite delle linee zoom"
zoomLinesMaskSize: "Ampiezza del diametro" zoomLinesMaskSize: "Ampiezza del diametro"
zoomLinesBlack: "Bande nere" zoomLinesBlack: "Bande nere"
drafts: "Bozza" drafts: "Bozze"
_drafts: _drafts:
select: "Selezionare bozza" select: "Selezionare bozza"
cannotCreateDraftAnymore: "Hai superato il numero massimo di bozze ammissibili." cannotCreateDraftAnymore: "Hai superato il numero massimo di bozze ammissibili."

View file

@ -1054,6 +1054,7 @@ permissionDeniedError: "操作が拒否されました"
permissionDeniedErrorDescription: "このアカウントにはこの操作を行うための権限がありません。" permissionDeniedErrorDescription: "このアカウントにはこの操作を行うための権限がありません。"
preset: "プリセット" preset: "プリセット"
selectFromPresets: "プリセットから選択" selectFromPresets: "プリセットから選択"
custom: "カスタム"
achievements: "実績" achievements: "実績"
gotInvalidResponseError: "サーバーの応答が無効です" gotInvalidResponseError: "サーバーの応答が無効です"
gotInvalidResponseErrorDescription: "サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから再度お試しください。" gotInvalidResponseErrorDescription: "サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから再度お試しください。"
@ -1244,7 +1245,7 @@ releaseToRefresh: "離してリロード"
refreshing: "リロード中" refreshing: "リロード中"
pullDownToRefresh: "引っ張ってリロード" pullDownToRefresh: "引っ張ってリロード"
useGroupedNotifications: "通知をグルーピング" useGroupedNotifications: "通知をグルーピング"
signupPendingError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。" emailVerificationFailedError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。"
cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要です。" cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要です。"
doReaction: "リアクションする" doReaction: "リアクションする"
code: "コード" code: "コード"
@ -1375,6 +1376,7 @@ safeModeEnabled: "セーフモードが有効です"
pluginsAreDisabledBecauseSafeMode: "セーフモードが有効なため、プラグインはすべて無効化されています。" pluginsAreDisabledBecauseSafeMode: "セーフモードが有効なため、プラグインはすべて無効化されています。"
customCssIsDisabledBecauseSafeMode: "セーフモードが有効なため、カスタムCSSは適用されていません。" customCssIsDisabledBecauseSafeMode: "セーフモードが有効なため、カスタムCSSは適用されていません。"
themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。" themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。"
thankYouForTestingBeta: "ベータ版の検証にご協力いただきありがとうございます!"
_order: _order:
newest: "新しい順" newest: "新しい順"
@ -1658,7 +1660,7 @@ _serverSettings:
fanoutTimelineDbFallbackDescription: "有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。" fanoutTimelineDbFallbackDescription: "有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。"
reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。" reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。"
remoteNotesCleaning: "リモート投稿の自動クリーニング" remoteNotesCleaning: "リモート投稿の自動クリーニング"
remoteNotesCleaning_description: "有効にすると、参照されていない古いリモートの投稿を定期的にクリーンアップしてデータベースの肥大化を抑制します。" remoteNotesCleaning_description: "有効にすると、一定期間経過したリモートの投稿を定期的にクリーンアップしてデータベースの肥大化を抑制します。"
remoteNotesCleaningMaxProcessingDuration: "最大クリーニング処理継続時間" remoteNotesCleaningMaxProcessingDuration: "最大クリーニング処理継続時間"
remoteNotesCleaningExpiryDaysForEachNotes: "最低ノート保持日数" remoteNotesCleaningExpiryDaysForEachNotes: "最低ノート保持日数"
inquiryUrl: "問い合わせ先URL" inquiryUrl: "問い合わせ先URL"
@ -1681,6 +1683,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "サーバーで受信したリモートのコンテンツを含め、サーバー内の全てのコンテンツを無条件でインターネットに公開することはリスクが伴います。特に、分散型の特性を知らない閲覧者にとっては、リモートのコンテンツであってもサーバー内で作成されたコンテンツであると誤って認識してしまう可能性があるため、注意が必要です。" userGeneratedContentsVisibilityForVisitor_description2: "サーバーで受信したリモートのコンテンツを含め、サーバー内の全てのコンテンツを無条件でインターネットに公開することはリスクが伴います。特に、分散型の特性を知らない閲覧者にとっては、リモートのコンテンツであってもサーバー内で作成されたコンテンツであると誤って認識してしまう可能性があるため、注意が必要です。"
restartServerSetupWizardConfirm_title: "サーバーの初期設定ウィザードをやり直しますか?" restartServerSetupWizardConfirm_title: "サーバーの初期設定ウィザードをやり直しますか?"
restartServerSetupWizardConfirm_text: "現在の一部の設定はリセットされます。" restartServerSetupWizardConfirm_text: "現在の一部の設定はリセットされます。"
entrancePageStyle: "エントランスページのスタイル"
showTimelineForVisitor: "タイムラインを表示する"
showActivitiesForVisitor: "アクティビティを表示する"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "全て公開" all: "全て公開"
@ -2321,6 +2326,7 @@ _time:
minute: "分" minute: "分"
hour: "時間" hour: "時間"
day: "日" day: "日"
month: "ヶ月"
_2fa: _2fa:
alreadyRegistered: "既に設定は完了しています。" alreadyRegistered: "既に設定は完了しています。"
@ -3210,8 +3216,8 @@ _serverSetupWizard:
doYouConnectToFediverse_description1: "分散型サーバーで構成されるネットワーク(Fediverse)に接続すると、他のサーバーと相互にコンテンツのやり取りが可能です。" doYouConnectToFediverse_description1: "分散型サーバーで構成されるネットワーク(Fediverse)に接続すると、他のサーバーと相互にコンテンツのやり取りが可能です。"
doYouConnectToFediverse_description2: "Fediverseと接続することは「連合」とも呼ばれます。" doYouConnectToFediverse_description2: "Fediverseと接続することは「連合」とも呼ばれます。"
youCanConfigureMoreFederationSettingsLater: "連合可能なサーバーの指定など、高度な設定も後ほど可能です。" youCanConfigureMoreFederationSettingsLater: "連合可能なサーバーの指定など、高度な設定も後ほど可能です。"
remoteContentsCleaning: "受信コンテンツの自動クリーニング" remoteContentsCleaning: "リモートコンテンツの自動クリーニング"
remoteContentsCleaning_description: "連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、参照されていない古くなったコンテンツを自動でサーバーから削除し、ストレージを節約できます。" remoteContentsCleaning_description: "連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、一定期間経過したリモートコンテンツを自動でサーバーから削除し、ストレージを節約できます。"
adminInfo: "管理者情報" adminInfo: "管理者情報"
adminInfo_description: "問い合わせを受け付けるために使用される管理者情報を設定します。" adminInfo_description: "問い合わせを受け付けるために使用される管理者情報を設定します。"
adminInfo_mustBeFilled: "オープンサーバー、または連合がオンの場合は必ず入力が必要です。" adminInfo_mustBeFilled: "オープンサーバー、または連合がオンの場合は必ず入力が必要です。"

View file

@ -1239,7 +1239,6 @@ releaseToRefresh: "離したらリロード"
refreshing: "リロードしとる" refreshing: "リロードしとる"
pullDownToRefresh: "引っ張ってリロードするで" pullDownToRefresh: "引っ張ってリロードするで"
useGroupedNotifications: "通知をグループ分けして出すで" useGroupedNotifications: "通知をグループ分けして出すで"
signupPendingError: "メアド確認してたらなんか変なことなったわ。リンクの期限切れてるかもしれん。"
cwNotationRequired: "「内容を隠す」んやったら注釈書かなアカンで。" cwNotationRequired: "「内容を隠す」んやったら注釈書かなアカンで。"
doReaction: "ツッコむで" doReaction: "ツッコむで"
code: "コード" code: "コード"

View file

@ -1054,6 +1054,7 @@ permissionDeniedError: "작업이 거부되었습니다"
permissionDeniedErrorDescription: "이 작업을 수행할 권한이 없습니다." permissionDeniedErrorDescription: "이 작업을 수행할 권한이 없습니다."
preset: "프리셋" preset: "프리셋"
selectFromPresets: "프리셋에서 선택" selectFromPresets: "프리셋에서 선택"
custom: "커스텀"
achievements: "도전 과제" achievements: "도전 과제"
gotInvalidResponseError: "서버의 응답이 올바르지 않습니다" gotInvalidResponseError: "서버의 응답이 올바르지 않습니다"
gotInvalidResponseErrorDescription: " 서버가 다운되었거나 점검중일 가능성이 있습니다. 잠시후에 다시 시도해 주십시오." gotInvalidResponseErrorDescription: " 서버가 다운되었거나 점검중일 가능성이 있습니다. 잠시후에 다시 시도해 주십시오."
@ -1244,7 +1245,7 @@ releaseToRefresh: "놓아서 새로고침"
refreshing: "새로고침 중" refreshing: "새로고침 중"
pullDownToRefresh: "아래로 내려서 새로고침" pullDownToRefresh: "아래로 내려서 새로고침"
useGroupedNotifications: "알림을 그룹화하고 표시" useGroupedNotifications: "알림을 그룹화하고 표시"
signupPendingError: "메일 주소 확인중에 문제가 발생했습니다. 링크의 유효기간이 지났을 가능성이 있습니다." emailVerificationFailedError: "메일 주소 확인에 실패했습니다. 확인에 필요한 URL의 유효기간이 지났을 가능성이 있습니다."
cwNotationRequired: "'내용을 숨기기'를 체크한 경우 주석을 써야 합니다." cwNotationRequired: "'내용을 숨기기'를 체크한 경우 주석을 써야 합니다."
doReaction: "리액션 추가" doReaction: "리액션 추가"
code: "문자열" code: "문자열"
@ -1375,6 +1376,7 @@ safeModeEnabled: "세이프 모드가 활성화돼있습니다"
pluginsAreDisabledBecauseSafeMode: "세이프 모드가 활성화돼있기에 플러그인은 전부 비활성화됩니다." pluginsAreDisabledBecauseSafeMode: "세이프 모드가 활성화돼있기에 플러그인은 전부 비활성화됩니다."
customCssIsDisabledBecauseSafeMode: "세이프 모드가 활성화돼있기에 커스텀 CSS는 적용되지 않습니다." customCssIsDisabledBecauseSafeMode: "세이프 모드가 활성화돼있기에 커스텀 CSS는 적용되지 않습니다."
themeIsDefaultBecauseSafeMode: "세이프 모드가 활성화돼있는 동안에는 기본 테마가 사용됩니다. 세이프 모드를 끄면 원래대로 돌아옵니다." themeIsDefaultBecauseSafeMode: "세이프 모드가 활성화돼있는 동안에는 기본 테마가 사용됩니다. 세이프 모드를 끄면 원래대로 돌아옵니다."
thankYouForTestingBeta: "베타 버전의 검증에 협력해 주셔서 감사합니다!"
_order: _order:
newest: "최신 순" newest: "최신 순"
oldest: "오래된 순" oldest: "오래된 순"
@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "서버에서 받은 리모트 콘텐츠를 포함해 서버 내의 모든 콘텐츠를 무조건 인터넷에 공개하는 것에는 위험이 따릅니다. 특히, 분산형 특성에 대해 모르는 열람자에게는 리모트 콘텐츠여도 서버 내에서 작성된 콘텐츠라고 잘못 인식할 수 있기에 주의가 필요합니다." userGeneratedContentsVisibilityForVisitor_description2: "서버에서 받은 리모트 콘텐츠를 포함해 서버 내의 모든 콘텐츠를 무조건 인터넷에 공개하는 것에는 위험이 따릅니다. 특히, 분산형 특성에 대해 모르는 열람자에게는 리모트 콘텐츠여도 서버 내에서 작성된 콘텐츠라고 잘못 인식할 수 있기에 주의가 필요합니다."
restartServerSetupWizardConfirm_title: "서버의 초기 설정 위자드를 재시도하시겠습니까?" restartServerSetupWizardConfirm_title: "서버의 초기 설정 위자드를 재시도하시겠습니까?"
restartServerSetupWizardConfirm_text: "현재 일부 설정은 리셋됩니다." restartServerSetupWizardConfirm_text: "현재 일부 설정은 리셋됩니다."
entrancePageStyle: "입구 페이지의 스타일"
showTimelineForVisitor: "타임라인 표시"
showActivitiesForVisitor: "액티비티 표시하기"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "모두 공개" all: "모두 공개"
localOnly: "로컬 콘텐츠만 공개하고 리모트 콘텐츠는 비공개" localOnly: "로컬 콘텐츠만 공개하고 리모트 콘텐츠는 비공개"
@ -2273,6 +2278,7 @@ _time:
minute: "분" minute: "분"
hour: "시간" hour: "시간"
day: "일" day: "일"
month: "개월"
_2fa: _2fa:
alreadyRegistered: "이미 설정이 완료되었습니다." alreadyRegistered: "이미 설정이 완료되었습니다."
registerTOTP: "인증 앱 설정 시작" registerTOTP: "인증 앱 설정 시작"

View file

@ -1243,7 +1243,6 @@ releaseToRefresh: "Solte para atualizar"
refreshing: "Atualizando..." refreshing: "Atualizando..."
pullDownToRefresh: "Puxe para baixo para atualizar" pullDownToRefresh: "Puxe para baixo para atualizar"
useGroupedNotifications: "Agrupar notificações" useGroupedNotifications: "Agrupar notificações"
signupPendingError: "Houve um problema ao verificar o endereço de email. O link pode ter expirado."
cwNotationRequired: "Se \"Esconder conteúdo\" está habilitado, uma descrição deve ser adicionada." cwNotationRequired: "Se \"Esconder conteúdo\" está habilitado, uma descrição deve ser adicionada."
doReaction: "Adicionar reação" doReaction: "Adicionar reação"
code: "Código" code: "Código"

View file

@ -1220,7 +1220,6 @@ flip: "Переворот"
showAvatarDecorations: "Показать украшения для аватара" showAvatarDecorations: "Показать украшения для аватара"
pullDownToRefresh: "Опустите что бы обновить" pullDownToRefresh: "Опустите что бы обновить"
useGroupedNotifications: "Отображать уведомления сгруппировано" useGroupedNotifications: "Отображать уведомления сгруппировано"
signupPendingError: "Возникла проблема с подтверждением вашего адреса электронной почты. Возможно, срок действия ссылки истёк."
cwNotationRequired: "Если включена опция «Скрыть содержимое», необходимо написать аннотацию." cwNotationRequired: "Если включена опция «Скрыть содержимое», необходимо написать аннотацию."
doReaction: "Добавить реакцию" doReaction: "Добавить реакцию"
code: "Код" code: "Код"

View file

@ -1054,6 +1054,7 @@ permissionDeniedError: "การดำเนินถูกปฏิเสธ"
permissionDeniedErrorDescription: "บัญชีนี้ไม่มีสิทธิ์อนุญาตในการดำเนินการนี้" permissionDeniedErrorDescription: "บัญชีนี้ไม่มีสิทธิ์อนุญาตในการดำเนินการนี้"
preset: "พรีเซ็ต" preset: "พรีเซ็ต"
selectFromPresets: "เลือกจากการพรีเซ็ต" selectFromPresets: "เลือกจากการพรีเซ็ต"
custom: "แบบกำหนดเอง"
achievements: "ความสำเร็จ" achievements: "ความสำเร็จ"
gotInvalidResponseError: "การตอบสนองเซิร์ฟเวอร์ไม่ถูกต้อง" gotInvalidResponseError: "การตอบสนองเซิร์ฟเวอร์ไม่ถูกต้อง"
gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะกำลังอยู่ในระหว่างปรับปรุง กรุณาลองใหม่อีกครั้งในภายหลังนะคะ" gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะกำลังอยู่ในระหว่างปรับปรุง กรุณาลองใหม่อีกครั้งในภายหลังนะคะ"
@ -1244,7 +1245,6 @@ releaseToRefresh: "ปล่อยเพื่อรีเฟรช"
refreshing: "กำลังรีเฟรช..." refreshing: "กำลังรีเฟรช..."
pullDownToRefresh: "ดึงลงเพื่อรีเฟรช" pullDownToRefresh: "ดึงลงเพื่อรีเฟรช"
useGroupedNotifications: "แสดงผลการแจ้งเตือนแบบกลุ่มแล้ว" useGroupedNotifications: "แสดงผลการแจ้งเตือนแบบกลุ่มแล้ว"
signupPendingError: "มีปัญหาในการตรวจสอบที่อยู่อีเมลลิงก์อาจหมดอายุแล้ว"
cwNotationRequired: "หากเปิดใช้งาน “ซ่อนเนื้อหา” จะต้องระบุคำอธิบาย" cwNotationRequired: "หากเปิดใช้งาน “ซ่อนเนื้อหา” จะต้องระบุคำอธิบาย"
doReaction: "เพิ่มรีแอคชั่น" doReaction: "เพิ่มรีแอคชั่น"
code: "โค้ด" code: "โค้ด"
@ -1375,6 +1375,7 @@ safeModeEnabled: "โหมดปลอดภัยถูกเปิดใช
pluginsAreDisabledBecauseSafeMode: "เนื่องจากโหมดปลอดภัยถูกเปิดใช้งาน ปลั๊กอินทั้งหมดจึงถูกปิดใช้งาน" pluginsAreDisabledBecauseSafeMode: "เนื่องจากโหมดปลอดภัยถูกเปิดใช้งาน ปลั๊กอินทั้งหมดจึงถูกปิดใช้งาน"
customCssIsDisabledBecauseSafeMode: "เนื่องจากโหมดปลอดภัยถูกเปิดใช้งาน CSS แบบกำหนดเองจึงไม่ได้ถูกนำมาใช้" customCssIsDisabledBecauseSafeMode: "เนื่องจากโหมดปลอดภัยถูกเปิดใช้งาน CSS แบบกำหนดเองจึงไม่ได้ถูกนำมาใช้"
themeIsDefaultBecauseSafeMode: "ในระหว่างที่โหมดปลอดภัยถูกเปิดใช้งาน จะใช้ธีมเริ่มต้น เมื่อปิดโหมดปลอดภัยจะกลับคืนดังเดิม" themeIsDefaultBecauseSafeMode: "ในระหว่างที่โหมดปลอดภัยถูกเปิดใช้งาน จะใช้ธีมเริ่มต้น เมื่อปิดโหมดปลอดภัยจะกลับคืนดังเดิม"
thankYouForTestingBeta: "ขอบคุณที่ให้ความร่วมมือในการทดสอบเวอร์ชันเบต้า!"
_order: _order:
newest: "เรียงจากใหม่ไปเก่า" newest: "เรียงจากใหม่ไปเก่า"
oldest: "เรียงจากเก่าไปใหม่" oldest: "เรียงจากเก่าไปใหม่"
@ -2273,6 +2274,7 @@ _time:
minute: "นาที" minute: "นาที"
hour: "ชั่วโมง" hour: "ชั่วโมง"
day: "วัน" day: "วัน"
month: "เดือน"
_2fa: _2fa:
alreadyRegistered: "คุณได้ลงทะเบียนอุปกรณ์ยืนยันตัวตนแบบ 2 ชั้นแล้ว" alreadyRegistered: "คุณได้ลงทะเบียนอุปกรณ์ยืนยันตัวตนแบบ 2 ชั้นแล้ว"
registerTOTP: "ลงทะเบียนแอพตัวตรวจสอบสิทธิ์" registerTOTP: "ลงทะเบียนแอพตัวตรวจสอบสิทธิ์"

View file

@ -31,7 +31,7 @@ openInWindow: "Pencerede aç"
profile: "Profil" profile: "Profil"
timeline: "Pano" timeline: "Pano"
noAccountDescription: "Bu kullanıcı henüz biyografisini yazmamış." noAccountDescription: "Bu kullanıcı henüz biyografisini yazmamış."
login: "Giriş Yap" login: "Oturum Aç"
loggingIn: "Giriş Yapılıyor..." loggingIn: "Giriş Yapılıyor..."
logout: ıkış Yap" logout: ıkış Yap"
signup: "Kaydol" signup: "Kaydol"
@ -310,7 +310,7 @@ agreeBelow: "Aşağıdakileri kabul ediyorum"
basicNotesBeforeCreateAccount: "Önemli notlar" basicNotesBeforeCreateAccount: "Önemli notlar"
termsOfService: "Hizmet Şartları" termsOfService: "Hizmet Şartları"
start: "Başla" start: "Başla"
home: "Ana sayfa" home: "Pano"
remoteUserCaution: "Bu kullanıcı uzak bir sunucudan geldiği için, gösterilen bilgiler eksik olabilir." remoteUserCaution: "Bu kullanıcı uzak bir sunucudan geldiği için, gösterilen bilgiler eksik olabilir."
activity: "Etkinlik" activity: "Etkinlik"
images: "Görseller" images: "Görseller"
@ -1054,6 +1054,7 @@ permissionDeniedError: "İşlem reddedildi"
permissionDeniedErrorDescription: "Bu hesap bu işlemi gerçekleştirmek için gerekli izne sahip değildir." permissionDeniedErrorDescription: "Bu hesap bu işlemi gerçekleştirmek için gerekli izne sahip değildir."
preset: "Ön ayar" preset: "Ön ayar"
selectFromPresets: "Ön ayarlardan seçim yapın" selectFromPresets: "Ön ayarlardan seçim yapın"
custom: "Özel"
achievements: "Başarılar" achievements: "Başarılar"
gotInvalidResponseError: "Geçersiz sunucu yanıtı" gotInvalidResponseError: "Geçersiz sunucu yanıtı"
gotInvalidResponseErrorDescription: "Sunucu erişilemez durumda olabilir veya bakım çalışması yapılmaktadır. Lütfen daha sonra tekrar dene." gotInvalidResponseErrorDescription: "Sunucu erişilemez durumda olabilir veya bakım çalışması yapılmaktadır. Lütfen daha sonra tekrar dene."
@ -1066,8 +1067,8 @@ collapseRenotesDescription: "Zaten yanıtladığın veya renote aldığın notla
internalServerError: "İç Sunucu Hatası" internalServerError: "İç Sunucu Hatası"
internalServerErrorDescription: "Sunucu beklenmedik bir hatayla karşılaştı." internalServerErrorDescription: "Sunucu beklenmedik bir hatayla karşılaştı."
copyErrorInfo: "Hata ayrıntılarını kopyala" copyErrorInfo: "Hata ayrıntılarını kopyala"
joinThisServer: "Bu sunucuda kaydolun" joinThisServer: "Kaydol"
exploreOtherServers: "Başka bir sunucu arayın" exploreOtherServers: "Diğer sunucuları keşfet"
letsLookAtTimeline: "Pano'ya bir göz atın" letsLookAtTimeline: "Pano'ya bir göz atın"
disableFederationConfirm: "Federasyonu cidden devre dışı bırakmak istiyor musun?" disableFederationConfirm: "Federasyonu cidden devre dışı bırakmak istiyor musun?"
disableFederationConfirmWarn: "Federasyondan ayrılsa bile, aksi belirtilmedikçe gönderiler herkese açık olmaya devam edecek. Genellikle bunu yapmanız gerekmez." disableFederationConfirmWarn: "Federasyondan ayrılsa bile, aksi belirtilmedikçe gönderiler herkese açık olmaya devam edecek. Genellikle bunu yapmanız gerekmez."
@ -1244,7 +1245,7 @@ releaseToRefresh: "Yenilemek için serbest bırak"
refreshing: "Yenileniyor..." refreshing: "Yenileniyor..."
pullDownToRefresh: "Yenilemek için aşağı çekin" pullDownToRefresh: "Yenilemek için aşağı çekin"
useGroupedNotifications: "Gruplandırılmış bildirimleri göster" useGroupedNotifications: "Gruplandırılmış bildirimleri göster"
signupPendingError: "E-posta adresini doğrulamada bir sorun oluştu. Bağlantının süresi dolmuş olabilir." emailVerificationFailedError: "E-posta adresi doğrulanırken bir sorun oluştu. Bağlantının geçerlilik süresi dolmuş olabilir."
cwNotationRequired: "“İçeriği gizle” seçeneği etkinleştirilirse, bir açıklama sağlanmalı." cwNotationRequired: "“İçeriği gizle” seçeneği etkinleştirilirse, bir açıklama sağlanmalı."
doReaction: "Tepki ekle" doReaction: "Tepki ekle"
code: "Kod" code: "Kod"
@ -1375,6 +1376,7 @@ safeModeEnabled: "Güvenli mod etkinleştirildi"
pluginsAreDisabledBecauseSafeMode: "Güvenli mod etkinleştirildiği için tüm eklentiler devre dışı bırakılmıştır." pluginsAreDisabledBecauseSafeMode: "Güvenli mod etkinleştirildiği için tüm eklentiler devre dışı bırakılmıştır."
customCssIsDisabledBecauseSafeMode: "Güvenli mod etkin olduğu için özel CSS uygulanmıyor." customCssIsDisabledBecauseSafeMode: "Güvenli mod etkin olduğu için özel CSS uygulanmıyor."
themeIsDefaultBecauseSafeMode: "Güvenli mod etkinken, varsayılan tema kullanılır. Güvenli modu devre dışı bırakmak bu değişiklikleri geri alır." themeIsDefaultBecauseSafeMode: "Güvenli mod etkinken, varsayılan tema kullanılır. Güvenli modu devre dışı bırakmak bu değişiklikleri geri alır."
thankYouForTestingBeta: "Beta sürümünü test ettiğin için teşekkür ederiz!"
_order: _order:
newest: "Önce yeni" newest: "Önce yeni"
oldest: "Önce eski" oldest: "Önce eski"
@ -1623,7 +1625,7 @@ _initialTutorial:
_timelineDescription: _timelineDescription:
home: "Ana Pano'da, takip ettiğin hesapların notlarını görebilirsin." home: "Ana Pano'da, takip ettiğin hesapların notlarını görebilirsin."
local: "Yerel Pano'da, bu sunucudaki tüm kullanıcıların notlarını görebilirsin." local: "Yerel Pano'da, bu sunucudaki tüm kullanıcıların notlarını görebilirsin."
social: "Sosyal Pano, Ana Sayfa ve Yerel Pano'dan gelen notları görüntüler." social: "Pano, Sosyal Pano ve Yerel Pano'dan gelen notları görüntüler."
global: "Global Pano'da, bağlı tüm sunuculardan gelen notları görebilirsin." global: "Global Pano'da, bağlı tüm sunuculardan gelen notları görebilirsin."
_serverRules: _serverRules:
description: "Kayıt öncesinde gösterilecek bir dizi kural. Hizmet Şartlarının özetini belirlemen önerilir." description: "Kayıt öncesinde gösterilecek bir dizi kural. Hizmet Şartlarının özetini belirlemen önerilir."
@ -1664,6 +1666,8 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Sunucu tarafından alınan uzak içerik dahil olmak üzere sunucudaki tüm içeriği koşulsuz olarak İnternet'e yayınlamak risklidir. Bu, içeriğin dağıtılmış yapısından haberdar olmayan misafirler için özellikle önemlidir, çünkü onlar yanlışlıkla uzak içeriğin bile sunucudaki kullanıcılar tarafından oluşturulan içerik olduğunu düşünebilirler." userGeneratedContentsVisibilityForVisitor_description2: "Sunucu tarafından alınan uzak içerik dahil olmak üzere sunucudaki tüm içeriği koşulsuz olarak İnternet'e yayınlamak risklidir. Bu, içeriğin dağıtılmış yapısından haberdar olmayan misafirler için özellikle önemlidir, çünkü onlar yanlışlıkla uzak içeriğin bile sunucudaki kullanıcılar tarafından oluşturulan içerik olduğunu düşünebilirler."
restartServerSetupWizardConfirm_title: "Sunucu kurulum sihirbazını yeniden başlatmak ister misin?" restartServerSetupWizardConfirm_title: "Sunucu kurulum sihirbazını yeniden başlatmak ister misin?"
restartServerSetupWizardConfirm_text: "Bazı mevcut ayarlar sıfırlanacaktır." restartServerSetupWizardConfirm_text: "Bazı mevcut ayarlar sıfırlanacaktır."
entrancePageStyle: "Giriş sayfası stili"
showTimelineForVisitor: "Panoyu göster"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "Her şey halka açıktır." all: "Her şey halka açıktır."
localOnly: "Yalnızca yerel içerik yayınlanır, uzak içerik gizli tutulur." localOnly: "Yalnızca yerel içerik yayınlanır, uzak içerik gizli tutulur."
@ -2273,6 +2277,7 @@ _time:
minute: "Dakika(lar)" minute: "Dakika(lar)"
hour: "Saat(ler)" hour: "Saat(ler)"
day: "Gün(ler)" day: "Gün(ler)"
month: "Ay"
_2fa: _2fa:
alreadyRegistered: "2fa kimlik doğrulama cihazını zaten kaydettin." alreadyRegistered: "2fa kimlik doğrulama cihazını zaten kaydettin."
registerTOTP: "Kimlik doğrulama uygulamasını kaydet" registerTOTP: "Kimlik doğrulama uygulamasını kaydet"
@ -2478,7 +2483,7 @@ _poll:
_visibility: _visibility:
public: "Halka açık" public: "Halka açık"
publicDescription: "Notunuz tüm kullanıcılar tarafından görülebilir olacaktır." publicDescription: "Notunuz tüm kullanıcılar tarafından görülebilir olacaktır."
home: "Ana sayfa" home: "Pano"
homeDescription: "Yalnızca ana zaman çizelgesine gönder" homeDescription: "Yalnızca ana zaman çizelgesine gönder"
followers: "Takipçiler" followers: "Takipçiler"
followersDescription: "Sadece takipçilerine görünür hale getir" followersDescription: "Sadece takipçilerine görünür hale getir"
@ -2554,7 +2559,7 @@ _instanceCharts:
files: "Dosya sayısındaki fark" files: "Dosya sayısındaki fark"
filesTotal: "Toplam dosya sayısı" filesTotal: "Toplam dosya sayısı"
_timelines: _timelines:
home: "Ana Sayfa" home: "Pano"
local: "Yerel" local: "Yerel"
social: "Sosyal" social: "Sosyal"
global: "Global" global: "Global"
@ -2672,7 +2677,7 @@ _notification:
chatRoomInvitationReceived: "Sohbet odasına davet edildi" chatRoomInvitationReceived: "Sohbet odasına davet edildi"
achievementEarned: "Başarı kilidi açıldı" achievementEarned: "Başarı kilidi açıldı"
exportCompleted: "İhracat işlemi tamamlandı." exportCompleted: "İhracat işlemi tamamlandı."
login: "Giriş Yap" login: "Oturum Aç"
createToken: "Erişim jetonu oluştur" createToken: "Erişim jetonu oluştur"
test: "Bildirim testi" test: "Bildirim testi"
app: "Bağlı uygulamalardan gelen bildirimler" app: "Bağlı uygulamalardan gelen bildirimler"
@ -2709,7 +2714,7 @@ _deck:
main: "Ana" main: "Ana"
widgets: "Widget'lar" widgets: "Widget'lar"
notifications: "Bildirimler" notifications: "Bildirimler"
tl: "Ana Sayfa" tl: "Pano"
antenna: "Antenler" antenna: "Antenler"
list: "Liste" list: "Liste"
channel: "Kanal" channel: "Kanal"

View file

@ -1196,7 +1196,6 @@ showAvatarDecorations: "Hiển thị trang trí ảnh đại diện"
releaseToRefresh: "Thả để làm mới" releaseToRefresh: "Thả để làm mới"
refreshing: "Đang làm mới" refreshing: "Đang làm mới"
pullDownToRefresh: "Kéo xuống để làm mới" pullDownToRefresh: "Kéo xuống để làm mới"
signupPendingError: "Đã xảy ra sự cố khi xác minh địa chỉ email của bạn. Liên kết có thể đã hết hạn."
cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích." cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
decorate: "Trang trí" decorate: "Trang trí"
lastNDays: "{n} ngày trước" lastNDays: "{n} ngày trước"

View file

@ -1054,6 +1054,7 @@ permissionDeniedError: "操作被拒绝"
permissionDeniedErrorDescription: "本账户没有执行该操作的权限。" permissionDeniedErrorDescription: "本账户没有执行该操作的权限。"
preset: "预设值" preset: "预设值"
selectFromPresets: "从预设值中选择" selectFromPresets: "从预设值中选择"
custom: "自定义"
achievements: "成就" achievements: "成就"
gotInvalidResponseError: "服务器无应答" gotInvalidResponseError: "服务器无应答"
gotInvalidResponseErrorDescription: "您的网络连接可能出现了问题, 或是远程服务器暂时不可用. 请稍后重试。" gotInvalidResponseErrorDescription: "您的网络连接可能出现了问题, 或是远程服务器暂时不可用. 请稍后重试。"
@ -1244,7 +1245,7 @@ releaseToRefresh: "松开以刷新"
refreshing: "刷新中" refreshing: "刷新中"
pullDownToRefresh: "下拉以刷新" pullDownToRefresh: "下拉以刷新"
useGroupedNotifications: "分组显示通知" useGroupedNotifications: "分组显示通知"
signupPendingError: "确认电子邮件时出现错误。链接可能已过期。" emailVerificationFailedError: "确认电子邮件时出现错误。链接可能已过期。"
cwNotationRequired: "在启用「隐藏内容」时必须输入注释" cwNotationRequired: "在启用「隐藏内容」时必须输入注释"
doReaction: "回应" doReaction: "回应"
code: "代码" code: "代码"
@ -1375,6 +1376,7 @@ safeModeEnabled: "已启用安全模式"
pluginsAreDisabledBecauseSafeMode: "因启用了安全模式,所有插件均已被禁用。" pluginsAreDisabledBecauseSafeMode: "因启用了安全模式,所有插件均已被禁用。"
customCssIsDisabledBecauseSafeMode: "因启用了安全模式,无法应用自定义 CSS。" customCssIsDisabledBecauseSafeMode: "因启用了安全模式,无法应用自定义 CSS。"
themeIsDefaultBecauseSafeMode: "启用安全模式时将使用默认主题。关闭安全模式后将还原。" themeIsDefaultBecauseSafeMode: "启用安全模式时将使用默认主题。关闭安全模式后将还原。"
thankYouForTestingBeta: "感谢您协助测试 beta 版!"
_order: _order:
newest: "从新到旧" newest: "从新到旧"
oldest: "从旧到新" oldest: "从旧到新"
@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "包含服务器接收到的远程内容在内,无条件将服务器上的所有内容公开在互联网上存在风险。特别是对去中心化的特性不是很了解的访问者有可能将远程服务器上的内容误认为是在此服务器内生成的,需要特别留意。" userGeneratedContentsVisibilityForVisitor_description2: "包含服务器接收到的远程内容在内,无条件将服务器上的所有内容公开在互联网上存在风险。特别是对去中心化的特性不是很了解的访问者有可能将远程服务器上的内容误认为是在此服务器内生成的,需要特别留意。"
restartServerSetupWizardConfirm_title: "要重新开始服务器初始设定向导吗?" restartServerSetupWizardConfirm_title: "要重新开始服务器初始设定向导吗?"
restartServerSetupWizardConfirm_text: "现有的部分设定将重置。" restartServerSetupWizardConfirm_text: "现有的部分设定将重置。"
entrancePageStyle: "入口页面样式"
showTimelineForVisitor: "显示时间线"
showActivitiesForVisitor: "显示活动"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "全部公开" all: "全部公开"
localOnly: "仅公开本地内容,隐藏远程内容" localOnly: "仅公开本地内容,隐藏远程内容"
@ -2273,6 +2278,7 @@ _time:
minute: "分" minute: "分"
hour: "小时" hour: "小时"
day: "日" day: "日"
month: "个月"
_2fa: _2fa:
alreadyRegistered: "此设备已被注册" alreadyRegistered: "此设备已被注册"
registerTOTP: "开始设置验证器" registerTOTP: "开始设置验证器"

View file

@ -1054,6 +1054,7 @@ permissionDeniedError: "操作被拒絕"
permissionDeniedErrorDescription: "此帳戶沒有執行這個操作的權限。" permissionDeniedErrorDescription: "此帳戶沒有執行這個操作的權限。"
preset: "預設值" preset: "預設值"
selectFromPresets: "從預設值中選擇" selectFromPresets: "從預設值中選擇"
custom: "自訂"
achievements: "成就" achievements: "成就"
gotInvalidResponseError: "伺服器的回應無效" gotInvalidResponseError: "伺服器的回應無效"
gotInvalidResponseErrorDescription: "伺服器可能已關閉或者在維護中,請稍後再試。" gotInvalidResponseErrorDescription: "伺服器可能已關閉或者在維護中,請稍後再試。"
@ -1244,7 +1245,7 @@ releaseToRefresh: "放開以更新內容"
refreshing: "載入更新中" refreshing: "載入更新中"
pullDownToRefresh: "往下拉來更新內容" pullDownToRefresh: "往下拉來更新內容"
useGroupedNotifications: "分組顯示通知訊息" useGroupedNotifications: "分組顯示通知訊息"
signupPendingError: "驗證您的電子郵件地址時出現問題。連結可能已過期。" emailVerificationFailedError: "驗證您的電子郵件地址時出現問題。連結可能已過期。"
cwNotationRequired: "如果開啟「隱藏內容」,則需要註解說明。" cwNotationRequired: "如果開啟「隱藏內容」,則需要註解說明。"
doReaction: "做出反應" doReaction: "做出反應"
code: "程式碼" code: "程式碼"
@ -1375,6 +1376,7 @@ safeModeEnabled: "啟用安全模式"
pluginsAreDisabledBecauseSafeMode: "由於啟用安全模式,所有的外掛都被停用。" pluginsAreDisabledBecauseSafeMode: "由於啟用安全模式,所有的外掛都被停用。"
customCssIsDisabledBecauseSafeMode: "由於啟用安全模式,所有的客製 CSS 都被停用。" customCssIsDisabledBecauseSafeMode: "由於啟用安全模式,所有的客製 CSS 都被停用。"
themeIsDefaultBecauseSafeMode: "在安全模式啟用期間將使用預設主題。關閉安全模式後會恢復原本的設定。" themeIsDefaultBecauseSafeMode: "在安全模式啟用期間將使用預設主題。關閉安全模式後會恢復原本的設定。"
thankYouForTestingBeta: "感謝您協助驗證 beta 版!"
_order: _order:
newest: "最新的在前" newest: "最新的在前"
oldest: "最舊的在前" oldest: "最舊的在前"
@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "包括伺服器接收到的遠端內容在內,無條件地將伺服器內所有內容公開到網際網路上是具有風險的。特別是對於不了解分散式架構特性的瀏覽者來說,他們可能會誤以為這些遠端內容是由該伺服器所創建的,因此需要特別留意。" userGeneratedContentsVisibilityForVisitor_description2: "包括伺服器接收到的遠端內容在內,無條件地將伺服器內所有內容公開到網際網路上是具有風險的。特別是對於不了解分散式架構特性的瀏覽者來說,他們可能會誤以為這些遠端內容是由該伺服器所創建的,因此需要特別留意。"
restartServerSetupWizardConfirm_title: "要重新執行伺服器的初始設定精靈嗎?" restartServerSetupWizardConfirm_title: "要重新執行伺服器的初始設定精靈嗎?"
restartServerSetupWizardConfirm_text: "當前的部分設定將會被重設。" restartServerSetupWizardConfirm_text: "當前的部分設定將會被重設。"
entrancePageStyle: "入口頁面的樣式"
showTimelineForVisitor: "顯示時間軸"
showActivitiesForVisitor: "顯示活動"
_userGeneratedContentsVisibilityForVisitor: _userGeneratedContentsVisibilityForVisitor:
all: "全部公開\n" all: "全部公開\n"
localOnly: "僅公開本地內容,遠端內容則不公開\n" localOnly: "僅公開本地內容,遠端內容則不公開\n"
@ -2273,6 +2278,7 @@ _time:
minute: "分鐘" minute: "分鐘"
hour: "小時" hour: "小時"
day: "日" day: "日"
month: "個月"
_2fa: _2fa:
alreadyRegistered: "此裝置已被註冊過了" alreadyRegistered: "此裝置已被註冊過了"
registerTOTP: "開始設定驗證應用程式" registerTOTP: "開始設定驗證應用程式"

View file

@ -1,12 +1,12 @@
{ {
"name": "misskey", "name": "misskey",
"version": "2025.8.0-alpha.13", "version": "2025.8.0",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/misskey-dev/misskey.git" "url": "https://github.com/misskey-dev/misskey.git"
}, },
"packageManager": "pnpm@10.14.0", "packageManager": "pnpm@10.15.0",
"workspaces": [ "workspaces": [
"packages/frontend-shared", "packages/frontend-shared",
"packages/frontend", "packages/frontend",
@ -27,6 +27,7 @@
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api", "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
"start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js", "start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
"cli": "cd packages/backend && pnpm cli",
"init": "pnpm migrate", "init": "pnpm migrate",
"migrate": "cd packages/backend && pnpm migrate", "migrate": "cd packages/backend && pnpm migrate",
"revert": "cd packages/backend && pnpm revert", "revert": "cd packages/backend && pnpm revert",
@ -52,8 +53,8 @@
"lodash": "4.17.21" "lodash": "4.17.21"
}, },
"dependencies": { "dependencies": {
"cssnano": "7.1.0", "cssnano": "7.1.1",
"esbuild": "0.25.8", "esbuild": "0.25.9",
"execa": "9.6.0", "execa": "9.6.0",
"fast-glob": "3.3.3", "fast-glob": "3.3.3",
"glob": "11.0.3", "glob": "11.0.3",
@ -66,15 +67,16 @@
}, },
"devDependencies": { "devDependencies": {
"@misskey-dev/eslint-plugin": "2.1.0", "@misskey-dev/eslint-plugin": "2.1.0",
"@types/node": "22.17.1", "@types/js-yaml": "4.0.9",
"@typescript-eslint/eslint-plugin": "8.39.0", "@types/node": "22.17.2",
"@typescript-eslint/parser": "8.39.0", "@typescript-eslint/eslint-plugin": "8.40.0",
"@typescript-eslint/parser": "8.40.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "14.5.4", "cypress": "14.5.4",
"eslint": "9.33.0", "eslint": "9.34.0",
"globals": "16.3.0", "globals": "16.3.0",
"ncp": "2.0.0", "ncp": "2.0.0",
"pnpm": "10.14.0", "pnpm": "10.15.0",
"start-server-and-test": "2.0.13" "start-server-and-test": "2.0.13"
}, },
"optionalDependencies": { "optionalDependencies": {

View file

@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class EntrancePageStyle1755574887486 {
name = 'EntrancePageStyle1755574887486'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "clientOptions" jsonb NOT NULL DEFAULT '{}'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "clientOptions"`);
}
}

View file

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class NonCascadingPageEyeCatching1756062689648 {
name = 'NonCascadingPageEyeCatching1756062689648'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "page" DROP CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa"`);
await queryRunner.query(`ALTER TABLE "page" ADD CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa" FOREIGN KEY ("eyeCatchingImageId") REFERENCES "drive_file"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "page" DROP CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa"`);
await queryRunner.query(`ALTER TABLE "page" ADD CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa" FOREIGN KEY ("eyeCatchingImageId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
}

View file

@ -11,6 +11,7 @@
"start:test": "cross-env NODE_ENV=test node ./built/boot/entry.js", "start:test": "cross-env NODE_ENV=test node ./built/boot/entry.js",
"migrate": "pnpm typeorm migration:run -d ormconfig.js", "migrate": "pnpm typeorm migration:run -d ormconfig.js",
"revert": "pnpm typeorm migration:revert -d ormconfig.js", "revert": "pnpm typeorm migration:revert -d ormconfig.js",
"cli": "node ./built/boot/cli.js",
"check:connect": "node ./scripts/check_connect.js", "check:connect": "node ./scripts/check_connect.js",
"build": "swc src -d built -D --strip-leading-paths", "build": "swc src -d built -D --strip-leading-paths",
"build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc --strip-leading-paths", "build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc --strip-leading-paths",
@ -38,17 +39,17 @@
}, },
"optionalDependencies": { "optionalDependencies": {
"@swc/core-android-arm64": "1.3.11", "@swc/core-android-arm64": "1.3.11",
"@swc/core-darwin-arm64": "1.13.3", "@swc/core-darwin-arm64": "1.13.4",
"@swc/core-darwin-x64": "1.13.3", "@swc/core-darwin-x64": "1.13.4",
"@swc/core-freebsd-x64": "1.3.11", "@swc/core-freebsd-x64": "1.3.11",
"@swc/core-linux-arm-gnueabihf": "1.13.3", "@swc/core-linux-arm-gnueabihf": "1.13.4",
"@swc/core-linux-arm64-gnu": "1.13.3", "@swc/core-linux-arm64-gnu": "1.13.4",
"@swc/core-linux-arm64-musl": "1.13.3", "@swc/core-linux-arm64-musl": "1.13.4",
"@swc/core-linux-x64-gnu": "1.13.3", "@swc/core-linux-x64-gnu": "1.13.4",
"@swc/core-linux-x64-musl": "1.13.3", "@swc/core-linux-x64-musl": "1.13.4",
"@swc/core-win32-arm64-msvc": "1.13.3", "@swc/core-win32-arm64-msvc": "1.13.4",
"@swc/core-win32-ia32-msvc": "1.13.3", "@swc/core-win32-ia32-msvc": "1.13.4",
"@swc/core-win32-x64-msvc": "1.13.3", "@swc/core-win32-x64-msvc": "1.13.4",
"@tensorflow/tfjs": "4.22.0", "@tensorflow/tfjs": "4.22.0",
"@tensorflow/tfjs-node": "4.22.0", "@tensorflow/tfjs-node": "4.22.0",
"bufferutil": "4.0.9", "bufferutil": "4.0.9",
@ -68,8 +69,8 @@
"utf-8-validate": "6.0.5" "utf-8-validate": "6.0.5"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "3.864.0", "@aws-sdk/client-s3": "3.873.0",
"@aws-sdk/lib-storage": "3.864.0", "@aws-sdk/lib-storage": "3.873.0",
"@discordapp/twemoji": "16.0.1", "@discordapp/twemoji": "16.0.1",
"@fastify/accepts": "5.0.2", "@fastify/accepts": "5.0.2",
"@fastify/cookie": "11.0.2", "@fastify/cookie": "11.0.2",
@ -92,7 +93,7 @@
"@sinonjs/fake-timers": "11.3.1", "@sinonjs/fake-timers": "11.3.1",
"@smithy/node-http-handler": "2.5.0", "@smithy/node-http-handler": "2.5.0",
"@swc/cli": "0.7.8", "@swc/cli": "0.7.8",
"@swc/core": "1.13.3", "@swc/core": "1.13.4",
"@twemoji/parser": "16.0.0", "@twemoji/parser": "16.0.0",
"@types/redis-info": "3.0.3", "@types/redis-info": "3.0.3",
"accepts": "1.3.8", "accepts": "1.3.8",
@ -102,10 +103,10 @@
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "2.0.5", "blurhash": "2.0.5",
"body-parser": "1.20.3", "body-parser": "1.20.3",
"bullmq": "5.56.9", "bullmq": "5.58.1",
"cacheable-lookup": "7.0.0", "cacheable-lookup": "7.0.0",
"cbor": "9.0.2", "cbor": "9.0.2",
"chalk": "5.5.0", "chalk": "5.6.0",
"chalk-template": "1.1.0", "chalk-template": "1.1.0",
"chokidar": "4.0.3", "chokidar": "4.0.3",
"cli-highlight": "2.1.11", "cli-highlight": "2.1.11",
@ -113,7 +114,7 @@
"content-disposition": "0.5.4", "content-disposition": "0.5.4",
"date-fns": "2.30.0", "date-fns": "2.30.0",
"deep-email-validator": "0.1.21", "deep-email-validator": "0.1.21",
"fastify": "5.4.0", "fastify": "5.5.0",
"fastify-raw-body": "5.0.0", "fastify-raw-body": "5.0.0",
"feed": "4.2.2", "feed": "4.2.2",
"file-type": "19.6.0", "file-type": "19.6.0",
@ -134,7 +135,7 @@
"jsonld": "8.3.3", "jsonld": "8.3.3",
"jsrsasign": "11.1.0", "jsrsasign": "11.1.0",
"juice": "11.0.1", "juice": "11.0.1",
"meilisearch": "0.51.0", "meilisearch": "0.52.0",
"mfm-js": "0.25.0", "mfm-js": "0.25.0",
"microformats-parser": "2.0.4", "microformats-parser": "2.0.4",
"mime-types": "2.1.35", "mime-types": "2.1.35",
@ -150,7 +151,7 @@
"oauth2orize": "1.12.0", "oauth2orize": "1.12.0",
"oauth2orize-pkce": "0.1.2", "oauth2orize-pkce": "0.1.2",
"os-utils": "0.0.14", "os-utils": "0.0.14",
"otpauth": "9.4.0", "otpauth": "9.4.1",
"parse5": "7.3.0", "parse5": "7.3.0",
"pg": "8.16.3", "pg": "8.16.3",
"pkce-challenge": "4.1.0", "pkce-challenge": "4.1.0",
@ -176,10 +177,10 @@
"stringz": "2.1.0", "stringz": "2.1.0",
"systeminformation": "5.27.7", "systeminformation": "5.27.7",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"tmp": "0.2.3", "tmp": "0.2.5",
"tsc-alias": "1.8.16", "tsc-alias": "1.8.16",
"tsconfig-paths": "4.2.0", "tsconfig-paths": "4.2.0",
"typeorm": "0.3.25", "typeorm": "0.3.26",
"typescript": "5.9.2", "typescript": "5.9.2",
"ulid": "2.4.0", "ulid": "2.4.0",
"vary": "1.1.2", "vary": "1.1.2",
@ -190,7 +191,7 @@
"devDependencies": { "devDependencies": {
"@jest/globals": "29.7.0", "@jest/globals": "29.7.0",
"@nestjs/platform-express": "10.4.20", "@nestjs/platform-express": "10.4.20",
"@sentry/vue": "9.45.0", "@sentry/vue": "9.46.0",
"@simplewebauthn/types": "12.0.0", "@simplewebauthn/types": "12.0.0",
"@swc/jest": "0.2.39", "@swc/jest": "0.2.39",
"@types/accepts": "1.3.7", "@types/accepts": "1.3.7",
@ -209,8 +210,8 @@
"@types/jsrsasign": "10.5.15", "@types/jsrsasign": "10.5.15",
"@types/mime-types": "2.1.4", "@types/mime-types": "2.1.4",
"@types/ms": "0.7.34", "@types/ms": "0.7.34",
"@types/node": "22.17.1", "@types/node": "22.17.2",
"@types/nodemailer": "6.4.17", "@types/nodemailer": "6.4.19",
"@types/oauth": "0.9.6", "@types/oauth": "0.9.6",
"@types/oauth2orize": "1.11.5", "@types/oauth2orize": "1.11.5",
"@types/oauth2orize-pkce": "0.1.2", "@types/oauth2orize-pkce": "0.1.2",
@ -230,8 +231,8 @@
"@types/vary": "1.1.3", "@types/vary": "1.1.3",
"@types/web-push": "3.6.4", "@types/web-push": "3.6.4",
"@types/ws": "8.18.1", "@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.39.0", "@typescript-eslint/eslint-plugin": "8.40.0",
"@typescript-eslint/parser": "8.39.0", "@typescript-eslint/parser": "8.40.0",
"aws-sdk-client-mock": "4.1.0", "aws-sdk-client-mock": "4.1.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint-plugin-import": "2.32.0", "eslint-plugin-import": "2.32.0",

View file

@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import 'reflect-metadata';
import { EventEmitter } from 'node:events';
import { NestFactory } from '@nestjs/core';
import { CommandModule } from '@/cli/CommandModule.js';
import { NestLogger } from '@/NestLogger.js';
import { CommandService } from '@/cli/CommandService.js';
process.title = 'Misskey Cli';
Error.stackTraceLimit = Infinity;
EventEmitter.defaultMaxListeners = 128;
const app = await NestFactory.createApplicationContext(CommandModule, {
logger: new NestLogger(),
});
const commandService = app.get(CommandService);
const command = process.argv[2] ?? 'help';
switch (command) {
case 'help': {
console.log('Available commands:');
console.log(' help - Displays this help message');
console.log(' reset-captcha - Resets the captcha');
break;
}
case 'ping': {
await commandService.ping();
break;
}
case 'reset-captcha': {
await commandService.resetCaptcha();
console.log('Captcha has been reset.');
break;
}
default: {
console.error(`Unrecognized command: ${command}`);
console.error('Use "help" to see available commands.');
process.exit(1);
}
}
process.exit(0);

View file

@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Module } from '@nestjs/common';
import { CoreModule } from '@/core/CoreModule.js';
import { GlobalModule } from '@/GlobalModule.js';
import { CommandService } from './CommandService.js';
@Module({
imports: [
GlobalModule,
CoreModule,
],
providers: [
CommandService,
],
exports: [
CommandService,
],
})
export class CommandModule {}

View file

@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import { MetaService } from '@/core/MetaService.js';
@Injectable()
export class CommandService {
private logger: Logger;
constructor(
@Inject(DI.config)
private config: Config,
private metaService: MetaService,
) {
}
@bindThis
public async ping() {
console.log('pong');
}
@bindThis
public async resetCaptcha() {
await this.metaService.update({
enableHcaptcha: false,
hcaptchaSiteKey: null,
hcaptchaSecretKey: null,
enableMcaptcha: false,
mcaptchaSitekey: null,
mcaptchaSecretKey: null,
mcaptchaInstanceUrl: null,
enableRecaptcha: false,
recaptchaSiteKey: null,
recaptchaSecretKey: null,
enableTurnstile: false,
turnstileSiteKey: null,
turnstileSecretKey: null,
enableTestcaptcha: false,
});
}
}

View file

@ -31,6 +31,7 @@ import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { NotificationService } from '@/core/NotificationService.js'; import { NotificationService } from '@/core/NotificationService.js';
import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common'; import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common';
// misskey-js の rolePolicies と同期すべし
export type RolePolicies = { export type RolePolicies = {
gtlAvailable: boolean; gtlAvailable: boolean;
ltlAvailable: boolean; ltlAvailable: boolean;

View file

@ -244,7 +244,6 @@ export class WebhookTestService {
case 'reaction': case 'reaction':
return; return;
default: { default: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _exhaustiveAssertion: never = params.type; const _exhaustiveAssertion: never = params.type;
return; return;
} }
@ -327,7 +326,6 @@ export class WebhookTestService {
break; break;
} }
default: { default: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _exhaustiveAssertion: never = params.type; const _exhaustiveAssertion: never = params.type;
return; return;
} }
@ -412,7 +410,7 @@ export class WebhookTestService {
name: user.name, name: user.name,
username: user.username, username: user.username,
host: user.host, host: user.host,
avatarUrl: user.avatarId == null ? null : user.avatarUrl, avatarUrl: (user.avatarId == null ? null : user.avatarUrl) ?? '',
avatarBlurhash: user.avatarId == null ? null : user.avatarBlurhash, avatarBlurhash: user.avatarId == null ? null : user.avatarBlurhash,
avatarDecorations: user.avatarDecorations.map(it => ({ avatarDecorations: user.avatarDecorations.map(it => ({
id: it.id, id: it.id,

View file

@ -54,12 +54,13 @@ export class ChatEntityService {
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src }); const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
const reactions: { user: Packed<'UserLite'>; reaction: string; }[] = []; // userは削除されている可能性があるのでnull許容
const reactions: { user: Packed<'UserLite'> | null; reaction: string; }[] = [];
for (const record of message.reactions) { for (const record of message.reactions) {
const [userId, reaction] = record.split('/'); const [userId, reaction] = record.split('/');
reactions.push({ reactions.push({
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId), user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId).catch(() => null),
reaction, reaction,
}); });
} }
@ -76,7 +77,7 @@ export class ChatEntityService {
toRoom: message.toRoomId ? (packedRooms?.get(message.toRoomId) ?? await this.packRoom(message.toRoom ?? message.toRoomId, me)) : undefined, toRoom: message.toRoomId ? (packedRooms?.get(message.toRoomId) ?? await this.packRoom(message.toRoom ?? message.toRoomId, me)) : undefined,
fileId: message.fileId, fileId: message.fileId,
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null, file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
reactions, reactions: reactions.filter((r): r is { user: Packed<'UserLite'>; reaction: string; } => r.user != null),
}; };
} }
@ -108,6 +109,7 @@ export class ChatEntityService {
} }
} }
// TODO: packedUsersに削除されたユーザーもnullとして含める
const [packedUsers, packedFiles, packedRooms] = await Promise.all([ const [packedUsers, packedFiles, packedRooms] = await Promise.all([
this.userEntityService.packMany(users, me) this.userEntityService.packMany(users, me)
.then(users => new Map(users.map(u => [u.id, u]))), .then(users => new Map(users.map(u => [u.id, u]))),
@ -183,12 +185,13 @@ export class ChatEntityService {
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src }); const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
const reactions: { user: Packed<'UserLite'>; reaction: string; }[] = []; // userは削除されている可能性があるのでnull許容
const reactions: { user: Packed<'UserLite'> | null; reaction: string; }[] = [];
for (const record of message.reactions) { for (const record of message.reactions) {
const [userId, reaction] = record.split('/'); const [userId, reaction] = record.split('/');
reactions.push({ reactions.push({
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId), user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId).catch(() => null),
reaction, reaction,
}); });
} }
@ -202,7 +205,7 @@ export class ChatEntityService {
toRoomId: message.toRoomId!, toRoomId: message.toRoomId!,
fileId: message.fileId, fileId: message.fileId,
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null, file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
reactions, reactions: reactions.filter((r): r is { user: Packed<'UserLite'>; reaction: string; } => r.user != null),
}; };
} }

View file

@ -109,6 +109,7 @@ export class MetaEntityService {
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, maxNoteTextLength: MAX_NOTE_TEXT_LENGTH,
defaultLightTheme, defaultLightTheme,
defaultDarkTheme, defaultDarkTheme,
clientOptions: instance.clientOptions,
ads: ads.map(ad => ({ ads: ads.map(ad => ({
id: ad.id, id: ad.id,
url: ad.url, url: ad.url,

View file

@ -49,15 +49,12 @@ export class NoteReactionEntityService implements OnModuleInit {
public async pack( public async pack(
src: MiNoteReaction['id'] | MiNoteReaction, src: MiNoteReaction['id'] | MiNoteReaction,
me?: { id: MiUser['id'] } | null | undefined, me?: { id: MiUser['id'] } | null | undefined,
options?: { options?: object,
withNote: boolean;
},
hints?: { hints?: {
packedUser?: Packed<'UserLite'> packedUser?: Packed<'UserLite'>
}, },
): Promise<Packed<'NoteReaction'>> { ): Promise<Packed<'NoteReaction'>> {
const opts = Object.assign({ const opts = Object.assign({
withNote: false,
}, options); }, options);
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src }); const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
@ -67,9 +64,6 @@ export class NoteReactionEntityService implements OnModuleInit {
createdAt: this.idService.parse(reaction.id).date.toISOString(), createdAt: this.idService.parse(reaction.id).date.toISOString(),
user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me), user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me),
type: this.reactionService.convertLegacyReaction(reaction.reaction), type: this.reactionService.convertLegacyReaction(reaction.reaction),
...(opts.withNote ? {
note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me),
} : {}),
}; };
} }
@ -77,16 +71,50 @@ export class NoteReactionEntityService implements OnModuleInit {
public async packMany( public async packMany(
reactions: MiNoteReaction[], reactions: MiNoteReaction[],
me?: { id: MiUser['id'] } | null | undefined, me?: { id: MiUser['id'] } | null | undefined,
options?: { options?: object,
withNote: boolean;
},
): Promise<Packed<'NoteReaction'>[]> { ): Promise<Packed<'NoteReaction'>[]> {
const opts = Object.assign({ const opts = Object.assign({
withNote: false,
}, options); }, options);
const _users = reactions.map(({ user, userId }) => user ?? userId); const _users = reactions.map(({ user, userId }) => user ?? userId);
const _userMap = await this.userEntityService.packMany(_users, me) const _userMap = await this.userEntityService.packMany(_users, me)
.then(users => new Map(users.map(u => [u.id, u]))); .then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(reactions.map(reaction => this.pack(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) }))); return Promise.all(reactions.map(reaction => this.pack(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) })));
} }
@bindThis
public async packWithNote(
src: MiNoteReaction['id'] | MiNoteReaction,
me?: { id: MiUser['id'] } | null | undefined,
options?: object,
hints?: {
packedUser?: Packed<'UserLite'>
},
): Promise<Packed<'NoteReactionWithNote'>> {
const opts = Object.assign({
}, options);
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
return {
id: reaction.id,
createdAt: this.idService.parse(reaction.id).date.toISOString(),
user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me),
type: this.reactionService.convertLegacyReaction(reaction.reaction),
note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me),
};
}
@bindThis
public async packManyWithNote(
reactions: MiNoteReaction[],
me?: { id: MiUser['id'] } | null | undefined,
options?: object,
): Promise<Packed<'NoteReactionWithNote'>[]> {
const opts = Object.assign({
}, options);
const _users = reactions.map(({ user, userId }) => user ?? userId);
const _userMap = await this.userEntityService.packMany(_users, me)
.then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(reactions.map(reaction => this.packWithNote(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) })));
}
} }

View file

@ -471,8 +471,8 @@ export class UserEntityService implements OnModuleInit {
(profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : (profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount :
null; null;
const isModerator = isMe && isDetailed ? this.roleService.isModerator(user) : null; const isModerator = isMe && isDetailed ? this.roleService.isModerator(user) : undefined;
const isAdmin = isMe && isDetailed ? this.roleService.isAdministrator(user) : null; const isAdmin = isMe && isDetailed ? this.roleService.isAdministrator(user) : undefined;
const unreadAnnouncements = isMe && isDetailed ? const unreadAnnouncements = isMe && isDetailed ?
(await this.announcementService.getUnreadAnnouncements(user)).map((announcement) => ({ (await this.announcementService.getUnreadAnnouncements(user)).map((announcement) => ({
createdAt: this.idService.parse(announcement.id).date.toISOString(), createdAt: this.idService.parse(announcement.id).date.toISOString(),
@ -481,6 +481,7 @@ export class UserEntityService implements OnModuleInit {
const notificationsInfo = isMe && isDetailed ? await this.getNotificationsInfo(user.id) : null; const notificationsInfo = isMe && isDetailed ? await this.getNotificationsInfo(user.id) : null;
// TODO: 例えば avatarUrl: true など間違った型を設定しても型エラーにならないのをどうにかする(ジェネリクス使わない方法で実装するしかなさそう?)
const packed = { const packed = {
id: user.id, id: user.id,
name: user.name, name: user.name,

View file

@ -22,7 +22,7 @@ import { packedFollowingSchema } from '@/models/json-schema/following.js';
import { packedMutingSchema } from '@/models/json-schema/muting.js'; import { packedMutingSchema } from '@/models/json-schema/muting.js';
import { packedRenoteMutingSchema } from '@/models/json-schema/renote-muting.js'; import { packedRenoteMutingSchema } from '@/models/json-schema/renote-muting.js';
import { packedBlockingSchema } from '@/models/json-schema/blocking.js'; import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js'; import { packedNoteReactionSchema, packedNoteReactionWithNoteSchema } from '@/models/json-schema/note-reaction.js';
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js'; import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js'; import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js';
import { packedPageBlockSchema, packedPageSchema } from '@/models/json-schema/page.js'; import { packedPageBlockSchema, packedPageSchema } from '@/models/json-schema/page.js';
@ -65,6 +65,7 @@ import {
packedMetaDetailedSchema, packedMetaDetailedSchema,
packedMetaLiteSchema, packedMetaLiteSchema,
} from '@/models/json-schema/meta.js'; } from '@/models/json-schema/meta.js';
import { packedUserWebhookSchema } from '@/models/json-schema/user-webhook.js';
import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js'; import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js'; import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessageLiteForRoomSchema, packedChatMessageLiteFor1on1Schema } from '@/models/json-schema/chat-message.js'; import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessageLiteForRoomSchema, packedChatMessageLiteFor1on1Schema } from '@/models/json-schema/chat-message.js';
@ -92,6 +93,7 @@ export const refs = {
Note: packedNoteSchema, Note: packedNoteSchema,
NoteDraft: packedNoteDraftSchema, NoteDraft: packedNoteDraftSchema,
NoteReaction: packedNoteReactionSchema, NoteReaction: packedNoteReactionSchema,
NoteReactionWithNote: packedNoteReactionWithNoteSchema,
NoteFavorite: packedNoteFavoriteSchema, NoteFavorite: packedNoteFavoriteSchema,
Notification: packedNotificationSchema, Notification: packedNotificationSchema,
DriveFile: packedDriveFileSchema, DriveFile: packedDriveFileSchema,
@ -133,6 +135,7 @@ export const refs = {
MetaLite: packedMetaLiteSchema, MetaLite: packedMetaLiteSchema,
MetaDetailedOnly: packedMetaDetailedOnlySchema, MetaDetailedOnly: packedMetaDetailedOnlySchema,
MetaDetailed: packedMetaDetailedSchema, MetaDetailed: packedMetaDetailedSchema,
UserWebhook: packedUserWebhookSchema,
SystemWebhook: packedSystemWebhookSchema, SystemWebhook: packedSystemWebhookSchema,
AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema, AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
ChatMessage: packedChatMessageSchema, ChatMessage: packedChatMessageSchema,

View file

@ -716,6 +716,11 @@ export class MiMeta {
default: 90, // days default: 90, // days
}) })
public remoteNotesCleaningExpiryDaysForEachNotes: number; public remoteNotesCleaningExpiryDaysForEachNotes: number;
@Column('jsonb', {
default: { },
})
public clientOptions: Record<string, any>;
} }
export type SoftwareSuspension = { export type SoftwareSuspension = {

View file

@ -10,6 +10,7 @@ import { MiAccessToken } from './AccessToken.js';
import { MiRole } from './Role.js'; import { MiRole } from './Role.js';
import { MiDriveFile } from './DriveFile.js'; import { MiDriveFile } from './DriveFile.js';
// misskey-js の notificationTypes と同期すべし
export type MiNotification = { export type MiNotification = {
type: 'note'; type: 'note';
id: string; id: string;

View file

@ -69,7 +69,7 @@ export class MiPage {
public eyeCatchingImageId: MiDriveFile['id'] | null; public eyeCatchingImageId: MiDriveFile['id'] | null;
@ManyToOne(type => MiDriveFile, { @ManyToOne(type => MiDriveFile, {
onDelete: 'CASCADE', onDelete: 'SET NULL',
}) })
@JoinColumn() @JoinColumn()
public eyeCatchingImage: MiDriveFile | null; public eyeCatchingImage: MiDriveFile | null;

View file

@ -71,6 +71,10 @@ export const packedMetaLiteSchema = {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
}, },
clientOptions: {
type: 'object',
optional: false, nullable: false,
},
disableRegistration: { disableRegistration: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,

View file

@ -10,7 +10,6 @@ export const packedNoteReactionSchema = {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
format: 'id', format: 'id',
example: 'xxxxxxxxxx',
}, },
createdAt: { createdAt: {
type: 'string', type: 'string',
@ -28,3 +27,33 @@ export const packedNoteReactionSchema = {
}, },
}, },
} as const; } as const;
export const packedNoteReactionWithNoteSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
user: {
type: 'object',
optional: false, nullable: false,
ref: 'UserLite',
},
type: {
type: 'string',
optional: false, nullable: false,
},
note: {
type: 'object',
optional: false, nullable: false,
ref: 'Note',
},
},
} as const;

View file

@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { webhookEventTypes } from '@/models/Webhook.js';
export const packedUserWebhookSchema = {
type: 'object',
properties: {
id: {
type: 'string',
format: 'id',
optional: false, nullable: false,
},
userId: {
type: 'string',
format: 'id',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
},
on: {
type: 'array',
items: {
type: 'string',
optional: false, nullable: false,
enum: webhookEventTypes,
},
},
url: {
type: 'string',
optional: false, nullable: false,
},
secret: {
type: 'string',
optional: false, nullable: false,
},
active: {
type: 'boolean',
optional: false, nullable: false,
},
latestSentAt: {
type: 'string',
format: 'date-time',
optional: false, nullable: true,
},
latestStatus: {
type: 'integer',
optional: false, nullable: true,
},
},
} as const;

View file

@ -65,7 +65,7 @@ export const packedUserLiteSchema = {
avatarUrl: { avatarUrl: {
type: 'string', type: 'string',
format: 'url', format: 'url',
nullable: true, optional: false, nullable: false, optional: false,
}, },
avatarBlurhash: { avatarBlurhash: {
type: 'string', type: 'string',
@ -465,11 +465,11 @@ export const packedMeDetailedOnlySchema = {
}, },
isModerator: { isModerator: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: false, optional: false,
}, },
isAdmin: { isAdmin: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: false, optional: false,
}, },
injectFeaturedNote: { injectFeaturedNote: {
type: 'boolean', type: 'boolean',
@ -591,7 +591,7 @@ export const packedMeDetailedOnlySchema = {
}, },
mutedInstances: { mutedInstances: {
type: 'array', type: 'array',
nullable: true, optional: false, nullable: false, optional: false,
items: { items: {
type: 'string', type: 'string',
nullable: false, optional: false, nullable: false, optional: false,

View file

@ -238,30 +238,6 @@ export class ServerService implements OnApplicationShutdown {
} }
}); });
fastify.get<{ Params: { code: string } }>('/verify-email/:code', async (request, reply) => {
const profile = await this.userProfilesRepository.findOneBy({
emailVerifyCode: request.params.code,
});
if (profile != null) {
await this.userProfilesRepository.update({ userId: profile.userId }, {
emailVerified: true,
emailVerifyCode: null,
});
this.globalEventService.publishMainStream(profile.userId, 'meUpdated', await this.userEntityService.pack(profile.userId, { id: profile.userId }, {
schema: 'MeDetailed',
includeSecrets: true,
}));
reply.code(200).send('Verification succeeded! メールアドレスの認証に成功しました。');
return;
} else {
reply.code(404).send('Verification failed. Please try again. メールアドレスの認証に失敗しました。もう一度お試しください');
return;
}
});
fastify.register(this.clientServerService.createServer); fastify.register(this.clientServerService.createServer);
this.streamingApiServerService.attach(fastify.server); this.streamingApiServerService.attach(fastify.server);

View file

@ -412,6 +412,7 @@ export * as 'users/search' from './endpoints/users/search.js';
export * as 'users/search-by-username-and-host' from './endpoints/users/search-by-username-and-host.js'; export * as 'users/search-by-username-and-host' from './endpoints/users/search-by-username-and-host.js';
export * as 'users/show' from './endpoints/users/show.js'; export * as 'users/show' from './endpoints/users/show.js';
export * as 'users/update-memo' from './endpoints/users/update-memo.js'; export * as 'users/update-memo' from './endpoints/users/update-memo.js';
export * as 'verify-email' from './endpoints/verify-email.js';
export * as 'chat/messages/create-to-user' from './endpoints/chat/messages/create-to-user.js'; export * as 'chat/messages/create-to-user' from './endpoints/chat/messages/create-to-user.js';
export * as 'chat/messages/create-to-room' from './endpoints/chat/messages/create-to-room.js'; export * as 'chat/messages/create-to-room' from './endpoints/chat/messages/create-to-room.js';
export * as 'chat/messages/delete' from './endpoints/chat/messages/delete.js'; export * as 'chat/messages/delete' from './endpoints/chat/messages/delete.js';

View file

@ -49,6 +49,34 @@ export const meta = {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
}, },
icon: {
type: 'string',
optional: false, nullable: true,
},
display: {
type: 'string',
optional: false, nullable: false,
},
isActive: {
type: 'boolean',
optional: false, nullable: false,
},
forExistingUsers: {
type: 'boolean',
optional: false, nullable: false,
},
silence: {
type: 'boolean',
optional: false, nullable: false,
},
needConfirmationToRead: {
type: 'boolean',
optional: false, nullable: false,
},
userId: {
type: 'string',
optional: false, nullable: true,
},
imageUrl: { imageUrl: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,

View file

@ -157,6 +157,22 @@ export const meta = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
maybeSensitive: {
type: 'boolean',
optional: false, nullable: false,
},
maybePorn: {
type: 'boolean',
optional: false, nullable: false,
},
requestIp: {
type: 'string',
optional: false, nullable: true,
},
requestHeaders: {
type: 'object',
optional: false, nullable: true,
},
}, },
}, },
} as const; } as const;

View file

@ -223,10 +223,12 @@ export const meta = {
sensitiveMediaDetection: { sensitiveMediaDetection: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
enum: ['none', 'all', 'local', 'remote'],
}, },
sensitiveMediaDetectionSensitivity: { sensitiveMediaDetectionSensitivity: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'],
}, },
setSensitiveFlagAutomatically: { setSensitiveFlagAutomatically: {
type: 'boolean', type: 'boolean',
@ -425,6 +427,10 @@ export const meta = {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
}, },
clientOptions: {
type: 'object',
optional: false, nullable: false,
},
description: { description: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
@ -469,6 +475,10 @@ export const meta = {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
}, },
feedbackUrl: {
type: 'string',
optional: false, nullable: true,
},
summalyProxy: { summalyProxy: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
@ -650,6 +660,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
logoImageUrl: instance.logoImageUrl, logoImageUrl: instance.logoImageUrl,
defaultLightTheme: instance.defaultLightTheme, defaultLightTheme: instance.defaultLightTheme,
defaultDarkTheme: instance.defaultDarkTheme, defaultDarkTheme: instance.defaultDarkTheme,
clientOptions: instance.clientOptions,
enableEmail: instance.enableEmail, enableEmail: instance.enableEmail,
enableServiceWorker: instance.enableServiceWorker, enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null, translatorAvailable: instance.deeplAuthKey != null,

View file

@ -67,6 +67,7 @@ export const paramDef = {
description: { type: 'string', nullable: true }, description: { type: 'string', nullable: true },
defaultLightTheme: { type: 'string', nullable: true }, defaultLightTheme: { type: 'string', nullable: true },
defaultDarkTheme: { type: 'string', nullable: true }, defaultDarkTheme: { type: 'string', nullable: true },
clientOptions: { type: 'object', nullable: false },
cacheRemoteFiles: { type: 'boolean' }, cacheRemoteFiles: { type: 'boolean' },
cacheRemoteSensitiveFiles: { type: 'boolean' }, cacheRemoteSensitiveFiles: { type: 'boolean' },
emailRequiredForSignup: { type: 'boolean' }, emailRequiredForSignup: { type: 'boolean' },
@ -326,6 +327,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.defaultDarkTheme = ps.defaultDarkTheme; set.defaultDarkTheme = ps.defaultDarkTheme;
} }
if (ps.clientOptions !== undefined) {
set.clientOptions = ps.clientOptions;
}
if (ps.cacheRemoteFiles !== undefined) { if (ps.cacheRemoteFiles !== undefined) {
set.cacheRemoteFiles = ps.cacheRemoteFiles; set.cacheRemoteFiles = ps.cacheRemoteFiles;
} }

View file

@ -5,6 +5,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js';
import type { ClipsRepository } from '@/models/_.js'; import type { ClipsRepository } from '@/models/_.js';
import { ClipEntityService } from '@/core/entities/ClipEntityService.js'; import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -29,7 +30,13 @@ export const meta = {
export const paramDef = { export const paramDef = {
type: 'object', type: 'object',
properties: {}, properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
},
required: [], required: [],
} as const; } as const;
@ -39,12 +46,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.clipsRepository) @Inject(DI.clipsRepository)
private clipsRepository: ClipsRepository, private clipsRepository: ClipsRepository,
private queryService: QueryService,
private clipEntityService: ClipEntityService, private clipEntityService: ClipEntityService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const clips = await this.clipsRepository.findBy({ const query = this.queryService.makePaginationQuery(this.clipsRepository.createQueryBuilder('clip'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
userId: me.id, .andWhere('clip.userId = :userId', { userId: me.id });
});
const clips = await query.limit(ps.limit).getMany();
return await this.clipEntityService.packMany(clips, me); return await this.clipEntityService.packMany(clips, me);
}); });

View file

@ -73,8 +73,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
updatedAt: new Date(), updatedAt: new Date(),
...Object.fromEntries( ...Object.fromEntries(
Object.entries(ps).filter( Object.entries(ps).filter(
([key, val]) => (key !== 'flashId') && Object.hasOwn(paramDef.properties, key) ([key, val]) => (key !== 'flashId') && Object.hasOwn(paramDef.properties, key),
) ),
), ),
}); });
}); });

View file

@ -46,6 +46,14 @@ export const meta = {
type: 'string', type: 'string',
}, },
}, },
iconUrl: {
type: 'string',
optional: true, nullable: true,
},
description: {
type: 'string',
optional: true, nullable: true,
},
}, },
}, },
}, },
@ -88,6 +96,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
createdAt: this.idService.parse(token.id).date.toISOString(), createdAt: this.idService.parse(token.id).date.toISOString(),
lastUsedAt: token.lastUsedAt?.toISOString(), lastUsedAt: token.lastUsedAt?.toISOString(),
permission: token.app ? token.app.permission : token.permission, permission: token.app ? token.app.permission : token.permission,
iconUrl: token.iconUrl,
description: token.description ?? token.app?.description ?? null,
}))); })));
}); });
} }

View file

@ -21,29 +21,7 @@ export const meta = {
type: 'array', type: 'array',
items: { items: {
type: 'object', type: 'object',
properties: { ref: 'UserWebhook',
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; } as const;
@ -65,19 +43,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
userId: me.id, userId: me.id,
}); });
return webhooks.map(webhook => ( return webhooks.map(webhook => ({
{ id: webhook.id,
id: webhook.id, userId: webhook.userId,
userId: webhook.userId, name: webhook.name,
name: webhook.name, on: webhook.on,
on: webhook.on, url: webhook.url,
url: webhook.url, secret: webhook.secret,
secret: webhook.secret, active: webhook.active,
active: webhook.active, latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null,
latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null, latestStatus: webhook.latestStatus,
latestStatus: webhook.latestStatus, }));
}
));
}); });
} }
} }

View file

@ -28,29 +28,7 @@ export const meta = {
res: { res: {
type: 'object', type: 'object',
properties: { ref: 'UserWebhook',
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; } as const;

View file

@ -91,6 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
qb.orWhere(new Brackets(qb => { qb.orWhere(new Brackets(qb => {
qb.where('note.text IS NOT NULL'); qb.where('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\''); qb.orWhere('note.fileIds != \'{}\'');
qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
})); }));
})); }));
} }

View file

@ -66,7 +66,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.orWhere(':meIdAsList <@ note.visibleUserIds'); .orWhere(':meIdAsList <@ note.visibleUserIds');
})) }))
// Avoid scanning primary key index // Avoid scanning primary key index
.orderBy('CONCAT(note.id)', 'DESC') .orderBy('CONCAT(note.id)', (ps.sinceDate || ps.sinceId) ? 'ASC' : 'DESC')
.innerJoinAndSelect('note.user', 'user') .innerJoinAndSelect('note.user', 'user')
.leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.reply', 'reply')
.leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('note.renote', 'renote')

View file

@ -242,6 +242,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
qb.orWhere(new Brackets(qb => { qb.orWhere(new Brackets(qb => {
qb.orWhere('note.text IS NOT NULL'); qb.orWhere('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\''); qb.orWhere('note.fileIds != \'{}\'');
qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
})); }));
})); }));
} }

View file

@ -223,6 +223,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
qb.orWhere(new Brackets(qb => { qb.orWhere(new Brackets(qb => {
qb.orWhere('note.text IS NOT NULL'); qb.orWhere('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\''); qb.orWhere('note.fileIds != \'{}\'');
qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
})); }));
})); }));
} }

View file

@ -23,6 +23,16 @@ export const meta = {
type: 'object', type: 'object',
optional: false, nullable: false, optional: false, nullable: false,
ref: 'UserList', ref: 'UserList',
properties: {
likedCount: {
type: 'number',
optional: true, nullable: false,
},
isLiked: {
type: 'boolean',
optional: true, nullable: false,
},
},
}, },
errors: { errors: {

View file

@ -28,7 +28,7 @@ export const meta = {
items: { items: {
type: 'object', type: 'object',
optional: false, nullable: false, optional: false, nullable: false,
ref: 'NoteReaction', ref: 'NoteReactionWithNote',
}, },
}, },
@ -120,7 +120,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
return true; return true;
}); });
return await this.noteReactionEntityService.packMany(reactions, me, { withNote: true }); return await this.noteReactionEntityService.packManyWithNote(reactions, me);
}); });
} }
} }

View file

@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UserProfilesRepository } from '@/models/_.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DI } from '@/di-symbols.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { ApiError } from '../error.js';
export const meta = {
requireCredential: false,
tags: ['account'],
errors: {
noSuchCode: {
message: 'No such code.',
code: 'NO_SUCH_CODE',
id: '97c1f576-e4b8-4b8a-a6dc-9cb65e7f6f85',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
code: { type: 'string' },
},
required: ['code'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
private userEntityService: UserEntityService,
private globalEventService: GlobalEventService,
) {
super(meta, paramDef, async (ps) => {
const profile = await this.userProfilesRepository.findOneBy({
emailVerifyCode: ps.code,
});
if (profile == null) {
throw new ApiError(meta.errors.noSuchCode);
}
await this.userProfilesRepository.update({ userId: profile.userId }, {
emailVerified: true,
emailVerifyCode: null,
});
this.globalEventService.publishMainStream(profile.userId, 'meUpdated', await this.userEntityService.pack(profile.userId, { id: profile.userId }, {
schema: 'MeDetailed',
includeSecrets: true,
}));
});
}
}

View file

@ -363,14 +363,11 @@ describe('クリップ', () => {
const clipLimit = DEFAULT_POLICIES.clipLimit; const clipLimit = DEFAULT_POLICIES.clipLimit;
const clips = await createMany({}, clipLimit); const clips = await createMany({}, clipLimit);
const res = await list({ const res = await list({
parameters: { limit: 1 }, // FIXME: 無視されて11全部返ってくる parameters: { limit: clips.length },
}); });
// 返ってくる配列には順序保障がないのでidでソートして厳密比較 // 作成responseの配列には順序保障がないのでidでソートして厳密比較
assert.deepStrictEqual( assert.deepStrictEqual(res.toReversed(), clips.sort(compareBy(s => s.id)));
res.sort(compareBy(s => s.id)),
clips.sort(compareBy(s => s.id)),
);
}); });
test('の一覧が取得できる(空)', async () => { test('の一覧が取得できる(空)', async () => {

View file

@ -16,7 +16,7 @@
"@rollup/pluginutils": "5.2.0", "@rollup/pluginutils": "5.2.0",
"@twemoji/parser": "16.0.0", "@twemoji/parser": "16.0.0",
"@vitejs/plugin-vue": "6.0.1", "@vitejs/plugin-vue": "6.0.1",
"@vue/compiler-sfc": "3.5.18", "@vue/compiler-sfc": "3.5.19",
"astring": "1.9.0", "astring": "1.9.0",
"buraha": "0.0.1", "buraha": "0.0.1",
"estree-walker": "3.0.3", "estree-walker": "3.0.3",
@ -26,16 +26,16 @@
"mfm-js": "0.25.0", "mfm-js": "0.25.0",
"misskey-js": "workspace:*", "misskey-js": "workspace:*",
"punycode.js": "2.3.1", "punycode.js": "2.3.1",
"rollup": "4.46.2", "rollup": "4.48.0",
"sass": "1.89.2", "sass": "1.90.0",
"shiki": "3.9.1", "shiki": "3.11.0",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"tsc-alias": "1.8.16", "tsc-alias": "1.8.16",
"tsconfig-paths": "4.2.0", "tsconfig-paths": "4.2.0",
"typescript": "5.9.2", "typescript": "5.9.2",
"uuid": "11.1.0", "uuid": "11.1.0",
"vite": "7.0.6", "vite": "7.1.3",
"vue": "3.5.18" "vue": "3.5.19"
}, },
"devDependencies": { "devDependencies": {
"@misskey-dev/summaly": "5.2.3", "@misskey-dev/summaly": "5.2.3",
@ -43,14 +43,14 @@
"@testing-library/vue": "8.1.0", "@testing-library/vue": "8.1.0",
"@types/estree": "1.0.8", "@types/estree": "1.0.8",
"@types/micromatch": "4.0.9", "@types/micromatch": "4.0.9",
"@types/node": "22.17.0", "@types/node": "22.17.2",
"@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/punycode.js": "npm:@types/punycode@2.1.4",
"@types/tinycolor2": "1.4.6", "@types/tinycolor2": "1.4.6",
"@types/ws": "8.18.1", "@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.38.0", "@typescript-eslint/eslint-plugin": "8.40.0",
"@typescript-eslint/parser": "8.38.0", "@typescript-eslint/parser": "8.40.0",
"@vitest/coverage-v8": "3.2.4", "@vitest/coverage-v8": "3.2.4",
"@vue/runtime-core": "3.5.18", "@vue/runtime-core": "3.5.19",
"acorn": "8.15.0", "acorn": "8.15.0",
"cross-env": "10.0.0", "cross-env": "10.0.0",
"eslint-plugin-import": "2.32.0", "eslint-plugin-import": "2.32.0",
@ -59,14 +59,14 @@
"happy-dom": "18.0.1", "happy-dom": "18.0.1",
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"micromatch": "4.0.8", "micromatch": "4.0.8",
"msw": "2.10.4", "msw": "2.10.5",
"nodemon": "3.1.10", "nodemon": "3.1.10",
"prettier": "3.6.2", "prettier": "3.6.2",
"start-server-and-test": "2.0.12", "start-server-and-test": "2.0.13",
"tsx": "4.20.3", "tsx": "4.20.4",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vue-component-type-helpers": "3.0.5", "vue-component-type-helpers": "3.0.6",
"vue-eslint-parser": "10.2.0", "vue-eslint-parser": "10.2.0",
"vue-tsc": "3.0.5" "vue-tsc": "3.0.6"
} }
} }

View file

@ -3,6 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
// TODO: (可能な部分を)sharedに抽出して frontend と共通化
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import lightTheme from '@@/themes/_light.json5'; import lightTheme from '@@/themes/_light.json5';
import darkTheme from '@@/themes/_dark.json5'; import darkTheme from '@@/themes/_dark.json5';

View file

@ -54,67 +54,6 @@ https://github.com/sindresorhus/file-type/blob/main/core.js
https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers
*/ */
export const notificationTypes = [
'note',
'follow',
'mention',
'reply',
'renote',
'quote',
'reaction',
'pollEnded',
'receiveFollowRequest',
'followRequestAccepted',
'roleAssigned',
'chatRoomInvitationReceived',
'achievementEarned',
'exportCompleted',
'login',
'createToken',
'test',
'app',
] as const;
export const obsoleteNotificationTypes = ['pollVote', 'groupInvited'] as const;
export const ROLE_POLICIES = [
'gtlAvailable',
'ltlAvailable',
'canPublicNote',
'mentionLimit',
'canInvite',
'inviteLimit',
'inviteLimitCycle',
'inviteExpirationTime',
'canManageCustomEmojis',
'canManageAvatarDecorations',
'canSearchNotes',
'canUseTranslator',
'canHideAds',
'driveCapacityMb',
'maxFileSizeMb',
'alwaysMarkNsfw',
'canUpdateBioMedia',
'pinLimit',
'antennaLimit',
'wordMuteLimit',
'webhookLimit',
'clipLimit',
'noteEachClipsLimit',
'userListLimit',
'userEachUserListsLimit',
'rateLimitFactor',
'avatarDecorationLimit',
'canImportAntennas',
'canImportBlocking',
'canImportFollowing',
'canImportMuting',
'canImportUserLists',
'chatAvailability',
'uploadableFileTypes',
'noteDraftLimit',
'watermarkAvailable',
] as const;
export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'border', 'font', 'blur', 'rainbow', 'sparkle', 'rotate', 'ruby', 'unixtime']; export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'border', 'font', 'blur', 'rainbow', 'sparkle', 'rotate', 'ruby', 'unixtime'];
export const MFM_PARAMS: Record<typeof MFM_TAGS[number], string[]> = { export const MFM_PARAMS: Record<typeof MFM_TAGS[number], string[]> = {
tada: ['speed=', 'delay='], tada: ['speed=', 'delay='],

View file

@ -21,10 +21,10 @@
"lint": "pnpm typecheck && pnpm eslint" "lint": "pnpm typecheck && pnpm eslint"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "22.17.0", "@types/node": "22.17.2",
"@typescript-eslint/eslint-plugin": "8.38.0", "@typescript-eslint/eslint-plugin": "8.40.0",
"@typescript-eslint/parser": "8.38.0", "@typescript-eslint/parser": "8.40.0",
"esbuild": "0.25.8", "esbuild": "0.25.9",
"eslint-plugin-vue": "10.4.0", "eslint-plugin-vue": "10.4.0",
"nodemon": "3.1.10", "nodemon": "3.1.10",
"typescript": "5.9.2", "typescript": "5.9.2",
@ -35,6 +35,6 @@
], ],
"dependencies": { "dependencies": {
"misskey-js": "workspace:*", "misskey-js": "workspace:*",
"vue": "3.5.18" "vue": "3.5.19"
} }
} }

View file

@ -6,7 +6,7 @@
import { HttpResponse, http } from 'msw'; import { HttpResponse, http } from 'msw';
import type { DefaultBodyType, HttpResponseResolver, JsonBodyType, PathParams } from 'msw'; import type { DefaultBodyType, HttpResponseResolver, JsonBodyType, PathParams } from 'msw';
import seedrandom from 'seedrandom'; import seedrandom from 'seedrandom';
import { action } from '@storybook/addon-actions'; import { action } from 'storybook/actions';
function getChartArray(seed: string, limit: number, option?: { accumulate?: boolean, mul?: number }): number[] { function getChartArray(seed: string, limit: number, option?: { accumulate?: boolean, mul?: number }): number[] {
const rng = seedrandom(seed); const rng = seedrandom(seed);

View file

@ -127,7 +127,7 @@ export function galleryPost(isSensitive = false) {
} }
} }
export function file(isSensitive = false) { export function file(isSensitive = false): entities.DriveFile {
return { return {
id: 'somefileid', id: 'somefileid',
createdAt: '2016-12-28T22:49:51.000Z', createdAt: '2016-12-28T22:49:51.000Z',
@ -207,6 +207,7 @@ export function federationInstance(): entities.FederationInstance {
isSuspended: false, isSuspended: false,
suspensionState: 'none', suspensionState: 'none',
isBlocked: false, isBlocked: false,
isMediaSilenced: false,
softwareName: 'misskey', softwareName: 'misskey',
softwareVersion: '2024.5.0', softwareVersion: '2024.5.0',
openRegistrations: false, openRegistrations: false,
@ -311,6 +312,8 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host: enti
alsoKnownAs: null, alsoKnownAs: null,
notify: 'none', notify: 'none',
memo: null, memo: null,
canChat: true,
chatScope: 'everyone',
}; };
} }
@ -378,6 +381,7 @@ export function role(params: {
asBadge: params.asBadge ?? true, asBadge: params.asBadge ?? true,
canEditMembersByModerator: params.canEditMembersByModerator ?? false, canEditMembersByModerator: params.canEditMembersByModerator ?? false,
usersCount: params.usersCount ?? 10, usersCount: params.usersCount ?? 10,
preserveAssignmentOnMoveAccount: false,
condFormula: { condFormula: {
id: '', id: '',
type: 'or', type: 'or',

View file

@ -42,7 +42,7 @@
"prefix": "storyimplevent", "prefix": "storyimplevent",
"body": [ "body": [
"/* eslint-disable @typescript-eslint/explicit-function-return-type */", "/* eslint-disable @typescript-eslint/explicit-function-return-type */",
"import { action } from '@storybook/addon-actions';", "import { action } from 'storybook/actions';",
"import { StoryObj } from '@storybook/vue3';", "import { StoryObj } from '@storybook/vue3';",
"import $1 from './$1.vue';", "import $1 from './$1.vue';",
"export const Default = {", "export const Default = {",

View file

@ -8,7 +8,7 @@
import { parse as vueSfcParse } from 'vue/compiler-sfc'; import { parse as vueSfcParse } from 'vue/compiler-sfc';
import { import {
createLogger, createLogger,
EnvironmentModuleGraph, type EnvironmentModuleGraph,
type LogErrorOptions, type LogErrorOptions,
type LogOptions, type LogOptions,
normalizePath, normalizePath,

View file

@ -24,14 +24,14 @@
"@rollup/plugin-json": "6.1.0", "@rollup/plugin-json": "6.1.0",
"@rollup/plugin-replace": "6.0.2", "@rollup/plugin-replace": "6.0.2",
"@rollup/pluginutils": "5.2.0", "@rollup/pluginutils": "5.2.0",
"@sentry/vue": "10.0.0", "@sentry/vue": "10.5.0",
"@syuilo/aiscript": "1.1.0", "@syuilo/aiscript": "1.1.0",
"@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0", "@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0",
"@twemoji/parser": "16.0.0", "@twemoji/parser": "16.0.0",
"@vitejs/plugin-vue": "6.0.1", "@vitejs/plugin-vue": "6.0.1",
"@vue/compiler-sfc": "3.5.18", "@vue/compiler-sfc": "3.5.19",
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15", "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15",
"analytics": "0.8.16", "analytics": "0.8.19",
"astring": "1.9.0", "astring": "1.9.0",
"broadcast-channel": "7.1.0", "broadcast-channel": "7.1.0",
"buraha": "0.0.1", "buraha": "0.0.1",
@ -52,9 +52,10 @@
"icons-subsetter": "workspace:*", "icons-subsetter": "workspace:*",
"idb-keyval": "6.2.2", "idb-keyval": "6.2.2",
"insert-text-at-cursor": "0.3.0", "insert-text-at-cursor": "0.3.0",
"ios-haptics": "0.1.0",
"is-file-animated": "1.0.2", "is-file-animated": "1.0.2",
"json5": "2.2.3", "json5": "2.2.3",
"magic-string": "0.30.17", "magic-string": "0.30.18",
"matter-js": "0.20.0", "matter-js": "0.20.0",
"mfm-js": "0.25.0", "mfm-js": "0.25.0",
"misskey-bubble-game": "workspace:*", "misskey-bubble-game": "workspace:*",
@ -62,10 +63,10 @@
"misskey-reversi": "workspace:*", "misskey-reversi": "workspace:*",
"photoswipe": "5.4.4", "photoswipe": "5.4.4",
"punycode.js": "2.3.1", "punycode.js": "2.3.1",
"rollup": "4.46.2", "rollup": "4.48.0",
"sanitize-html": "2.17.0", "sanitize-html": "2.17.0",
"sass": "1.89.2", "sass": "1.90.0",
"shiki": "3.9.1", "shiki": "3.11.0",
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.179.1", "three": "0.179.1",
@ -75,17 +76,16 @@
"tsconfig-paths": "4.2.0", "tsconfig-paths": "4.2.0",
"typescript": "5.9.2", "typescript": "5.9.2",
"v-code-diff": "1.13.1", "v-code-diff": "1.13.1",
"vite": "7.0.6", "vite": "7.1.3",
"vue": "3.5.18", "vue": "3.5.19",
"vuedraggable": "next", "vuedraggable": "next",
"wanakana": "5.3.1" "wanakana": "5.3.1"
}, },
"devDependencies": { "devDependencies": {
"@misskey-dev/summaly": "5.2.3", "@misskey-dev/summaly": "5.2.3",
"@storybook/addon-actions": "9.0.8",
"@storybook/addon-essentials": "8.6.14", "@storybook/addon-essentials": "8.6.14",
"@storybook/addon-interactions": "8.6.14", "@storybook/addon-interactions": "8.6.14",
"@storybook/addon-links": "9.1.0", "@storybook/addon-links": "9.1.3",
"@storybook/addon-mdx-gfm": "8.6.14", "@storybook/addon-mdx-gfm": "8.6.14",
"@storybook/addon-storysource": "8.6.14", "@storybook/addon-storysource": "8.6.14",
"@storybook/blocks": "8.6.14", "@storybook/blocks": "8.6.14",
@ -93,34 +93,34 @@
"@storybook/core-events": "8.6.14", "@storybook/core-events": "8.6.14",
"@storybook/manager-api": "8.6.14", "@storybook/manager-api": "8.6.14",
"@storybook/preview-api": "8.6.14", "@storybook/preview-api": "8.6.14",
"@storybook/react": "9.1.0", "@storybook/react": "9.1.3",
"@storybook/react-vite": "9.1.0", "@storybook/react-vite": "9.1.3",
"@storybook/test": "8.6.14", "@storybook/test": "8.6.14",
"@storybook/theming": "8.6.14", "@storybook/theming": "8.6.14",
"@storybook/types": "8.6.14", "@storybook/types": "8.6.14",
"@storybook/vue3": "9.1.0", "@storybook/vue3": "9.1.3",
"@storybook/vue3-vite": "9.1.0", "@storybook/vue3-vite": "9.1.3",
"@tabler/icons-webfont": "3.34.1", "@tabler/icons-webfont": "3.34.1",
"@testing-library/vue": "8.1.0", "@testing-library/vue": "8.1.0",
"@types/canvas-confetti": "1.9.0", "@types/canvas-confetti": "1.9.0",
"@types/estree": "1.0.8", "@types/estree": "1.0.8",
"@types/matter-js": "0.19.8", "@types/matter-js": "0.20.0",
"@types/micromatch": "4.0.9", "@types/micromatch": "4.0.9",
"@types/node": "22.17.0", "@types/node": "22.17.2",
"@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/punycode.js": "npm:@types/punycode@2.1.4",
"@types/sanitize-html": "2.16.0", "@types/sanitize-html": "2.16.0",
"@types/seedrandom": "3.0.8", "@types/seedrandom": "3.0.8",
"@types/throttle-debounce": "5.0.2", "@types/throttle-debounce": "5.0.2",
"@types/tinycolor2": "1.4.6", "@types/tinycolor2": "1.4.6",
"@types/ws": "8.18.1", "@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.38.0", "@typescript-eslint/eslint-plugin": "8.40.0",
"@typescript-eslint/parser": "8.38.0", "@typescript-eslint/parser": "8.40.0",
"@vitest/coverage-v8": "3.2.4", "@vitest/coverage-v8": "3.2.4",
"@vue/compiler-core": "3.5.18", "@vue/compiler-core": "3.5.19",
"@vue/runtime-core": "3.5.18", "@vue/runtime-core": "3.5.19",
"acorn": "8.15.0", "acorn": "8.15.0",
"cross-env": "10.0.0", "cross-env": "10.0.0",
"cypress": "14.5.3", "cypress": "14.5.4",
"eslint-plugin-import": "2.32.0", "eslint-plugin-import": "2.32.0",
"eslint-plugin-vue": "10.4.0", "eslint-plugin-vue": "10.4.0",
"fast-glob": "3.3.3", "fast-glob": "3.3.3",
@ -128,22 +128,22 @@
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"micromatch": "4.0.8", "micromatch": "4.0.8",
"minimatch": "10.0.3", "minimatch": "10.0.3",
"msw": "2.10.4", "msw": "2.10.5",
"msw-storybook-addon": "2.0.5", "msw-storybook-addon": "2.0.5",
"nodemon": "3.1.10", "nodemon": "3.1.10",
"prettier": "3.6.2", "prettier": "3.6.2",
"react": "19.1.1", "react": "19.1.1",
"react-dom": "19.1.1", "react-dom": "19.1.1",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
"start-server-and-test": "2.0.12", "start-server-and-test": "2.0.13",
"storybook": "9.1.0", "storybook": "9.1.3",
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
"tsx": "4.20.3", "tsx": "4.20.4",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vitest": "3.2.4", "vitest": "3.2.4",
"vitest-fetch-mock": "0.4.5", "vitest-fetch-mock": "0.4.5",
"vue-component-type-helpers": "3.0.5", "vue-component-type-helpers": "3.0.6",
"vue-eslint-parser": "10.2.0", "vue-eslint-parser": "10.2.0",
"vue-tsc": "3.0.5" "vue-tsc": "3.0.6"
} }
} }

View file

@ -16,7 +16,7 @@ import '@/style.scss';
import { mainBoot } from '@/boot/main-boot.js'; import { mainBoot } from '@/boot/main-boot.js';
import { subBoot } from '@/boot/sub-boot.js'; import { subBoot } from '@/boot/sub-boot.js';
const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete', '/install-extensions']; const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete', '/verify-email', '/install-extensions'];
if (subBootPaths.some(i => window.location.pathname === i || window.location.pathname.startsWith(i + '/'))) { if (subBootPaths.some(i => window.location.pathname === i || window.location.pathname.startsWith(i + '/'))) {
subBoot(); subBoot();

View file

@ -23,7 +23,7 @@ export async function getAccounts(): Promise<{
host: string; host: string;
id: Misskey.entities.User['id']; id: Misskey.entities.User['id'];
username: Misskey.entities.User['username']; username: Misskey.entities.User['username'];
user?: Misskey.entities.User | null; user?: Misskey.entities.MeDetailed | null;
token: string | null; token: string | null;
}[]> { }[]> {
const tokens = store.s.accountTokens; const tokens = store.s.accountTokens;
@ -38,7 +38,7 @@ export async function getAccounts(): Promise<{
})); }));
} }
async function addAccount(host: string, user: Misskey.entities.User, token: AccountWithToken['token']) { async function addAccount(host: string, user: Misskey.entities.MeDetailed, token: AccountWithToken['token']) {
if (!prefer.s.accounts.some(x => x[0] === host && x[1].id === user.id)) { if (!prefer.s.accounts.some(x => x[0] === host && x[1].id === user.id)) {
store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + user.id]: token }); store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + user.id]: token });
store.set('accountInfos', { ...store.s.accountInfos, [host + '/' + user.id]: user }); store.set('accountInfos', { ...store.s.accountInfos, [host + '/' + user.id]: user });
@ -149,9 +149,10 @@ export function updateCurrentAccountPartial(accountData: Partial<Misskey.entitie
export async function refreshCurrentAccount() { export async function refreshCurrentAccount() {
if (!$i) return; if (!$i) return;
const me = $i;
return fetchAccount($i.token, $i.id).then(updateCurrentAccount).catch(reason => { return fetchAccount($i.token, $i.id).then(updateCurrentAccount).catch(reason => {
if (reason === isAccountDeleted) { if (reason === isAccountDeleted) {
removeAccount(host, $i.id); removeAccount(host, me.id);
if (Object.keys(store.s.accountTokens).length > 0) { if (Object.keys(store.s.accountTokens).length > 0) {
login(Object.values(store.s.accountTokens)[0]); login(Object.values(store.s.accountTokens)[0]);
} else { } else {
@ -214,19 +215,37 @@ export async function openAccountMenu(opts: {
includeCurrentAccount?: boolean; includeCurrentAccount?: boolean;
withExtraOperation: boolean; withExtraOperation: boolean;
active?: Misskey.entities.User['id']; active?: Misskey.entities.User['id'];
onChoose?: (account: Misskey.entities.User) => void; onChoose?: (account: Misskey.entities.MeDetailed) => void;
}, ev: MouseEvent) { }, ev: MouseEvent) {
if (!$i) return; if (!$i) return;
const me = $i;
function createItem(host: string, id: Misskey.entities.User['id'], username: Misskey.entities.User['username'], account: Misskey.entities.User | null | undefined, token: string): MenuItem { const callback = opts.onChoose;
function createItem(host: string, id: Misskey.entities.User['id'], username: Misskey.entities.User['username'], account: Misskey.entities.MeDetailed | null | undefined, token: string | null): MenuItem {
if (account) { if (account) {
return { return {
type: 'user' as const, type: 'user' as const,
user: account, user: account,
active: opts.active != null ? opts.active === id : false, active: opts.active != null ? opts.active === id : false,
action: async () => { action: async () => {
if (opts.onChoose) { if (callback) {
opts.onChoose(account); callback(account);
} else {
switchAccount(host, id);
}
},
};
} else if (token != null) {
return {
type: 'button' as const,
text: username,
active: opts.active != null ? opts.active === id : false,
action: async () => {
if (callback) {
fetchAccount(token, id).then(account => {
callback(account);
});
} else { } else {
switchAccount(host, id); switchAccount(host, id);
} }
@ -238,13 +257,7 @@ export async function openAccountMenu(opts: {
text: username, text: username,
active: opts.active != null ? opts.active === id : false, active: opts.active != null ? opts.active === id : false,
action: async () => { action: async () => {
if (opts.onChoose) { // TODO
fetchAccount(token, id).then(account => {
opts.onChoose(account);
});
} else {
switchAccount(host, id);
}
}, },
}; };
} }
@ -253,7 +266,7 @@ export async function openAccountMenu(opts: {
const menuItems: MenuItem[] = []; const menuItems: MenuItem[] = [];
// TODO: $iのホストも比較したいけど通常null // TODO: $iのホストも比較したいけど通常null
const accountItems = (await getAccounts().then(accounts => accounts.filter(x => x.id !== $i.id))).map(a => createItem(a.host, a.id, a.username, a.user, a.token)); const accountItems = (await getAccounts().then(accounts => accounts.filter(x => x.id !== me.id))).map(a => createItem(a.host, a.id, a.username, a.user, a.token));
if (opts.withExtraOperation) { if (opts.withExtraOperation) {
menuItems.push({ menuItems.push({

View file

@ -86,7 +86,7 @@ export function createAiScriptEnv(opts: { storageKey: string, token?: string })
throw new errors.AiScriptRuntimeError('expected param'); throw new errors.AiScriptRuntimeError('expected param');
} }
utils.assertObject(param); utils.assertObject(param);
return misskeyApi(ep.value, utils.valToJs(param) as object, actualToken).then(res => { return misskeyApi(ep.value as keyof Misskey.Endpoints, utils.valToJs(param) as object, actualToken).then(res => {
return utils.jsToVal(res); return utils.jsToVal(res);
}, err => { }, err => {
return values.ERROR('request_failed', utils.jsToVal(err)); return values.ERROR('request_failed', utils.jsToVal(err));

View file

@ -4,11 +4,11 @@
*/ */
import { utils, values } from '@syuilo/aiscript'; import { utils, values } from '@syuilo/aiscript';
import { genId } from '@/utility/id.js';
import { ref } from 'vue'; import { ref } from 'vue';
import type { Ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { assertStringAndIsIn } from './common.js'; import { assertStringAndIsIn } from './common.js';
import type { Ref } from 'vue';
import { genId } from '@/utility/id.js';
const ALIGNS = ['left', 'center', 'right'] as const; const ALIGNS = ['left', 'center', 'right'] as const;
const FONTS = ['serif', 'sans-serif', 'monospace'] as const; const FONTS = ['serif', 'sans-serif', 'monospace'] as const;
@ -21,16 +21,15 @@ type BorderStyle = (typeof BORDER_STYLES)[number];
export type AsUiComponentBase = { export type AsUiComponentBase = {
id: string; id: string;
hidden?: boolean; hidden?: boolean;
children?: AsUiComponent['id'][];
}; };
export type AsUiRoot = AsUiComponentBase & { export type AsUiRoot = AsUiComponentBase & {
type: 'root'; type: 'root';
children: AsUiComponent['id'][];
}; };
export type AsUiContainer = AsUiComponentBase & { export type AsUiContainer = AsUiComponentBase & {
type: 'container'; type: 'container';
children?: AsUiComponent['id'][];
align?: Align; align?: Align;
bgColor?: string; bgColor?: string;
fgColor?: string; fgColor?: string;
@ -123,7 +122,6 @@ export type AsUiSelect = AsUiComponentBase & {
export type AsUiFolder = AsUiComponentBase & { export type AsUiFolder = AsUiComponentBase & {
type: 'folder'; type: 'folder';
children?: AsUiComponent['id'][];
title?: string; title?: string;
opened?: boolean; opened?: boolean;
}; };

View file

@ -29,6 +29,7 @@ import { miLocalStorage } from '@/local-storage.js';
import { fetchCustomEmojis } from '@/custom-emojis.js'; import { fetchCustomEmojis } from '@/custom-emojis.js';
import { prefer } from '@/preferences.js'; import { prefer } from '@/preferences.js';
import { $i } from '@/i.js'; import { $i } from '@/i.js';
import { launchPlugins } from '@/plugin.js';
export async function common(createVue: () => Promise<App<Element>>) { export async function common(createVue: () => Promise<App<Element>>) {
console.info(`Misskey v${version}`); console.info(`Misskey v${version}`);
@ -338,6 +339,12 @@ export async function common(createVue: () => Promise<App<Element>>) {
}); });
} }
try {
await launchPlugins();
} catch (error) {
console.error('Failed to launch plugins:', error);
}
app.mount(rootEl); app.mount(rootEl);
// boot.jsのやつを解除 // boot.jsのやつを解除

View file

@ -26,7 +26,6 @@ import { mainRouter } from '@/router.js';
import { makeHotkey } from '@/utility/hotkey.js'; import { makeHotkey } from '@/utility/hotkey.js';
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js'; import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
import { prefer } from '@/preferences.js'; import { prefer } from '@/preferences.js';
import { launchPlugins } from '@/plugin.js';
import { updateCurrentAccountPartial } from '@/accounts.js'; import { updateCurrentAccountPartial } from '@/accounts.js';
import { migrateOldSettings } from '@/pref-migrate.js'; import { migrateOldSettings } from '@/pref-migrate.js';
import { unisonReload } from '@/utility/unison-reload.js'; import { unisonReload } from '@/utility/unison-reload.js';
@ -79,8 +78,6 @@ export async function mainBoot() {
} }
} }
launchPlugins();
try { try {
if (prefer.s.enableSeasonalScreenEffect) { if (prefer.s.enableSeasonalScreenEffect) {
const month = new Date().getMonth() + 1; const month = new Date().getMonth() + 1;
@ -371,11 +368,6 @@ export async function mainBoot() {
}); });
}); });
main.on('unreadAntenna', () => {
updateCurrentAccountPartial({ hasUnreadAntenna: true });
sound.playMisskeySfx('antenna');
});
main.on('newChatMessage', () => { main.on('newChatMessage', () => {
updateCurrentAccountPartial({ hasUnreadChatMessages: true }); updateCurrentAccountPartial({ hasUnreadChatMessages: true });
sound.playMisskeySfx('chatMessage'); sound.playMisskeySfx('chatMessage');
@ -421,7 +413,7 @@ export async function mainBoot() {
} }
}, },
allowRepeat: true, allowRepeat: true,
} },
} as const satisfies Keymap; } as const satisfies Keymap;
window.document.addEventListener('keydown', makeHotkey(keymap), { passive: false }); window.document.addEventListener('keydown', makeHotkey(keymap), { passive: false });

View file

@ -2,14 +2,13 @@
* SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { action } from 'storybook/actions';
import { action } from '@storybook/addon-actions';
import type { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw'; import { HttpResponse, http } from 'msw';
import { userDetailed } from '../../.storybook/fakes.js'; import { userDetailed } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js'; import { commonHandlers } from '../../.storybook/mocks.js';
import MkAbuseReportWindow from './MkAbuseReportWindow.vue'; import MkAbuseReportWindow from './MkAbuseReportWindow.vue';
import type { StoryObj } from '@storybook/vue3';
export const Default = { export const Default = {
render(args) { render(args) {
return { return {

View file

@ -4,7 +4,7 @@
*/ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable @typescript-eslint/explicit-function-return-type */
import { action } from '@storybook/addon-actions'; import { action } from 'storybook/actions';
import type { StoryObj } from '@storybook/vue3'; import type { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw'; import { HttpResponse, http } from 'msw';
import { commonHandlers } from '../../.storybook/mocks.js'; import { commonHandlers } from '../../.storybook/mocks.js';

View file

@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
[$style.iconFrame_platinum]: ACHIEVEMENT_BADGES[achievement.name].frame === 'platinum', [$style.iconFrame_platinum]: ACHIEVEMENT_BADGES[achievement.name].frame === 'platinum',
}]" }]"
> >
<div :class="[$style.iconInner]" :style="{ background: ACHIEVEMENT_BADGES[achievement.name].bg }"> <div :class="[$style.iconInner]" :style="{ background: ACHIEVEMENT_BADGES[achievement.name].bg ?? '' }">
<img :class="$style.iconImg" :src="ACHIEVEMENT_BADGES[achievement.name].img"> <img :class="$style.iconImg" :src="ACHIEVEMENT_BADGES[achievement.name].img">
</div> </div>
</div> </div>
@ -61,8 +61,8 @@ import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/utili
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
user: Misskey.entities.User; user: Misskey.entities.User;
withLocked: boolean; withLocked?: boolean;
withDescription: boolean; withDescription?: boolean;
}>(), { }>(), {
withLocked: true, withLocked: true,
withDescription: true, withDescription: true,
@ -71,7 +71,7 @@ const props = withDefaults(defineProps<{
const achievements = ref<Misskey.entities.UsersAchievementsResponse | null>(null); const achievements = ref<Misskey.entities.UsersAchievementsResponse | null>(null);
const lockedAchievements = computed(() => ACHIEVEMENT_TYPES.filter(x => !(achievements.value ?? []).some(a => a.name === x))); const lockedAchievements = computed(() => ACHIEVEMENT_TYPES.filter(x => !(achievements.value ?? []).some(a => a.name === x)));
function fetch() { function _fetch_() {
misskeyApi('users/achievements', { userId: props.user.id }).then(res => { misskeyApi('users/achievements', { userId: props.user.id }).then(res => {
achievements.value = []; achievements.value = [];
for (const t of ACHIEVEMENT_TYPES) { for (const t of ACHIEVEMENT_TYPES) {
@ -84,11 +84,11 @@ function fetch() {
function clickHere() { function clickHere() {
claimAchievement('clickedClickHere'); claimAchievement('clickedClickHere');
fetch(); _fetch_();
} }
onMounted(() => { onMounted(() => {
fetch(); _fetch_();
}); });
</script> </script>

View file

@ -44,7 +44,7 @@ function initShaderProgram(gl: WebGLRenderingContext, vsSource: string, fsSource
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
const shaderProgram = gl.createProgram(); const shaderProgram = gl.createProgram();
if (shaderProgram == null || vertexShader == null || fragmentShader == null) return null; if (vertexShader == null || fragmentShader == null) return null;
gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader); gl.attachShader(shaderProgram, fragmentShader);
@ -71,8 +71,10 @@ onMounted(() => {
canvas.width = width; canvas.width = width;
canvas.height = height; canvas.height = height;
const gl = canvas.getContext('webgl', { premultipliedAlpha: true }); const maybeGl = canvas.getContext('webgl', { premultipliedAlpha: true });
if (gl == null) return; if (maybeGl == null) return;
const gl = maybeGl;
gl.clearColor(0.0, 0.0, 0.0, 0.0); gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
@ -229,8 +231,8 @@ onMounted(() => {
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
if (isChromatic()) { if (isChromatic()) {
gl!.uniform1f(u_time, 0); gl.uniform1f(u_time, 0);
gl!.drawArrays(gl!.TRIANGLE_STRIP, 0, 4); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
} else { } else {
function render(timeStamp: number) { function render(timeStamp: number) {
let sizeChanged = false; let sizeChanged = false;
@ -249,8 +251,8 @@ onMounted(() => {
gl.viewport(0, 0, width, height); gl.viewport(0, 0, width, height);
} }
gl!.uniform1f(u_time, timeStamp); gl.uniform1f(u_time, timeStamp);
gl!.drawArrays(gl!.TRIANGLE_STRIP, 0, 4); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
handle = window.requestAnimationFrame(render); handle = window.requestAnimationFrame(render);
} }
@ -263,6 +265,8 @@ onUnmounted(() => {
if (handle) { if (handle) {
window.cancelAnimationFrame(handle); window.cancelAnimationFrame(handle);
} }
// TODO: WebGL
}); });
</script> </script>

View file

@ -4,7 +4,7 @@
*/ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable @typescript-eslint/explicit-function-return-type */
import { action } from '@storybook/addon-actions'; import { action } from 'storybook/actions';
import type { StoryObj } from '@storybook/vue3'; import type { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw'; import { HttpResponse, http } from 'msw';
import { commonHandlers } from '../../.storybook/mocks.js'; import { commonHandlers } from '../../.storybook/mocks.js';

Some files were not shown because too many files have changed in this diff Show more