diff --git a/.config/example.yml b/.config/example.yml index 38d5e59ea..4da739935 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -155,6 +155,9 @@ id: 'aid' # Media Proxy #mediaProxy: https://example.com/proxy +# Proxy remote files (default: false) +#proxyRemoteFiles: true + # Sign to ActivityPub GET request (default: false) #signToActivityPubGet: true diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.md b/.github/ISSUE_TEMPLATE/01_bug-report.md index 019f8c739..8734fc0c3 100644 --- a/.github/ISSUE_TEMPLATE/01_bug-report.md +++ b/.github/ISSUE_TEMPLATE/01_bug-report.md @@ -16,11 +16,11 @@ First, in order to avoid duplicate Issues, please search to see if the problem y -## 🙂 Expected Behavior +## đŸĨ° Expected Behavior -## ☚ī¸ Actual Behavior +## đŸ¤Ŧ Actual Behavior @@ -33,3 +33,7 @@ First, in order to avoid duplicate Issues, please search to see if the problem y ## 📌 Environment + +Misskey version: +Your OS: +Your browser: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1de4615f5..79ca97dfa 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,10 +1,7 @@ - - # What diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8abca405f..2625cf75d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,18 @@ version: 2 updates: - - package-ecosystem: "npm" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "daily" +- package-ecosystem: npm + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 0 +- package-ecosystem: npm + directory: "/packages/backend" + schedule: + interval: daily + open-pull-requests-limit: 0 +- package-ecosystem: npm + directory: "/packages/client" + schedule: + interval: daily + open-pull-requests-limit: 0 diff --git a/.node-version b/.node-version index 971a6537e..bf79505bb 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -v16.6.2 +v16.14.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 09b5a2ac8..4fc812233 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,21 +2,139 @@ ## 12.x.x (unreleased) ### Improvements +- ### Bugfixes +- +You should also include the user name that made the change. --> ## 12.x.x (unreleased) +### NOTE +こぎバãƒŧジョãƒŗからNode v16.14.0äģĨ降がåŋ…čĻã§ã™ + +### Changes +- ノãƒŧãƒˆãŽæœ€å¤§æ–‡å­—æ•°ã‚’č¨­åŽšã§ãã‚‹æŠŸčƒŊがåģƒæ­ĸされ、デフりãƒĢトで一型3000文字ãĢãĒりぞした @syuilo + ### Improvements +- イãƒŗã‚šã‚ŋãƒŗ゚デフりãƒĢトテãƒŧãƒžã‚’č¨­åŽšã§ãã‚‹ã‚ˆã†ãĢ @syuilo +- プロフã‚ŖãƒŧãƒĢぎčŋŊåŠ æƒ…å ąã‚’æœ€å¤§16ぞでäŋå­˜ã§ãã‚‹ã‚ˆã†ãĢ @syuilo +- é€Ŗ合チãƒŖãƒŧトãĢPub&SubをčŋŊ加 @syuilo ### Bugfixes -- 投į¨ŋぎNSFWį”ģåƒã‚’čĄ¨į¤ēしたあとãĢãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗが更新されるとį”ģåƒãŒéžčĄ¨į¤ēãĢãĒã‚‹å•éĄŒã‚’äŋŽæ­Ŗ -- 「クãƒĒップ」ペãƒŧジが開かãĒã„å•éĄŒã‚’äŋŽæ­Ŗ -- トãƒŦãƒŗドã‚Ļã‚Ŗジェットが動äŊœã—ãĒいぎをäŋŽæ­Ŗ -- ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗč¨­åŽšã§įĩĩ文字ピッã‚Ģãƒŧが開かãĒいぎをäŋŽæ­Ŗ -- DMペãƒŧã‚¸ã§ãƒĄãƒŗã‚ˇãƒ§ãƒŗがåĢãžã‚Œã‚‹å•éĄŒã‚’äŋŽæ­Ŗ +- Client: ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗピッã‚ĢãƒŧぎéĢ˜ã•ãŒäŊŽããĒãŖたぞぞæˆģらãĒいことがあるぎをäŋŽæ­Ŗ @syuilo +- Client: ãƒĻãƒŧã‚ļãƒŧ名ã‚Ēãƒŧトã‚ŗãƒŗプãƒĒãƒŧトがæ­Ŗしく動äŊœã—ãĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo +- Client: ã‚ŋッチ操äŊœã ã¨ã‚Ļã‚Ŗジェットぎįˇ¨é›†ãŒã—ãĢくいぎをäŋŽæ­Ŗ @xianonn + +## 12.107.0 (2022/02/12) + +### Improvements +- クナイã‚ĸãƒŗト: テãƒŧマをčŋŊ加 @syuilo + +### Bugfixes +- API: stats APIで内部エナãƒŧがį™ēį”Ÿã™ã‚‹å•éĄŒã‚’äŋŽæ­Ŗ @syuilo +- クナイã‚ĸãƒŗト: ã‚ŊフトミãƒĨãƒŧトですずãĻがマッチしãĻしぞう場合があるぎをäŋŽæ­Ŗ @tamaina +- クナイã‚ĸãƒŗト: デバイ゚ぎ゚クãƒĒãƒŧãƒŗぎã‚ģãƒŧフエãƒĒã‚ĸã‚’č€ƒæ…Žã™ã‚‹ã‚ˆã†ãĢ @syuilo +- クナイã‚ĸãƒŗト: 一部į’°åĸƒã§ã‚ĩイドバãƒŧぎ投į¨ŋボã‚ŋãƒŗãŒčĄ¨į¤ēされãĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo + +## 12.106.3 (2022/02/11) + +### Improvements +- クナイã‚ĸãƒŗト: ゚マãƒŧトフりãƒŗでぎäŊ™į™ŊをčĒŋ整 @syuilo + +### Bugfixes +- クナイã‚ĸãƒŗト: ノãƒŧトぎčŠŗį´°ãŒčĄ¨į¤ēされãĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo + +## 12.106.2 (2022/02/11) + +### Bugfixes +- クナイã‚ĸãƒŗト: 削除したノãƒŧトがã‚ŋイムナイãƒŗからč‡Ē動でæļˆãˆãĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo +- クナイã‚ĸãƒŗト: ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗ数がæ­ŖしくãĒã„ã“ã¨ãŒã‚ã‚‹å•éĄŒã‚’äŋŽæ­Ŗ @syuilo +- 一部į’°åĸƒã§ãƒžã‚¤ã‚°ãƒŦãƒŧã‚ˇãƒ§ãƒŗが動äŊœã—ãĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo + +## 12.106.1 (2022/02/11) + +### Bugfixes +- クナイã‚ĸãƒŗト: ワãƒŧドミãƒĨãƒŧトがäŋå­˜ã§ããĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo + +## 12.106.0 (2022/02/11) + +### Improvements +- Improve federation chart @syuilo +- クナイã‚ĸãƒŗト: ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗピッã‚Ģãƒŧぎã‚ĩイã‚ēã‚’č¨­åŽšã§ãã‚‹ã‚ˆã†ãĢ @syuilo +- クナイã‚ĸãƒŗト: ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗピッã‚Ģãƒŧぎ嚅、éĢ˜ã•åˆļ限をįˇŠå’Œ @syuilo +- Docker: Update to Node v16.13.2 @mei23 +- Update dependencies + +### Bugfixes +- validate regular expressions in word mutes @Johann150 + +## 12.105.0 (2022/02/09) + +### Improvements +- イãƒŗã‚šã‚ŋãƒŗ゚ぎテãƒŧマã‚Ģナãƒŧã‚’č¨­åŽšã§ãã‚‹ã‚ˆã†ãĢ @syuilo + +### Bugfixes +- 一部į’°åĸƒã§ãƒžã‚¤ã‚°ãƒŦãƒŧã‚ˇãƒ§ãƒŗãŒå¤ąæ•—ã™ã‚‹å•éĄŒã‚’äŋŽæ­Ŗ @syuilo + +## 12.104.0 (2022/02/09) + +### Note +ビãƒĢドする前ãĢ`npm run clean`ã‚’åŽŸčĄŒã—ãĻください。 + +こぎãƒĒãƒĒãƒŧ゚はマイグãƒŦãƒŧã‚ˇãƒ§ãƒŗぎčĻæ¨ĄãŒå¤§ãã„ため、イãƒŗã‚šã‚ŋãƒŗã‚šãĢよãŖãĻはマイグãƒŦãƒŧã‚ˇãƒ§ãƒŗãĢ時間がかかる可čƒŊ性がありぞす。 +マイグãƒŦãƒŧã‚ˇãƒ§ãƒŗがįĩ‚わらãĒい場合は、チãƒŖãƒŧãƒˆãŽæƒ…å ąã¯ãƒĒã‚ģットされãĻしぞいぞすが`__chart__`で始ぞるテãƒŧブãƒĢぎ**ãƒŦã‚ŗãƒŧド**を全ãĻ削除(テãƒŧブãƒĢč‡ĒäŊ“はæļˆã•ãĒいでください)しãĻから再åēĻčŠĻす斚æŗ•ã‚‚ありぞす。 + +### Improvements +- チãƒŖãƒŧトエãƒŗジãƒŗぎåŧˇåŒ– @syuilo + - テãƒŧブãƒĢã‚ĩイã‚ēぎ削減 + - notes/instance/perUserNotesチãƒŖãƒŧトãĢæˇģäģ˜ãƒ•ã‚Ąã‚¤ãƒĢäģ˜ããƒŽãƒŧトぎ数をčŋŊ加 + - activeUsersチãƒŖãƒŧトãĢ新しい項į›Žã‚’čŋŊ加 + - federationチãƒŖãƒŧトãĢ新しい項į›Žã‚’čŋŊ加 + - apRequestチãƒŖãƒŧトをčŋŊ加 + - networkチãƒŖãƒŧトåģƒæ­ĸ +- クナイã‚ĸãƒŗト: č‡Ēイãƒŗã‚šã‚ŋãƒŗã‚šæƒ…å ąãƒšãƒŧジでチãƒŖãƒŧトをčĻ‹ã‚Œã‚‹ã‚ˆã†ãĢ @syuilo +- クナイã‚ĸãƒŗト: デバイ゚ぎį¨ŽéĄžã‚’手動指厚できるようãĢ @syuilo +- クナイã‚ĸãƒŗト: UIぎã‚ĸイã‚ŗãƒŗを更新 @syuilo +- クナイã‚ĸãƒŗト: UIぎã‚ĸイã‚ŗãƒŗをã‚ģãƒĢフポテã‚ŖãƒŗグするようãĢ @syuilo +- NodeInfo ぎãƒĻãƒŧã‚ļãƒŧ数と投į¨ŋ数ぎ内厚をčĻ‹į›´ã™ @xianonn + +### Bugfixes +- Client: ã‚ŋイムナイãƒŗį¨ŽåˆĨを切りæ›ŋえると「新しいノãƒŧãƒˆãŒã‚ã‚Šãžã™ã€ãŽčĄ¨į¤ēが掋į•™ã—ãĻしぞうぎをäŋŽæ­Ŗ @tamaina +- Client: UIぎã‚ĩイã‚ēがおかしくãĒã‚‹å•éĄŒãŽäŋŽæ­Ŗ @tamaina +- Client: Setting instance information of notes to always show breaks the timeline @Johann150 +- Client: į’°åĸƒãĢ䞝ãŖãĻはčŋ”äŋĄã™ã‚‹éš›ãŽã‚Ģãƒŧã‚ŊãƒĢäŊįŊŽãŒæ­ŖしくãĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo +- Client: ã‚ŗãƒŗトロãƒŧãƒĢパネãƒĢぎãƒĻãƒŧã‚ļãƒŧã€ãƒ•ã‚Ąã‚¤ãƒĢãĢãĻ、イãƒŗã‚šã‚ŋãƒŗã‚šãŽčĄ¨į¤ēį¯„å›˛åˆ‡ã‚Šæ›ŋえが抟čƒŊしãĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo +- Client: ã‚ĸップデãƒŧトおįŸĨらせダイã‚ĸログがå‡ēãĒいぎをäŋŽæ­Ŗ @syuilo +- Client: Follows/Followers Visibility changes won't be saved unless clicking on an other checkbox @Johann150 +- API: Fix API cast @mei23 +- add instance favicon where it's missing @solfisher +- チãƒŖãƒŧトぎ厚期resyncが動äŊœã—ãĻいãĒã„å•éĄŒã‚’äŋŽæ­Ŗ @syuilo + +## 12.103.1 (2022/02/02) + +### Bugfixes +- クナイã‚ĸãƒŗト: ツãƒŧãƒĢãƒãƒƒãƒ—ãŽčĄ¨į¤ēäŊįŊŽãŒæ­ŖしくãĒã„å•éĄŒã‚’äŋŽæ­Ŗ + +## 12.103.0 (2022/02/02) + +### Improvements +- クナイã‚ĸãƒŗト: é€Ŗ合イãƒŗã‚šã‚ŋãƒŗ゚ペãƒŧジからイãƒŗã‚šã‚ŋãƒŗã‚šæƒ…å ąå†å–åž—ã‚’čĄŒãˆã‚‹ã‚ˆã†ãĢ + +### Bugfixes +- クナイã‚ĸãƒŗト: 投į¨ŋぎNSFWį”ģåƒã‚’čĄ¨į¤ēしたあとãĢãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗが更新されるとį”ģåƒãŒéžčĄ¨į¤ēãĢãĒã‚‹å•éĄŒã‚’äŋŽæ­Ŗ +- クナイã‚ĸãƒŗト: 「クãƒĒップ」ペãƒŧジが開かãĒã„å•éĄŒã‚’äŋŽæ­Ŗ +- クナイã‚ĸãƒŗト: トãƒŦãƒŗドã‚Ļã‚Ŗジェットが動äŊœã—ãĒいぎをäŋŽæ­Ŗ +- クナイã‚ĸãƒŗト: フェデãƒŦãƒŧã‚ˇãƒ§ãƒŗã‚Ļã‚Ŗジェットが動äŊœã—ãĒいぎをäŋŽæ­Ŗ +- クナイã‚ĸãƒŗト: ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗč¨­åŽšã§įĩĩ文字ピッã‚Ģãƒŧが開かãĒいぎをäŋŽæ­Ŗ +- クナイã‚ĸãƒŗト: DMペãƒŧã‚¸ã§ãƒĄãƒŗã‚ˇãƒ§ãƒŗがåĢãžã‚Œã‚‹å•éĄŒã‚’äŋŽæ­Ŗ +- クナイã‚ĸãƒŗト: 投į¨ŋフりãƒŧãƒ ãŽãƒãƒƒã‚ˇãƒĨã‚ŋグäŋæŒãƒ•ã‚ŖãƒŧãƒĢドが動äŊœã—ãĒã„å•éĄŒã‚’äŋŽæ­Ŗ +- クナイã‚ĸãƒŗト: ã‚ĩイドビãƒĨãƒŧが動かãĒいぎをäŋŽæ­Ŗ +- クナイã‚ĸãƒŗト: ensure that specified users does not get duplicates +- Add `img-src` and `media-src` directives to `Content-Security-Policy` for + files and media proxy ## 12.102.1 (2022/01/27) ### Bugfixes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27f5598a6..6e0f500be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ We're glad you're interested in contributing Misskey! In this document you will **ℹī¸ Important:** This project uses Japanese as its major language, **but you do not need to translate and write the Issues/PRs in Japanese.** Also, you might receive comments on your Issue/PR in Japanese, but you do not need to reply to them in Japanese as well.\ -The accuracy of translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language. +The accuracy of machine translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language. It will also allow the reader to use the translation tool of their preference if necessary. ## Issues @@ -16,6 +16,9 @@ Before creating an issue, please check the following: ## Before implementation When you want to add a feature or fix a bug, **first have the design and policy reviewed in an Issue** (if it is not there, please make one). Without this step, there is a high possibility that the PR will not be merged even if it is implemented. +At this point, you also need to clarify the goals of the PR you will create, and make sure that the other members of the team are aware of them. +PRs that do not have a clear set of do's and don'ts tend to be bloated and difficult to review. + Also, when you start implementation, assign yourself to the Issue (if you cannot do it yourself, ask another member to assign you). By expressing your intention to work the Issue, you can prevent conflicts in the work. ## Well-known branches @@ -39,6 +42,23 @@ Thank you for your PR! Before creating a PR, please check the following: Thanks for your cooperation 🤗 +## Reviewers guide +Be willing to comment on the good points and not just the things you want fixed đŸ’¯ + +### Review perspective +- Scope + - Are the goals of the PR clear? + - Is the granularity of the PR appropriate? +- Security + - Does merging this PR create a vulnerability? +- Performance + - Will merging this PR cause unexpected performance degradation? + - Is there a more efficient way? +- Testing + - Does the test ensure the expected behavior? + - Are there any omissions or gaps? + - Does it check for anomalies? + ## Localization (l10n) Misskey uses [Crowdin](https://crowdin.com/project/misskey) for localization management. You can improve our translations with your Crowdin account. diff --git a/Dockerfile b/Dockerfile index df8603430..e4959756e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16.6.2-alpine3.13 AS base +FROM node:16.14.0-alpine3.15 AS base ENV NODE_ENV=production diff --git a/cypress/integration/basic.js b/cypress/integration/basic.js index aca44ef15..7d27b649f 100644 --- a/cypress/integration/basic.js +++ b/cypress/integration/basic.js @@ -176,3 +176,7 @@ describe('After user singed in', () => { cy.contains('Hello, Misskey!'); }); }); + +// TODO: 投į¨ŋフりãƒŧムぎå…Ŧ開į¯„å›˛æŒ‡åŽšãŽãƒ†ã‚šãƒˆ +// TODO: 投į¨ŋフりãƒŧãƒ ãŽãƒ•ã‚Ąã‚¤ãƒĢæˇģäģ˜ãŽãƒ†ã‚šãƒˆ +// TODO: 投į¨ŋフりãƒŧãƒ ãŽãƒãƒƒã‚ˇãƒĨã‚ŋグäŋæŒãƒ•ã‚ŖãƒŧãƒĢドぎテ゚ト diff --git a/gulpfile.js b/gulpfile.js index 3bc0b23be..b7aa4e328 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -19,6 +19,10 @@ gulp.task('copy:client:fonts', () => gulp.src('./packages/client/node_modules/three/examples/fonts/**/*').pipe(gulp.dest('./built/_client_dist_/fonts/')) ); +gulp.task('copy:client:fontawesome', () => + gulp.src('./packages/client/node_modules/@fortawesome/fontawesome-free/**/*').pipe(gulp.dest('./built/_client_dist_/fontawesome/')) +); + gulp.task('copy:client:locales', cb => { fs.mkdirSync('./built/_client_dist_/locales', { recursive: true }); @@ -50,7 +54,7 @@ gulp.task('build:backend:style', () => { }); gulp.task('build', gulp.parallel( - 'copy:client:locales', 'copy:backend:views', 'build:backend:script', 'build:backend:style', 'copy:client:fonts' + 'copy:client:locales', 'copy:backend:views', 'build:backend:script', 'build:backend:style', 'copy:client:fonts', 'copy:client:fontawesome' )); gulp.task('default', gulp.task('build')); diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 5a053cdee..914a16bb2 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -1110,6 +1110,8 @@ _exportOrImport: blockingList: "اŲ„Ų…ØŗØĒ؎دŲ…ŲˆŲ† اŲ„Ų…Ø­ØŦŲˆØ¨ŲˆŲ†" userLists: "اŲ„Ų‚ŲˆØ§ØĻŲ…" _charts: + federation: "اŲ„ŲØ¯ŲŠØąØ§Ų„ŲŠØŠ" + apRequest: "اŲ„ØˇŲ„باØĒ" usersIncDec: "ا؎ØĒŲ„اŲ ؚدد اŲ„Ų…ØŗØĒ؎دŲ…ŲŠŲ†" usersTotal: "Ų…ØŦŲ…ŲˆØš ؚدد اŲ„Ų…ØŗØĒ؎دŲ…ŲŠŲ† ŲˆØ§Ų„Ų…ØŗØĒ؎دŲ…اØĒ" activeUsers: "اŲ„Ų…ØŗØĒ؎دŲ…ŲˆŲ† اŲ„Ų†Ø´ØˇŲˆŲ†" diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index ed97d539c..5cc2bb91b 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -1 +1,1640 @@ --- +_lang_: "āĻŦāĻžāĻ‚āĻ˛āĻž" +headlineMisskey: "āĻ¨ā§‹āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ¨ā§‡āĻŸāĻ“ā§ŸāĻžāĻ°ā§āĻ•" +introMisskey: "āĻ¸ā§āĻŦāĻžāĻ—āĻ¤āĻŽ! āĻŽāĻŋāĻ¸āĻ•āĻŋ āĻāĻ•āĻŸāĻŋ āĻ“āĻĒā§‡āĻ¨ āĻ¸ā§‹āĻ°ā§āĻ¸, āĻĄāĻŋāĻ¸ā§‡āĻ¨ā§āĻŸā§āĻ°āĻžāĻ˛āĻžāĻ‡āĻœāĻĄ āĻŽāĻžāĻ‡āĻ•ā§āĻ°ā§‹āĻŦā§āĻ˛āĻ—āĻŋāĻ‚ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĨ¤ \n\"āĻ¨ā§‹āĻŸ\" āĻ¤ā§ˆāĻ°āĻŋāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ¯āĻž āĻ˜āĻŸāĻ›ā§‡ āĻ¤āĻž āĻ¸āĻŦāĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻļā§‡ā§ŸāĻžāĻ° āĻ•āĻ°ā§āĻ¨ 📡\n\"āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨\" āĻ—ā§āĻ˛āĻŋāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ¯ā§‡āĻ•ā§‹āĻ¨ā§‹ āĻ¨ā§‹āĻŸ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…āĻ¨ā§āĻ­ā§‚āĻ¤āĻŋ āĻŦā§āĻ¯āĻžāĻ•ā§āĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ 👍\nāĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻĻā§āĻ¨āĻŋā§ŸāĻž āĻ˜ā§āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨ 🚀\n" +monthAndDay: "{day}/{month}" +search: "āĻ–ā§āĻāĻœā§āĻ¨" +notifications: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ" +username: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ" +password: "āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ" +forgotPassword: "āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ­ā§āĻ˛ā§‡ āĻ—ā§‡āĻ›ā§‡āĻ¨" +fetchingAsApObject: "āĻĢā§‡āĻĄāĻŋāĻ­āĻžāĻ°ā§āĻ¸ āĻĨā§‡āĻ•ā§‡ āĻ–āĻŦāĻ° āĻ†āĻ¨āĻž āĻšāĻšā§āĻ›ā§‡..." +ok: "āĻ āĻŋāĻ•" +gotIt: "āĻŦā§āĻā§‡āĻ›āĻŋ" +cancel: "āĻŦāĻžāĻ¤āĻŋāĻ˛" +enterUsername: "āĻ‡āĻ‰āĻœāĻžāĻ°āĻ¨ā§‡āĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨" +renotedBy: "{user} āĻ°āĻŋāĻ¨ā§‹āĻŸ āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨" +noNotes: "āĻ•ā§‹āĻ¨ āĻ¨ā§‹āĻŸ āĻ¨ā§‡āĻ‡" +noNotifications: "āĻ•ā§‹āĻ¨ā§‹ āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ āĻ¨ā§‡āĻ‡" +instance: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸" +settings: "āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸" +basicSettings: "āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸" +otherSettings: "āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸" +openInWindow: "āĻ¨āĻ¤ā§āĻ¨ āĻ‰āĻ‡āĻ¨ā§āĻĄā§‹āĻ¤ā§‡ āĻ–ā§āĻ˛āĻž" +profile: "āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛" +timeline: "āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨" +noAccountDescription: "āĻāĻ‡ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ•ā§‹āĻ¨ āĻŦāĻžā§Ÿā§‹ āĻ¨ā§‡āĻ‡" +login: "āĻĒā§āĻ°āĻŦā§‡āĻļ āĻ•āĻ°ā§āĻ¨" +loggingIn: "āĻĒā§āĻ°āĻŦā§‡āĻļ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡..." +logout: "āĻ˛āĻ—āĻ†āĻ‰āĻŸ" +signup: "āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨ āĻ•āĻ°ā§āĻ¨" +uploading: "āĻ†āĻĒāĻ˛ā§‹āĻĄ āĻšāĻšā§āĻ› â€Ļ" +save: "āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ" +users: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ—āĻŖ" +addUser: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +favorite: "āĻĒāĻ›āĻ¨ā§āĻĻ" +favorites: "āĻĒāĻ›āĻ¨ā§āĻĻāĻ—ā§āĻ˛āĻŋ" +unfavorite: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ¨āĻž" +favorited: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +alreadyFavorited: "āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡ āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +cantFavorite: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻž āĻ¯āĻžā§ŸāĻ¨āĻŋ" +pin: "āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻž" +unpin: "āĻĒāĻŋāĻ¨ āĻ¸āĻ°āĻžāĻ¨" +copyContent: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§ āĻ•āĻĒāĻŋ āĻ•āĻ°ā§āĻ¨" +copyLink: "āĻ˛āĻŋāĻ™ā§āĻ• āĻ•āĻĒāĻŋ āĻ•āĻ°ā§āĻ¨" +delete: "āĻŽā§āĻ›ā§āĻ¨" +deleteAndEdit: "āĻŽā§āĻ›ā§āĻ¨ āĻāĻŦāĻ‚ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" +deleteAndEditConfirm: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻāĻ‡ āĻ¨ā§‹āĻŸāĻŸāĻŋ āĻŽā§āĻ›ā§‡ āĻāĻŸāĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°āĻžāĻ° āĻŦāĻŋāĻˇāĻ¯āĻŧā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤? āĻ†āĻĒāĻ¨āĻŋ āĻāĻŸāĻŋāĻ° āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨, āĻ°āĻŋāĻ¨ā§‹āĻŸ āĻāĻŦāĻ‚ āĻœāĻŦāĻžāĻŦ āĻšāĻžāĻ°āĻžāĻŦā§‡āĻ¨āĨ¤" +addToList: "āĻ˛āĻŋāĻ¸ā§āĻŸ āĻ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +sendMessage: "āĻāĻ•āĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒāĻžāĻ āĻžāĻ¨" +copyUsername: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ āĻ•āĻĒāĻŋ āĻ•āĻ°ā§āĻ¨" +searchUser: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ–ā§āĻāĻœā§āĻ¨..." +reply: "āĻœāĻŦāĻžāĻŦ" +loadMore: "āĻ†āĻ°āĻ“ āĻĻā§‡āĻ–ā§āĻ¨" +showMore: "āĻ†āĻ°āĻ“ āĻĻā§‡āĻ–ā§āĻ¨" +youGotNewFollower: "āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻ›ā§‡" +receiveFollowRequest: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻĒāĻžāĻ“ā§ŸāĻž āĻ—ā§‡āĻ›ā§‡" +followRequestAccepted: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ—ā§ƒāĻšā§€āĻ¤ āĻšā§Ÿā§‡āĻ›ā§‡" +mention: "āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–" +mentions: "āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–āĻ¸āĻŽā§‚āĻš" +directNotes: "āĻĄāĻžāĻ‡āĻ°ā§‡āĻ•ā§āĻŸ āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ" +importAndExport: "āĻ†āĻŽāĻĻāĻžāĻ¨āĻŋ āĻāĻŦāĻ‚ āĻ°āĻĒā§āĻ¤āĻžāĻ¨āĻŋ" +import: "āĻ†āĻŽāĻĻāĻžāĻ¨āĻŋ āĻ•āĻ°ā§āĻŖ" +export: "āĻ°āĻĒā§āĻ¤āĻžāĻ¨āĻŋ" +files: "āĻĢāĻžāĻ‡āĻ˛āĻ—ā§āĻ˛āĻŋ" +download: "āĻĄāĻžāĻ‰āĻ¨āĻ˛ā§‹āĻĄ" +driveFileDeleteConfirm: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ¯ā§‡ āĻ†āĻĒāĻ¨āĻŋ \"{name}\" āĻĄāĻŋāĻ˛āĻŋāĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨? āĻ¯ā§‡ āĻ¸āĻ•āĻ˛ āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻāĻ‡ āĻĢāĻžāĻ‡āĻ˛āĻŸāĻŋ āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ¸ā§‡āĻ—ā§āĻ˛ā§‹āĻ“ āĻĄāĻŋāĻ˛āĻŋāĻŸ āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤" +unfollowConfirm: "{name} āĻ•ā§‡ āĻ†āĻ¨āĻĢāĻ˛ā§‹āĻ“ āĻ•āĻ°āĻžāĻ° āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤?" +exportRequested: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¤āĻĨā§āĻ¯āĻ¸āĻŽā§‚āĻš āĻ°āĻĒā§āĻ¤āĻžāĻ¨āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨āĨ¤ āĻāĻ¤ā§‡ āĻ•āĻŋāĻ›ā§ āĻ¸āĻŽā§Ÿ āĻ˛āĻžāĻ—āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ āĻ°āĻĒā§āĻ¤āĻžāĻ¨āĻŋ āĻ¸āĻŽā§āĻĒāĻ¨ā§āĻ¨ āĻšāĻ˛ā§‡ āĻ¤āĻž āĻ†āĻĒāĻ¨āĻžāĻ° āĻĄā§āĻ°āĻžāĻ‡āĻ­ā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŋāĻ¤ āĻšāĻŦā§‡āĨ¤" +importRequested: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¤āĻĨā§āĻ¯āĻ¸āĻŽā§‚āĻš āĻ†āĻŽāĻĻāĻžāĻ¨āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨āĨ¤ āĻāĻ¤ā§‡ āĻ•āĻŋāĻ›ā§ āĻ¸āĻŽā§Ÿ āĻ˛āĻžāĻ—āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ " +lists: "āĻ˛āĻŋāĻ¸ā§āĻŸ" +noLists: "āĻ•ā§‹āĻ¨ āĻ˛āĻŋāĻ¸ā§āĻŸ āĻ¨ā§‡āĻ‡" +note: "āĻ¨ā§‹āĻŸ" +notes: "āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ" +following: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡" +followers: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€" +followsYou: "āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡" +createList: "āĻ˛āĻŋāĻ¸ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +manageLists: "āĻ˛āĻŋāĻ¸ā§āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻž" +error: "āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž" +somethingHappened: "āĻāĻ•āĻŸāĻŋ āĻ¤ā§āĻ°ā§āĻŸāĻŋ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡" +retry: "āĻ†āĻŦāĻžāĻ° āĻšā§‡āĻˇā§āĻŸāĻž āĻ•āĻ°ā§āĻ¨" +pageLoadError: "āĻĒā§‡āĻœ āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻž āĻ¯āĻžā§ŸāĻ¨āĻŋ" +pageLoadErrorDescription: "āĻāĻŸāĻŋ āĻ¸āĻžāĻ§āĻžāĻ°āĻ¨āĻ¤ āĻ¨ā§‡āĻŸāĻ“ā§ŸāĻžāĻ°ā§āĻ•ā§‡āĻ° āĻ¸āĻŽāĻ¸ā§āĻ¯āĻžāĻ° āĻŦāĻž āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻ•ā§āĻ¯āĻžāĻļā§‡āĻ° āĻ•āĻžāĻ°āĻŖā§‡ āĻ˜āĻŸā§‡ āĻĨāĻžāĻ•ā§‡āĨ¤ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻāĻ° āĻ•ā§āĻ¯āĻžāĻļ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°ā§āĻ¨ āĻāĻŦāĻ‚ āĻāĻ•āĻŸā§ āĻĒāĻ° āĻ†āĻŦāĻžāĻ° āĻšā§‡āĻˇā§āĻŸāĻž āĻ•āĻ°ā§āĻ¨āĨ¤ " +serverIsDead: "āĻāĻ‡ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ā§‡ āĻ¸āĻžā§œāĻž āĻĻāĻŋāĻšā§āĻ›ā§‡ āĻ¨āĻžāĨ¤ āĻāĻ•āĻŸā§ āĻĒāĻ°ā§‡ āĻ†āĻŦāĻžāĻ° āĻšā§‡āĻˇā§āĻŸāĻž āĻ•āĻ°ā§āĻ¨āĨ¤" +youShouldUpgradeClient: "āĻāĻ‡ āĻĒā§‡āĻœ āĻĻā§‡āĻ–āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻĒāĻ¨āĻžāĻ° āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ° āĻ°āĻŋāĻĢā§āĻ°ā§‡āĻļ āĻ•āĻ°ā§‡ āĻ•ā§āĻ˛āĻžā§Ÿā§‡āĻ¨ā§āĻŸ āĻ†āĻĒāĻĄā§‡āĻŸ āĻ•āĻ°ā§āĻ¨āĨ¤ " +enterListName: "āĻ˛āĻŋāĻ¸ā§āĻŸā§‡āĻ° āĻ¨āĻžāĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨" +privacy: "āĻ—ā§‹āĻĒāĻ¨ā§€ā§ŸāĻ¤āĻž" +makeFollowManuallyApprove: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ—ā§āĻ˛āĻŋ āĻ—ā§ƒāĻšā§€āĻ¤ āĻšāĻ“ā§ŸāĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ āĻ˛āĻžāĻ—āĻŦā§‡" +defaultNoteVisibility: "āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻĻā§ƒāĻļā§āĻ¯āĻŽāĻžāĻ¨ā§āĻ¯āĻ¤āĻž" +follow: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ" +followRequest: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§" +followRequests: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ¸āĻŽā§‚āĻš" +unfollow: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻŦāĻžāĻ¤āĻŋāĻ˛" +followRequestPending: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻŦāĻŋāĻšāĻžāĻ°āĻžāĻ§ā§€āĻ¨" +enterEmoji: "āĻ‡āĻŽā§‹āĻœāĻŋ āĻĒā§āĻ°āĻŦā§‡āĻļ āĻ•āĻ°āĻžāĻ¨" +renote: "āĻ°āĻŋāĻ¨ā§‹āĻŸ" +unrenote: "āĻ°āĻŋāĻ¨ā§‹āĻŸ āĻ¸āĻ°āĻžāĻ¨ " +renoted: "āĻ°āĻŋāĻ¨ā§‹āĻŸ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +cantRenote: "āĻāĻ‡ āĻ¨ā§‹āĻŸāĻŸāĻŋ āĻ°āĻŋāĻ¨ā§‹āĻŸ āĻ•āĻ°āĻž āĻ¯āĻžāĻŦā§‡ āĻ¨āĻžāĨ¤" +cantReRenote: "āĻ°āĻŋāĻ¨ā§‹āĻŸāĻ•ā§‡ āĻ°āĻŋāĻ¨ā§‹āĻŸ āĻ•āĻ°āĻž āĻ¯āĻžāĻŦā§‡ āĻ¨āĻžāĨ¤" +quote: "āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤āĻŋ" +pinnedNote: "āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻž āĻ¨ā§‹āĻŸ" +pinned: "āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻž" +you: "āĻ†āĻĒāĻ¨āĻŋ" +clickToShow: "āĻĻā§‡āĻ–āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°ā§āĻ¨" +sensitive: "āĻ¸āĻ‚āĻŦā§‡āĻĻāĻ¨āĻļā§€āĻ˛ āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§" +add: "āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" +reaction: "āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž" +reactionSetting: "āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻĒāĻŋāĻ•āĻžāĻ°ā§‡ āĻ¯ā§‡āĻ¸āĻ•āĻ˛ āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋā§ŸāĻž āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻšāĻŦā§‡" +reactionSettingDescription2: "āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻ¸āĻžāĻœāĻžāĻ¤ā§‡ āĻŸā§‡āĻ¨ā§‡ āĻ†āĻ¨ā§āĻ¨, āĻŽā§āĻ›āĻ¤ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°ā§āĻ¨, āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ + āĻŸāĻŋāĻĒā§āĻ¨āĨ¤" +rememberNoteVisibility: "āĻ¨ā§‹āĻŸā§‡āĻ° āĻĻā§ƒāĻļā§āĻ¯āĻŽāĻžāĻ¨ā§āĻ¯āĻ¤āĻžāĻ° āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸ āĻŽāĻ¨ā§‡ āĻ°āĻžāĻ–ā§āĻ¨" +attachCancel: "āĻ…ā§āĻ¯āĻžāĻŸāĻžāĻšāĻŽā§‡āĻ¨ā§āĻŸ āĻ¸āĻ°āĻžāĻ¨ " +markAsSensitive: "āĻ¸āĻ‚āĻŦā§‡āĻĻāĻ¨āĻļā§€āĻ˛ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +unmarkAsSensitive: "āĻ¸āĻ‚āĻŦā§‡āĻĻāĻ¨āĻļā§€āĻ˛ āĻšāĻŋāĻšā§āĻ¨ āĻ¸āĻ°āĻžāĻ¨" +enterFileName: "āĻĢāĻžāĻ‡āĻ˛ā§‡āĻ° āĻ¨āĻžāĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨" +mute: "āĻŽāĻŋāĻ‰āĻŸ" +unmute: "āĻ†āĻ¨āĻŽāĻŋāĻ‰āĻŸ" +block: "āĻŦā§āĻ˛āĻ•" +unblock: "āĻŦā§āĻ˛āĻ• āĻ¸āĻ°āĻžāĻ¨" +suspend: "āĻ¸ā§āĻĨāĻ—āĻŋāĻ¤ āĻ•āĻ°āĻž" +unsuspend: "āĻ…āĻ¸ā§āĻĨāĻ—āĻŋāĻ¤ āĻ•āĻ°āĻž" +blockConfirm: "āĻŦā§āĻ˛āĻ• āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +unblockConfirm: "āĻŦā§āĻ˛āĻ• āĻ¸āĻ°āĻžāĻ¤ā§‡ āĻšāĻžāĻ¨?" +suspendConfirm: "āĻ¸ā§āĻĨāĻ—āĻŋāĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +unsuspendConfirm: "āĻ…āĻ¸ā§āĻĨāĻ—āĻŋāĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +selectList: "āĻ˛āĻŋāĻ¸ā§āĻŸ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +selectAntenna: "āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸā§‡āĻ¨āĻž āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +selectWidget: "āĻ‰āĻ‡āĻœā§‡āĻŸ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +editWidgets: "āĻ‰āĻ‡āĻœā§‡āĻŸ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" +editWidgetsExit: "āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻļā§‡āĻˇ āĻ•āĻ°ā§āĻ¨" +customEmojis: "āĻ¸ā§āĻŦāĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŋāĻ¤ āĻ‡āĻŽā§‹āĻœāĻŋāĻ—ā§āĻ˛āĻŋ" +emoji: "āĻ‡āĻŽā§‹āĻœāĻŋ" +emojis: "āĻ‡āĻŽā§‹āĻœāĻŋāĻ—ā§āĻ˛āĻŋ" +emojiName: "āĻ‡āĻŽā§‹āĻœāĻŋāĻ° āĻ¨āĻžāĻŽ" +emojiUrl: "āĻ‡āĻŽā§‹āĻœāĻŋāĻ° URL" +addEmoji: "āĻ‡āĻŽā§‹āĻœāĻŋ āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" +settingGuide: "āĻ¸ā§āĻĒāĻžāĻ°āĻŋāĻļāĻ•ā§ƒāĻ¤ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸" +cacheRemoteFiles: "āĻ°āĻŋāĻŽā§‹āĻŸ āĻĢāĻžāĻ‡āĻ˛āĻ¸āĻŽā§āĻš āĻ•ā§āĻ¯āĻžāĻļ āĻ•āĻ°ā§āĻ¨" +cacheRemoteFilesDescription: "āĻ¯āĻ–āĻ¨ āĻāĻ‡ āĻ…āĻĒāĻļāĻ¨āĻŸāĻŋ āĻŦāĻ¨ā§āĻ§ āĻĨāĻžāĻ•ā§‡ āĻ¤āĻ–āĻ¨ āĻ°āĻŋāĻŽā§‹āĻŸ āĻĢāĻžāĻ‡āĻ˛ āĻ¸āĻŽā§‚āĻš āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ āĻ°āĻŋāĻŽā§‹āĻŸ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻĨā§‡āĻ•ā§‡ āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻž āĻšā§ŸāĨ¤ āĻāĻ‡ āĻ…āĻĒāĻļāĻ¨āĻŸāĻŋ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°āĻ˛ā§‡ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻāĻ° āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻŽāĻŦā§‡ āĻ¤āĻŦā§‡ āĻĨāĻžāĻŽā§āĻŦāĻ¨ā§‡āĻ‡āĻ˛ āĻ¤ā§ˆāĻ°āĻŋ āĻ¨āĻž āĻ•āĻ°āĻžāĻ° āĻ•āĻžāĻ°āĻŖā§‡ āĻ¨ā§‡āĻŸāĻ“ā§ŸāĻžāĻ°ā§āĻ• āĻŦā§āĻ¯āĻžāĻ¨ā§āĻĄāĻ‰āĻ‡āĻĨ āĻŦā§‡āĻļā§€ āĻ˛āĻžāĻ—āĻŦā§‡āĨ¤ " +flagAsBot: "āĻŦāĻŸ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +flagAsBotDescription: "āĻāĻ‡ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻŸāĻŋ āĻ¯āĻĻāĻŋ āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ°ā§‹āĻ—ā§āĻ°āĻžāĻŽ āĻĻā§āĻŦāĻžāĻ°āĻž āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻŋāĻ¤ āĻšāĻ¯āĻŧ, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻāĻ‡ āĻ…āĻĒāĻļāĻ¨āĻŸāĻŋ āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨āĨ¤ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ…ā§āĻ¯āĻžāĻ•āĻļāĻžāĻ¨ āĻšā§‡āĻ‡āĻ¨āĻŋāĻ‚ āĻ°ā§‹āĻ§ āĻ•āĻ°āĻ¤ā§‡, āĻŽāĻŋāĻ¸ā§āĻ•āĻŋāĻ° āĻ¸āĻŋāĻ¸ā§āĻŸā§‡āĻŽ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻžāĻ•ā§‡ āĻŦāĻŸ-āĻŦāĻžāĻ¨ā§āĻ§āĻŦ āĻ•āĻ°āĻ¤ā§‡ āĻāĻŦāĻ‚ āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻĄā§‡āĻ­ā§‡āĻ˛āĻĒāĻžāĻ°āĻĻā§‡āĻ° āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ āĻ•āĻ°āĻ¤ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻŦāĻŸ āĻ āĻāĻ‡ āĻ…āĻĒāĻļāĻ¨āĻŸāĻŋ āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨ā§ˇ" +flagAsCat: "āĻŦāĻŋā§œāĻžāĻ˛ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +flagAsCatDescription: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻŸāĻŋāĻ•ā§‡ āĻŦāĻŋā§œāĻžāĻ˛ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻĒāĻļāĻ¨āĻŸāĻŋ āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨āĨ¤" +flagShowTimelineReplies: "āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋāĻ° āĻ°āĻŋāĻĒā§āĻ˛āĻžāĻ‡ āĻĻā§‡āĻ–āĻžāĻ¨" +flagShowTimelineRepliesDescription: "āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻ˛ā§‡, āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨ā§‹āĻŸ āĻ›āĻžāĻĄāĻŧāĻžāĻ“ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻ¨ā§‹āĻŸā§‡āĻ° āĻœāĻŦāĻžāĻŦāĻ—ā§āĻ˛ā§‹ āĻĻā§‡āĻ–āĻžāĻ¯āĻŧāĨ¤" +autoAcceptFollowed: "āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡āĻ¸āĻŦ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡āĻ¨, āĻ¸ā§āĻŦā§ŸāĻ‚āĻ•ā§āĻ°āĻŋā§ŸāĻ­āĻžāĻŦā§‡ āĻ¤āĻžāĻĻā§‡āĻ° āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖā§‡āĻ° āĻ…āĻ¨ā§āĻ°āĻ§ āĻ¸ā§āĻŦā§€āĻ•āĻžāĻ° āĻ•āĻ°ā§āĻ¨" +addAccount: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +loginFailed: "āĻĒā§āĻ°āĻŦā§‡āĻļ āĻ•āĻ°āĻž āĻ¯āĻžā§ŸāĻ¨āĻŋ" +showOnRemote: "āĻ°āĻŋāĻŽā§‹āĻŸ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨" +general: "āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ" +wallpaper: "āĻ“āĻ¯āĻŧāĻžāĻ˛āĻĒā§‡āĻĒāĻžāĻ°" +setWallpaper: "āĻ“āĻ¯āĻŧāĻžāĻ˛āĻĒā§‡āĻĒāĻžāĻ° āĻ¸ā§‡āĻŸ āĻ•āĻ°ā§āĻ¨" +removeWallpaper: "āĻ“ā§ŸāĻžāĻ˛āĻĒā§‡āĻĒāĻžāĻ° āĻ¸āĻ°āĻžāĻ¨" +searchWith: "āĻ–ā§āĻāĻœā§āĻ¨: {q}" +youHaveNoLists: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ•ā§‹āĻ¨ āĻ˛āĻŋāĻ¸ā§āĻŸ āĻ¨ā§‡āĻ‡" +followConfirm: "{name} āĻ•ā§‡ āĻĢāĻ˛ā§‹āĻ“ āĻ•āĻ°āĻžāĻ° āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤?" +proxyAccount: "āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ" +proxyAccountDescription: "āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻāĻŽāĻ¨ āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¯āĻž āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻļāĻ°ā§āĻ¤ā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ°āĻŋāĻŽā§‹āĻŸ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡āĨ¤ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻ¯āĻ–āĻ¨ āĻāĻ•āĻœāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻāĻ•āĻŸāĻŋ āĻ°āĻŋāĻŽā§‹āĻŸ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ•ā§‡ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻžāĻ­ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§‡, āĻ¤āĻ–āĻ¨ āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ˛āĻžāĻĒā§‡āĻ° āĻĻā§ƒāĻˇā§āĻŸāĻžāĻ¨ā§āĻ¤ā§‡ āĻŦāĻŋāĻ¤āĻ°āĻŖ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻ¨āĻž āĻ¯āĻĻāĻŋ āĻ¨āĻž āĻ•ā§‡āĻ‰ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻžāĻ­ā§āĻ•ā§āĻ¤ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡, āĻ¤āĻžāĻ‡ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻĻā§āĻŦāĻžāĻ°āĻž āĻ¤āĻžāĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤" +host: "āĻšā§‹āĻ¸ā§āĻŸ" +selectUser: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +recipient: "āĻĒā§āĻ°āĻ¤āĻŋ" +annotation: "āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯" +federation: "āĻĢā§‡āĻĄāĻŋāĻ­āĻžāĻ°ā§āĻ¸" +instances: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸" +registeredAt: "āĻ¯ā§‹āĻ— āĻĻāĻŋā§Ÿā§‡āĻ›ā§‡āĻ¨" +latestRequestSentAt: "āĻļā§‡āĻˇ āĻ°āĻŋāĻ•ā§ā§Ÿā§‡āĻ¸ā§āĻŸ āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻšā§Ÿā§‡āĻ›ā§‡" +latestRequestReceivedAt: "āĻļā§‡āĻˇ āĻ°āĻŋāĻ•ā§ā§Ÿā§‡āĻ¸ā§āĻŸ āĻ—ā§ƒāĻšā§€āĻ¤ āĻšā§Ÿā§‡āĻ›ā§‡" +latestStatus: "āĻ¸āĻ°ā§āĻŦāĻļā§‡āĻˇ āĻ…āĻŦāĻ¸ā§āĻĨāĻž" +storageUsage: "āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœā§‡āĻ° āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°" +charts: "āĻšāĻžāĻ°ā§āĻŸ" +perHour: "āĻ˜āĻ¨ā§āĻŸāĻž āĻĒā§āĻ°āĻ¤āĻŋ" +perDay: "āĻĻā§ˆāĻ¨āĻŋāĻ•" +stopActivityDelivery: "āĻ…ā§āĻ¯āĻžāĻ•ā§āĻŸāĻŋāĻ­āĻŋāĻŸāĻŋ āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨" +blockThisInstance: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻŦā§āĻ˛āĻ• āĻ•āĻ°ā§āĻ¨" +operations: "āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ˛āĻžāĻĒ" +software: "āĻ¸āĻĢāĻŸāĻ“ā§Ÿā§āĻ¯āĻžāĻ°" +version: "āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖ" +metadata: "āĻŽā§‡āĻŸāĻžāĻĄāĻžāĻŸāĻž" +withNFiles: "{n} āĻŸāĻŋ āĻĢāĻžāĻ‡āĻ˛" +monitor: "āĻŽāĻ¨āĻŋāĻŸāĻ°" +jobQueue: "āĻœāĻŦ āĻ•āĻŋāĻ‰" +cpuAndMemory: "āĻ¸āĻŋāĻĒāĻŋāĻ‰ āĻāĻŦāĻ‚ āĻŽā§‡āĻŽāĻ°āĻŋ" +network: "āĻ¨ā§‡āĻŸāĻ“ā§ŸāĻžāĻ°ā§āĻ•" +disk: "āĻĄāĻŋāĻ¸ā§āĻ•" +instanceInfo: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻ¤āĻĨā§āĻ¯" +statistics: "āĻĒāĻ°āĻŋāĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ¨" +clearQueue: "āĻ•āĻŋāĻ‰ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°ā§āĻ¨" +clearQueueConfirmTitle: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ•āĻŋāĻ‰ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°āĻžāĻ° āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤?" +clearQueueConfirmText: "āĻŦāĻŋāĻ¤āĻ°āĻŖ āĻ¨āĻž āĻ•āĻ°āĻž āĻ¨ā§‹āĻŸ āĻ†āĻ° āĻŦāĻŋāĻ¤āĻ°āĻŖ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻ¨āĻžāĨ¤ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖāĻ¤ āĻ†āĻĒāĻ¨āĻžāĻ° āĻāĻŸāĻŋ āĻ•āĻ°āĻžāĻ° āĻĻāĻ°āĻ•āĻžāĻ° āĻ¨ā§‡āĻ‡āĨ¤" +clearCachedFiles: "āĻ•ā§āĻ¯āĻžāĻļ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°ā§āĻ¨" +clearCachedFilesConfirm: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ•ā§āĻ¯āĻžāĻļ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°āĻžāĻ° āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤?" +blockedInstances: "āĻŦā§āĻ˛āĻ•āĻ•ā§ƒāĻ¤ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸āĻ¸āĻŽā§āĻš" +blockedInstancesDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸āĻ—ā§āĻ˛āĻŋ āĻŦā§āĻ˛āĻ• āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨ āĻ¤āĻžāĻ° āĻšā§‹āĻ¸ā§āĻŸāĻ¨ā§‡āĻŽāĻ—ā§āĻ˛āĻŋ āĻĒā§āĻ°āĻ¤ā§āĻ¯ā§‡āĻ•āĻŸāĻŋ āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨āĨ¤ āĻŦā§āĻ˛āĻ•āĻ•ā§ƒāĻ¤ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸āĻ—ā§āĻ˛āĻŋ āĻāĻ‡ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŦā§‡āĻ¨āĻžā§ˇ" +muteAndBlock: "āĻŽāĻŋāĻ‰āĻŸ āĻāĻŦāĻ‚ āĻŦā§āĻ˛āĻ•āĻ—ā§āĻ˛āĻŋ" +mutedUsers: "āĻ¨āĻŋāĻƒāĻļāĻŦā§āĻĻāĻ•ā§ƒāĻ¤ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€" +blockedUsers: "āĻ¯āĻžāĻĻā§‡āĻ° āĻŦā§āĻ˛āĻ• āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +noUsers: "āĻ•ā§‹āĻ¨ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ¨ā§‡āĻ‡" +editProfile: "āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" +noteDeleteConfirm: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ¨ā§‹āĻŸ āĻĄāĻŋāĻ˛āĻŋāĻŸ āĻ•āĻ°āĻžāĻ° āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤?" +pinLimitExceeded: "āĻ†āĻĒāĻ¨āĻŋ āĻ†āĻ° āĻ•ā§‹āĻ¨ āĻ¨ā§‹āĻŸ āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŦā§‡āĻ¨ āĻ¨āĻž" +intro: "Misskey āĻāĻ° āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛ā§‡āĻļāĻ¨ āĻ¸āĻŽā§āĻĒāĻ¨ā§āĻ¨ āĻšā§Ÿā§‡āĻ›ā§‡īŧāĻĻā§ŸāĻž āĻ•āĻ°ā§‡ āĻ…ā§āĻ¯āĻžāĻĄāĻŽāĻŋāĻ¨ āĻ‡āĻ‰āĻœāĻžāĻ° āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨āĨ¤" +done: "āĻ¸āĻŽā§āĻĒāĻ¨ā§āĻ¨" +processing: "āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋā§ŸāĻžāĻ§ā§€āĻ¨..." +preview: "āĻĒā§‚āĻ°ā§āĻŦāĻ°ā§‚āĻĒ āĻĻā§‡āĻ–ā§āĻ¨" +default: "āĻĒā§‚āĻ°ā§āĻŦāĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŋāĻ¤" +noCustomEmojis: "āĻ•ā§‹āĻ¨ āĻ‡āĻŽā§‹āĻœāĻŋ āĻ¨āĻžāĻ‡" +noJobs: "āĻ•ā§‹āĻ¨ āĻœāĻŦ āĻ¨āĻžāĻ‡" +federating: "āĻĢā§‡āĻĄāĻžāĻ°ā§‡āĻŸ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡" +blocked: "āĻŦā§āĻ˛āĻ• āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +suspended: "āĻ¸ā§āĻĨāĻ—āĻŋāĻ¤ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +all: "āĻ¸āĻŦāĻ—ā§āĻ˛ā§‹" +subscribing: "āĻ¸āĻĻāĻ¸ā§āĻ¯āĻ¤āĻž āĻ¨ā§‡ā§ŸāĻž āĻšāĻšā§āĻ›ā§‡" +publishing: "āĻĒā§āĻ°āĻ•āĻžāĻļ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡" +notResponding: "āĻ¸āĻžā§œāĻž āĻ¨ā§‡āĻ‡" +instanceFollowing: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡" +instanceFollowers: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€" +instanceUsers: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€" +changePassword: "āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§āĻ¨" +security: "āĻ¨āĻŋāĻ°āĻžāĻĒāĻ¤ā§āĻ¤āĻž" +retypedNotMatch: "āĻ‡āĻ¨āĻĒā§āĻŸ āĻŽā§‡āĻ˛ā§‡ āĻ¨āĻžāĨ¤" +currentPassword: "āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ āĻĒāĻžāĻ¸āĻ“ā§ŸāĻžāĻ°ā§āĻĄ" +newPassword: "āĻ¨āĻ¤ā§āĻ¨ āĻĒāĻžāĻ¸āĻ“ā§ŸāĻžāĻ°ā§āĻĄ" +newPasswordRetype: "āĻ¨āĻ¤ā§āĻ¨ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ (āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻ˛āĻŋāĻ–ā§āĻ¨)" +attachFile: "āĻĢāĻžāĻ‡āĻ˛ āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" +more: "āĻ†āĻ°āĻ“!" +featured: "āĻšāĻžāĻ‡āĻ˛āĻžāĻ‡āĻŸ" +usernameOrUserId: "āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ āĻŦāĻž āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ ID" +noSuchUser: "āĻ•ā§‹āĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ–ā§āĻāĻœā§‡ āĻĒāĻžāĻ“āĻ¯āĻŧāĻž āĻ¯āĻžāĻ¯āĻŧāĻ¨āĻŋ" +lookup: "āĻ–ā§āĻāĻœā§‡ āĻĻā§‡āĻ–ā§‹" +announcements: "āĻ˜ā§‹āĻˇāĻŖāĻž" +imageUrl: "āĻšāĻŋāĻ¤ā§āĻ°ā§‡āĻ° URL" +remove: "āĻŽā§āĻ›ā§āĻ¨" +removed: "āĻ¸āĻ°āĻžāĻ¨ā§‹ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡" +removeAreYouSure: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ \"{x}\" āĻ¸āĻ°āĻžāĻ¨ā§‹āĻ° āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤?" +deleteAreYouSure: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ \"{x}\" āĻ¸āĻ°āĻžāĻ¨ā§‹āĻ° āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤?" +resetAreYouSure: "āĻ°āĻŋāĻ¸ā§‡āĻŸ āĻ•āĻ°āĻžāĻ° āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤?" +saved: "āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŋāĻ¤ āĻšā§Ÿā§‡āĻ›ā§‡" +messaging: "āĻšā§āĻ¯āĻžāĻŸ" +upload: "āĻ†āĻĒāĻ˛ā§‹āĻĄ" +keepOriginalUploading: "āĻ†āĻ¸āĻ˛ āĻ›āĻŦāĻŋ āĻ°āĻžāĻ–ā§āĻ¨" +keepOriginalUploadingDescription: "āĻ›āĻŦāĻŋāĻŸāĻŋ āĻ†āĻĒāĻ˛ā§‹āĻĄ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ†āĻ¸āĻ˛ āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖāĻŸāĻŋ āĻ°āĻžāĻ–ā§āĻ¨āĨ¤ āĻ…āĻĒāĻļāĻ¨āĻŸāĻŋ āĻŦāĻ¨ā§āĻ§ āĻĨāĻžāĻ•āĻ˛ā§‡, āĻ†āĻĒāĻ˛ā§‹āĻĄā§‡āĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻĒā§āĻ°āĻ•āĻžāĻļāĻ¨āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ›āĻŦāĻŋ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤" +fromDrive: "āĻĄā§āĻ°āĻžāĻ‡āĻ­ āĻšāĻ¤ā§‡" +fromUrl: "URL āĻšāĻ¤ā§‡" +uploadFromUrl: "URL āĻšāĻ¤ā§‡ āĻ†āĻĒāĻ˛ā§‹āĻĄ" +uploadFromUrlDescription: "āĻ¯ā§‡ āĻĢāĻžāĻ‡āĻ˛āĻŸāĻŋ āĻ†āĻĒāĻ˛ā§‹āĻĄ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨, āĻ¸ā§‡āĻŸāĻŋāĻ° URL" +uploadFromUrlRequested: "āĻ†āĻĒāĻ˛ā§‹āĻĄ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +uploadFromUrlMayTakeTime: "URL āĻšāĻ¤ā§‡ āĻ†āĻĒāĻ˛ā§‹āĻĄ āĻšāĻ¤ā§‡ āĻ•āĻŋāĻ›ā§ āĻ¸āĻŽā§Ÿ āĻ˛āĻžāĻ—āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤" +explore: "āĻ˜ā§āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨" +messageRead: "āĻĒāĻĄāĻŧāĻž" +noMoreHistory: "āĻ†āĻ° āĻ•ā§‹āĻ¨ āĻ‡āĻ¤āĻŋāĻšāĻžāĻ¸ āĻ¨ā§‡āĻ‡" +startMessaging: "āĻšā§āĻ¯āĻžāĻŸ āĻļā§āĻ°ā§ āĻ•āĻ°ā§āĻ¨" +nUsersRead: "{n} āĻœāĻ¨ āĻĒā§œā§‡āĻ›ā§‡āĻ¨" +agreeTo: "{0} āĻāĻ° āĻĒā§āĻ°āĻ¤āĻŋ āĻ†āĻŽāĻŋ āĻ¸āĻŽā§āĻŽāĻ¤" +tos: "āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻļāĻ°ā§āĻ¤āĻžāĻĻāĻŋ" +start: "āĻļā§āĻ°ā§ āĻ•āĻ°ā§āĻ¨" +home: "āĻŽā§‚āĻ˛ āĻĒāĻžāĻ¤āĻž" +remoteUserCaution: "āĻāĻ‡ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ°āĻŋāĻŽā§‹āĻŸ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ°, āĻ¨āĻŋāĻŽā§āĻ¨āĻ•ā§āĻ¤ āĻ¤āĻĨā§āĻ¯ āĻ…āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤" +activity: "āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ˛āĻžāĻĒ" +images: "āĻ›āĻŦāĻŋ" +birthday: "āĻœāĻ¨ā§āĻŽāĻĻāĻŋāĻ¨" +yearsOld: "{age} āĻŦāĻ›āĻ°" +registeredDate: "āĻ¯ā§‹āĻ—āĻĻāĻžāĻ¨ā§‡āĻ° āĻ¤āĻžāĻ°āĻŋāĻ–" +location: "āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨" +theme: "āĻĨāĻŋāĻŽ" +themeForLightMode: "āĻ˛āĻžāĻ‡āĻŸ āĻŽā§‹āĻĄā§‡āĻ° āĻĨāĻŋāĻŽ" +themeForDarkMode: "āĻĄāĻžāĻ°ā§āĻ• āĻŽā§‹āĻĄā§‡āĻ° āĻĨāĻŋāĻŽ" +light: "āĻ†āĻ˛ā§‹āĻ•āĻŋāĻ¤" +dark: "āĻ…āĻ¨ā§āĻ§āĻ•āĻžāĻ°" +lightThemes: "āĻ†āĻ˛ā§‹āĻ•āĻŋāĻ¤ āĻĨāĻŋāĻŽ" +darkThemes: "āĻ…āĻ¨ā§āĻ§āĻ•āĻžāĻ° āĻĨāĻŋāĻŽ" +syncDeviceDarkMode: "āĻĄāĻŋāĻ­āĻžāĻ‡āĻ¸ā§‡āĻ° āĻ¸ā§‡āĻŸāĻŋāĻ‚ āĻ…āĻ¨ā§āĻ¯āĻžā§Ÿā§€ āĻĄāĻžāĻ°ā§āĻ• āĻŽā§‹āĻĄ āĻ¸ā§‡āĻŸ āĻ•āĻ°ā§āĻ¨" +drive: "āĻĄā§āĻ°āĻžāĻ‡āĻ­" +fileName: "āĻĢāĻžāĻ‡āĻ˛ā§‡āĻ° āĻ¨āĻžāĻŽ" +selectFile: "āĻĢāĻžāĻ‡āĻ˛ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +selectFiles: "āĻĢāĻžāĻ‡āĻ˛ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +selectFolder: "āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ° āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +selectFolders: "āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ° āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +renameFile: "āĻĢāĻžāĻ‡āĻ˛ āĻĒā§āĻ¨āĻƒāĻ¨āĻžāĻŽāĻ•āĻ°āĻ¨" +folderName: "āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°ā§‡āĻ° āĻ¨āĻžāĻŽ" +createFolder: "āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ° āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +renameFolder: "āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ° āĻĒā§āĻ¨āĻƒāĻ¨āĻžāĻŽāĻ•āĻ°āĻ¨" +deleteFolder: "āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ° āĻŽā§āĻ›ā§āĻ¨" +addFile: "āĻĢāĻžāĻ‡āĻ˛ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +emptyDrive: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻĄā§āĻ°āĻžāĻ‡āĻ­ āĻ–āĻžāĻ˛āĻŋ" +emptyFolder: "āĻāĻ‡ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ° āĻ–āĻžāĻ˛āĻŋ" +unableToDelete: "āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻž āĻ¯āĻžā§ŸāĻ¨āĻŋ" +inputNewFileName: "āĻĢāĻžāĻ‡āĻ˛ā§‡āĻ° āĻ¨āĻ¤ā§āĻ¨ āĻ¨āĻžāĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨" +inputNewDescription: "āĻ¨āĻ¤ā§āĻ¨ āĻ•ā§āĻ¯āĻžāĻĒāĻļāĻ¨ āĻ˛āĻŋāĻ–ā§āĻ¨" +inputNewFolderName: "āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°ā§‡āĻ° āĻ¨āĻ¤ā§āĻ¨ āĻ¨āĻžāĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨" +circularReferenceFolder: "āĻ—āĻ¨ā§āĻ¤āĻŦā§āĻ¯ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°āĻŸāĻŋ āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°āĻŸāĻŋ āĻ¸āĻ°āĻžāĻ¤ā§‡ āĻšāĻžāĻ¨ āĻ¤āĻžāĻ° āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻŦāĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°āĨ¤" +hasChildFilesOrFolders: "āĻāĻ‡ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°āĻŸāĻŋ āĻ–āĻžāĻ˛āĻŋ āĻ¨āĻž āĻšāĻ“ā§ŸāĻžā§Ÿ āĻĄāĻŋāĻ˛āĻŋāĻŸ āĻ•āĻ°āĻž āĻ¯āĻžā§ŸāĻ¨āĻŋāĨ¤" +copyUrl: "URL āĻ•āĻĒāĻŋ āĻ•āĻ°ā§āĻ¨" +rename: "āĻĒā§āĻ¨āĻƒāĻ¨āĻžāĻŽāĻ•āĻ°āĻŖ" +avatar: "āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛ āĻ›āĻŦāĻŋ" +banner: "āĻŦā§āĻ¯āĻžāĻ¨āĻžāĻ°" +nsfw: "āĻ¸āĻ‚āĻŦā§‡āĻĻāĻ¨āĻļā§€āĻ˛ āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§" +whenServerDisconnected: "āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻŦāĻŋāĻšā§āĻ›āĻŋāĻ¨ā§āĻ¨ āĻšāĻ¯āĻŧā§‡ āĻ—ā§‡āĻ˛ā§‡" +disconnectedFromServer: "āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻĨā§‡āĻ•ā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻŦāĻŋāĻšā§āĻ›āĻŋāĻ¨ā§āĻ¨ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡" +reload: "āĻ†āĻŦāĻžāĻ° āĻ˛ā§‹āĻĄ āĻ•āĻ°ā§āĻ¨" +doNothing: "āĻ•āĻŋāĻ›ā§ āĻ•āĻ°āĻŦā§‡āĻ¨ āĻ¨āĻž" +reloadConfirm: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ°āĻŋāĻ˛ā§‹āĻĄ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +watch: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ āĻĒāĻžāĻ¨" +unwatch: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ āĻĒāĻžāĻ“ā§ŸāĻž āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨ " +accept: "āĻ…āĻ¨ā§āĻŽā§‹āĻĻāĻ¨" +reject: "āĻĒā§āĻ°āĻ¤ā§āĻ¯āĻžāĻ–ā§āĻ¯āĻžāĻ¨" +normal: "āĻ¸ā§āĻŦāĻžāĻ­āĻžāĻŦāĻŋāĻ•" +instanceName: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻ¨āĻžāĻŽ" +instanceDescription: "āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻŦāĻ°ā§āĻŖāĻ¨āĻž" +maintainerName: "āĻŽā§‡āĻ‡āĻ¨āĻŸā§‡āĻ‡āĻ¨āĻžāĻ°" +maintainerEmail: "āĻŽā§‡āĻ‡āĻ¨āĻŸā§‡āĻ‡āĻ¨āĻžāĻ°ā§‡āĻ° āĻ‡āĻŽā§‡āĻ‡āĻ˛" +tosUrl: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°ā§‡āĻ° āĻļāĻ°ā§āĻ¤āĻžāĻŦāĻ˛ā§€āĻ° URL" +thisYear: "āĻŦāĻ›āĻ°" +thisMonth: "āĻŽāĻžāĻ¸" +today: "āĻ†āĻœ" +dayX: "{day}" +monthX: "{month}" +yearX: "{year}" +pages: "āĻĒā§ƒāĻˇā§āĻ āĻž" +integration: "āĻ‡āĻ¨ā§āĻŸāĻŋāĻ—ā§āĻ°ā§‡āĻļāĻ¨" +connectService: "āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" +disconnectService: "āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻŦāĻŋāĻšā§āĻ›āĻŋāĻ¨ā§āĻ¨ āĻ•āĻ°ā§āĻ¨" +enableLocalTimeline: "āĻ¸ā§āĻĨāĻžāĻ¨ā§€ā§Ÿ āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨" +enableGlobalTimeline: "āĻ—ā§āĻ˛ā§‹āĻŦāĻžāĻ˛ āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨" +disablingTimelinesInfo: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ‡ āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨āĻ—ā§āĻ˛āĻŋ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°āĻ˛ā§‡āĻ“ āĻĒā§āĻ°āĻļāĻžāĻ¸āĻ• āĻāĻŦāĻ‚ āĻŽāĻĄāĻžāĻ°ā§‡āĻŸāĻ°āĻ°āĻž āĻāĻ‡ āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨āĻ—ā§āĻ˛āĻŋ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŦā§‡" +registration: "āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨" +enableRegistration: "āĻ¨āĻ¤ā§āĻ¨ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨ āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨" +invite: "āĻ†āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻŖ" +proxyRemoteFiles: "āĻ°āĻŋāĻŽā§‹āĻŸ āĻĢāĻžāĻ‡āĻ˛āĻ¸āĻŽā§āĻš āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ•āĻ°ā§āĻ¨" +proxyRemoteFilesDescription: "āĻ¯āĻ–āĻ¨ āĻāĻ‡ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻŸāĻŋ āĻšāĻžāĻ˛ā§ āĻĨāĻžāĻ•ā§‡, āĻ¤āĻ–āĻ¨ āĻ…āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŋāĻ¤ āĻŦāĻž āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻ•ā§āĻˇāĻŽāĻ¤āĻžāĻ° āĻ•āĻžāĻ°āĻŖā§‡ āĻĻā§‚āĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻĢāĻžāĻ‡āĻ˛āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧāĻ­āĻžāĻŦā§‡ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻĨāĻžāĻŽā§āĻŦāĻ¨ā§‡āĻ˛āĻ—ā§āĻ˛āĻŋāĻ“ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻšāĻŦā§‡ā§ˇ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ¨āĻž," +driveCapacityPerLocalAccount: "āĻĒā§āĻ°āĻ¤ā§āĻ¯ā§‡āĻ• āĻ¸ā§āĻĨāĻžāĻ¨ā§€ā§Ÿ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻœāĻ¨ā§āĻ¯ āĻĄā§āĻ°āĻžāĻ‡āĻ­ā§‡āĻ° āĻœāĻžā§ŸāĻ—āĻž" +driveCapacityPerRemoteAccount: "āĻĒā§āĻ°āĻ¤ā§āĻ¯ā§‡āĻ• āĻ°āĻŋāĻŽā§‹āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻœāĻ¨ā§āĻ¯ āĻĄā§āĻ°āĻžāĻ‡āĻ­ā§‡āĻ° āĻœāĻžā§ŸāĻ—āĻž" +inMb: "āĻŽā§‡āĻ—āĻžāĻŦāĻžāĻ‡āĻŸā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨" +iconUrl: "āĻ†āĻ‡āĻ•āĻ¨ā§‡āĻ° URL (āĻĢā§āĻ¯āĻžāĻ­āĻŋāĻ•āĻ¨, āĻ‡āĻ¤ā§āĻ¯āĻžāĻĻāĻŋ)" +bannerUrl: "āĻŦā§āĻ¯āĻžāĻ¨āĻžāĻ° āĻ›āĻŦāĻŋāĻ° URL" +backgroundImageUrl: "āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋāĻ° āĻšāĻŋāĻ¤ā§āĻ°ā§‡āĻ° URL" +basicInfo: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻŦā§āĻ¯āĻ•ā§āĻ¤āĻŋāĻ—āĻ¤ āĻ¤āĻĨā§āĻ¯" +pinnedUsers: "āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻž āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ—āĻŖ" +pinnedUsersDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡āĻ¸āĻŦ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° \"āĻ˜ā§āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨\" āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¯āĻŧ āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨ āĻ¤āĻžāĻĻā§‡āĻ° āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°ā§āĻ¨, āĻĒā§āĻ°āĻ¤ā§āĻ¯ā§‡āĻ•ā§‡āĻ° āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨" +pinnedPages: "āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻž āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¸ā§āĻŽāĻš" +pinnedPagesDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡āĻ¸āĻ•āĻ˛ āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¸āĻŽā§‚āĻšāĻ•ā§‡ \"āĻ˜ā§āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨\" āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¯āĻŧ āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨ āĻ¤āĻžāĻĻā§‡āĻ° āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°ā§āĻ¨, āĻĒā§āĻ°āĻ¤ā§āĻ¯ā§‡āĻ•ā§‡āĻ° āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨" +pinnedClipId: "āĻĒāĻŋāĻ¨āĻ•ā§ƒāĻ¤ āĻ•ā§āĻ˛āĻŋāĻĒā§‡āĻ° ID" +pinnedNotes: "āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻž āĻ¨ā§‹āĻŸ" +hcaptcha: "hCaptcha" +enableHcaptcha: "hCaptcha āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨" +hcaptchaSiteKey: "āĻ¸āĻžāĻ‡āĻŸ āĻ•ā§€" +hcaptchaSecretKey: "āĻ¸āĻŋāĻ•ā§āĻ°ā§‡āĻŸ āĻ•ā§€" +recaptcha: "reCAPTCHA" +enableRecaptcha: "reCAPTCHA āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨" +recaptchaSiteKey: "āĻ¸āĻžāĻ‡āĻŸ āĻ•ā§€" +recaptchaSecretKey: "āĻ¸āĻŋāĻ•ā§āĻ°ā§‡āĻŸ āĻ•ā§€" +avoidMultiCaptchaConfirm: "āĻāĻ•āĻžāĻ§āĻŋāĻ• Captcha āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ˛ā§‡ āĻ¤āĻžāĻ°āĻž āĻĒāĻ°āĻ¸ā§āĻĒāĻ°ā§‡āĻ° āĻ•āĻžāĻœā§‡ āĻŦāĻžāĻ§āĻž āĻĻāĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ Captcha āĻ¨āĻŋāĻˇā§āĻ•ā§āĻ°āĻŋāĻ¯āĻŧ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨? āĻ†āĻĒāĻ¨āĻŋ 'āĻŦāĻžāĻ¤āĻŋāĻ˛' āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°āĻžāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻāĻ•āĻžāĻ§āĻŋāĻ• Captcha āĻšāĻžāĻ˛ā§ āĻ°āĻžāĻ–āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" +antennas: "āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸā§‡āĻ¨āĻž" +manageAntennas: "āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸā§‡āĻ¨āĻž āĻŦā§āĻ¯āĻŦāĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻž" +name: "āĻ¨āĻžāĻŽ" +antennaSource: "āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸā§‡āĻ¨āĻžāĻ° āĻ‰ā§ŽāĻ¸" +antennaKeywords: "āĻ¯ā§‡āĻ¸āĻŦ āĻ•ā§€āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻĻā§‡āĻ–āĻž āĻšāĻŦā§‡" +antennaExcludeKeywords: "āĻ¯ā§‡āĻ¸āĻŦ āĻ•ā§€āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻĻā§‡āĻ–āĻž āĻšāĻŦā§‡ āĻ¨āĻž" +antennaKeywordsDescription: "āĻ¸ā§āĻĒā§‡āĻ¸ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ•āĻ°āĻ˛ā§‡ AND āĻļāĻ°ā§āĻ¤ āĻ¤ā§ˆāĻ°āĻŋ āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–āĻ˛ā§‡ OR āĻļāĻ°ā§āĻ¤ āĻ¤ā§ˆāĻ°āĻŋ āĻšāĻŦā§‡āĨ¤" +notifyAntenna: "āĻ¨āĻ¤ā§āĻ¨ āĻ¨ā§‹āĻŸ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ…āĻŦāĻšāĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +withFileAntenna: "āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻĢāĻžāĻ‡āĻ˛āĻ¯ā§āĻ•ā§āĻ¤ āĻ¨ā§‹āĻŸ" +enableServiceworker: "ServiceWorker āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨" +antennaUsersDescription: "āĻĒā§āĻ°āĻ¤ā§āĻ¯ā§‡āĻ• āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻāĻ•āĻœāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨" +caseSensitive: "āĻ›ā§‹āĻŸ āĻšāĻžāĻ¤ā§‡āĻ° āĻāĻŦāĻ‚ āĻŦā§œ āĻšāĻžāĻ¤ā§‡āĻ° āĻ…āĻ•ā§āĻˇāĻ° āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻ°ā§āĻ¨" +withReplies: "āĻœāĻŦāĻžāĻŦāĻ¸āĻŽā§āĻš āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" +connectedTo: "āĻ†āĻĒāĻ¨āĻŋ āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤" +notesAndReplies: "āĻ¨ā§‹āĻŸāĻ¸āĻŽā§‚āĻš āĻāĻŦāĻ‚ āĻœāĻŦāĻžāĻŦāĻ—ā§āĻ˛āĻŋ" +withFiles: "āĻĢāĻžāĻ‡āĻ˛āĻ—ā§āĻ˛āĻŋ āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" +silence: "āĻ¨ā§€āĻ°āĻŦ" +silenceConfirm: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻāĻ‡ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ•ā§‡āĻ° āĻ¨ā§€āĻ°āĻŦ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +unsilence: "āĻ¸āĻ°āĻŦ" +unsilenceConfirm: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻāĻ‡ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ•ā§‡āĻ° āĻ¸āĻ°āĻŦ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +popularUsers: "āĻœāĻ¨āĻĒā§āĻ°āĻŋāĻ¯āĻŧ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ—āĻ¨" +recentlyUpdatedUsers: "āĻ¸āĻŽā§āĻĒā§āĻ°āĻ¤āĻŋ āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°āĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ—āĻ¨" +recentlyRegisteredUsers: "āĻ¨āĻ¤ā§āĻ¨ āĻ¯ā§‹āĻ— āĻĻā§‡āĻ“ā§ŸāĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ—āĻ¨" +recentlyDiscoveredUsers: "āĻ¨āĻ¤ā§āĻ¨ āĻ–ā§āĻāĻœā§‡ āĻĒāĻžāĻ“ā§ŸāĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ—āĻ¨" +exploreUsersCount: "{count} āĻœāĻ¨ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€" +exploreFediverse: "Fediverse āĻ˜ā§āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨" +popularTags: "āĻœāĻ¨āĻĒā§āĻ°āĻŋā§Ÿ āĻŸā§āĻ¯āĻžāĻ—āĻ—ā§āĻ˛āĻŋ" +userList: "āĻ˛āĻŋāĻ¸ā§āĻŸ" +about: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡" +aboutMisskey: "Misskey āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡" +administrator: "āĻĒā§āĻ°āĻļāĻžāĻ¸āĻ•" +token: "āĻŸā§‹āĻ•ā§‡āĻ¨" +twoStepAuthentication: "ā§¨-āĻ§āĻžāĻĒ āĻĒā§āĻ°āĻŽāĻžāĻŖā§€āĻ•āĻ°āĻŖ" +moderator: "āĻŽāĻĄāĻžāĻ°ā§‡āĻŸāĻ°" +nUsersMentioned: "{n} āĻœāĻ¨āĻ•ā§‡ āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ– āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +securityKey: "āĻ¸āĻŋāĻ•āĻŋāĻ‰āĻ°āĻŋāĻŸāĻŋ āĻ•ā§€" +securityKeyName: "āĻ•ā§€'āĻ° āĻ¨āĻžāĻŽ" +registerSecurityKey: "āĻ¸āĻŋāĻ•āĻŋāĻ‰āĻ°āĻŋāĻŸāĻŋ āĻ•ā§€ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨ āĻ•āĻ°ā§āĻ¨" +lastUsed: "āĻļā§‡āĻˇ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +unregister: "āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨āĻŽā§āĻ•ā§āĻ¤ āĻšāĻ¨" +passwordLessLogin: "āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ-āĻŦāĻŋāĻšā§€āĻ¨ āĻ˛āĻ—āĻ‡āĻ¨ āĻ¸ā§‡āĻŸ āĻ†āĻĒ āĻ•āĻ°ā§āĻ¨" +resetPassword: "āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ°āĻŋāĻ¸ā§‡āĻŸ āĻ•āĻ°ā§āĻ¨" +newPasswordIs: "āĻ¨āĻ¤ā§āĻ¨ āĻĒāĻžāĻ¸āĻ“ā§ŸāĻžāĻ°ā§āĻĄ āĻšāĻšā§āĻ›ā§‡ \"{password}\"" +reduceUiAnimation: "UI āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ āĻ•āĻŽāĻžāĻ¨" +share: "āĻļā§‡ā§ŸāĻžāĻ°" +notFound: "āĻĒāĻžāĻ“ā§ŸāĻž āĻ¯āĻžā§ŸāĻ¨āĻŋ" +notFoundDescription: "āĻāĻ‡ URL-āĻāĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāĻ¤ āĻ•ā§‹āĻ¨ā§‹ āĻĒā§ƒāĻˇā§āĻ āĻž āĻ¨ā§‡āĻ‡āĨ¤" +uploadFolder: "āĻ†āĻĒāĻ˛ā§‹āĻĄā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°" +cacheClear: "āĻ•ā§āĻ¯āĻžāĻļ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°ā§āĻ¨" +markAsReadAllNotifications: "āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋāĻ—ā§āĻ˛āĻŋ āĻĒāĻ āĻŋāĻ¤ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +markAsReadAllUnreadNotes: "āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻĒāĻ āĻŋāĻ¤ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +markAsReadAllTalkMessages: "āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻŽā§‡āĻ¸ā§‡āĻœ āĻĒāĻ āĻŋāĻ¤ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +help: "āĻ¸āĻšāĻžāĻ¯āĻŧāĻ¤āĻž" +inputMessageHere: "āĻāĻ–āĻžāĻ¨ā§‡ āĻŽā§‡āĻ¸ā§‡āĻœ āĻ˛āĻŋāĻ–ā§āĻ¨" +close: "āĻŦāĻ¨ā§āĻ§" +group: "āĻ—ā§āĻ°ā§āĻĒ" +groups: "āĻ—ā§āĻ°ā§āĻĒāĻ¸āĻŽā§‚āĻš" +createGroup: "āĻ—ā§āĻ°ā§āĻĒ āĻ¤ā§ˆāĻ°ā§€ āĻ•āĻ°ā§āĻ¨" +ownedGroups: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ—ā§āĻ°ā§āĻĒāĻ—ā§āĻ˛āĻŋ" +joinedGroups: "āĻ¯ā§‡āĻ¸āĻŦ āĻ—ā§āĻ°ā§āĻĒā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ†āĻ›ā§‡āĻ¨" +invites: "āĻ†āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻŖ" +groupName: "āĻ—ā§āĻ°ā§āĻĒā§‡āĻ° āĻ¨āĻžāĻŽ" +members: "āĻ¸āĻĻāĻ¸ā§āĻ¯āĻŦā§ƒāĻ¨ā§āĻĻ" +transfer: "āĻšāĻ¸ā§āĻ¤āĻžāĻ¨ā§āĻ¤āĻ°" +messagingWithUser: "āĻĒā§āĻ°āĻžāĻ‡āĻ­ā§‡āĻŸ āĻšā§āĻ¯āĻžāĻŸ" +messagingWithGroup: "āĻ—ā§āĻ°ā§āĻĒ āĻšā§āĻ¯āĻžāĻŸ" +title: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" +text: "āĻĒāĻžāĻ ā§āĻ¯" +enable: "āĻ¸āĻ•ā§āĻ°āĻŋā§Ÿ" +next: "āĻĒāĻ°āĻŦāĻ°ā§āĻ¤ā§€" +retype: "āĻĒā§āĻ¨āĻƒ āĻĒā§āĻ°āĻŦā§‡āĻļ" +noteOf: "{user} āĻāĻ° āĻ¨ā§‹āĻŸ" +inviteToGroup: "āĻ—ā§āĻ°ā§āĻĒā§‡ āĻ†āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻŖ āĻœāĻžāĻ¨āĻžāĻ¨" +maxNoteTextLength: "āĻ¨ā§‹āĻŸ āĻāĻ° āĻ¸āĻ°ā§āĻŦā§‹āĻšā§āĻš āĻĻā§ˆāĻ°ā§āĻ˜ā§āĻ¯" +quoteAttached: "āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤" +quoteQuestion: "āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤āĻŋ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻŦā§‡āĻ¨?" +noMessagesYet: "āĻ•ā§‹āĻ¨ āĻŽā§‡āĻ¸ā§‡āĻœ āĻ¨ā§‡āĻ‡" +newMessageExists: "āĻ¨āĻ¤ā§āĻ¨ āĻŽā§‡āĻ¸ā§‡āĻœ āĻĒā§‡ā§Ÿā§‡āĻ›ā§‡āĻ¨" +onlyOneFileCanBeAttached: "āĻ†āĻĒāĻ¨āĻŋ āĻŽā§‡āĻ¸ā§‡āĻœā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻ°ā§āĻŦā§‹āĻšā§āĻš āĻāĻ•āĻŸāĻŋ āĻĢāĻžāĻ‡āĻ˛ āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŦā§‡āĻ¨" +signinRequired: "āĻĻāĻ¯āĻŧāĻž āĻ•āĻ°ā§‡ āĻ˛āĻ— āĻ‡āĻ¨ āĻ•āĻ°ā§āĻ¨" +invitations: "āĻ†āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻŖ" +invitationCode: "āĻ‡āĻ¨āĻ­āĻžāĻ‡āĻŸ āĻ•ā§‹āĻĄ" +checking: "āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡..." +available: "āĻ‰āĻĒāĻ˛āĻŦā§āĻ§" +unavailable: "āĻ…āĻ¨ā§āĻĒāĻ˛āĻŦā§āĻ§" +usernameInvalidFormat: "āĻ†āĻĒāĻ¨āĻŋ āĻ•ā§‡āĻŦāĻ˛āĻŽāĻžāĻ¤ā§āĻ° a-z, A-Z, 0-9, _ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨" +tooShort: "āĻ–ā§āĻŦ āĻ›ā§‹āĻŸ" +tooLong: "āĻ–ā§āĻŦ āĻŦā§œ" +weakPassword: "āĻĻā§āĻ°ā§āĻŦāĻ˛ āĻĒāĻžāĻ¸āĻ“ā§ŸāĻžāĻ°ā§āĻĄ" +normalPassword: "āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻĒāĻžāĻ¸āĻ“ā§ŸāĻžāĻ°ā§āĻĄ" +strongPassword: "āĻļāĻ•ā§āĻ¤āĻŋāĻļāĻžāĻ˛ā§€ āĻĒāĻžāĻ¸āĻ“ā§ŸāĻžāĻ°ā§āĻĄ" +passwordMatched: "āĻŽāĻŋāĻ˛ā§‡āĻ›ā§‡" +passwordNotMatched: "āĻŽāĻŋāĻ˛ā§‡āĻ¨āĻŋ" +signinWith: "{x} āĻāĻ° āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ā§‡ āĻ¸āĻžāĻ‡āĻ¨ āĻ‡āĻ¨ āĻ•āĻ°ā§āĻ¨" +signinFailed: "āĻ˛āĻ— āĻ‡āĻ¨ āĻ•āĻ°āĻž āĻ¯āĻžāĻ¯āĻŧāĻ¨āĻŋāĨ¤ āĻ†āĻĒāĻ¨āĻžāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ āĻāĻŦāĻ‚ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻšā§‡āĻ• āĻ•āĻ°ā§āĻ¨." +tapSecurityKey: "āĻ¸āĻŋāĻ•āĻŋāĻ‰āĻ°āĻŋāĻŸāĻŋ āĻ•ā§€ āĻ¸ā§āĻĒāĻ°ā§āĻļ āĻ•āĻ°ā§āĻ¨" +or: "āĻ…āĻĨāĻŦāĻž" +language: "āĻ­āĻžāĻˇāĻž" +uiLanguage: "UI āĻāĻ° āĻ­āĻžāĻˇāĻž" +groupInvited: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ āĻ—ā§āĻ°ā§āĻĒā§‡ āĻ†āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻŋāĻ¤ āĻšā§Ÿā§‡āĻ›ā§‡āĻ¨" +aboutX: "{x} āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡" +useOsNativeEmojis: "āĻ…āĻĒāĻžāĻ°ā§‡āĻŸāĻŋāĻ‚ āĻ¸āĻŋāĻ¸ā§āĻŸā§‡āĻŽā§‡āĻ° āĻ¨ā§‡āĻŸāĻŋāĻ­ āĻ‡āĻŽā§‹āĻœāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +disableDrawer: "āĻĄā§āĻ°āĻ¯āĻŧāĻžāĻ° āĻŽā§‡āĻ¨ā§ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°āĻŦā§‡āĻ¨ āĻ¨āĻž" +youHaveNoGroups: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ•ā§‹āĻ¨ āĻ—ā§āĻ°ā§āĻĒ āĻ¨ā§‡āĻ‡ " +joinOrCreateGroup: "āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨ āĻ—ā§āĻ°ā§āĻĒā§‡āĻ° āĻ†āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻŖ āĻĒāĻžāĻ¨ āĻŦāĻž āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻ—ā§āĻ°ā§āĻĒ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨ā§ˇ" +noHistory: "āĻ•ā§‹āĻ¨ā§‹ āĻ‡āĻ¤āĻŋāĻšāĻžāĻ¸ āĻ¨ā§‡āĻ‡" +signinHistory: "āĻĒā§āĻ°āĻŦā§‡āĻļ āĻ•āĻ°āĻžāĻ° āĻ‡āĻ¤āĻŋāĻšāĻžāĻ¸" +disableAnimatedMfm: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻŸā§‡āĻĄ MFM āĻ…āĻ•ā§āĻˇāĻŽ āĻ•āĻ°ā§āĻ¨" +doing: "āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋā§ŸāĻž āĻ•āĻ°āĻ›ā§‡..." +category: "āĻŦāĻŋāĻ­āĻžāĻ—" +tags: "āĻŸâ€ā§āĻ¯āĻžāĻ—āĻ¸āĻŽā§‚āĻš" +docSource: "āĻĄāĻ•ā§āĻŽā§‡āĻ¨ā§āĻŸā§‡āĻ° āĻ‰ā§ŽāĻ¸" +createAccount: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +existingAccount: "āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ" +regenerate: "āĻ†āĻŦāĻžāĻ°āĻ“ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +fontSize: "āĻĢāĻ¨ā§āĻŸā§‡āĻ° āĻ†āĻ•āĻžāĻ°" +noFollowRequests: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ•ā§‹āĻ¨ āĻĢāĻ˛ā§‹āĻ“ āĻ°āĻŋāĻ•ā§ā§Ÿā§‡āĻ¸ā§āĻŸ āĻ¨ā§‡āĻ‡" +openImageInNewTab: "āĻ›āĻŦāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻŸā§āĻ¯āĻžāĻŦā§‡ āĻ–ā§āĻ˛ā§āĻ¨" +dashboard: "āĻĄā§āĻ¯āĻžāĻļāĻŦā§‹āĻ°ā§āĻĄ" +local: "āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ" +remote: "āĻ°āĻŋāĻŽā§‹āĻŸ" +total: "āĻŽā§‹āĻŸ" +weekOverWeekChanges: "āĻ—āĻ¤ āĻ¸āĻĒā§āĻ¤āĻžāĻšā§‡" +dayOverDayChanges: "āĻ—āĻ¤āĻ•āĻžāĻ˛" +appearance: "āĻ…āĻŦā§ŸāĻŦ" +clientSettings: "āĻ•ā§āĻ˛āĻžā§Ÿā§‡āĻ¨ā§āĻŸ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸" +accountSettings: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸" +promotion: "āĻĒā§āĻ°āĻŽā§‹āĻļāĻ¨" +promote: "āĻĒā§āĻ°āĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +numberOfDays: "āĻĻāĻŋāĻ¨ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +hideThisNote: "āĻ¨ā§‹āĻŸāĻŸāĻŋ āĻ˛ā§āĻ•āĻžāĻ¨" +showFeaturedNotesInTimeline: "āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ¸ā§āĻĒāĻžāĻ°āĻŋāĻļāĻ•ā§ƒāĻ¤ āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–āĻžāĻ¨" +objectStorage: "āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ" +useObjectStorage: "āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +objectStorageBaseUrl: "Base URL" +objectStorageBaseUrlDesc: "āĻ°ā§‡āĻĢāĻžāĻ°ā§‡āĻ¨ā§āĻ¸ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤ URLāĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ CDN āĻŦāĻž āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ˛ā§‡ URL, S3: 'https://.s3.amazonaws.com', GCS: 'https://storage.googleapis.com/'āĨ¤" +objectStorageBucket: "Bucket" +objectStorageBucketDesc: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° bucket āĻāĻ° āĻ¨āĻžāĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨āĨ¤ " +objectStoragePrefix: "Prefix" +objectStoragePrefixDesc: "āĻĢāĻžāĻ‡āĻ˛āĻ¸āĻŽā§‚āĻš āĻāĻ‡ prefix āĻ¯ā§āĻ•ā§āĻ¤ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°ā§‡āĻ° āĻ…āĻ§ā§€āĻ¨ā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤" +objectStorageEndpoint: "āĻāĻ¨ā§āĻĄāĻĒā§Ÿā§‡āĻ¨ā§āĻŸ" +objectStorageEndpointDesc: "S3 āĻāĻ° āĻœāĻ¨ā§āĻ¯ āĻĢāĻžāĻāĻ•āĻž āĻ°āĻžāĻ–ā§āĻ¨, āĻ…āĻ¨ā§āĻ¯āĻĨāĻžāĻ¯āĻŧ āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻāĻ¨ā§āĻĄāĻĒā§Ÿā§‡āĻ¨ā§āĻŸ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻ°ā§āĻ¨āĨ¤ ''āĻŦāĻž': ' āĻšāĻŋāĻ¸ā§‡āĻŦā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨āĨ¤" +objectStorageRegion: "Region" +objectStorageRegionDesc: "'xx-east-1'-āĻāĻ° āĻŽāĻ¤ā§‹ āĻāĻ•āĻŸāĻŋ region āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻ°ā§āĻ¨āĨ¤ āĻ¯āĻĻāĻŋ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ¤ā§‡ region āĻāĻ° āĻ§āĻžāĻ°āĻŖāĻž āĻ¨āĻž āĻĨāĻžāĻ•ā§‡, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻāĻŸāĻŋ āĻ–āĻžāĻ˛āĻŋ āĻŦāĻž 'us-east-1' āĻšāĻ“āĻ¯āĻŧāĻž āĻ‰āĻšāĻŋāĻ¤āĨ¤" +objectStorageUseSSL: "SSL āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +objectStorageUseSSLDesc: "API āĻ•āĻžāĻ¨ā§‡āĻ•āĻļāĻ¨āĻ—ā§āĻ˛āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻ¯āĻĻāĻŋ https āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ¨āĻž āĻ•āĻ°ā§‡āĻ¨, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻāĻ‡ āĻ…āĻĒāĻļāĻ¨āĻŸāĻŋ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨" +objectStorageUseProxy: "Proxy āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +objectStorageUseProxyDesc: "āĻ†āĻĒāĻ¨āĻŋ API āĻ¸āĻ‚āĻ¯ā§‹āĻ—ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ proxy āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ¨āĻž āĻ•āĻ°āĻ˛ā§‡, āĻāĻŸāĻŋ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨āĨ¤" +objectStorageSetPublicRead: "āĻ†āĻĒāĻ˛ā§‹āĻĄā§‡āĻ° āĻ‰āĻĒāĻ° ''public-read' āĻ¸ā§‡āĻŸ āĻ•āĻ°ā§āĻ¨" +serverLogs: "āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻ˛āĻ—" +deleteAll: "āĻ¸āĻŦ āĻŽā§āĻ›ā§āĻ¨" +showFixedPostForm: "āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ā§‡āĻ° āĻļā§€āĻ°ā§āĻˇā§‡ āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°āĻžāĻ° āĻĢāĻ°ā§āĻŽāĻŸāĻŋ āĻĻā§‡āĻ–āĻžāĻ¨" +newNoteRecived: "āĻ¨āĻ¤ā§āĻ¨ āĻ¨ā§‹āĻŸ āĻ†āĻ›ā§‡" +sounds: "āĻļāĻŦā§āĻĻ" +listen: "āĻļā§āĻ¨ā§āĻ¨" +none: "āĻ•āĻŋāĻ›ā§āĻ‡ āĻ¨āĻž" +showInPage: "āĻĒā§‡āĻœā§‡ āĻĻā§‡āĻ–āĻžāĻ¨" +popout: "āĻĒāĻĒ-āĻ†āĻ‰āĻŸ" +volume: "āĻ†āĻ“ā§ŸāĻžāĻœā§‡āĻ° āĻŽāĻžāĻ¤ā§āĻ°āĻž" +masterVolume: "āĻŽāĻžāĻ¸ā§āĻŸāĻžāĻ° āĻ†āĻ“ā§ŸāĻžāĻœā§‡āĻ° āĻŽāĻžāĻ¤ā§āĻ°āĻž" +details: "āĻ†āĻ°āĻ“ āĻœāĻžāĻ¨ā§āĻ¨" +chooseEmoji: "āĻ‡āĻŽā§‹āĻœāĻŋ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" +unableToProcess: "āĻ•āĻžāĻœāĻŸāĻŋ āĻ¸āĻŽā§āĻĒāĻ¨ā§āĻ¨ āĻ•āĻ°āĻž āĻ¯āĻžā§ŸāĻ¨āĻŋ" +recentUsed: "āĻ¸āĻŽā§āĻĒā§āĻ°āĻ¤āĻŋ āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤" +install: "āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛" +uninstall: "āĻ†āĻ¨āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛" +installedApps: "āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛ āĻ•āĻ°āĻž āĻ…ā§āĻ¯āĻžāĻĒāĻ¸āĻŽā§‚āĻš" +nothing: "āĻāĻ–āĻžāĻ¨ā§‡ āĻ•āĻŋāĻ›ā§āĻ‡ āĻ¨āĻžāĻ‡" +installedDate: "āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛ āĻ•āĻ°āĻžāĻ° āĻ¤āĻžāĻ°āĻŋāĻ–" +lastUsedDate: "āĻ¸āĻ°ā§āĻŦāĻļā§‡āĻˇ āĻŦā§āĻ¯āĻžāĻŦāĻšā§ƒāĻ¤" +state: "āĻ…āĻŦāĻ¸ā§āĻĨāĻž" +sort: "āĻ¸āĻžāĻœāĻžāĻ¨" +ascendingOrder: "āĻŠāĻ°ā§āĻ§ā§āĻŦāĻ•ā§āĻ°āĻŽā§‡" +descendingOrder: "āĻ¨āĻŋāĻŽā§āĻ¨āĻ•ā§āĻ°āĻŽā§‡" +scratchpad: "āĻ¸ā§āĻ•ā§āĻ°ā§āĻ¯āĻžāĻšāĻĒā§āĻ¯āĻžāĻĄ" +scratchpadDescription: "āĻ¸ā§āĻ•ā§āĻ°ā§āĻ¯āĻžāĻšāĻĒā§āĻ¯āĻžāĻĄ AiScript-āĻāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻžāĻŽā§‚āĻ˛āĻ• āĻĒāĻ°āĻŋāĻŦā§‡āĻļ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°ā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻŽāĻŋāĻ¸ā§āĻ•āĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ…ā§āĻ¯āĻžāĻ•ā§āĻŸ āĻ•āĻ°ā§‡ āĻāĻŽāĻ¨ āĻ•ā§‹āĻĄ āĻ˛āĻŋāĻ–āĻ¤ā§‡, āĻšāĻžāĻ˛āĻžāĻ¤ā§‡ āĻāĻŦāĻ‚ āĻ¤āĻžāĻ° āĻĢāĻ˛āĻžāĻĢāĻ˛ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" +output: "āĻ†āĻ‰āĻŸāĻĒā§āĻŸ" +script: "āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ" +disablePagesScript: "āĻĒā§‡āĻœāĻ—ā§āĻ˛ā§‹āĻ¤ā§‡ AiScript āĻ…āĻ•ā§āĻˇāĻŽ āĻ•āĻ°ā§āĻ¨" +updateRemoteUser: "āĻ°āĻŋāĻŽā§‹āĻŸ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¤āĻĨā§āĻ¯ āĻ†āĻĒāĻĄā§‡āĻŸ āĻ•āĻ°ā§āĻ¨" +deleteAllFiles: "āĻ¸āĻ•āĻ˛ āĻĢāĻžāĻ‡āĻ˛ āĻĄāĻŋāĻ˛āĻŋāĻŸ āĻ•āĻ°ā§āĻ¨" +deleteAllFilesConfirm: "āĻ¸āĻ•āĻ˛ āĻĢāĻžāĻ‡āĻ˛ āĻĄāĻŋāĻ˛āĻŋāĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +removeAllFollowing: "āĻ¸āĻ•āĻ˛ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻŦāĻžāĻ¤āĻŋāĻ˛ āĻ•āĻ°ā§āĻ¨" +removeAllFollowingDescription: "{host} āĻāĻ° āĻ¸āĻ•āĻ˛ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ•ā§‡ āĻ†āĻ° āĻĢāĻ˛ā§‹āĻ“ āĻ•āĻ°āĻŦā§‡āĻ¨ āĻ¨āĻž āĨ¤ āĻ¯āĻĻāĻŋ āĻ‡āĻ¨ā§āĻ¸āĻ¤ā§āĻ¯āĻžāĻ¨ā§āĻ¸āĻŸāĻŋāĻ° āĻ•ā§‹āĻ¨ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž (āĻ¯ā§‡āĻŽāĻ¨āĻƒ āĻ‡āĻ¨ā§āĻ¸āĻ¤ā§āĻ¯āĻžāĻ¨ā§āĻ¸āĻŸāĻŋ āĻ†āĻ° āĻ¨ā§‡āĻ‡) āĻšā§Ÿā§‡ āĻĨāĻžāĻ•ā§‡ āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨ āĨ¤ " +userSuspended: "āĻāĻ‡ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°āĻŋāĻ° āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¸ā§āĻĨāĻ—āĻŋāĻ¤ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +userSilenced: "āĻāĻ‡ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°āĻŋāĻ•ā§‡ āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +yourAccountSuspendedTitle: "āĻāĻ‡ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻŸāĻŋ āĻ¸ā§āĻĨāĻ—āĻŋāĻ¤ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +yourAccountSuspendedDescription: "āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡āĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°ā§‡āĻ° āĻļāĻ°ā§āĻ¤āĻžāĻŦāĻ˛ā§€ āĻ˛āĻ™ā§āĻ˜āĻ¨ā§‡āĻ° āĻŽāĻ¤ā§‹ āĻ•āĻžāĻ°āĻŖā§‡ āĻāĻ‡ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻŸāĻŋ āĻ¸ā§āĻĨāĻ—āĻŋāĻ¤ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡ā§ˇ āĻŦāĻŋāĻ¸ā§āĻ¤āĻžāĻ°āĻŋāĻ¤ āĻœāĻžāĻ¨āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻļāĻžāĻ¸āĻ•ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨ āĨ¤ āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŦā§‡āĻ¨ āĻ¨āĻž āĻĻāĻ¯āĻŧāĻž āĻ•āĻ°ā§‡ āĨ¤" +menu: "āĻŽā§‡āĻ¨ā§" +divider: "āĻ–āĻ¨ā§āĻĄāĻ•" +addItem: "āĻ†āĻ‡āĻŸā§‡āĻŽ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +relays: "āĻ°āĻŋāĻ˛ā§‡āĻ—ā§āĻ˛āĻŋ" +addRelay: "āĻ°āĻŋāĻ˛ā§‡ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +inboxUrl: "inbox āĻāĻ° URL" +addedRelays: "āĻ¯ā§‹āĻ—āĻ•ā§ƒāĻ¤ āĻ°āĻŋāĻ˛ā§‡āĻ—ā§āĻ˛āĻŋ" +serviceworkerInfo: "āĻĒā§āĻļ āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻž āĻ˛āĻžāĻ—āĻŦā§‡āĨ¤" +deletedNote: "āĻĄāĻŋāĻ˛āĻŋāĻŸ āĻ•āĻ°āĻž āĻ¨ā§‹āĻŸ" +invisibleNote: "āĻ…āĻĻā§ƒāĻļā§āĻ¯ āĻ¨ā§‹āĻŸ" +enableInfiniteScroll: "āĻ‡āĻ¨āĻĢāĻŋāĻ¨āĻŋāĻŸ āĻ¸ā§āĻ•ā§āĻ°āĻ˛ āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨" +visibility: "āĻĻā§ƒāĻļā§āĻ¯āĻŽāĻžāĻ¨āĻ¤āĻž" +poll: "āĻœāĻ°āĻŋāĻĒ" +useCw: "āĻ•āĻ¨ā§āĻŸā§‡āĻ¨ā§āĻŸ āĻ˛ā§āĻ•āĻžāĻ¨" +enablePlayer: "āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĒā§āĻ˛ā§‡ā§ŸāĻžāĻ° āĻ–ā§āĻ˛ā§āĻ¨" +disablePlayer: "āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĒā§āĻ˛ā§‡ā§ŸāĻžāĻ° āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨" +expandTweet: "āĻŸā§āĻ‡āĻŸ āĻŦāĻŋāĻ¸ā§āĻ¤āĻžāĻ°āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +themeEditor: "āĻĨāĻŋāĻŽ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ•" +description: "āĻŦāĻ°ā§āĻŖāĻ¨āĻž" +describeFile: "āĻ•ā§āĻ¯āĻžāĻĒāĻļāĻ¨ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +enterFileDescription: "āĻ•ā§āĻ¯āĻžāĻĒāĻļāĻ¨ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +author: "āĻ˛ā§‡āĻ–āĻ•" +leaveConfirm: "āĻ•āĻŋāĻ›ā§ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ¸ā§‡āĻ­ āĻ•āĻ°āĻž āĻšā§ŸāĻ¨āĻŋāĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻšāĻ˛ā§‡ āĻ¯ā§‡āĻ¤ā§‡ āĻšāĻžāĻ¨?" +manage: "āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻž" +plugins: "āĻĒā§āĻ˛āĻžāĻ—āĻ‡āĻ¨āĻ¸āĻŽā§‚āĻš" +deck: "āĻĄā§‡āĻ•" +undeck: "āĻĄā§‡āĻ•āĻŽā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" +useBlurEffectForModal: "āĻŽā§‹āĻĄāĻžāĻ˛ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§āĻ˛āĻžāĻ° āĻ‡āĻĢā§‡āĻ•ā§āĻŸ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +useFullReactionPicker: "āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻŦā§ˆāĻļāĻŋāĻˇā§āĻŸā§āĻ¯āĻ¯ā§āĻ•ā§āĻ¤ āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻĒāĻŋāĻ•āĻžāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +width: "āĻĒā§āĻ°āĻ¸ā§āĻĨ" +height: "āĻ‰āĻšā§āĻšāĻ¤āĻž" +large: "āĻŦā§œ" +medium: "āĻŽāĻžāĻāĻžāĻ°āĻŋ" +small: "āĻ›ā§‹āĻŸ" +generateAccessToken: "āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +permission: "āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ" +enableAll: "āĻ¸āĻŦāĻ—ā§āĻ˛āĻŋ āĻ¸āĻ•ā§āĻ°āĻŋā§Ÿ āĻ•āĻ°ā§āĻ¨" +disableAll: "āĻ¸āĻŦāĻ—ā§āĻ˛āĻŋ āĻ¨āĻŋāĻˇā§āĻ•ā§āĻ°āĻŋā§Ÿ āĻ•āĻ°ā§āĻ¨" +tokenRequested: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°āĻŦā§‡āĻ¨" +pluginTokenRequestedDescription: "āĻāĻ‡ āĻĒā§āĻ˛āĻžāĻ—āĻ‡āĻ¨āĻŸāĻŋ āĻāĻ–āĻžāĻ¨ā§‡ āĻĻā§‡āĻ“ā§ŸāĻž āĻ…āĻ¨ā§āĻŽā§āĻ¤āĻŋāĻ¸āĻŽā§‚āĻš āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦā§‡" +notificationType: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋāĻ° āĻ§āĻ°āĻ¨" +edit: "āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž" +useStarForReactionFallback: "āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ā§‡āĻ° āĻ‡āĻŽā§‹āĻœāĻŋ āĻ¨āĻž āĻœāĻžāĻ¨āĻ˛ā§‡ ★ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +emailServer: "āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°" +enableEmail: "āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻŦāĻŋāĻ¤āĻ°āĻŖ āĻšāĻžāĻ˛ā§ āĻ•āĻ°ā§āĻ¨" +emailConfigInfo: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ‡āĻŽā§‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻž āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤ āĻšāĻ¯āĻŧ" +email: "āĻ‡āĻŽā§‡āĻ‡āĻ˛" +emailAddress: "āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻž" +smtpConfig: "SMTP āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨" +smtpHost: "āĻšā§‹āĻ¸ā§āĻŸ" +smtpPort: "āĻĒā§‹āĻ°ā§āĻŸ" +smtpUser: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ" +smtpPass: "āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ" +emptyToDisableSmtpAuth: "āĻ†āĻĒāĻ¨āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ āĻāĻŦāĻ‚ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻĢāĻžāĻāĻ•āĻž āĻ°ā§‡āĻ–ā§‡ SMTP āĻĒā§āĻ°āĻŽāĻžāĻŖā§€āĻ•āĻ°āĻŖ āĻ¨āĻŋāĻˇā§āĻ•ā§āĻ°āĻŋāĻ¯āĻŧ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" +smtpSecure: "SMTP āĻ¸āĻ‚āĻ¯ā§‹āĻ—ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ SSL/TLS āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +smtpSecureInfo: "STARTTLS āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻāĻŸāĻŋ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨āĨ¤" +testEmail: "āĻ‡āĻŽā§‡āĻ˛ āĻŦāĻŋāĻ¤āĻ°āĻŖ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻž āĻ•āĻ°ā§āĻ¨" +wordMute: "āĻŦāĻŋāĻļā§‡āĻˇ āĻ•ā§‹āĻ¨ āĻļāĻŦā§āĻĻāĻ•ā§‡ āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°ā§āĻ¨" +regexpError: "āĻ°ā§‡āĻ—ā§āĻ˛āĻžāĻ° āĻāĻ•ā§āĻ¸āĻĒā§āĻ°ā§‡āĻļāĻ¨ āĻ¤ā§āĻ°ā§āĻŸāĻŋ" +regexpErrorDescription: "{tab} āĻ“ā§ŸāĻžāĻ°ā§āĻĄ āĻŽāĻŋāĻ‰āĻŸā§‡āĻ° {line} āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ°ā§‡āĻ—ā§āĻ˛āĻžāĻ° āĻāĻ•ā§āĻ¸āĻĒā§āĻ°ā§‡āĻļāĻ¨ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¤ā§āĻ°ā§āĻŸāĻŋ āĻ›āĻŋāĻ˛:" +instanceMute: "āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°āĻž āĻ‡āĻ¨ā§āĻ¸āĻ¤ā§āĻ¯āĻžāĻ¨ā§āĻ¸āĻ—ā§āĻ˛āĻŋ" +userSaysSomething: "{name} āĻ•āĻŋāĻ›ā§ āĻŦāĻ˛ā§‡āĻ›ā§‡" +makeActive: "āĻ¸āĻ•ā§āĻ°āĻŋāĻ¯āĻŧ āĻ•āĻ°āĻž" +display: "āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨" +copy: "āĻ…āĻ¨ā§āĻ˛āĻŋāĻĒāĻŋ" +metrics: "āĻŽā§‡āĻŸā§āĻ°āĻŋāĻ•ā§āĻ¸" +overview: "āĻ¸āĻžāĻ°āĻžāĻ‚āĻļ" +logs: "āĻ˛āĻ—" +delayed: "āĻĻā§‡āĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +database: "āĻĄā§‡āĻŸāĻžāĻŦā§‡āĻœ" +channel: "āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛āĻ—ā§āĻ˛āĻŋ" +create: "āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +notificationSetting: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋāĻ° āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸" +notificationSettingDesc: "āĻ•āĻŋ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ āĻĒāĻžāĻŦā§‡āĻ¨ āĻ¤āĻž āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŖ āĻ•āĻ°ā§āĻ¨" +useGlobalSetting: "āĻ—ā§āĻ˛ā§‹āĻŦāĻžāĻ˛ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +useGlobalSettingDesc: "āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻ˛ā§‡, āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°āĻ˛ā§‡, āĻāĻŸāĻŋ āĻĒā§ƒāĻĨāĻ•āĻ­āĻžāĻŦā§‡ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤" +other: "āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯" +regenerateLoginToken: "āĻ˛āĻ—āĻ‡āĻ¨ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻ†āĻŦāĻžāĻ° āĻŦāĻžāĻ¨āĻžāĻ¨" +regenerateLoginTokenDescription: "āĻ˛āĻ— āĻ‡āĻ¨ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤ āĻ…āĻ­ā§āĻ¯āĻ¨ā§āĻ¤āĻ°ā§€āĻŖ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§‡āĨ¤ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖāĻ¤ āĻ†āĻĒāĻ¨āĻžāĻ° āĻāĻŸāĻŋ āĻ•āĻ°āĻžāĻ° āĻĻāĻ°āĻ•āĻžāĻ° āĻ¨ā§‡āĻ‡āĨ¤ āĻāĻŸāĻŋ āĻ•āĻ°āĻ˛ā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻĄāĻŋāĻ­āĻžāĻ‡āĻ¸ā§‡ āĻ˛āĻ— āĻ†āĻ‰āĻŸ āĻšāĻ¯āĻŧā§‡ āĻ¯āĻžāĻŦā§‡āĻ¨ā§ˇ" +setMultipleBySeparatingWithSpace: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻĒā§‡āĻ¸ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ•āĻ°ā§‡ āĻāĻ•āĻžāĻ§āĻŋāĻ• āĻāĻ¨ā§āĻŸā§āĻ°āĻŋ āĻĻāĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" +fileIdOrUrl: "āĻĢāĻžāĻ‡āĻ˛ ID āĻ…āĻĨāĻŦāĻž URL" +behavior: "āĻ†āĻšāĻ°āĻŖ" +sample: "āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ" +abuseReports: "āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ—" +reportAbuse: "āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ—" +reportAbuseOf: "{name} āĻ āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +fillAbuseReportDescription: "āĻ°āĻŋāĻĒā§‹āĻ°ā§āĻŸā§‡āĻ° āĻ•āĻžāĻ°āĻŖ āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°ā§āĻ¨. āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻļā§‡āĻˇ āĻ¨ā§‹āĻŸ āĻāĻ° āĻœāĻ¨ā§āĻ¯ āĻ°āĻŋāĻĒā§‹āĻ°ā§āĻŸāĻŸāĻŋ āĻšā§Ÿā§‡ āĻĨāĻžāĻ•ā§‡ āĻ¤āĻŦā§‡ āĻ¤āĻžāĻ° URL āĻŸāĻŋ āĻ…āĻ¨ā§āĻ¤āĻ°ā§āĻ­ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨āĨ¤ " +abuseReported: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ—āĻŸāĻŋ āĻĻāĻžāĻ–āĻŋāĻ˛ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ§āĻ¨ā§āĻ¯āĻŦāĻžāĻĻāĨ¤" +reporter: "āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ—āĻ•āĻžāĻ°ā§€" +reporteeOrigin: "āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ—āĻŸāĻŋāĻ° āĻ‰ā§ŽāĻ¸" +reporterOrigin: "āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ—āĻ•āĻžāĻ°ā§€āĻ° āĻ‰ā§ŽāĻ¸" +forwardReport: "āĻ°āĻŋāĻŽā§‹āĻŸ āĻ‡āĻ¨ā§āĻ¸āĻ¤ā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡ āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ—āĻŸāĻŋ āĻĒāĻžāĻ āĻžāĻ¨" +forwardReportIsAnonymous: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¤āĻĨā§āĻ¯ āĻ°āĻŋāĻŽā§‹āĻŸ āĻ‡āĻ¨ā§āĻ¸āĻ¤ā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡ āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻšāĻŦā§‡ āĻ¨āĻž āĻāĻŦāĻ‚ āĻāĻ•āĻŸāĻŋ āĻŦā§‡āĻ¨āĻžāĻŽā§€ āĻ¸āĻŋāĻ¸ā§āĻŸā§‡āĻŽ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻŋāĻ¤ āĻšāĻŦā§‡āĨ¤" +send: "āĻĒāĻžāĻ āĻžāĻ¨" +abuseMarkAsResolved: "āĻ…āĻ­āĻŋāĻ¯ā§‹āĻ—āĻŸāĻŋāĻ•ā§‡ āĻ¸āĻŽāĻžāĻ§āĻžāĻ•ā§ƒāĻ¤ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +openInNewTab: "āĻ¨āĻ¤ā§āĻ¨ āĻŸā§āĻ¯āĻžāĻŦā§‡ āĻ–ā§āĻ˛ā§āĻ¨" +openInSideView: "āĻ¸āĻžāĻ‡āĻĄ āĻ­āĻŋāĻ‰āĻ¤ā§‡ āĻ–ā§āĻ˛ā§āĻ¨" +defaultNavigationBehaviour: "āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻ¨ā§‡āĻ­āĻŋāĻ—ā§‡āĻļāĻ¨" +editTheseSettingsMayBreakAccount: "āĻāĻ¸āĻŦ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°āĻ˛ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻ•ā§āĻˇāĻ¤āĻŋ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ " +instanceTicker: "āĻ‡āĻ¨ā§āĻ¸āĻ¤ā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡ āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¤āĻĨā§āĻ¯" +waitingFor: "{x} āĻāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻĒā§‡āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡" +random: "āĻ°â€ā§āĻ¯āĻžāĻ¨ā§āĻĄāĻŽ" +system: "āĻ¸āĻŋāĻ¸ā§āĻŸā§‡āĻŽ" +switchUi: "UI āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§āĻ¨" +desktop: "āĻĄā§‡āĻ¸ā§āĻ•āĻŸāĻĒ" +clip: "āĻ•ā§āĻ˛āĻŋāĻĒ" +createNew: "āĻ¨āĻ¤ā§āĻ¨" +optional: "āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€ā§Ÿ āĻ¨ā§Ÿ" +createNewClip: "āĻ¨āĻ¤ā§āĻ¨ āĻ•ā§āĻ˛āĻŋāĻĒ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +public: "āĻ¸āĻ°ā§āĻŦāĻœāĻ¨ā§€āĻ¨" +i18nInfo: "Misskey āĻ¸ā§āĻŦā§‡āĻšā§āĻ›āĻžāĻ¸ā§‡āĻŦāĻ•āĻĻā§‡āĻ° āĻĻā§āĻŦāĻžāĻ°āĻž āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ­āĻžāĻˇāĻžāĻ¯āĻŧ āĻ…āĻ¨ā§āĻŦāĻžāĻĻ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ {link} āĻ āĻ—āĻŋā§Ÿā§‡ āĻ…āĻ¨ā§āĻŦāĻžāĻĻā§‡ āĻ¸āĻšāĻ¯ā§‹āĻ—āĻŋāĻ¤āĻž āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" +manageAccessTokens: "āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻž āĻ•āĻ°ā§āĻ¨" +accountInfo: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻ¤āĻĨā§āĻ¯" +notesCount: "āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +repliesCount: "āĻœāĻŦāĻžāĻŦā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +renotesCount: "āĻ°āĻŋāĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +repliedCount: "āĻœāĻŦāĻžāĻŦ āĻ—ā§āĻ°āĻšāĻ¨ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +renotedCount: "āĻ°āĻŋāĻ¨ā§‹āĻŸ āĻĒā§‡ā§Ÿā§‡āĻ›ā§‡āĻ¨" +followingCount: "āĻ¯āĻžāĻĻā§‡āĻ°āĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡āĻ¨, āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +followersCount: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +sentReactionsCount: "āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻšā§Ÿā§‡āĻ›ā§‡" +receivedReactionsCount: "āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻĒā§‡ā§Ÿā§‡āĻ›ā§‡āĻ¨" +pollVotesCount: "āĻĒā§‹āĻ˛ āĻ­ā§‹āĻŸ āĻĻāĻŋā§Ÿā§‡āĻ›ā§‡āĻ¨" +pollVotedCount: "āĻĒā§‹āĻ˛ āĻ­ā§‹āĻŸ āĻĒā§‡ā§Ÿā§‡āĻ›ā§‡āĻ¨" +yes: "āĻšā§āĻ¯āĻžāĻ" +no: "āĻ¨āĻž" +driveFilesCount: "āĻĄā§āĻ°āĻžāĻ‡āĻ­ā§‡ āĻĢāĻžāĻ‡āĻ˛ āĻāĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +driveUsage: "āĻĄā§āĻ°āĻžāĻ‡āĻ­ āĻāĻ° āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°" +noCrawle: "āĻ•ā§āĻ°āĻ˛āĻžāĻ° āĻ‡āĻ¨ā§āĻĄā§‡āĻ•ā§āĻ¸āĻŋāĻ‚ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨" +noCrawleDescription: "āĻ¸āĻžāĻ°ā§āĻš āĻ‡āĻžā§āĻœāĻŋāĻ¨āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛, āĻ¨ā§‹āĻŸ, āĻĒā§‡āĻœ āĻ‡āĻ¤ā§āĻ¯āĻžāĻĻāĻŋ āĻ‡āĻ¨āĻĄā§‡āĻ•ā§āĻ¸ āĻ•āĻ°āĻ¤ā§‡ āĻ¨āĻŋāĻˇā§‡āĻ§ āĻ•āĻ°ā§āĻ¨āĨ¤ " +lockedAccountInfo: "āĻāĻŽāĻ¨āĻ•āĻŋ āĻ†āĻĒāĻ¨āĻŋ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻŦā§‡āĻ›ā§‡ āĻŦā§‡āĻ›ā§‡ āĻ…āĻ¨ā§āĻŽā§‹āĻĻāĻ¨ āĻ•āĻ°āĻ˛ā§‡āĻ“, āĻ¯ā§‡ āĻ•ā§‡āĻ‰ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦā§‡, āĻ¯āĻ¤āĻ•ā§āĻˇāĻŖ āĻ¨āĻž āĻ†āĻĒāĻ¨āĻŋ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ \"āĻ…āĻ¨ā§āĻ¸āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯\" āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻ¸ā§‡āĻŸ āĻ¨āĻž āĻ•āĻ°ā§‡āĻ¨ā§ˇ" +alwaysMarkSensitive: "āĻ¸āĻ°ā§āĻŦāĻĻāĻž āĻ¸ā§āĻĒāĻ°ā§āĻļāĻ•āĻžāĻ¤āĻ° āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +loadRawImages: "āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ›āĻŦāĻŋāĻ° āĻĨāĻžāĻŽā§āĻŦāĻ¨ā§‡āĻ‡āĻ˛āĻŸāĻŋ āĻĻā§‡āĻ–āĻžāĻ¨āĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§‡ āĻ†āĻ¸āĻ˛ āĻ›āĻŦāĻŋ āĻĻā§‡āĻ–āĻžāĻ¨" +disableShowingAnimatedImages: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻŸā§‡āĻĄ āĻšāĻŋāĻ¤ā§āĻ° āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨" +verificationEmailSent: "āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤āĻ•āĻ°āĻŖ āĻ‡āĻŽā§‡āĻ˛ āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻšā§Ÿā§‡āĻ›ā§‡āĨ¤ āĻ¸ā§‡āĻŸāĻ†āĻĒ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ•āĻ°āĻ¤ā§‡ āĻ‡āĻŽā§‡āĻ˛ āĻāĻ° āĻ˛āĻŋāĻ™ā§āĻ• āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§āĻ¨āĨ¤" +notSet: "āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻž āĻšā§ŸāĻ¨āĻŋ" +emailVerified: "āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +noteFavoritesCount: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻž āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +pageLikesCount: "āĻĒā§‡āĻœ āĻ˛āĻžāĻ‡āĻ• āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨" +pageLikedCount: "āĻĒā§‡āĻœ āĻ˛āĻžāĻ‡āĻ• āĻĒā§‡ā§Ÿā§‡āĻ›ā§‡āĻ¨" +contact: "āĻĒāĻ°āĻŋāĻšāĻŋāĻ¤āĻŋ āĻ¸āĻŽā§‚āĻš" +useSystemFont: "āĻ¸āĻŋāĻ¸ā§āĻŸā§‡āĻŽ āĻĢāĻ¨ā§āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +clips: "āĻ•ā§āĻ˛āĻŋāĻĒāĻ—ā§āĻ˛āĻŋ " +experimentalFeatures: "āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻžāĻŽā§‚āĻ˛āĻ• āĻŦā§ˆāĻļāĻŋāĻˇā§āĻŸā§āĻ¯āĻ—ā§āĻ˛āĻŋ" +developer: "āĻĄā§‡āĻ­ā§‡āĻ˛āĻĒāĻžāĻ°" +makeExplorable: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ \"āĻ˜ā§āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨\" āĻĒā§ƒāĻˇā§āĻ āĻžā§Ÿ āĻĻā§‡āĻ–āĻžāĻ¨" +makeExplorableDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻŸāĻŋ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°āĻ˛ā§‡, āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ \"āĻ˜ā§āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨\" āĻĒā§ƒāĻˇā§āĻ āĻžā§Ÿ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻŋāĻ¤ āĻšāĻŦā§‡ āĻ¨āĻžāĨ¤" +showGapBetweenNotesInTimeline: "āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ āĻāĻŦāĻ‚ āĻ¨ā§‹āĻŸā§‡āĻ° āĻŽāĻžāĻā§‡ āĻĢāĻžāĻ•āĻž āĻœāĻžā§ŸāĻ—āĻž āĻ°āĻžāĻ–ā§āĻ¨" +duplicate: "āĻĒā§āĻ°āĻ¤āĻŋāĻ°ā§‚āĻĒ" +left: "āĻŦāĻžāĻŽ" +center: "āĻŽāĻžāĻāĻ–āĻžāĻ¨" +wide: "āĻšāĻ“ā§œāĻž" +narrow: "āĻ¸āĻ‚āĻ•ā§€āĻ°ā§āĻŖ" +reloadToApplySetting: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻŸāĻŋ āĻ°āĻŋāĻ˛ā§‹āĻĄ āĻ•āĻ°āĻžāĻ° āĻĒāĻ° āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸āĻŸāĻŋ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻ— āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻāĻ–āĻ¨ āĻ°āĻŋāĻ˛ā§‹āĻĄ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +needReloadToApply: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻŸāĻŋ āĻ°āĻŋāĻ˛ā§‹āĻĄ āĻ•āĻ°āĻžāĻ° āĻĒāĻ° āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸āĻŸāĻŋ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻ— āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤" +showTitlebar: "āĻŸāĻžāĻ‡āĻŸā§‡āĻ˛ āĻŦāĻžāĻ° āĻĻā§‡āĻ–āĻžāĻ¨" +clearCache: "āĻ•ā§āĻ¯āĻžāĻļ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°ā§āĻ¨" +onlineUsersCount: "{n} āĻœāĻ¨ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ…āĻ¨āĻ˛āĻžāĻ‡āĻ¨" +nUsers: "{n} āĻœāĻ¨ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€" +nNotes: "{n} āĻŸāĻŋ āĻ¨ā§‹āĻŸ" +sendErrorReports: "āĻ•ā§āĻ°ā§āĻŸāĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻŦā§‡āĻĻāĻ¨ āĻĒāĻžāĻ āĻžāĻ¨" +sendErrorReportsDescription: "āĻšāĻžāĻ˛ā§ āĻĨāĻžāĻ•āĻ˛ā§‡, āĻŦāĻŋāĻ¸ā§āĻ¤āĻžāĻ°āĻŋāĻ¤ āĻ¤ā§āĻ°ā§āĻŸāĻŋāĻ° āĻ¤āĻĨā§āĻ¯ Misskey-āĻāĻ° āĻ¸āĻžāĻĨā§‡ āĻļā§‡āĻ¯āĻŧāĻžāĻ° āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤ āĻ¯āĻž āĻ¸āĻĢā§āĻŸāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ°āĻŸāĻŋāĻ° āĻ—ā§āĻŖāĻŽāĻžāĻ¨ āĻ‰āĻ¨ā§āĻ¨āĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ āĻ•āĻ°ā§‡āĨ¤ āĻ¤ā§āĻ°ā§āĻŸāĻŋāĻ° āĻ¤āĻĨā§āĻ¯ā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡ OS āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖ, āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡āĻ° āĻ§āĻ°āĻ¨, āĻ•āĻ°ā§āĻŽā§‡āĻ° āĻ‡āĻ¤āĻŋāĻšāĻžāĻ¸ āĻ‡āĻ¤ā§āĻ¯āĻžāĻĻāĻŋāĨ¤" +myTheme: "āĻ†āĻŽāĻžāĻ° āĻĨāĻŋāĻŽ" +backgroundColor: "āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋāĻ° āĻ°āĻ‚" +accentColor: "āĻāĻ•ā§āĻ¸ā§‡āĻ¨ā§āĻŸā§‡āĻ° āĻ°āĻ‚" +textColor: "āĻ˛ā§‡āĻ–āĻžāĻ° āĻ°āĻ‚" +saveAs: "āĻāĻ‡āĻ°ā§‚āĻĒā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°ā§āĻ¨" +advanced: "āĻ‰āĻ¨ā§āĻ¨āĻ¤" +value: "āĻŽāĻžāĻ¨" +createdAt: "āĻ¤ā§ˆāĻ°āĻŋ āĻšā§Ÿā§‡āĻ›ā§‡" +updatedAt: "āĻļā§‡āĻˇ āĻšāĻžāĻ˛āĻ¨āĻžāĻ—āĻžāĻĻ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡" +saveConfirm: "āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨āĻ—ā§āĻ˛āĻŋ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ¨?" +deleteConfirm: "āĻ†āĻ¸āĻ˛ā§‡āĻ‡ āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻ¤ā§‡ āĻšāĻžāĻ¨?" +invalidValue: "āĻ…āĻ—ā§āĻ°āĻšāĻŖāĻ¯ā§‹āĻ—ā§āĻ¯ āĻŽāĻžāĻ¨" +registry: "āĻ°ā§‡āĻœāĻŋāĻ¸ā§āĻŸā§āĻ°āĻŋ" +closeAccount: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨" +currentVersion: "āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖ" +latestVersion: "āĻ¸āĻ°ā§āĻŦāĻļā§‡āĻˇ āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖ" +youAreRunningUpToDateClient: "āĻ†āĻĒāĻ¨āĻŋ āĻ¸āĻŦāĻšā§‡ā§Ÿā§‡ āĻ¨āĻ¤ā§āĻ¨ āĻ•ā§āĻ˛āĻžā§Ÿā§‡āĻ¨ā§āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ›ā§‡āĻ¨" +newVersionOfClientAvailable: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ•ā§āĻ˛āĻžā§Ÿā§‡āĻ¨ā§āĻŸā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻ­āĻžāĻ°ā§āĻ¸āĻ¨ āĻšāĻ˛ā§‡ āĻāĻ¸ā§‡āĻ›ā§‡" +usageAmount: "āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°" +capacity: "āĻ§āĻžāĻ°āĻŖāĻ•ā§āĻˇāĻŽāĻ¤āĻž" +inUse: "āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤" +editCode: "āĻ•ā§‹āĻĄ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" +apply: "āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +receiveAnnouncementFromInstance: "āĻāĻ‡ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻĨā§‡āĻ•ā§‡ āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ āĻĒāĻžāĻ¨" +emailNotification: "āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ" +publish: "āĻĒā§āĻ°āĻ•āĻžāĻļ" +inChannelSearch: "āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛ā§‡ āĻ–ā§āĻāĻœā§āĻ¨" +useReactionPickerForContextMenu: "āĻ°āĻžāĻ‡āĻŸ āĻ•ā§āĻ˛āĻŋāĻ•ā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻĒāĻŋāĻ•āĻžāĻ° āĻ–ā§āĻ˛ā§āĻ¨" +typingUsers: "{users} āĻ˛ā§‡āĻ–āĻ›ā§‡" +jumpToSpecifiedDate: "āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ¤āĻžāĻ°āĻŋāĻ–ā§‡ āĻ¯āĻžāĻ¨" +showingPastTimeline: "āĻ…āĻ¤ā§€āĻ¤ā§‡āĻ° āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻšāĻšā§āĻ›ā§‡" +clear: "āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ°" +markAllAsRead: "āĻ¸āĻŦ āĻĒāĻ āĻŋāĻ¤ āĻšāĻŋāĻ¸ā§‡āĻŦā§‡ āĻšāĻŋāĻšā§āĻ¨āĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨" +goBack: "āĻĒāĻŋāĻ›āĻ¨ā§‡" +unlikeConfirm: "āĻ†āĻ¸āĻ˛ā§‡āĻ‡ āĻ˛āĻžāĻ‡āĻ• āĻ¸āĻ°āĻŋā§Ÿā§‡ āĻ¨āĻŋāĻŦā§‡āĻ¨?" +fullView: "āĻĢā§āĻ˛ āĻ­āĻŋāĻ‰" +quitFullView: "āĻĢā§āĻ˛ āĻ­āĻŋāĻ‰ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°ā§āĻ¨" +addDescription: "āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" +userPagePinTip: "āĻ†āĻĒāĻ¨āĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻ¨ā§‹āĻŸā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŽā§‡āĻ¨ā§ āĻĨā§‡āĻ•ā§‡ \"āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛ā§‡ āĻĒāĻŋāĻ¨ āĻ•āĻ°ā§āĻ¨\" āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻāĻ–āĻžāĻ¨ā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" +notSpecifiedMentionWarning: "āĻĒā§āĻ°āĻžāĻĒāĻ• āĻ›āĻžā§œāĻžāĻ“ āĻāĻ‡ āĻ¨ā§‹āĻŸā§‡ āĻ…āĻ¨ā§āĻ¯ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–ā§āĻ¯ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" +info: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡" +userInfo: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¤āĻĨā§āĻ¯" +unknown: "āĻ…āĻœāĻžāĻ¨āĻž" +onlineStatus: "āĻ…āĻ¨āĻ˛āĻžāĻ‡āĻ¨ āĻ¸ā§āĻŸā§āĻ¯āĻžāĻŸāĻžāĻ¸" +hideOnlineStatus: "āĻ…āĻ¨āĻ˛āĻžāĻ‡āĻ¨ āĻ¸ā§āĻŸā§āĻ¯āĻžāĻŸāĻžāĻ¸ āĻ˛ā§āĻ•āĻžāĻ¨" +hideOnlineStatusDescription: "āĻ…āĻ¨āĻ˛āĻžāĻ‡āĻ¨ āĻ¸ā§āĻŸā§āĻ¯āĻžāĻŸāĻžāĻ¸ āĻ˛ā§āĻ•āĻŋāĻ¯āĻŧā§‡ āĻ°āĻžāĻ–āĻ˛ā§‡ āĻ¸āĻžāĻ°ā§āĻšā§‡āĻ° āĻŽāĻ¤ā§‹ āĻ•āĻŋāĻ›ā§ āĻĢāĻžāĻ‚āĻļāĻ¨ā§‡āĻ° āĻ¸ā§āĻŦāĻŋāĻ§āĻž āĻ•āĻŽā§‡ āĻ¯āĻžā§ŸāĨ¤" +online: "āĻ…āĻ¨āĻ˛āĻžāĻ‡āĻ¨" +active: "āĻ…ā§āĻ¯āĻžāĻ•āĻŸāĻŋāĻ­" +offline: "āĻ…āĻĢāĻ˛āĻžāĻ‡āĻ¨" +notRecommended: "āĻ¸ā§āĻĒāĻžāĻ°āĻŋāĻļ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ āĻ¨āĻž" +botProtection: "āĻŦāĻŸ āĻĒā§āĻ°ā§‹āĻŸā§‡āĻ•āĻļāĻ¨" +instanceBlocking: "āĻŦā§āĻ˛āĻ• āĻ•āĻ°āĻž āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸āĻ—ā§āĻ˛āĻŋ" +selectAccount: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨" +switchAccount: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻĒāĻžāĻ˛ā§āĻŸāĻžāĻ¨" +enabled: "āĻšāĻžāĻ˛ā§" +disabled: "āĻŦāĻ¨ā§āĻ§" +quickAction: "āĻ•ā§āĻ‡āĻ• āĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨" +user: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ—āĻŖ" +administration: "āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻž" +accounts: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻ—ā§āĻ˛āĻŋ" +switch: "āĻĒāĻžāĻ˛ā§āĻŸāĻžāĻ¨" +noMaintainerInformationWarning: "āĻĒā§āĻ°āĻļāĻžāĻ¸āĻ•ā§‡āĻ° āĻ¤āĻĨā§āĻ¯ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĻ¨āĻŋāĨ¤" +noBotProtectionWarning: "āĻŦāĻŸ āĻĒā§āĻ°ā§‹āĻŸā§‡āĻ•āĻļāĻ¨ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĻ¨āĻŋāĨ¤" +configure: "āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ° āĻ•āĻ°ā§āĻ¨" +postToGallery: "āĻ—ā§āĻ¯āĻžāĻ˛āĻžāĻ°ā§€ āĻĒā§‹āĻ¸ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨" +gallery: "āĻ—ā§āĻ¯āĻžāĻ˛āĻžāĻ°ā§€" +recentPosts: "āĻ¨āĻ¤ā§āĻ¨ āĻĒā§‹āĻ¸ā§āĻŸ" +popularPosts: "āĻœāĻ¨āĻĒā§āĻ°āĻŋā§Ÿ āĻĒā§‹āĻ¸ā§āĻŸ" +shareWithNote: "āĻ¨ā§‹āĻŸā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻļā§‡ā§ŸāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +ads: "āĻŦāĻŋāĻœā§āĻžāĻžāĻĒāĻ¨" +expiration: "āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ¸āĻŽāĻ¯āĻŧāĻ¸ā§€āĻŽāĻž" +memo: "āĻŽā§‡āĻŽā§‹" +priority: "āĻ…āĻ—ā§āĻ°āĻžāĻ§āĻŋāĻ•āĻžāĻ°" +high: "āĻ‰āĻšā§āĻš" +middle: "āĻŽāĻžāĻāĻžāĻ°āĻŋ" +low: "āĻ¨āĻŋāĻŽā§āĻ¨" +emailNotConfiguredWarning: "āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻ…ā§āĻ¯āĻžāĻĄā§āĻ°ā§‡āĻ¸ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻž āĻšā§ŸāĻ¨āĻŋāĨ¤" +ratio: "āĻ…āĻ¨ā§āĻĒāĻžāĻ¤" +previewNoteText: "āĻĒā§āĻ°āĻŋāĻ­āĻŋāĻ‰ āĻĻā§‡āĻ–āĻžāĻ¨" +customCss: "āĻ•āĻžāĻ¸ā§āĻŸāĻŽ CSS" +customCssWarn: "āĻāĻ‡ āĻŦā§āĻ¯āĻžāĻĒāĻžāĻ°ā§‡ āĻ…āĻ­āĻŋāĻœā§āĻžāĻ¤āĻž āĻ¨āĻž āĻĨāĻžāĻ•āĻ˛ā§‡ āĻāĻ‡ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻŸāĻŋ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦā§‡āĻ¨ āĻ¨āĻžāĨ¤ āĻ…āĻ¨ā§āĻĒāĻ¯ā§āĻ•ā§āĻ¤ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸ āĻ•ā§āĻ˛āĻžāĻ¯āĻŧā§‡āĻ¨ā§āĻŸāĻ•ā§‡ āĻ¸ā§āĻŦāĻžāĻ­āĻžāĻŦāĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻŦāĻžāĻ§āĻž āĻĻāĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤" +global: "āĻ—ā§āĻ˛ā§‹āĻŦāĻžāĻ˛" +squareAvatars: "āĻšāĻžāĻ°āĻ•ā§‹āĻ¨āĻž āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛ āĻĒāĻŋāĻ•āĻšāĻžāĻ° āĻĻā§‡āĻ–āĻžāĻ¨ " +sent: "āĻĒāĻžāĻ āĻžāĻ¨" +received: "āĻĒā§āĻ°āĻžāĻĒā§āĻ¤" +searchResult: "āĻ…āĻ¨ā§āĻ¸āĻ¨ā§āĻ§āĻžāĻ¨ā§‡āĻ° āĻĢāĻ˛āĻžāĻĢāĻ˛" +hashtags: "āĻšā§āĻ¯āĻžāĻļāĻŸā§āĻ¯āĻžāĻ—" +troubleshooting: "āĻŸā§āĻ°āĻžāĻŦāĻ˛āĻļā§āĻŸāĻŋāĻ‚" +useBlurEffect: "UI āĻ¤ā§‡ āĻŦā§āĻ˛āĻžāĻ° āĻ‡āĻĢā§‡āĻ•ā§āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨" +learnMore: "āĻ†āĻ°āĻ“ āĻœāĻžāĻ¨ā§āĻ¨" +misskeyUpdated: "Misskey āĻ†āĻĒāĻĄā§‡āĻŸ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡īŧ" +whatIsNew: "āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨āĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–āĻžāĻ¨" +translate: "āĻ…āĻ¨ā§āĻŦāĻžāĻĻ" +translatedFrom: "{x} āĻšāĻ¤ā§‡ āĻ…āĻ¨ā§āĻŦāĻžāĻĻ āĻ•āĻ°āĻž" +accountDeletionInProgress: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻž āĻšāĻšā§āĻ›ā§‡" +usernameInfo: "āĻāĻ•āĻŸāĻŋ āĻ¨āĻžāĻŽ āĻ¯āĻž āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻŸāĻŋāĻ•ā§‡ āĻ…āĻ¨āĻ¨ā§āĻ¯āĻ­āĻžāĻŦā§‡ āĻ¸āĻ¨āĻžāĻ•ā§āĻ¤ āĻ•āĻ°ā§‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻŦāĻ°ā§āĻŖāĻŽāĻžāĻ˛āĻž (a ~ z, A ~ Z), āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž (0 ~ 9), āĻāĻŦāĻ‚ āĻ†āĻ¨ā§āĻĄāĻžāĻ°āĻ¸ā§āĻ•ā§‹āĻ° (_) āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ āĻĒāĻ°ā§‡ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻž āĻ¯āĻžāĻŦā§‡ āĻ¨āĻžāĨ¤" +aiChanMode: "Ai āĻŽā§‹āĻĄ" +keepCw: "CW āĻ°āĻžāĻ–ā§āĻ¨" +pubSub: "Pub/Sub āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻ—ā§āĻ˛ā§‹" +lastCommunication: "āĻļā§‡āĻˇ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ—" +resolved: "āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡" +unresolved: "āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻšāĻ¯āĻŧāĻ¨āĻŋ" +breakFollow: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻŦāĻ¨ā§āĻ§" +itsOn: "āĻšāĻžāĻ˛ā§" +itsOff: "āĻŦāĻ¨ā§āĻ§" +emailRequiredForSignup: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻāĻ° āĻĻāĻ°āĻ•āĻžāĻ° āĻĒā§œāĻŦā§‡" +unread: "āĻ…āĻĒāĻ āĻŋāĻ¤" +filter: "āĻĢāĻŋāĻ˛ā§āĻŸāĻžāĻ°" +controlPanel: "āĻ¨āĻŋā§ŸāĻ¨ā§āĻ¤ā§āĻ°āĻ¨ āĻ•ā§‡āĻ¨ā§āĻĻā§āĻ°" +manageAccounts: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻ—ā§āĻ˛āĻŋ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻž āĻ•āĻ°ā§āĻ¨" +makeReactionsPublic: "āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ā§‡āĻ° āĻ‡āĻ¤āĻŋāĻšāĻžāĻ¸ āĻ‰āĻ¨ā§āĻŽā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" +makeReactionsPublicDescription: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āĻ¤ā§€ āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨āĻ—ā§āĻ˛āĻŋāĻ° āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻ¯ā§‡ āĻ•āĻžāĻ°āĻ“ āĻ•āĻžāĻ›ā§‡ āĻĻā§ƒāĻļā§āĻ¯āĻŽāĻžāĻ¨ āĻšāĻŦā§‡āĨ¤" +classic: "āĻ•ā§āĻ˛āĻžāĻ¸āĻŋāĻ•" +muteThread: "āĻĨā§āĻ°ā§‡āĻĄ āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°ā§āĻ¨" +unmuteThread: "āĻĨā§āĻ°ā§‡āĻĄ āĻ†āĻ¨āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°ā§āĻ¨" +ffVisibility: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ/āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻĻā§ƒāĻļā§āĻ¯āĻŽāĻžāĻ¨ā§āĻ¯āĻ¤āĻž" +ffVisibilityDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻžāĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡āĻ¨ āĻāĻŦāĻ‚ āĻ•ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡, āĻ¸ā§‡āĻŸāĻž āĻ•āĻžāĻ°āĻž āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦā§‡ āĻ¤āĻž āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŖ āĻ•āĻ°ā§‡āĨ¤" +continueThread: "āĻ†āĻ°ā§‹ āĻĨā§āĻ°ā§‡āĻĄ āĻĻā§‡āĻ–ā§āĻ¨" +deleteAccountConfirm: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻž āĻšāĻŦā§‡āĨ¤ āĻ āĻŋāĻ• āĻ†āĻ›ā§‡?" +incorrectPassword: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻĻā§‡āĻ“ā§ŸāĻž āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄāĻŸāĻŋ āĻ­ā§āĻ˛āĨ¤" +voteConfirm: "\"{choice}\" āĻ āĻ­ā§‹āĻŸ āĻĻāĻŋāĻ¤ā§‡ āĻšāĻžāĻ¨īŧŸ" +hide: "āĻ˛ā§āĻ•āĻžāĻ¨" +leaveGroup: "āĻ—ā§āĻ°ā§āĻĒ āĻ›ā§‡ā§œā§‡ āĻšāĻ˛ā§‡ āĻ¯āĻžāĻ¨" +leaveGroupConfirm: "\"{name}\" āĻ—ā§āĻ°ā§āĻĒ āĻ›ā§‡ā§œā§‡ āĻšāĻ˛ā§‡ āĻ¯ā§‡āĻ¤ā§‡ āĻšāĻžāĻ¨?" +useDrawerReactionPickerForMobile: "āĻŽā§‹āĻŦāĻžāĻ‡āĻ˛ā§‡ āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻĒāĻŋāĻ•āĻžāĻ°āĻ•ā§‡ āĻĄā§āĻ°āĻ¯āĻŧāĻžāĻ°ā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°ā§āĻ¨" +welcomeBackWithName: "āĻ†āĻŦāĻžāĻ° āĻ¸ā§āĻŦāĻžāĻ—āĻ¤āĻŽ, {name}" +clickToFinishEmailVerification: " [{ok}] āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°āĻžāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ‡āĻŽā§‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻž āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨āĨ¤" +overridedDeviceKind: "āĻĄāĻŋāĻ­āĻžāĻ‡āĻ¸ā§‡āĻ° āĻ§āĻ°āĻ¨" +smartphone: "āĻ¸ā§āĻŽāĻžāĻ°ā§āĻŸāĻĢā§‹āĻ¨" +tablet: "āĻŸā§āĻ¯āĻžāĻŦāĻ˛ā§‡āĻŸ" +auto: "āĻ¸ā§āĻŦāĻ¯āĻŧāĻ‚āĻ•ā§āĻ°āĻŋāĻ¯āĻŧ" +themeColor: "āĻĨāĻŋāĻŽā§‡āĻ° āĻ°āĻ‚" +_emailUnavailable: + used: "āĻāĻ‡ āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻžāĻŸāĻŋ āĻ‡āĻ¤ā§‹āĻŽāĻ§ā§āĻ¯ā§‡ āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤ āĻšā§Ÿā§‡āĻ›ā§‡" + format: "āĻāĻ‡ āĻ‡āĻŽā§‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻžāĻŸāĻŋ āĻ¸āĻ āĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻ˛āĻŋāĻ–āĻž āĻšā§ŸāĻ¨āĻŋ" + disposable: "āĻ…āĻ¸ā§āĻĨāĻžā§Ÿā§€ āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻž āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻ¯āĻžāĻŦā§‡ āĻ¨āĻž" + mx: "āĻ‡āĻŽā§‡āĻ‡āĻ˛ ​​āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°āĻŸāĻŋ āĻ āĻŋāĻ• āĻ¨āĻžāĻ‡" + smtp: "āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°āĻŸāĻŋ āĻ¸āĻžā§œāĻž āĻĻāĻŋāĻšā§āĻ›ā§‡ āĻ¨āĻž" +_ffVisibility: + public: "āĻĒā§āĻ°āĻ•āĻžāĻļ" + followers: "āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ•āĻžāĻ›ā§‡ āĻĻā§ƒāĻļā§āĻ¯āĻŽāĻžāĻ¨" + private: "āĻŦā§āĻ¯āĻžāĻ•ā§āĻ¤āĻŋāĻ—āĻ¤" +_signup: + almostThere: "āĻĒā§āĻ°āĻžāĻ¯āĻŧ āĻļā§‡āĻˇ" + emailAddressInfo: "āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡ āĻ‡āĻŽā§‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻžāĻŸāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦā§‡āĻ¨ āĻ¸ā§‡āĻŸāĻŋ āĻ˛āĻŋāĻ–ā§āĻ¨āĨ¤ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻž āĻĒā§āĻ°āĻ•āĻžāĻļ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻ¨āĻžāĨ¤" + emailSent: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻĻā§‡āĻ“āĻ¯āĻŧāĻž āĻ‡āĻŽā§‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻžāĻ¯āĻŧ ({email}) āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤āĻ•āĻ°āĻŖ āĻ‡āĻŽā§‡āĻ˛ āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ•āĻ°āĻ¤ā§‡ āĻ‡āĻŽā§‡āĻ˛ā§‡āĻ° āĻ˛āĻŋāĻ™ā§āĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ•āĻ°ā§āĻ¨āĨ¤" +_accountDelete: + accountDelete: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛ā§āĻ¨" + mayTakeTime: "āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻž āĻāĻ•āĻŸāĻŋ āĻĻā§€āĻ°ā§āĻ˜ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻĒā§āĻ°āĻšā§āĻ° āĻĒāĻ°āĻŋāĻŽāĻžāĻŖā§‡ āĻ¸āĻžāĻŽāĻ—ā§āĻ°ā§€ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§‡ āĻĨāĻžāĻ•ā§‡āĻ¨ āĻŦāĻž āĻĢāĻžāĻ‡āĻ˛ āĻ†āĻĒāĻ˛ā§‹āĻĄ āĻ•āĻ°ā§‡āĻ¨ āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻšāĻ¤ā§‡ āĻĻā§€āĻ°ā§āĻ˜ āĻ¸āĻŽāĻ¯āĻŧ āĻ¨āĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤" + sendEmail: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻž āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻšāĻ˛ā§‡, āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻŋāĻ¤ āĻ‡āĻŽā§‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻžāĻ¯āĻŧ āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻšāĻŦā§‡āĨ¤" + requestAccountDelete: "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°ā§āĻ¨" + started: "āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻžāĻ° āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻļā§āĻ°ā§ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤" + inProgress: "āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻžāĻ° āĻ•āĻžāĻœ āĻšāĻ˛āĻ›ā§‡" +_ad: + back: "āĻĒāĻŋāĻ›āĻ¨ā§‡" + reduceFrequencyOfThisAd: "āĻāĻ‡ āĻŦāĻŋāĻœā§āĻžāĻžāĻĒāĻ¨āĻŸāĻŋ āĻ•āĻŽ āĻĻā§‡āĻ–āĻžāĻ¨" +_forgotPassword: + enterEmail: "āĻ†āĻĒāĻ¨āĻŋ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻŋāĻ¤ āĻ‡āĻŽā§‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻž āĻ˛āĻŋāĻ–ā§āĻ¨. āĻ¸ā§‡āĻ‡ āĻ āĻŋāĻ•āĻžāĻ¨āĻžāĻ¯āĻŧ āĻāĻ•āĻŸāĻŋ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ°āĻŋāĻ¸ā§‡āĻŸ āĻ˛āĻŋāĻ™ā§āĻ• āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻšāĻŦā§‡āĨ¤" + ifNoEmail: "āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨ā§‡āĻ° āĻ¸āĻŽā§Ÿ āĻ‡-āĻŽā§‡āĻ‡āĻ˛ āĻ āĻŋāĻ•āĻžāĻ¨āĻž āĻ¨āĻž āĻĻāĻŋā§Ÿā§‡ āĻĨāĻžāĻ•ā§‡āĻ¨, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ…āĻ¨ā§āĻ—ā§āĻ°āĻš āĻ•āĻ°ā§‡ āĻĒā§āĻ°āĻļāĻžāĻ¸āĻ•ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨āĨ¤" + contactAdmin: "āĻāĻ‡ āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸āĻŸāĻŋ āĻ‡āĻŽā§‡āĻ‡āĻ˛ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ¨āĻž, āĻ¤āĻžāĻ‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĒā§āĻ°āĻļāĻžāĻ¸āĻ•ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨ā§ˇ" +_gallery: + my: "āĻ†āĻŽāĻžāĻ° āĻ—ā§āĻ¯āĻžāĻ˛āĻžāĻ°ā§€" + liked: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻž āĻĒā§‹āĻ¸ā§āĻŸ" + like: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻž" + unlike: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ¸āĻ°āĻžāĻ¨" +_email: + _follow: + title: "āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻ›ā§‡" + _receiveFollowRequest: + title: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻĒā§‡ā§Ÿā§‡āĻ›ā§‡āĻ¨" +_plugin: + install: "āĻĒā§āĻ˛āĻžāĻ—āĻ‡āĻ¨ āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛ āĻ•āĻ°ā§āĻ¨" + installWarn: "āĻ…āĻŦāĻŋāĻļā§āĻŦāĻ¸ā§āĻ¤ āĻĒā§āĻ˛āĻžāĻ—āĻ‡āĻ¨ āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°āĻŦā§‡āĻ¨ āĻ¨āĻžāĨ¤" + manage: "āĻĒā§āĻ˛āĻžāĻ—āĻ‡āĻ¨ āĻŽā§āĻ¯āĻžāĻ¨ā§‡āĻœ āĻ•āĻ°ā§āĻ¨" +_registry: + scope: "āĻ¸ā§āĻ•ā§‹āĻĒ" + key: "āĻ•ā§€" + keys: "āĻ•ā§€ - āĻ¸āĻŽā§‚āĻš" + domain: "āĻĄā§‹āĻŽā§‡āĻ¨" + createKey: "āĻ•ā§€ āĻŦāĻžāĻ¨āĻžāĻ¨" +_aboutMisskey: + about: "Misskey, āĻāĻ•āĻŸāĻŋ āĻ“āĻĒā§‡āĻ¨ āĻ¸ā§‹āĻ°ā§āĻ¸ āĻ¸āĻĢā§āĻŸāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻ¯āĻž 2014 āĻ¸āĻžāĻ˛ āĻĨā§‡āĻ•ā§‡ syuilo āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ›ā§‡āĻ¨āĨ¤" + contributors: "āĻĒā§āĻ°āĻ§āĻžāĻ¨ āĻ•āĻ¨ā§āĻŸā§āĻ°āĻŋāĻŦāĻŋāĻ‰āĻŸāĻžāĻ°āĻ—āĻŖ" + allContributors: "āĻ¸āĻ•āĻ˛ āĻ•āĻ¨ā§āĻŸā§āĻ°āĻŋāĻŦāĻŋāĻ‰āĻŸāĻžāĻ°āĻ—āĻŖ" + source: "āĻ¸ā§‹āĻ°ā§āĻ¸ āĻ•ā§‹āĻĄ" + translation: "Misskey āĻ…āĻ¨ā§āĻŦāĻžāĻĻ āĻ•āĻ°ā§āĻ¨" + donate: "Misskey āĻ¤ā§‡ āĻĻāĻžāĻ¨ āĻ•āĻ°ā§āĻ¨" + morePatrons: "āĻ†āĻ°āĻ“ āĻ…āĻ¨ā§‡āĻ•ā§‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ āĻ•āĻ°āĻ›ā§‡āĻ¨āĨ¤ āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻŦāĻžāĻ‡āĻ•ā§‡ āĻ§āĻ¨ā§āĻ¯āĻŦāĻžāĻĻ đŸĨ°" + patrons: "āĻ¸āĻŽāĻ°ā§āĻĨāĻ¨āĻ•āĻžāĻ°ā§€" +_nsfw: + respect: "āĻ¸ā§āĻĒāĻ°ā§āĻļāĻ•āĻžāĻ¤āĻ° āĻŽāĻŋāĻĄāĻŋā§ŸāĻž āĻ˛ā§āĻ•āĻžāĻ¨" + ignore: "āĻ¸ā§āĻĒāĻ°ā§āĻļāĻ•āĻžāĻ¤āĻ° āĻŽāĻŋāĻĄāĻŋā§ŸāĻž āĻ˛ā§āĻ•āĻžāĻŦā§‡āĻ¨ āĻ¨āĻž" + force: "āĻ¸āĻ•āĻ˛ āĻŽāĻŋāĻĄāĻŋā§ŸāĻž āĻ˛ā§āĻ•āĻžāĻ¨" +_mfm: + cheatSheet: "MFM āĻšāĻŋāĻŸāĻļāĻŋāĻŸ" + intro: "MFM āĻāĻ•āĻŸāĻŋ āĻŽāĻžāĻ°ā§āĻ•āĻ†āĻĒ āĻ­āĻžāĻˇāĻž āĻ¯āĻž Misskey-āĻāĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻœāĻžāĻ¯āĻŧāĻ—āĻžāĻ¯āĻŧ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻĒāĻ¨āĻŋ MFM-āĻāĻ° āĻ¸āĻŋāĻ¨āĻŸā§āĻ¯āĻžāĻ•ā§āĻ¸āĻ—ā§āĻ˛āĻŋāĻ° āĻāĻ•āĻŸāĻŋ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŦā§‡āĻ¨āĨ¤" + dummy: "āĻŽāĻŋāĻ¸āĻ•āĻŋ āĻĢā§‡āĻĄāĻŋāĻ­āĻžāĻ°ā§āĻ¸ā§‡āĻ° āĻŦāĻŋāĻļā§āĻŦāĻ•ā§‡ āĻĒā§āĻ°āĻ¸āĻžāĻ°āĻŋāĻ¤ āĻ•āĻ°ā§‡" + mention: "āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–" + mentionDescription: "@ āĻšāĻŋāĻšā§āĻ¨ + āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ•ā§‡ āĻ¨āĻŋāĻ°ā§āĻĻā§‡āĻļ āĻ•āĻ°āĻ¤ā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻ¯āĻžā§ŸāĨ¤" + hashtag: "āĻšā§āĻ¯āĻžāĻļāĻŸā§āĻ¯āĻžāĻ—" + hashtagDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ # āĻšāĻŋāĻšā§āĻ¨ + āĻŸā§āĻ¯āĻžāĻ— āĻ¸āĻš āĻāĻ•āĻŸāĻŋ āĻšā§āĻ¯āĻžāĻļāĻŸā§āĻ¯āĻžāĻ— āĻ¨āĻŋāĻ°ā§āĻĻā§‡āĻļ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" + url: "URL" + urlDescription: "URL āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻ¸āĻŽā§āĻ­āĻŦāĨ¤" + link: "āĻ˛āĻŋāĻ‚āĻ•" + linkDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻĒāĻžāĻ ā§āĻ¯ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ…āĻ‚āĻļāĻ•ā§‡ URL āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻĻā§‡āĻ–āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ā§ˇ" + bold: "āĻ—āĻžā§" + boldDescription: "āĻ…āĻ•ā§āĻˇāĻ°āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻŽā§‹āĻŸāĻžāĻ•āĻ°ā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤" + small: "āĻ›ā§‹āĻŸ" + smallDescription: "āĻ˛ā§‡āĻ–āĻž āĻ›ā§‹āĻŸ āĻāĻŦāĻ‚ āĻĒāĻžāĻ¤āĻ˛āĻž āĻ•āĻ°ā§‡ āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻšāĻŦā§‡āĨ¤" + center: "āĻ¸ā§‡āĻ¨ā§āĻŸāĻžāĻ°" + centerDescription: "āĻ˛ā§‡āĻ–āĻž āĻŽāĻžāĻ āĻŦāĻ°āĻžāĻŦāĻ° āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻšāĻŦā§‡" + inlineCode: "āĻ•ā§‹āĻĄ (āĻ‡āĻ¨āĻ˛āĻžāĻ‡āĻ¨)" + inlineCodeDescription: " āĻĒā§āĻ°ā§‹āĻ—ā§āĻ°āĻžāĻŽā§‡āĻ° āĻ•ā§‹āĻĄā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ‡āĻ¨āĻ˛āĻžāĻ‡āĻ¨ āĻ¸āĻŋāĻ¨āĻŸā§āĻ¯āĻžāĻ•ā§āĻ¸ āĻšāĻžāĻ‡āĻ˛āĻžāĻ‡āĻŸāĻŋāĻ‚ āĻ•āĻ°āĻž āĻšāĻŦā§‡" + blockCode: "āĻ•ā§‹āĻĄ (āĻŦā§āĻ˛āĻ•)" + blockCodeDescription: "āĻŽāĻžāĻ˛ā§āĻŸāĻŋ-āĻ˛āĻžāĻ‡āĻ¨ āĻĒā§āĻ°ā§‹āĻ—ā§āĻ°āĻžāĻŽā§‡āĻ° āĻ•ā§‹āĻĄā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¸āĻŋāĻ¨āĻŸā§āĻ¯āĻžāĻ•ā§āĻ¸ āĻšāĻžāĻ‡āĻ˛āĻžāĻ‡āĻŸ āĻ•āĻ°ā§‡āĨ¤" + inlineMath: "āĻ—āĻžāĻŖāĻŋāĻ¤āĻŋāĻ• āĻ¸ā§‚āĻ¤ā§āĻ° (āĻ‡āĻ¨āĻ˛āĻžāĻ‡āĻ¨)" + inlineMathDescription: "āĻ—āĻžāĻŖāĻŋāĻ¤āĻŋāĻ• āĻ¸ā§‚āĻ¤ā§āĻ° āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°ā§āĻ¨ (KaTeX) āĻ‡āĻ¨āĻ˛āĻžāĻ‡āĻ¨āĨ¤" + blockMath: "āĻ—āĻžāĻŖāĻŋāĻ¤āĻŋāĻ• āĻ¸ā§‚āĻ¤ā§āĻ° (āĻŦā§āĻ˛āĻ•)" + blockMathDescription: "āĻāĻ•āĻŸāĻŋ āĻŦā§āĻ˛āĻ•ā§‡ āĻāĻ•āĻžāĻ§āĻŋāĻ• āĻ˛āĻžāĻ‡āĻ¨ā§‡āĻ° āĻ—āĻžāĻŖāĻŋāĻ¤āĻŋāĻ• āĻ¸ā§‚āĻ¤ā§āĻ° āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°ā§āĻ¨ (KaTeX)āĨ¤" + quote: "āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤āĻŋ" + quoteDescription: "āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§āĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤āĻŋ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻšāĻŦā§‡āĨ¤" + emoji: "āĻ¸ā§āĻŦāĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŋāĻ¤ āĻ‡āĻŽā§‹āĻœāĻŋāĻ—ā§āĻ˛āĻŋ" + emojiDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ āĻ•āĻžāĻ¸ā§āĻŸāĻŽ āĻ‡āĻŽā§‹āĻœāĻŋāĻ° āĻ¨āĻžāĻŽ āĻ•ā§‹āĻ˛āĻ¨ā§‡ āĻ†āĻŦāĻĻā§āĻ§ āĻ•āĻ°ā§‡ āĻ•āĻžāĻ¸ā§āĻŸāĻŽ āĻ‡āĻŽā§‹āĻœāĻŋāĻŸāĻŋ āĻĻā§‡āĻ–āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ā§ˇ" + search: "āĻ–ā§āĻāĻœā§āĻ¨" + searchDescription: "āĻĒā§‚āĻ°ā§āĻŦ-āĻŸāĻžāĻ‡āĻĒ āĻ•āĻ°āĻž āĻĒāĻžāĻ ā§āĻ¯ āĻ¸āĻš āĻāĻ•āĻŸāĻŋ āĻ…āĻ¨ā§āĻ¸āĻ¨ā§āĻ§āĻžāĻ¨ āĻŦāĻžāĻ•ā§āĻ¸ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°ā§‡āĨ¤" + flip: "āĻ‰āĻ˛ā§āĻŸāĻžāĻ¨" + flipDescription: "āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻ‰āĻĒāĻ°ā§‡/āĻ¨ā§€āĻšā§‡ āĻŦāĻž āĻŦāĻžāĻŽ/āĻĄāĻžāĻ¨ā§‡ āĻ‰āĻ˛ā§āĻŸāĻžāĻ¨āĨ¤" + jelly: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ (āĻœā§‡āĻ˛āĻŋ)" + jellyDescription: "āĻœā§‡āĻ˛āĻŋāĻ° āĻŽāĻ¤ āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + tada: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ (āĻŸāĻžāĻĄāĻž)" + tadaDescription: "\"āĻŸāĻžāĻĄāĻž!\" āĻāĻ° āĻŽāĻ¤ āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + jump: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ (āĻ˛āĻžāĻĢ)" + jumpDescription: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§āĻ¤ā§‡ āĻ˛āĻžāĻĢ āĻŽāĻžāĻ°āĻžāĻ° āĻŽāĻ¤ āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + bounce: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ (āĻ¤āĻŋā§œāĻŋāĻ‚ āĻŦāĻŋā§œāĻŋāĻ‚)" + bounceDescription: "āĻ¤āĻŋā§œāĻŋāĻ‚ āĻŦāĻŋā§œāĻŋāĻ‚ āĻ•āĻ°āĻžāĻ° āĻŽāĻ¤ āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + shake: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ (āĻāĻžāĻāĻ•āĻŋ)" + shakeDescription: "āĻāĻžāĻāĻ•āĻŋāĻ° āĻŽāĻ¤ āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + twitch: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ (āĻŽā§‹āĻšāĻĄāĻŧāĻžāĻ¨ā§‹)" + twitchDescription: "āĻŽā§‹āĻšāĻĄāĻŧāĻžāĻ¨ā§‹āĻ° āĻŽāĻ¤ āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + spin: "āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ (āĻ˜ā§āĻ°āĻž)" + spinDescription: "āĻ˜ā§āĻ°āĻžāĻ° āĻŽāĻ¤ āĻ…ā§āĻ¯āĻžāĻ¨āĻŋāĻŽā§‡āĻļāĻ¨ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + x2: "āĻŦā§œ" + x2Description: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§ āĻŦā§œ āĻ•āĻ°ā§‡ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + x3: "āĻ…āĻ¨ā§‡āĻ• āĻŦā§œ" + x3Description: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§ āĻ†āĻ°āĻ“ āĻŦā§œ āĻ•āĻ°ā§‡ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + x4: "āĻ…āĻ¸ā§āĻŦāĻžāĻ­āĻžāĻŦāĻŋāĻ• āĻŦā§œ" + x4Description: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§āĻ•ā§‡ āĻ†āĻ—ā§‡āĻ° āĻĨā§‡āĻ•ā§‡āĻ“ āĻ†āĻ°āĻ“ āĻŦā§œ āĻ•āĻ°ā§‡ āĻĻā§‡āĻ–āĻžā§ŸāĨ¤" + blur: "āĻŦā§āĻ˛āĻžāĻ°" + blurDescription: "āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§āĻ•ā§‡ āĻŦā§āĻ˛āĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻāĻ° āĻ‰āĻĒāĻ° āĻŽāĻžāĻ‰āĻ¸ āĻ•āĻžāĻ°ā§āĻ¸āĻžāĻ° āĻ°āĻžāĻ–āĻ˛ā§‡, āĻāĻŸāĻŋ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ°āĻ­āĻžāĻŦā§‡ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦā§‡āĻ¨āĨ¤" + font: "āĻĢāĻ¨ā§āĻŸ" + fontDescription: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§āĻ•ā§‡ āĻ•ā§‹āĻ¨ āĻĢāĻ¨ā§āĻŸā§‡ āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻšāĻŦā§‡ āĻ¤āĻž āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŖ āĻ•āĻ°ā§‡āĨ¤" + rainbow: "āĻ°ā§‡āĻ‡āĻ¨āĻŦā§‹" + rainbowDescription: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§āĻ•ā§‡ āĻ°āĻ‚āĻ§āĻ¨ā§āĻ° āĻ°āĻ‚ āĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°ā§‡āĨ¤" + sparkle: "āĻšāĻŋāĻ• āĻšāĻŋāĻ•" + sparkleDescription: "āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§āĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻšāĻŋāĻ•āĻšāĻŋāĻ•ā§‡ āĻ•āĻŖāĻž āĻĒā§āĻ°āĻ­āĻžāĻŦ āĻĻā§‡āĻ¯āĻŧāĨ¤" + rotate: "āĻ˜ā§āĻ°āĻžāĻ¨" + rotateDescription: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§āĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•ā§‹āĻ¨ā§‡ āĻ˜ā§āĻ°āĻžā§ŸāĨ¤" +_instanceTicker: + none: "āĻĻā§‡āĻ–āĻžāĻŦā§‡āĻ¨ āĻ¨āĻž" + remote: "āĻ°āĻŋāĻŽā§‹āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĻā§‡āĻ–āĻžāĻ¨" + always: "āĻ¸āĻ°ā§āĻŦāĻĻāĻž āĻĻā§‡āĻ–āĻžāĻ¨" +_serverDisconnectedBehavior: + reload: "āĻ¸ā§āĻŦā§ŸāĻ‚āĻ•ā§āĻ°āĻŋā§ŸāĻ­āĻžāĻŦā§‡ āĻ°āĻŋāĻ˛ā§‹āĻĄ" + dialog: "āĻ¸āĻ¤āĻ°ā§āĻ•āĻ¤āĻž āĻĄāĻžā§ŸāĻžāĻ˛āĻ— āĻĻā§‡āĻ–āĻžāĻ¨" + quiet: "āĻ…āĻ—āĻšāĻ°ā§€ āĻ¸āĻ¤āĻ°ā§āĻ•āĻ¤āĻž āĻĻā§‡āĻ–āĻžāĻ¨" +_channel: + create: "āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛ āĻŦāĻžāĻ¨āĻžāĻ¨" + edit: "āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + setBanner: "āĻŦā§āĻ¯āĻžāĻ¨āĻžāĻ° āĻ¸ā§‡āĻŸ āĻ•āĻ°ā§āĻ¨" + removeBanner: "āĻŦā§āĻ¯āĻžāĻ¨āĻžāĻ° āĻ¸āĻ°āĻžāĻ¨" + featured: "āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ā§‡ āĻœāĻ¨āĻĒā§āĻ°āĻŋā§Ÿ" + owned: "āĻ¨āĻŋāĻœā§‡āĻ°" + following: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡" + usersCount: "{n} āĻœāĻ¨ āĻ…āĻ‚āĻļāĻ—ā§āĻ°āĻšāĻŖāĻ•āĻžāĻ°ā§€" + notesCount: "{n} āĻŸāĻŋ āĻ¨ā§‹āĻŸ" +_menuDisplay: + sideFull: "āĻĒāĻžāĻļā§‡" + sideIcon: "āĻĒāĻžāĻļā§‡ (āĻ†āĻ‡āĻ•āĻ¨)" + top: "āĻļā§€āĻ°ā§āĻˇā§‡" + hide: "āĻ˛ā§āĻ•āĻžāĻ¨" +_wordMute: + muteWords: "āĻ¨āĻŋāĻƒāĻļāĻŦā§āĻĻ āĻ•āĻ°āĻž āĻļāĻŦā§āĻĻāĻ—ā§āĻ˛āĻŋ" + muteWordsDescription: "āĻ¸ā§āĻĒā§‡āĻ¸ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ•āĻ°āĻ˛ā§‡ AND āĻļāĻ°ā§āĻ¤ āĻ¤ā§ˆāĻ°āĻŋ āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–āĻ˛ā§‡ OR āĻļāĻ°ā§āĻ¤ āĻ¤ā§ˆāĻ°āĻŋ āĻšāĻŦā§‡āĨ¤" + muteWordsDescription2: "āĻ°ā§‡āĻ—ā§āĻ˛āĻžāĻ° āĻāĻ•ā§āĻ¸āĻĒā§āĻ°ā§‡āĻļāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻ¸ā§āĻ˛ā§āĻ¯āĻžāĻļ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻ•ā§€āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄāĻ•ā§‡ āĻ˜āĻŋāĻ°ā§‡ āĻ°āĻžāĻ–ā§āĻ¨āĨ¤" + softDescription: "āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ āĻĨā§‡āĻ•ā§‡ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻļāĻ°ā§āĻ¤āĻžāĻ¨ā§āĻ¯āĻžā§Ÿā§€ āĻ¨ā§‹āĻŸ āĻ˛ā§āĻ•āĻŋāĻ¯āĻŧā§‡ āĻ°āĻžāĻ–ā§‡āĨ¤" + hardDescription: "āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻļāĻ°ā§āĻ¤āĻžāĻ¨ā§āĻ¯āĻžā§Ÿā§€ āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ āĻĨā§‡āĻ•ā§‡ āĻŦāĻžāĻĻ āĻĻā§‡ā§ŸāĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻļāĻ°ā§āĻ¤ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻ˛ā§‡āĻ“ āĻ¯ā§‡ āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĻ¨āĻŋ āĻ¸ā§‡āĻ—ā§āĻ˛āĻŋ āĻŦāĻžāĻĻ āĻĻā§‡āĻ“āĻ¯āĻŧāĻž āĻšāĻŦā§‡āĨ¤" + soft: "āĻ¨āĻŽāĻ¨ā§€ā§Ÿ" + hard: "āĻ•āĻ ā§‹āĻ°" + mutedNotes: "āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°āĻž āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ" +_instanceMute: + instanceMuteDescription: "āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ° āĻ•āĻ°āĻž āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻ¸āĻŦ āĻ¨ā§‹āĻŸ āĻāĻŦāĻ‚ āĻ°āĻŋāĻ¨ā§‹āĻŸ āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°ā§āĻ¨, āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°āĻž āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ‰āĻ¤ā§āĻ¤āĻ° āĻ¸āĻšāĨ¤" + instanceMuteDescription2: "āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋāĻ•ā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨" + title: "āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ° āĻ•āĻ°āĻž āĻ‡āĻ¨ā§āĻ¸āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ˛ā§āĻ•āĻŋāĻ¯āĻŧā§‡ āĻ°āĻžāĻ–ā§‡āĨ¤" + heading: "āĻŽāĻŋāĻ‰āĻŸ āĻ•āĻ°āĻž āĻ‡āĻ¨ā§āĻ¸āĻ¤ā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž" +_theme: + explore: "āĻĨāĻŋāĻŽāĻ—ā§āĻ˛āĻŋ āĻ˜ā§āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨" + install: "āĻĨāĻŋāĻŽ āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°ā§āĻ¨" + manage: "āĻĨāĻŋāĻŽ āĻŦā§āĻ¯āĻžāĻŦāĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻž" + code: "āĻĨāĻŋāĻŽ āĻ•ā§‹āĻĄ" + description: "āĻŦāĻ°ā§āĻŖāĻ¨āĻž" + installed: "{name} āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" + installedThemes: "āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛ āĻ•āĻ°āĻž āĻĨāĻŋāĻŽāĻ¸āĻŽā§‚āĻš" + builtinThemes: "āĻŦāĻŋāĻ˛ā§āĻŸ-āĻ‡āĻ¨ āĻĨāĻŋāĻŽāĻ¸āĻŽā§‚āĻš" + alreadyInstalled: "āĻāĻ‡ āĻĨāĻŋāĻŽāĻŸāĻŋ āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡ āĻ‡āĻ¨ā§āĻ¸āĻŸāĻ˛ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" + invalid: "āĻĨāĻŋāĻŽāĻŸāĻŋāĻ° āĻĢāĻ°āĻŽā§āĻ¯āĻžāĻŸ āĻ¸āĻ āĻŋāĻ• āĻ¨ā§Ÿ" + make: "āĻĨāĻŋāĻŽ āĻŦāĻžāĻ¨āĻžāĻ¨" + base: "āĻŦā§‡āĻ¸" + addConstant: "āĻ§ā§āĻ°ā§āĻŦāĻ• āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" + constant: "āĻ§ā§āĻ°ā§āĻŦāĻ•" + defaultValue: "āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻŽāĻžāĻ¨" + color: "āĻ°āĻ‚" + refProp: "āĻĒā§āĻ°ā§‹āĻĒāĻžāĻ°ā§āĻŸāĻŋ āĻ°ā§‡āĻĢāĻžāĻ°ā§‡āĻ¨ā§āĻ¸ āĻ•āĻ°ā§āĻ¨" + refConst: "āĻ§ā§āĻ°ā§āĻŦāĻ• āĻ°ā§‡āĻĢāĻžāĻ°ā§‡āĻ¨ā§āĻ¸ āĻ•āĻ°ā§āĻ¨" + key: "āĻ•ā§€" + func: "āĻĢāĻžāĻ‚āĻļāĻ¨" + funcKind: "āĻĢāĻžāĻ‚āĻļāĻ¨ā§‡āĻ° āĻ§āĻ°āĻ¨" + argument: "āĻ†āĻ°ā§āĻ—ā§āĻŽā§‡āĻ¨ā§āĻŸ" + basedProp: "āĻ°ā§‡āĻĢāĻžāĻ°ā§‡āĻ¨ā§āĻ¸ āĻ•āĻ°āĻž āĻĒā§āĻ°ā§‹āĻĒāĻžāĻ°ā§āĻŸāĻŋ" + alpha: "āĻ…āĻ¸ā§āĻŦāĻšā§āĻ›āĻ¤āĻž" + darken: "āĻ…āĻ¨ā§āĻ§āĻ•āĻžāĻ° āĻ•āĻ°ā§āĻ¨" + lighten: "āĻ‰āĻœā§āĻœā§āĻŦāĻ˛ āĻ•āĻ°ā§āĻ¨" + inputConstantName: "āĻ§ā§āĻ°ā§āĻŦāĻ•āĻŸāĻŋāĻ° āĻ¨āĻžāĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨" + importInfo: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ–āĻžāĻ¨ā§‡ āĻĨāĻŋāĻŽ āĻ•ā§‹āĻĄ āĻĒā§‡āĻ¸ā§āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻāĻŦāĻ‚ āĻ¸ā§‡āĻŸāĻŋāĻ•ā§‡ āĻāĻĄāĻŋāĻŸāĻ°ā§‡ āĻ‡āĻŽā§āĻĒā§‹āĻ°ā§āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨" + deleteConstantConfirm: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ§ā§āĻ°ā§āĻŦāĻ• {const} āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻ¤ā§‡ āĻšāĻžāĻ¨īŧŸ" + keys: + accent: "āĻ…ā§āĻ¯āĻžāĻ•āĻ¸ā§‡āĻ¨ā§āĻŸ" + bg: "āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + fg: "āĻ˛ā§‡āĻ–āĻž" + focus: "āĻĢā§‹āĻ•āĻžāĻ¸" + indicator: "āĻ‡āĻ¨āĻĄāĻŋāĻ•ā§‡āĻŸāĻ°" + panel: "āĻĒā§āĻ¯āĻžāĻ¨ā§‡āĻ˛" + shadow: "āĻ›āĻžā§ŸāĻž" + header: "āĻšā§‡āĻĄāĻžāĻ°" + navBg: "āĻ¸āĻžāĻ‡āĻĄāĻŦāĻžāĻ°ā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + navFg: "āĻ¸āĻžāĻ‡āĻĄāĻŦāĻžāĻ°ā§‡āĻ° āĻĒāĻžāĻ ā§āĻ¯" + navHoverFg: "āĻ¸āĻžāĻ‡āĻĄāĻŦāĻžāĻ°ā§‡āĻ° āĻĒāĻžāĻ ā§āĻ¯ (āĻšāĻ­āĻžāĻ°)" + navActive: "āĻ¸āĻžāĻ‡āĻĄāĻŦāĻžāĻ°ā§‡āĻ° āĻĒāĻžāĻ ā§āĻ¯ (āĻ…ā§āĻ¯āĻžāĻ•āĻŸāĻŋāĻ­)" + navIndicator: "āĻ¸āĻžāĻ‡āĻĄāĻŦāĻžāĻ°ā§‡āĻ° āĻ‡āĻ¨āĻĄāĻŋāĻ•ā§‡āĻŸāĻ°" + link: "āĻ˛āĻŋāĻ‚āĻ•" + hashtag: "āĻšā§āĻ¯āĻžāĻļāĻŸā§āĻ¯āĻžāĻ—" + mention: "āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–" + mentionMe: "āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–ā§āĻ¯ āĻ•āĻ°āĻž" + renote: "āĻ°āĻŋāĻ¨ā§‹āĻŸ" + modalBg: "āĻŽā§‹āĻĄāĻžāĻ˛ā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + divider: "āĻ–āĻ¨ā§āĻĄāĻ•" + scrollbarHandle: "āĻ¸ā§āĻ•ā§āĻ°āĻ˛āĻŦāĻžāĻ° āĻšā§āĻ¯āĻžāĻ¨ā§āĻĄā§‡āĻ˛" + scrollbarHandleHover: "āĻ¸ā§āĻ•ā§āĻ°āĻ˛āĻŦāĻžāĻ° āĻšā§āĻ¯āĻžāĻ¨ā§āĻĄā§‡āĻ˛ (āĻšāĻ­āĻžāĻ°)" + dateLabelFg: "āĻ¤āĻžāĻ°āĻŋāĻ– āĻ˛ā§‡āĻŦā§‡āĻ˛ā§‡āĻ° āĻĒāĻžāĻ ā§āĻ¯" + infoBg: "āĻ¤āĻĨā§āĻ¯ā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + infoFg: "āĻ¤āĻĨā§āĻ¯ā§‡āĻ° āĻĒāĻžāĻ ā§āĻ¯" + infoWarnBg: "āĻ“ā§ŸāĻžāĻ°ā§āĻ¨āĻŋāĻ‚ āĻāĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + infoWarnFg: "āĻ“ā§ŸāĻžāĻ°ā§āĻ¨āĻŋāĻ‚ āĻāĻ° āĻĒāĻžāĻ ā§āĻ¯" + cwBg: "CW āĻŦāĻžāĻŸāĻ¨ā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + cwFg: "CW āĻŦāĻžāĻŸāĻ¨ā§‡āĻ° āĻĒāĻžāĻ ā§āĻ¯" + cwHoverBg: "CW āĻŦāĻžāĻŸāĻ¨ā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ (āĻšāĻ­āĻžāĻ°)" + toastBg: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋāĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + toastFg: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋāĻ° āĻĒāĻžāĻ ā§āĻ¯" + buttonBg: "āĻŦāĻžāĻŸāĻ¨ā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + buttonHoverBg: "āĻŦāĻžāĻŸāĻ¨ā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ (āĻšāĻ­āĻžāĻ°)" + inputBorder: "āĻ‡āĻ¨āĻĒā§āĻŸ āĻĢāĻŋāĻ˛ā§āĻĄā§‡āĻ° āĻŦāĻ°ā§āĻĄāĻžāĻ°" + listItemHoverBg: "āĻ˛āĻŋāĻ¸ā§āĻŸ āĻ†āĻ‡āĻŸā§‡āĻŽā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ (āĻšā§‹āĻ­āĻžāĻ°)" + driveFolderBg: "āĻĄā§āĻ°āĻžāĻ‡āĻ­ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°ā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + wallpaperOverlay: "āĻ“āĻ¯āĻŧāĻžāĻ˛āĻĒā§‡āĻĒāĻžāĻ° āĻ“āĻ­āĻžāĻ°āĻ˛ā§‡" + badge: "āĻŦā§āĻ¯āĻžāĻœ" + messageBg: "āĻšā§āĻ¯āĻžāĻŸā§‡āĻ° āĻĒāĻŸāĻ­ā§‚āĻŽāĻŋ" + accentDarken: "āĻ…ā§āĻ¯āĻžāĻ•āĻ¸ā§‡āĻ¨ā§āĻŸ (āĻ—āĻžā§)" + accentLighten: "āĻ…ā§āĻ¯āĻžāĻ•āĻ¸ā§‡āĻ¨ā§āĻŸ (āĻšāĻžāĻ˛ā§āĻ•āĻž)" + fgHighlighted: "āĻšāĻžāĻ‡āĻ˛āĻžāĻ‡āĻŸ āĻ•āĻ°āĻž āĻĒāĻžāĻ ā§āĻ¯" +_sfx: + note: "āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ" + noteMy: "āĻ¨ā§‹āĻŸ (āĻ†āĻĒāĻ¨āĻžāĻ°)" + notification: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ" + chat: "āĻšā§āĻ¯āĻžāĻŸ" + chatBg: "āĻšā§āĻ¯āĻžāĻŸ (āĻŦā§āĻ¯āĻžāĻ•āĻ—ā§āĻ°āĻžāĻ‰āĻ¨ā§āĻĄ)" + antenna: "āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸā§‡āĻ¨āĻžāĻ—ā§āĻ˛āĻŋ" + channel: "āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛ā§‡āĻ° āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ" +_ago: + unknown: "āĻ…āĻœāĻžāĻ¨āĻž" + future: "āĻ­āĻŦāĻŋāĻˇā§āĻ¯ā§Ž" + justNow: "āĻāĻ‡āĻŽāĻžāĻ¤ā§āĻ°" + secondsAgo: "{n} āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄ āĻ†āĻ—ā§‡" + minutesAgo: "{n} āĻŽāĻŋāĻ¨āĻŋāĻŸ āĻ†āĻ—ā§‡" + hoursAgo: "{n} āĻ˜āĻŖā§āĻŸāĻž āĻ†āĻ—ā§‡" + daysAgo: "{n} āĻĻāĻŋāĻ¨ āĻ†āĻ—ā§‡" + weeksAgo: "{n} āĻ¸āĻĒā§āĻ¤āĻžāĻš āĻ†āĻ—ā§‡" + monthsAgo: "{n} āĻŽāĻžāĻ¸ āĻ†āĻ—ā§‡" + yearsAgo: "{n} āĻŦāĻ›āĻ° āĻ†āĻ—ā§‡" +_time: + second: "āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄ" + minute: "āĻŽāĻŋāĻ¨āĻŋāĻŸ" + hour: "āĻ˜āĻŖā§āĻŸāĻž" + day: "āĻĻāĻŋāĻ¨" +_tutorial: + title: "Misskey āĻ•āĻŋāĻ­āĻžāĻŦā§‡ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦā§‡āĻ¨" + step1_1: "āĻ¸ā§āĻŦāĻžāĻ—āĻ¤āĻŽ!" + step1_2: "āĻāĻ‡ āĻ¸ā§āĻ•ā§āĻ°ā§€āĻ¨āĻŸāĻŋāĻ•ā§‡ \"āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨\" āĻŦāĻ˛āĻž āĻšāĻ¯āĻŧ āĻāĻŦāĻ‚ āĻ•āĻžāĻ˛āĻžāĻ¨ā§āĻ•ā§āĻ°āĻŽāĻŋāĻ• āĻ•ā§āĻ°āĻŽā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻžāĻĻā§‡āĻ° \"āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡āĻ¨\" āĻ¤āĻžāĻĻā§‡āĻ° \"āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ\" āĻĻā§‡āĻ–āĻžāĻ¯āĻŧā§ˇ" + step1_3: "āĻ†āĻĒāĻ¨āĻŋ āĻ†āĻĒāĻ¨āĻžāĻ° āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ•āĻŋāĻ›ā§ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦā§‡āĻ¨ āĻ¨āĻž āĻ•āĻžāĻ°āĻŖ āĻ†āĻĒāĻ¨āĻŋ āĻāĻ–āĻ¨āĻ“ āĻ•ā§‹āĻ¨ā§‹ āĻ¨ā§‹āĻŸ āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°ā§‡āĻ¨āĻ¨āĻŋ āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻžāĻ‰āĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻ›ā§‡āĻ¨ āĻ¨āĻžā§ˇ" + step2_1: "āĻ¨ā§‹āĻŸ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻžāĻ° āĻ†āĻ—ā§‡ āĻŦāĻž āĻ•āĻžāĻ‰āĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻ†āĻ—ā§‡ āĻĒā§āĻ°āĻĨāĻŽā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛āĻŸāĻŋ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ•āĻ°ā§āĻ¨āĨ¤" + step2_2: "āĻ†āĻĒāĻ¨āĻŋ āĻ•ā§‡ āĻ¤āĻž āĻœāĻžāĻ¨āĻž āĻ…āĻ¨ā§‡āĻ• āĻ˛ā§‹āĻ•ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–āĻž āĻāĻŦāĻ‚ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ•ā§‡ āĻ¸āĻšāĻœ āĻ•āĻ°ā§‡ āĻ¤ā§‹āĻ˛ā§‡ā§ˇ" + step3_1: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ¸āĻĢāĻ˛āĻ­āĻžāĻŦā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛ āĻ¸ā§‡āĻŸ āĻ†āĻĒ āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨?" + step3_2: "āĻāĻ–āĻ¨, āĻ•āĻŋāĻ›ā§ āĻ¨ā§‹āĻŸ āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°āĻžāĻ° āĻšā§‡āĻˇā§āĻŸāĻž āĻ•āĻ°ā§āĻ¨āĨ¤ āĻĒā§‹āĻ¸ā§āĻŸ āĻĢāĻ°ā§āĻŽ āĻ–ā§āĻ˛āĻ¤ā§‡ āĻĒā§‡āĻ¨ā§āĻ¸āĻŋāĻ˛ āĻšāĻŋāĻšā§āĻ¨āĻ¯ā§āĻ•ā§āĻ¤ āĻŦāĻžāĻŸāĻ¨ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°ā§āĻ¨āĨ¤" + step3_3: "āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻ˛ā§‡āĻ–āĻžāĻ° āĻĒāĻ°ā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻĢāĻ°ā§āĻŽā§‡āĻ° āĻ‰āĻĒāĻ°ā§‡āĻ° āĻĄāĻžāĻ¨āĻĻāĻŋāĻ•ā§‡āĻ° āĻŦāĻžāĻŸāĻ¨ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°ā§‡ āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" + step3_4: "āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°āĻžāĻ° āĻŽāĻ¤ āĻ•āĻŋāĻ›ā§ āĻŽāĻ¨ā§‡ āĻĒāĻ°āĻ›ā§‡ āĻ¨āĻž? \"āĻ†āĻŽāĻŋ āĻŽāĻŋāĻ¸āĻ•āĻŋ āĻ¸ā§‡āĻŸ āĻ†āĻĒ āĻ•āĻ°āĻ›āĻŋ\" āĻŦāĻ˛āĻ˛ā§‡ āĻ•ā§‡āĻŽāĻ¨ āĻšāĻ¯āĻŧ?" + step4_1: "āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨?" + step4_2: "āĻ¸āĻžāĻŦāĻžāĻļ! āĻāĻ–āĻ¨ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨ā§‹āĻŸ āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻŦā§‡āĨ¤" + step5_1: "āĻāĻ–āĻ¨ āĻ…āĻ¨ā§āĻ¯āĻĻā§‡āĻ°āĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨āĻ•ā§‡ āĻĒā§āĻ°āĻžāĻŖāĻŦāĻ¨ā§āĻ¤ āĻ•āĻ°ā§‡ āĻ¤ā§āĻ˛ā§āĻ¨āĨ¤" + step5_2: "āĻ†āĻĒāĻ¨āĻŋ {featured}-āĻ āĻœāĻ¨āĻĒā§āĻ°āĻŋāĻ¯āĻŧ āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻ¯āĻžāĻ¤ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡ āĻŦā§āĻ¯āĻ•ā§āĻ¤āĻŋāĻ•ā§‡ āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°ā§‡āĻ¨ āĻ¤āĻžāĻ•ā§‡ āĻŦā§‡āĻ›ā§‡ āĻ¨āĻŋāĻ¤ā§‡ āĻāĻŦāĻ‚ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻ…āĻĨāĻŦāĻž {explore}-āĻ āĻœāĻ¨āĻĒā§āĻ°āĻŋāĻ¯āĻŧ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ā§ˇ" + step5_3: "āĻāĻ•āĻœāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻ¤ā§‡, āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ†āĻ‡āĻ•āĻ¨ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°ā§āĻ¨ āĻāĻŦāĻ‚ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻĒā§ƒāĻˇā§āĻ āĻžāĻ¤ā§‡ \"āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§āĻ¨\" āĻŦāĻžāĻŸāĻ¨ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°ā§āĻ¨āĨ¤" + step5_4: "āĻ¯āĻĻāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽā§‡āĻ° āĻĒāĻžāĻļā§‡ āĻāĻ•āĻŸāĻŋ āĻ˛āĻ• āĻ†āĻ‡āĻ•āĻ¨ āĻĨāĻžāĻ•ā§‡ āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖā§‡āĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ—ā§āĻ°āĻšāĻŖ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ¤āĻžāĻ°āĻž āĻ•āĻŋāĻ›ā§ āĻ¸āĻŽāĻ¯āĻŧ āĻ¨āĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤" + step6_1: "āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻ āĻŋāĻ• āĻĨāĻžāĻ•āĻ˛ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ…āĻ¨ā§āĻ¯ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¨ā§‹āĻŸ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦā§‡āĻ¨āĨ¤" + step6_2: "āĻ†āĻĒāĻ¨āĻŋ āĻ¸āĻšāĻœā§‡āĻ‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻœāĻžāĻ¨āĻžāĻ¤ā§‡ āĻ…āĻ¨ā§āĻ¯ āĻŦā§āĻ¯āĻ•ā§āĻ¤āĻŋāĻ° āĻ¨ā§‹āĻŸā§‡ \"āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨\" āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" + step6_3: "āĻāĻ•āĻŸāĻŋ āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡, āĻ¨ā§‹āĻŸā§‡ \"+\" āĻšāĻŋāĻšā§āĻ¨ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°ā§āĻ¨ āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒāĻ›āĻ¨ā§āĻĻā§‡āĻ° āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨āĨ¤" + step7_1: "āĻ…āĻ­āĻŋāĻ¨āĻ¨ā§āĻĻāĻ¨! āĻ†āĻĒāĻ¨āĻŋ āĻāĻ–āĻ¨ Misskey-āĻ° āĻĒā§āĻ°āĻžāĻĨāĻŽāĻŋāĻ• āĻŸāĻŋāĻ‰āĻŸā§‹āĻ°āĻŋāĻ¯āĻŧāĻžāĻ˛āĻŸāĻŋ āĻļā§‡āĻˇ āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨āĨ¤" + step7_2: "āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ Misskey āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ†āĻ°āĻ“ āĻœāĻžāĻ¨āĻ¤ā§‡ āĻšāĻžāĻ¨, āĻ¤āĻžāĻšāĻ˛ā§‡ {help} āĻ āĻĻā§‡āĻ–ā§āĻ¨āĨ¤" + step7_3: "āĻāĻ–āĻ¨ Misskey āĻ‰āĻĒāĻ­ā§‹āĻ— āĻ•āĻ°ā§āĻ¨ 🚀" +_2fa: + alreadyRegistered: "āĻ†āĻĒāĻ¨āĻŋ āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡ āĻāĻ•āĻŸāĻŋ 2-āĻĢā§āĻ¯āĻžāĻ•ā§āĻŸāĻ° āĻ…āĻĨā§‡āĻ¨āĻŸāĻŋāĻ•ā§‡āĻļāĻ¨ āĻĄāĻŋāĻ­āĻžāĻ‡āĻ¸ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨ āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨ā§ˇ" + registerDevice: "āĻ¨āĻ¤ā§āĻ¨ āĻĄāĻŋāĻ­āĻžāĻ‡āĻ¸ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨ āĻ•āĻ°ā§āĻ¨" + registerKey: "āĻ¸āĻŋāĻ•āĻŋāĻ‰āĻ°āĻŋāĻŸāĻŋ āĻ•ā§€ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻ¨ āĻ•āĻ°ā§āĻ¨" + step1: "āĻĒā§āĻ°āĻĨāĻŽā§‡, āĻ†āĻĒāĻ¨āĻžāĻ° āĻĄāĻŋāĻ­āĻžāĻ‡āĻ¸ā§‡ {a} āĻŦāĻž {b} āĻāĻ° āĻŽāĻ¤ā§‹ āĻāĻ•āĻŸāĻŋ āĻ…āĻĨā§‡āĻ¨āĻŸāĻŋāĻ•ā§‡āĻļāĻ¨ āĻ…ā§āĻ¯āĻžāĻĒ āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°ā§āĻ¨ā§ˇ" + step2: "āĻāĻ°āĻĒāĻ°ā§‡, āĻ…ā§āĻ¯āĻžāĻĒā§‡āĻ° āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻŋāĻ¤ QR āĻ•ā§‹āĻĄāĻŸāĻŋ āĻ¸ā§āĻ•ā§āĻ¯āĻžāĻ¨ āĻ•āĻ°ā§āĻ¨āĨ¤" + step3: "āĻ…ā§āĻ¯āĻžāĻĒā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻŋāĻ¤ āĻŸā§‹āĻ•ā§‡āĻ¨āĻŸāĻŋ āĻ˛āĻŋāĻ–ā§āĻ¨ āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ•āĻžāĻœ āĻļā§‡āĻˇāĨ¤" + step4: "āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻāĻ–āĻ¨ āĻĨā§‡āĻ•ā§‡ āĻ˛āĻ— āĻ‡āĻ¨ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ, āĻāĻ‡āĻ­āĻžāĻŦā§‡ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻ˛āĻŋāĻ–āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤" + securityKeyInfo: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ āĻšāĻžāĻ°ā§āĻĄāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻ¸āĻŋāĻ•āĻŋāĻ‰āĻ°āĻŋāĻŸāĻŋ āĻ•ā§€ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ˛āĻ— āĻ‡āĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻ¯āĻž FIDO2 āĻŦāĻž āĻĄāĻŋāĻ­āĻžāĻ‡āĻ¸ā§‡āĻ° āĻĢāĻŋāĻ™ā§āĻ—āĻžāĻ°āĻĒā§āĻ°āĻŋāĻ¨ā§āĻŸ āĻ¸ā§‡āĻ¨ā§āĻ¸āĻ° āĻŦāĻž āĻĒāĻŋāĻ¨ āĻ¸āĻŽāĻ°ā§āĻĨāĻ¨ āĻ•āĻ°ā§‡ā§ˇ" +_permissions: + "read:account": "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻ¤āĻĨā§āĻ¯ āĻĻā§‡āĻ–ā§āĻ¨" + "write:account": "āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻ¤āĻĨā§āĻ¯ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨ āĻ•āĻ°ā§āĻ¨" + "read:blocks": "āĻŦā§āĻ˛āĻ• āĻ•āĻ°āĻž āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĻā§‡āĻ–ā§āĻ¨" + "write:blocks": "āĻŦā§āĻ˛āĻ• āĻ•āĻ°āĻž āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + "read:drive": "āĻĄā§āĻ°āĻžāĻ‡āĻ­ā§‡āĻ° āĻĢāĻžāĻ‡āĻ˛ āĻāĻŦāĻ‚ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°āĻ¸āĻŽā§‚āĻš āĻĒā§œāĻž" + "write:drive": "āĻĄā§āĻ°āĻžāĻ‡āĻ­ā§‡āĻ° āĻĢāĻžāĻ‡āĻ˛ āĻāĻŦāĻ‚ āĻĢā§‹āĻ˛ā§āĻĄāĻžāĻ°āĻ¸āĻŽā§‚āĻš āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°āĻž" + "read:favorites": "āĻĒāĻ›āĻ¨ā§āĻĻā§‡āĻ° āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĒā§œāĻž" + "write:favorites": "āĻĒāĻ›āĻ¨ā§āĻĻā§‡āĻ° āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°āĻž" + "read:following": "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ¤āĻĨā§āĻ¯ āĻĻā§‡āĻ–ā§āĻ¨" + "write:following": "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ¤āĻĨā§āĻ¯ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°āĻž" + "read:messaging": "āĻšā§āĻ¯āĻžāĻŸāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + "write:messaging": "āĻšā§āĻ¯āĻžāĻŸāĻ—ā§āĻ˛āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + "read:mutes": "āĻŽāĻŋāĻ‰āĻŸā§‡āĻ° āĻ˛āĻŋāĻ¸ā§āĻŸ āĻĻā§‡āĻ–ā§āĻ¨" + "write:mutes": "āĻŽāĻŋāĻ‰āĻŸā§‡āĻ° āĻ˛āĻŋāĻ¸ā§āĻŸ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + "write:notes": "āĻ¨ā§‹āĻŸ āĻ˛āĻŋāĻ–āĻž" + "read:notifications": "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + "write:notifications": "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ āĻ¨āĻŋā§Ÿā§‡ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡" + "read:reactions": "āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨āĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + "write:reactions": "āĻ°āĻŋāĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨āĻ—ā§āĻ˛āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + "write:votes": "āĻ­ā§‹āĻŸ āĻĻāĻŋāĻ¨" + "read:pages": "āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§‡āĻœāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + "write:pages": "āĻĒā§‡āĻœāĻ—ā§āĻ˛āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻŦāĻž āĻĄāĻŋāĻ˛āĻŋāĻŸ āĻ•āĻ°ā§āĻ¨" + "read:page-likes": "āĻĒā§ƒāĻˇā§āĻ āĻžā§Ÿ āĻĻā§‡ā§ŸāĻž āĻĒāĻ›āĻ¨ā§āĻĻāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + "write:page-likes": "āĻĒā§ƒāĻˇā§āĻ āĻžā§Ÿ āĻĻā§‡ā§ŸāĻž āĻĒāĻ›āĻ¨ā§āĻĻāĻ—ā§āĻ˛āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + "read:user-groups": "āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ—ā§āĻ°ā§āĻĒāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + "write:user-groups": "āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ—ā§āĻ°ā§āĻĒāĻ—ā§āĻ˛āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + "read:channels": "āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛āĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + "write:channels": "āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛āĻ—ā§āĻ˛āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + "read:gallery": "āĻ—ā§āĻ¯āĻžāĻ˛āĻžāĻ°ā§€ āĻĻā§‡āĻ–ā§āĻ¨" + "write:gallery": "āĻ—ā§āĻ¯āĻžāĻ˛āĻžāĻ°ā§€ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + "read:gallery-likes": "āĻ—ā§āĻ¯āĻžāĻ˛āĻžāĻ°ā§€āĻ° āĻĒāĻ›āĻ¨ā§āĻĻāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + "write:gallery-likes": "āĻ—ā§āĻ¯āĻžāĻ˛āĻžāĻ°ā§€āĻ° āĻĒāĻ›āĻ¨ā§āĻĻāĻ—ā§āĻ˛āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" +_auth: + shareAccess: "\"{name}\" āĻ•ā§‡ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻĻāĻŋāĻŦā§‡āĻ¨?" + shareAccessAsk: "āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ•ā§‡ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻĻāĻŋāĻŦā§‡āĻ¨?" + permissionAsk: "āĻāĻ‡ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋ āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ āĻšāĻžāĻ‡" + pleaseGoBack: "āĻĻā§ŸāĻž āĻ•āĻ°ā§‡ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡ āĻĢāĻŋāĻ°ā§‡ āĻ¯āĻžāĻ¨" + callback: "āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡ āĻĢāĻŋāĻ°ā§‡ āĻ¯āĻžāĻšā§āĻ›āĻŋ" + denied: "āĻĒā§āĻ°āĻŦā§‡āĻļ āĻ¨āĻŋāĻˇā§‡āĻ§" +_antennaSources: + all: "āĻ¸āĻ•āĻ˛ āĻ¨ā§‹āĻŸ" + homeTimeline: "āĻ†āĻĒāĻ¨āĻŋ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻ›ā§‡āĻ¨, āĻāĻŽāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¨ā§‹āĻŸ" + users: "āĻāĻ• āĻŦāĻž āĻāĻ•āĻžāĻ§āĻŋāĻ• āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨ā§‹āĻŸ" + userList: "āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻžāĻ¯āĻŧ āĻ¨āĻžāĻŽ āĻĨāĻžāĻ•āĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¨ā§‹āĻŸ" + userGroup: "āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ—ā§āĻ°ā§āĻĒā§‡ āĻĨāĻžāĻ•āĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¨ā§‹āĻŸ" +_weekday: + sunday: "āĻ°āĻŦāĻŋāĻŦāĻžāĻ°" + monday: "āĻ¸ā§‹āĻŽāĻŦāĻžāĻ°" + tuesday: "āĻŽāĻ™ā§āĻ—āĻ˛āĻŦāĻžāĻ°" + wednesday: "āĻŦā§āĻ§āĻŦāĻžāĻ°" + thursday: "āĻŦā§ƒāĻšāĻ¸ā§āĻĒāĻ¤āĻŋāĻŦāĻžāĻ°" + friday: "āĻļā§āĻ•ā§āĻ°āĻŦāĻžāĻ°" + saturday: "āĻļāĻ¨āĻŋāĻŦāĻžāĻ°" +_widgets: + memo: "āĻ¸ā§āĻŸāĻŋāĻ•āĻŋ āĻ¨ā§‹āĻŸ" + notifications: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ" + timeline: "āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨" + calendar: "āĻ•ā§āĻ¯āĻžāĻ˛ā§‡āĻ¨ā§āĻĄāĻžāĻ°" + trends: "āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ā§‡ āĻœāĻ¨āĻĒā§āĻ°āĻŋā§Ÿ" + clock: "āĻ˜āĻĄāĻŧāĻŋ" + rss: "RSS āĻ°āĻŋāĻĄāĻžāĻ°" + activity: "āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ˛āĻžāĻĒ" + photos: "āĻĢāĻŸā§‹āĻ—ā§āĻ˛āĻŋ" + digitalClock: "āĻĄāĻŋāĻœāĻŋāĻŸāĻžāĻ˛ āĻ˜ā§œāĻŋ" + federation: "āĻĢā§‡āĻĄāĻŋāĻ­āĻžāĻ°ā§āĻ¸" + postForm: "āĻ¨ā§‹āĻŸ āĻ˛āĻŋāĻ–ā§āĻ¨" + slideshow: "āĻ¸ā§āĻ˛āĻžāĻ‡āĻĄāĻļā§‹" + button: "āĻŦāĻžāĻŸāĻ¨" + onlineUsers: "āĻ…āĻ¨āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻĨāĻžāĻ•āĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ—āĻŖ" + jobQueue: "āĻœāĻŦ āĻ•āĻŋāĻ‰" + serverMetric: "āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻŽā§‡āĻŸā§āĻ°āĻŋāĻ•ā§āĻ¸" + aiscript: "AiScript āĻ•āĻ¨āĻ¸ā§‹āĻ˛" + aichan: "āĻ†āĻ‡ āĻšāĻžāĻ¨" +_cw: + hide: "āĻ˛ā§āĻ•āĻžāĻ¨" + show: "āĻ†āĻ°āĻ“ āĻĻā§‡āĻ–ā§āĻ¨" + chars: "{count} āĻŸāĻŋ āĻ…āĻ•ā§āĻˇāĻ°" + files: "{count} āĻŸāĻŋ āĻĢāĻžāĻ‡āĻ˛" +_poll: + noOnlyOneChoice: "āĻ¸āĻ°ā§āĻŦāĻ¨āĻŋāĻŽā§āĻ¨ 2 āĻŸāĻŋ āĻ…āĻĒāĻļāĻ¨ āĻŦā§‡āĻ›ā§‡ āĻ¨āĻŋāĻ¤ā§‡ āĻšāĻŦā§‡" + choiceN: "āĻŦāĻŋāĻ•āĻ˛ā§āĻĒāĻ—ā§āĻ˛āĻŋ {n}" + noMore: "āĻ†āĻĒāĻ¨āĻŋ āĻ†āĻ° āĻ•ā§‹āĻ¨ āĻŦāĻŋāĻ•āĻ˛ā§āĻĒ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŦā§‡āĻ¨ āĻ¨āĻž" + canMultipleVote: "āĻāĻ•āĻžāĻ§āĻŋāĻ• āĻŦāĻŋāĻ•āĻ˛ā§āĻĒ āĻŦāĻžāĻ›āĻžāĻ‡ āĻ•āĻ°āĻž āĻ¯āĻžāĻŦā§‡" + expiration: "āĻĒā§‹āĻ˛ā§‡āĻ° āĻ¸āĻŽāĻ¯āĻŧāĻ¸ā§€āĻŽāĻž" + infinite: "āĻ…āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ" + at: "āĻļā§‡āĻˇ āĻšāĻŦā§‡" + after: "āĻļā§‡āĻˇ āĻšāĻŦā§‡" + deadlineDate: "āĻļā§‡āĻˇ āĻšāĻ“ā§ŸāĻžāĻ° āĻ¤āĻžāĻ°āĻŋāĻ–" + deadlineTime: "āĻ˜āĻŖā§āĻŸāĻž" + duration: "āĻŦā§āĻ¯āĻžāĻĒā§āĻ¤āĻŋāĻ•āĻžāĻ˛" + votesCount: "{n} āĻŸāĻŋ āĻ­ā§‹āĻŸ" + totalVotes: "āĻ¸āĻ°ā§āĻŦāĻŽā§‹āĻŸ {n} āĻŸāĻŋ āĻ­ā§‹āĻŸ" + vote: "āĻ­ā§‹āĻŸ āĻĻāĻŋāĻ¨" + showResult: "āĻ°ā§‡āĻœāĻžāĻ˛ā§āĻŸ āĻĻā§‡āĻ–āĻžāĻ¨" + voted: "āĻ­ā§‹āĻŸ āĻĻāĻŋāĻ¯āĻŧā§‡āĻ›ā§‡āĻ¨" + closed: "āĻļā§‡āĻˇ āĻšā§Ÿā§‡ āĻ—ā§‡āĻ›ā§‡" + remainingDays: "āĻ†āĻ° {d} āĻĻāĻŋāĻ¨ {h} āĻ˜āĻŖā§āĻŸāĻž āĻŦāĻžāĻ•āĻŋ āĻ†āĻ›ā§‡" + remainingHours: "āĻ†āĻ° {h} āĻ˜āĻŖā§āĻŸāĻž {m} āĻŽāĻŋāĻ¨āĻŋāĻŸ āĻŦāĻžāĻ•āĻŋ āĻ†āĻ›ā§‡" + remainingMinutes: "āĻ†āĻ° āĻŦāĻžāĻ•āĻŋ āĻ†āĻ›ā§‡ {m} āĻŽāĻŋāĻ¨āĻŋāĻŸ {s} āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄ" + remainingSeconds: "āĻ†āĻ° āĻŦāĻžāĻ•āĻŋ āĻ†āĻ›ā§‡ {s} āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄ" +_visibility: + public: "āĻ¸āĻ°ā§āĻŦāĻœāĻ¨ā§€āĻ¨" + publicDescription: "āĻ¸āĻŦāĻžāĻ‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦā§‡" + home: "āĻŽā§‚āĻ˛ āĻĒāĻžāĻ¤āĻž" + homeDescription: "āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻšā§‹āĻŽ āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°ā§āĻ¨" + followers: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€" + followersDescription: "āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¨āĻŋāĻ•āĻŸ āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°ā§āĻ¨" + specified: "āĻĄāĻžāĻ‡āĻ°ā§‡āĻ•ā§āĻŸ āĻ¨ā§‹āĻŸ" + specifiedDescription: "āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻŋāĻ•āĻŸ āĻĒāĻžāĻ āĻžāĻ¨" + localOnly: "āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ˛ā§‹āĻ•āĻžāĻ˛" + localOnlyDescription: "āĻ°āĻŋāĻŽā§‹āĻŸ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¨āĻŋāĻ•āĻŸ āĻĻā§ƒāĻļā§āĻ¯āĻŽāĻžāĻ¨ āĻ¨ā§Ÿ" +_postForm: + replyPlaceholder: "āĻ¨ā§‹āĻŸāĻŸāĻŋāĻ° āĻœāĻŦāĻžāĻŦ āĻĻāĻŋāĻ¨..." + quotePlaceholder: "āĻ¨ā§‹āĻŸāĻŸāĻŋāĻ•ā§‡ āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤ āĻ•āĻ°ā§āĻ¨..." + channelPlaceholder: "āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛ā§‡ āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°ā§āĻ¨..." + _placeholders: + a: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ–āĻ¨ āĻ•āĻŋ āĻ•āĻ°āĻ›ā§‡āĻ¨?" + b: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ†āĻļā§‡ āĻĒāĻžāĻļā§‡ āĻ•āĻŋ āĻšāĻšā§āĻ›ā§‡?" + c: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻ­āĻžāĻŦāĻ›ā§‡āĻ¨?" + d: "āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻŋ āĻŦāĻ˛āĻ¤ā§‡ āĻšāĻžāĻ¨?" + e: "āĻ˛ā§‡āĻ–āĻž āĻļā§āĻ°ā§ āĻ•āĻ°ā§āĻ¨..." + f: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ˛ā§‡āĻ–āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻĒā§‡āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻ›āĻŋ..." +_profile: + name: "āĻ¨āĻžāĻŽ" + username: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ¨āĻžāĻŽ" + description: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡" + youCanIncludeHashtags: "āĻšā§āĻ¯āĻžāĻļāĻŸā§āĻ¯āĻžāĻ— āĻ…āĻ¨ā§āĻ¤āĻ°ā§āĻ­ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤" + metadata: "āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻ¤āĻĨā§āĻ¯" + metadataEdit: "āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻ¤āĻĨā§āĻ¯ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + metadataDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛ā§‡ āĻāĻ•āĻŸāĻŋ āĻŸā§‡āĻŦāĻŋāĻ˛ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻšāĻžāĻ°āĻŸāĻŋ āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻ¤āĻĨā§āĻ¯ āĻĻā§‡āĻ–āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤" + metadataLabel: "āĻ˛ā§‡āĻŦā§‡āĻ˛" + metadataContent: "āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§" + changeAvatar: "āĻ…ā§āĻ¯āĻžāĻ­āĻžāĻŸāĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§āĻ¨" + changeBanner: "āĻŦā§āĻ¯āĻžāĻ¨āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§āĻ¨" +_exportOrImport: + allNotes: "āĻ¸āĻ•āĻ˛ āĻ¨ā§‹āĻŸ" + followingList: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡" + muteList: "āĻŽāĻŋāĻ‰āĻŸ" + blockingList: "āĻŦā§āĻ˛āĻ•" + userLists: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + excludeMutingUsers: "āĻŽāĻŋāĻ‰āĻŸāĻ•ā§ƒāĻ¤ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻŦāĻžāĻĻ āĻĻāĻŋāĻ¨" + excludeInactiveUsers: "āĻ…āĻŦā§āĻ¯āĻžāĻŦāĻšā§ƒāĻ¤ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŦāĻžāĻĻ āĻĻāĻŋāĻ¨" +_charts: + federation: "āĻĢā§‡āĻĄāĻŋāĻ­āĻžāĻ°ā§āĻ¸" + apRequest: "āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ¸āĻŽā§‚āĻš" + usersIncDec: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + usersTotal: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + activeUsers: "āĻ¸āĻ•ā§āĻ°āĻŋā§Ÿ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€" + notesIncDec: "āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + localNotesIncDec: "āĻ˛ā§‹āĻ•āĻžāĻ˛ āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + remoteNotesIncDec: "āĻ°āĻŋāĻŽā§‹āĻŸ āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + notesTotal: "āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + filesIncDec: "āĻĢāĻžāĻ‡āĻ˛ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + filesTotal: "āĻĢāĻžāĻ‡āĻ˛ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + storageUsageIncDec: "āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœā§‡āĻ° āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°ā§‡āĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + storageUsageTotal: "āĻŽā§‹āĻŸ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœā§‡āĻ° āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°" +_instanceCharts: + requests: "āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ¸āĻŽā§‚āĻš" + users: "āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + usersTotal: "āĻ•ā§āĻ°āĻŽāĻŦāĻ°ā§āĻ§āĻŽāĻžāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + notes: "āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + notesTotal: "āĻ•ā§āĻ°āĻŽāĻŦāĻ°ā§āĻ§āĻŽāĻžāĻ¨ āĻ¨ā§‹āĻŸā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + ff: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€ / āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + ffTotal: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖāĻ•āĻžāĻ°ā§€ / āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻ•ā§āĻ°āĻŽāĻŦāĻ°ā§āĻ§āĻŽāĻžāĻ¨ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + cacheSize: "āĻ•ā§āĻ¯āĻžāĻļ āĻ¸āĻžāĻ‡āĻœā§‡āĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + cacheSizeTotal: "āĻ•ā§āĻ°āĻŽāĻŦāĻ°ā§āĻ§āĻŽāĻžāĻ¨ āĻ•ā§āĻ¯āĻžāĻļ āĻ¸āĻžāĻ‡āĻœ" + files: "āĻĢāĻžāĻ‡āĻ˛ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨" + filesTotal: "āĻ•ā§āĻ°āĻŽāĻŦāĻ°ā§āĻ§āĻŽāĻžāĻ¨ āĻĢāĻžāĻ‡āĻ˛ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" +_timelines: + home: "āĻŽā§‚āĻ˛ āĻĒāĻžāĻ¤āĻž" + local: "āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ" + social: "āĻ¸āĻžāĻŽāĻžāĻœāĻŋāĻ•" + global: "āĻ—ā§āĻ˛ā§‹āĻŦāĻžāĻ˛" +_pages: + newPage: "āĻ¨āĻ¤ā§āĻ¨ āĻĒā§ƒāĻˇā§āĻ āĻž āĻŦāĻžāĻ¨āĻžāĻ¨" + editPage: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻŸāĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + readPage: "āĻ‰ā§ŽāĻ¸ āĻĻā§‡āĻ–āĻ›ā§‡āĻ¨" + created: "āĻĒā§ƒāĻˇā§āĻ āĻž āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" + updated: "āĻĒā§ƒāĻˇā§āĻ āĻž āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" + deleted: "āĻĒā§ƒāĻˇā§āĻ āĻž āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻž āĻšā§Ÿā§‡āĻ›ā§‡" + pageSetting: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸" + nameAlreadyExists: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° URLāĻŸāĻŋ āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡āĻ‡ āĻŦā§āĻ¯āĻžāĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" + invalidNameTitle: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° URL āĻ…āĻŦā§ˆāĻ§" + invalidNameText: "āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨ āĻ¯ā§‡ āĻāĻŸāĻŋ āĻĢāĻžāĻāĻ•āĻž āĻ¨āĻ¯āĻŧ" + editThisPage: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻŸāĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°ā§āĻ¨" + viewSource: "āĻ‰ā§ŽāĻ¸ āĻĻā§‡āĻ–ā§āĻ¨" + viewPage: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§‡āĻœāĻ—ā§āĻ˛āĻŋ āĻĻā§‡āĻ–ā§āĻ¨" + like: "āĻĒāĻ›āĻ¨ā§āĻĻ" + unlike: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ¸āĻ°āĻžāĻ¨" + my: "āĻ†āĻŽāĻžāĻ° āĻĒā§ƒāĻˇā§āĻ āĻžāĻ—ā§āĻ˛āĻŋ" + liked: "āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻž āĻĒā§ƒāĻˇā§āĻ āĻžāĻ—ā§āĻ˛āĻŋ" + featured: "āĻœāĻ¨āĻĒā§āĻ°āĻŋāĻ¯āĻŧ" + inspector: "āĻ‡āĻ¨āĻŋāĻ¸ā§āĻĒā§‡āĻ•ā§āĻŸāĻ°" + contents: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§" + content: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻŦā§āĻ˛āĻ•" + variables: "āĻšāĻ˛āĻ•āĻ—ā§āĻ˛āĻŋ" + title: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" + url: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° URL" + summary: "āĻĒā§ƒāĻˇā§āĻ āĻžāĻ° āĻŦāĻ°ā§āĻŖāĻ¨āĻž" + alignCenter: "āĻ¸ā§‡āĻ¨ā§āĻŸāĻžāĻ°" + hideTitleWhenPinned: "āĻĒāĻŋāĻ¨ āĻ•āĻ°āĻž āĻšāĻ˛ā§‡ āĻŸāĻžāĻ‡āĻŸā§‡āĻ˛ āĻ˛ā§āĻ•āĻžāĻ¨" + font: "āĻĢāĻ¨ā§āĻŸ" + fontSerif: "āĻ¸ā§‡āĻ°āĻŋāĻĢ" + fontSansSerif: "āĻ¸ā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻ¸ā§‡āĻ°āĻŋāĻĢ" + eyeCatchingImageSet: "āĻĨāĻžāĻŽā§āĻŦāĻ¨ā§‡āĻ‡āĻ˛ āĻ¸ā§‡āĻŸ āĻ•āĻ°ā§āĻ¨" + eyeCatchingImageRemove: "āĻĨāĻžāĻŽā§āĻŦāĻ¨ā§‡āĻ‡āĻ˛ āĻ¸āĻ°āĻžāĻ¨" + chooseBlock: "āĻŦā§āĻ˛āĻ• āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨" + selectType: "āĻ§āĻ°āĻ¨ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" + enterVariableName: "āĻšāĻ˛āĻ•ā§‡āĻ° āĻ¨āĻžāĻŽ āĻ˛āĻŋāĻ–ā§āĻ¨" + variableNameIsAlreadyUsed: "āĻšāĻ˛āĻ•ā§‡āĻ° āĻ¨āĻžāĻŽāĻŸāĻŋ āĻ‡āĻ¤āĻŋāĻĒā§‚āĻ°ā§āĻŦā§‡ āĻŦā§āĻ¯āĻžāĻŦāĻšā§ƒāĻ¤ āĻšā§Ÿā§‡āĻ›ā§‡" + contentBlocks: "āĻŦāĻŋāĻˇā§ŸāĻŦāĻ¸ā§āĻ¤ā§" + inputBlocks: "āĻ‡āĻ¨āĻĒā§āĻŸ" + specialBlocks: "āĻŦāĻŋāĻļā§‡āĻˇ" + blocks: + text: "āĻ˛ā§‡āĻ–āĻž" + textarea: "āĻŸā§‡āĻ•ā§āĻ¸āĻŸ āĻāĻ°āĻŋā§ŸāĻž" + section: "āĻŦāĻŋāĻ­āĻžāĻ—" + image: "āĻ›āĻŦāĻŋ" + button: "āĻŦāĻžāĻŸāĻ¨" + if: "āĻ¯āĻĻāĻŋ" + _if: + variable: "āĻšāĻ˛āĻ•āĻ—ā§āĻ˛āĻŋ" + post: "āĻ¨ā§‹āĻŸ āĻ˛āĻŋāĻ–ā§āĻ¨" + _post: + text: "āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§" + attachCanvasImage: "āĻ•ā§āĻ¯āĻžāĻ¨āĻ­āĻžāĻ¸ āĻ›āĻŦāĻŋāĻ¸āĻš āĻĒā§‹āĻ¸ā§āĻŸ āĻ•āĻ°ā§āĻ¨" + canvasId: "āĻ•ā§āĻ¯āĻžāĻ¨āĻ­āĻžāĻ¸ ID" + textInput: "āĻŸā§‡āĻ•ā§āĻ¸āĻŸ āĻ‡āĻ¨āĻĒā§āĻŸ" + _textInput: + name: "āĻšāĻ˛āĻ•ā§‡āĻ° āĻ¨āĻžāĻŽ" + text: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" + default: "āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻŽāĻžāĻ¨" + textareaInput: "āĻāĻ•āĻžāĻ§āĻŋāĻ• āĻ˛āĻžāĻ‡āĻ¨ā§‡āĻ° āĻŸā§‡āĻ•ā§āĻ¸āĻŸ āĻ‡āĻ¨āĻĒā§āĻŸ" + _textareaInput: + name: "āĻšāĻ˛āĻ•ā§‡āĻ° āĻ¨āĻžāĻŽ" + text: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" + default: "āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻŽāĻžāĻ¨" + numberInput: "āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž āĻ‡āĻ¨āĻĒā§āĻŸ" + _numberInput: + name: "āĻšāĻ˛āĻ•ā§‡āĻ° āĻ¨āĻžāĻŽ" + text: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" + default: "āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻŽāĻžāĻ¨" + canvas: "āĻ•ā§āĻ¯āĻžāĻ¨āĻ­āĻžāĻ¸" + _canvas: + id: "āĻ•ā§āĻ¯āĻžāĻ¨āĻ­āĻžāĻ¸ ID" + width: "āĻĒā§āĻ°āĻ¸ā§āĻĨ" + height: "āĻ‰āĻšā§āĻšāĻ¤āĻž" + note: "āĻāĻŽā§āĻŦā§‡āĻĄ āĻ¨ā§‹āĻŸ" + _note: + id: "āĻ¨ā§‹āĻŸ ID" + idDescription: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ° āĻŦāĻĻāĻ˛ā§‡ āĻ¨ā§‹āĻŸā§‡āĻ° URL āĻĒā§‡āĻ¸ā§āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨." + detailed: "āĻŦāĻŋāĻ¸ā§āĻ¤āĻžāĻ°āĻŋāĻ¤ āĻĻā§‡āĻ–ā§āĻ¨" + switch: "āĻ¸ā§āĻ‡āĻš" + _switch: + name: "āĻšāĻ˛āĻ•ā§‡āĻ° āĻ¨āĻžāĻŽ" + text: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" + default: "āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻŽāĻžāĻ¨" + counter: "āĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻžāĻ°" + _counter: + name: "āĻšāĻ˛āĻ•ā§‡āĻ° āĻ¨āĻžāĻŽ" + text: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" + inc: "āĻāĻ­āĻžāĻŦā§‡ āĻŽāĻžāĻ¨ āĻŦāĻžāĻĄāĻŧāĻžāĻ¨" + _button: + text: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" + colored: "āĻ°āĻ™ā§āĻ—āĻŋāĻ¨" + action: "āĻŦāĻžāĻŸāĻ¨ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°āĻ˛ā§‡ āĻ¯āĻž āĻšāĻŦā§‡" + _action: + dialog: "āĻĄāĻžā§ŸāĻžāĻ˛āĻ— āĻĻā§‡āĻ–āĻžāĻ¨ " + _dialog: + content: "āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§" + resetRandom: "āĻ°â€ā§āĻ¯āĻžāĻ¨āĻĄāĻŽ āĻ¸āĻŋāĻĄ āĻ°āĻŋāĻ¸ā§‡āĻŸ āĻ•āĻ°ā§āĻ¨" + pushEvent: "āĻ‡āĻ­ā§‡āĻ¨ā§āĻŸ āĻĒāĻžāĻ āĻžāĻ¨" + _pushEvent: + event: "āĻ‡āĻ­ā§‡āĻ¨ā§āĻŸā§‡āĻ° āĻ¨āĻžāĻŽ" + message: "āĻšāĻžāĻ˛ā§ āĻšāĻ˛ā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦāĻžāĻ°ā§āĻ¤āĻž" + variable: "āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻšāĻ˛āĻ•" + no-variable: "āĻ•āĻŋāĻ›ā§āĻ‡ āĻ¨āĻž" + callAiScript: "AiScript āĻšāĻžāĻ˛āĻžāĻ¨" + _callAiScript: + functionName: "āĻĢāĻžāĻ‚āĻļāĻ¨ā§‡āĻ° āĻ¨āĻžāĻŽ" + radioButton: "āĻŦāĻšā§āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ā§€" + _radioButton: + name: "āĻšāĻ˛āĻ•ā§‡āĻ° āĻ¨āĻžāĻŽ" + title: "āĻļāĻŋāĻ°ā§‹āĻ¨āĻžāĻŽ" + values: "āĻŦāĻŋāĻ•āĻ˛ā§āĻĒāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨" + default: "āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻŽāĻžāĻ¨" + script: + categories: + flow: "āĻ¨āĻŋāĻ¯āĻŧāĻ¨ā§āĻ¤ā§āĻ°āĻŖ" + logical: "āĻ˛āĻœāĻŋāĻ•ā§āĻ¯āĻžāĻ˛ āĻ…āĻĒāĻžāĻ°ā§‡āĻļāĻ¨" + operation: "āĻšāĻŋāĻ¸āĻžāĻŦ-āĻ¨āĻŋāĻ•āĻžāĻļ" + comparison: "āĻ¤ā§āĻ˛āĻ¨āĻž" + random: "āĻ°â€ā§āĻ¯āĻžāĻ¨ā§āĻĄāĻŽ" + value: "āĻŽāĻžāĻ¨" + fn: "āĻĢāĻžāĻ‚āĻļāĻ¨" + text: "āĻŸā§‡āĻ•ā§āĻ¸āĻŸ āĻŽā§āĻ¯āĻžāĻ¨āĻŋāĻĒā§āĻ˛ā§‡āĻļāĻ¨" + convert: "āĻ°ā§āĻĒāĻžāĻ¨ā§āĻ¤āĻ°" + list: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + blocks: + text: "āĻ˛ā§‡āĻ–āĻž" + multiLineText: "āĻ˛ā§‡āĻ–āĻž (āĻāĻ•āĻžāĻ§āĻŋāĻ• āĻ˛āĻžāĻ‡āĻ¨)" + textList: "āĻ˛ā§‡āĻ–āĻžāĻ° āĻ˛āĻŋāĻ¸ā§āĻŸ" + _textList: + info: "āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻāĻ¨ā§āĻŸā§āĻ°āĻŋāĻ•ā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨" + strLen: "āĻ˛ā§‡āĻ–āĻžāĻ° āĻĻā§ˆāĻ°ā§āĻ˜ā§āĻ¯" + _strLen: + arg1: "āĻ˛ā§‡āĻ–āĻž" + strPick: "āĻ…āĻ•ā§āĻˇāĻ° āĻŦā§‡āĻ° āĻ•āĻ°ā§‡ āĻ†āĻ¨ā§āĻ¨" + _strPick: + arg1: "āĻ˛ā§‡āĻ–āĻž" + arg2: "āĻ…āĻ•ā§āĻˇāĻ°ā§‡āĻ° āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨" + strReplace: "āĻ˛ā§‡āĻ–āĻž āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨" + _strReplace: + arg1: "āĻ˛ā§‡āĻ–āĻž" + arg2: "āĻ¯ā§‡ āĻ˛ā§‡āĻ–āĻž āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻž āĻšāĻŦā§‡" + arg3: "āĻ¯āĻž āĻĻā§āĻŦāĻžāĻ°āĻž āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻž āĻšāĻŦā§‡" + strReverse: "āĻ˛ā§‡āĻ–āĻž āĻ‰āĻ˛ā§āĻŸāĻžāĻ¨" + _strReverse: + arg1: "āĻ˛ā§‡āĻ–āĻž" + join: "āĻ˛ā§‡āĻ–āĻž āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" + _join: + arg1: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + arg2: "āĻŦāĻŋāĻ­āĻžāĻœāĻ•" + add: "āĻ¯ā§‹āĻ—" + _add: + arg1: "A" + arg2: "B" + subtract: "āĻŦāĻŋāĻ¯āĻŧā§‹āĻ—" + _subtract: + arg1: "A" + arg2: "B" + multiply: "āĻ—ā§āĻ¨" + _multiply: + arg1: "A" + arg2: "B" + divide: "āĻ­āĻžāĻ—" + _divide: + arg1: "A" + arg2: "B" + mod: "āĻ­āĻžāĻ—āĻļā§‡āĻˇ" + _mod: + arg1: "A" + arg2: "B" + round: "āĻĻāĻļāĻŽāĻŋāĻ• āĻ°āĻžāĻ‰āĻ¨ā§āĻĄ āĻ•āĻ°ā§āĻ¨" + _round: + arg1: "āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + eq: "A āĻ“ B āĻ¸āĻŽāĻžāĻ¨" + _eq: + arg1: "A" + arg2: "B" + notEq: "A āĻ“ B āĻ¸āĻŽāĻžāĻ¨ āĻ¨āĻž" + _notEq: + arg1: "A" + arg2: "B" + and: "A āĻāĻŦāĻ‚ B" + _and: + arg1: "A" + arg2: "B" + or: "A āĻ…āĻĨāĻŦāĻž B" + _or: + arg1: "A" + arg2: "B" + lt: "< A , B āĻšāĻ¤ā§‡ āĻ•āĻŽ" + _lt: + arg1: "A" + arg2: "B" + gt: "> A , B āĻšāĻ¤ā§‡ āĻŦā§‡āĻļā§€" + _gt: + arg1: "A" + arg2: "B" + ltEq: "<= A , B āĻšāĻ¤ā§‡ āĻ•āĻŽ āĻŦāĻž āĻ¸āĻŽāĻžāĻ¨" + _ltEq: + arg1: "A" + arg2: "B" + gtEq: ">= A , B āĻšāĻ¤ā§‡ āĻŦā§‡āĻļā§€ āĻŦāĻž āĻ¸āĻŽāĻžāĻ¨" + _gtEq: + arg1: "A" + arg2: "B" + if: "āĻ¯āĻĻāĻŋ" + _if: + arg1: "āĻ¯āĻĻāĻŋ" + arg2: "āĻ¤āĻžāĻšāĻ˛ā§‡" + arg3: "āĻ¤āĻžāĻ›āĻžā§œāĻž" + not: "āĻ¨āĻž" + _not: + arg1: "āĻ¨āĻž" + random: "āĻ°â€ā§āĻ¯āĻžāĻ¨ā§āĻĄāĻŽ" + _random: + arg1: "āĻ¸āĻŽā§āĻ­āĻžāĻŦā§āĻ¯āĻ¤āĻž" + rannum: "āĻ°â€ā§āĻ¯āĻžāĻ¨āĻĄāĻŽ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + _rannum: + arg1: "āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ āĻŽāĻžāĻ¨" + arg2: "āĻ¸āĻ°ā§āĻŦā§‹āĻšā§āĻš āĻŽāĻžāĻ¨" + randomPick: "āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĨā§‡āĻ•ā§‡ āĻĻā§ˆāĻŦāĻšā§ŸāĻ¨ āĻ•āĻ°ā§āĻ¨" + _randomPick: + arg1: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + dailyRandom: "āĻ°â€ā§āĻ¯āĻžāĻ¨ā§āĻĄāĻŽ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž (āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ¤āĻŋāĻĻāĻŋāĻ¨ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§€āĻ¤ āĻšā§Ÿ)" + _dailyRandom: + arg1: "āĻ¸āĻŽā§āĻ­āĻžāĻŦā§āĻ¯āĻ¤āĻž" + dailyRannum: "āĻ°â€ā§āĻ¯āĻžāĻ¨ā§āĻĄāĻŽ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž (āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ¤āĻŋāĻĻāĻŋāĻ¨ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§€āĻ¤ āĻšā§Ÿ)" + _dailyRannum: + arg1: "āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ āĻŽāĻžāĻ¨" + arg2: "āĻ¸āĻ°ā§āĻŦā§‹āĻšā§āĻš āĻŽāĻžāĻ¨" + dailyRandomPick: "āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĨā§‡āĻ•ā§‡ āĻāĻ˛ā§‹āĻŽā§‡āĻ˛ā§‹āĻ­āĻžāĻŦā§‡ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨ (āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ¤āĻŋāĻĻāĻŋāĻ¨ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§€āĻ¤ āĻšā§Ÿ)" + _dailyRandomPick: + arg1: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + seedRandom: "āĻ°â€ā§āĻ¯āĻžāĻ¨āĻĄāĻŽ (āĻ¸ā§€āĻĄ āĻĻā§āĻŦāĻžāĻ°āĻž)" + _seedRandom: + arg1: "āĻ¸ā§€āĻĄ" + arg2: "āĻ¸āĻŽā§āĻ­āĻžāĻŦā§āĻ¯āĻ¤āĻž" + seedRannum: "āĻ°â€ā§āĻ¯āĻžāĻ¨āĻĄāĻŽ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž (āĻ¸ā§€āĻĄ āĻĻā§āĻŦāĻžāĻ°āĻž)" + _seedRannum: + arg1: "āĻ¸ā§€āĻĄ" + arg2: "āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ āĻŽāĻžāĻ¨" + arg3: "āĻ¸āĻ°ā§āĻŦā§‹āĻšā§āĻš āĻŽāĻžāĻ¨" + seedRandomPick: "āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĨā§‡āĻ•ā§‡ āĻĻā§ˆāĻŦāĻšā§ŸāĻ¨ āĻ•āĻ°ā§āĻ¨ (āĻ¸ā§€āĻĄ āĻĻā§āĻŦāĻžāĻ°āĻž)" + _seedRandomPick: + arg1: "āĻ¸ā§€āĻĄ" + arg2: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + DRPWPM: "āĻ¸āĻŽā§āĻ­āĻžāĻŦā§āĻ¯āĻ¤āĻž āĻ¸āĻš āĻāĻ•āĻŸāĻŋ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĨā§‡āĻ•ā§‡ āĻāĻ˛ā§‹āĻŽā§‡āĻ˛ā§‹āĻ­āĻžāĻŦā§‡ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨ (āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ¤āĻŋāĻĻāĻŋāĻ¨)" + _DRPWPM: + arg1: "āĻ˛ā§‡āĻ–āĻžāĻ° āĻ˛āĻŋāĻ¸ā§āĻŸ" + pick: "āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĨā§‡āĻ•ā§‡ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§āĻ¨" + _pick: + arg1: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + arg2: "āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨" + listLen: "āĻ˛āĻŋāĻ¸ā§āĻŸā§‡āĻ° āĻĻā§ˆāĻ°ā§āĻ˜ā§āĻ¯ āĻĒāĻžāĻ¨" + _listLen: + arg1: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + number: "āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + stringToNumber: "āĻĒāĻžāĻ ā§āĻ¯ āĻĨā§‡āĻ•ā§‡ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + _stringToNumber: + arg1: "āĻ˛ā§‡āĻ–āĻž" + numberToString: "āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž āĻĨā§‡āĻ•ā§‡ āĻĒāĻžāĻ ā§āĻ¯" + _numberToString: + arg1: "āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + splitStrByLine: "āĻĒāĻžāĻ ā§āĻ¯āĻ•ā§‡ āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" + _splitStrByLine: + arg1: "āĻ˛ā§‡āĻ–āĻž" + ref: "āĻšāĻ˛āĻ•" + aiScriptVar: "AiScript āĻšāĻ˛āĻ•" + fn: "āĻĢāĻžāĻ‚āĻļāĻ¨" + _fn: + slots: "āĻ¸ā§āĻ˛āĻŸāĻ—ā§āĻ˛āĻŋ" + slots-info: "āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻ¸ā§āĻ˛āĻŸāĻ•ā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ˛āĻžāĻ‡āĻ¨ā§‡ āĻ˛āĻŋāĻ–ā§āĻ¨" + arg1: "āĻ†āĻ‰āĻŸāĻĒā§āĻŸ" + for: "for-āĻ˛ā§āĻĒ" + _for: + arg1: "āĻ•āĻ¤āĻŦāĻžāĻ° āĻšāĻ˛āĻŦā§‡" + arg2: "āĻ…ā§āĻ¯āĻžāĻ•āĻļāĻ¨" + typeError: "āĻ¸ā§āĻ˛āĻŸ {slot}, {expect} āĻ§āĻ°āĻ¨ā§‡āĻ° āĻŽāĻžāĻ¨ āĻ—ā§āĻ°āĻšāĻŖ āĻ•āĻ°ā§‡, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ {actual} āĻ§āĻ°āĻ¨ā§‡āĻ° āĻŽāĻžāĻ¨ āĻĻā§‡āĻ“ā§ŸāĻž āĻšā§Ÿā§‡āĻ›ā§‡!" + thereIsEmptySlot: "āĻ¸ā§āĻ˛āĻŸ {slot} āĻ–āĻžāĻ˛āĻŋīŧ" + types: + string: "āĻ˛ā§‡āĻ–āĻž" + number: "āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž" + boolean: "āĻĢā§āĻ˛ā§āĻ¯āĻžāĻ—" + array: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + stringArray: "āĻ˛ā§‡āĻ–āĻžāĻ° āĻ˛āĻŋāĻ¸ā§āĻŸ" + emptySlot: "āĻ–āĻžāĻ˛āĻŋ āĻ¸ā§āĻ˛āĻŸ" + enviromentVariables: "āĻāĻ¨āĻ­āĻžāĻ‡āĻ°āĻ¨āĻŽā§‡āĻ¨ā§āĻŸ āĻ­ā§āĻ¯āĻžāĻ°āĻŋā§Ÿā§‡āĻŦāĻ˛" + pageVariables: "āĻĒā§‡āĻœā§‡āĻ° āĻšāĻ˛āĻ•" + argVariables: "āĻ‡āĻ¨āĻĒā§āĻŸā§‡āĻ° āĻœāĻžā§ŸāĻ—āĻž" +_relayStatus: + requesting: "āĻ…āĻĒā§‡āĻ•ā§āĻˇāĻŽāĻžāĻ¨" + accepted: "āĻ…āĻ¨ā§āĻŽā§‹āĻĻāĻŋāĻ¤" + rejected: "āĻĒā§āĻ°āĻ¤ā§āĻ¯āĻžāĻ–āĻŋāĻ¤" +_notification: + fileUploaded: "āĻĢāĻžāĻ‡āĻ˛ āĻ¸āĻĢāĻ˛āĻ­āĻžāĻŦā§‡ āĻ†āĻĒāĻ˛ā§‹āĻĄ āĻ•āĻ°āĻž āĻšā§Ÿā§‡āĻ›ā§‡" + youGotMention: "{name} āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–ā§āĻ¯ āĻ•āĻ°ā§‡āĻ›ā§‡" + youGotReply: "{name} āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻœāĻŦāĻžāĻŦ āĻĻāĻŋā§Ÿā§‡āĻ›ā§‡" + youGotQuote: "{name} āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤ āĻ•āĻ°ā§‡āĻ›ā§‡" + youRenoted: "{name} āĻāĻ° Renote" + youGotPoll: "{name} āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒā§‹āĻ˛ā§‡ āĻ­ā§‹āĻŸ āĻĻāĻŋā§Ÿā§‡āĻ›ā§‡" + youGotMessagingMessageFromUser: "{name} āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻŽā§‡āĻ¸ā§‡āĻœ āĻ•āĻ°ā§‡āĻ›ā§‡" + youGotMessagingMessageFromGroup: "{name} āĻ—ā§āĻ°ā§āĻĒā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻŽā§‡āĻ¸ā§‡āĻœ āĻ†āĻ›ā§‡" + youWereFollowed: "āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻ›ā§‡" + youReceivedFollowRequest: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻĒāĻžāĻ“ā§ŸāĻž āĻ—ā§‡āĻ›ā§‡" + yourFollowRequestAccepted: "āĻ†āĻĒāĻ¨āĻžāĻ° āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ—ā§ƒāĻšā§€āĻ¤ āĻšā§Ÿā§‡āĻ›ā§‡" + youWereInvitedToGroup: "āĻ†āĻĒāĻ¨āĻŋ āĻāĻ•āĻŸāĻŋ āĻ—ā§āĻ°ā§āĻĒā§‡ āĻ†āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻŋāĻ¤ āĻšā§Ÿā§‡āĻ›ā§‡āĻ¨" + _types: + all: "āĻ¸āĻ•āĻ˛" + follow: "āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡" + mention: "āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–" + reply: "āĻ‰āĻ¤ā§āĻ¤āĻ° āĻĻāĻŋāĻ¨" + renote: "āĻ°āĻŋāĻ¨ā§‹āĻŸ" + quote: "āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤āĻŋ" + reaction: "āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž" + pollVote: "āĻĒā§‹āĻ˛ā§‡ āĻ­ā§‹āĻŸ āĻ†āĻ›ā§‡" + receiveFollowRequest: "āĻĒā§āĻ°āĻžāĻĒā§āĻ¤ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖā§‡āĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ¸āĻŽā§‚āĻš" + followRequestAccepted: "āĻ—ā§ƒāĻšā§€āĻ¤ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖā§‡āĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ¸āĻŽā§‚āĻš" + groupInvited: "āĻ—ā§āĻ°ā§āĻĒā§‡āĻ° āĻ†āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻ¨āĻ¸āĻŽā§‚āĻš" + app: "āĻ˛āĻŋāĻ™ā§āĻ• āĻ•āĻ°āĻž āĻ…ā§āĻ¯āĻžāĻĒ āĻĨā§‡āĻ•ā§‡ āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ" +_deck: + alwaysShowMainColumn: "āĻ¸āĻ°ā§āĻŦāĻĻāĻž āĻŽā§‡āĻ‡āĻ¨ āĻ•āĻ˛āĻžāĻŽ āĻĻā§‡āĻ–āĻžāĻ¨" + columnAlign: "āĻ•āĻ˛āĻžāĻŽ āĻ¸āĻžāĻœāĻžāĻ¨" + columnMargin: "āĻ•āĻ˛āĻžāĻŽā§‡āĻ° āĻŽāĻ§ā§āĻ¯āĻŦāĻ°ā§āĻ¤ā§€ āĻŽāĻžāĻ°ā§āĻœāĻŋāĻ¨" + columnHeaderHeight: "āĻ•āĻ˛āĻžāĻŽā§‡āĻ° āĻšā§‡āĻĄāĻžāĻ°ā§‡āĻ° āĻ‰āĻšā§āĻšāĻ¤āĻž" + addColumn: "āĻ•āĻ˛āĻžāĻŽ āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°ā§āĻ¨" + swapLeft: "āĻŦāĻžāĻŽā§‡ āĻ¸āĻ°āĻžāĻ¨" + swapRight: "āĻĄāĻžāĻ¨ā§‡ āĻ¸āĻ°āĻžāĻ¨" + swapUp: "āĻ‰āĻĒāĻ°ā§‡ āĻ‰āĻ āĻžāĻ¨" + swapDown: "āĻ¨āĻŋāĻšā§‡ āĻ¨āĻžāĻŽāĻžāĻ¨" + stackLeft: "āĻŦāĻžāĻŽ āĻ•āĻ˛āĻžāĻŽā§‡ āĻ¸āĻžāĻœāĻžāĻ¨" + popRight: "āĻĄāĻžāĻ¨āĻĻāĻŋāĻ•ā§‡ āĻ°āĻžāĻ–ā§āĻ¨" + profile: "āĻĒā§āĻ°ā§‹āĻĢāĻžāĻ‡āĻ˛" + _columns: + main: "āĻĒā§āĻ°āĻ§āĻžāĻ¨" + widgets: "āĻ‰āĻ‡āĻœā§‡āĻŸāĻ—ā§āĻ˛āĻŋ" + notifications: "āĻŦāĻŋāĻœā§āĻžāĻĒā§āĻ¤āĻŋ" + tl: "āĻŸāĻžāĻ‡āĻŽāĻ˛āĻžāĻ‡āĻ¨" + antenna: "āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸā§‡āĻ¨āĻž" + list: "āĻ˛āĻŋāĻ¸ā§āĻŸ" + mentions: "āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–āĻ¸āĻŽā§‚āĻš" + direct: "āĻĄāĻžāĻ‡āĻ°ā§‡āĻ•ā§āĻŸ āĻ¨ā§‹āĻŸāĻ—ā§āĻ˛āĻŋ" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 2f327a905..c5bf40740 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -141,6 +141,8 @@ flagAsBot: "Als Bot markieren" flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag fÃŧr andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskeys interne Systeme dieses Benutzerkonto als Bot behandeln." flagAsCat: "Als Katze markieren" flagAsCatDescription: "Aktiviere diese Option, um dieses Benutzerkonto als Katze zu markieren." +flagShowTimelineReplies: "Antworten in der Chronik anzeigen" +flagShowTimelineRepliesDescription: "Ist diese Option aktiviert, so werden Antworten von Benutzern auf die Notizen anderer Benuzter in der Chronik an angezeigt." autoAcceptFollowed: "Follow-Anfragen von Benutzern, denen du folgst, automatisch akzeptieren" addAccount: "Benutzerkonto hinzufÃŧgen" loginFailed: "Anmeldung fehlgeschlagen" @@ -235,6 +237,8 @@ resetAreYouSure: "Wirklich zurÃŧcksetzen?" saved: "Gespeichert" messaging: "Chat" upload: "Hochladen" +keepOriginalUploading: "Originalbild speichern" +keepOriginalUploadingDescription: "Speichert das Originalbild so, wie es ist. Ist dies deaktiviert, wird eine Version zum Anzeigen im Internet generiert." fromDrive: "Aus Drive" fromUrl: "Von einer URL" uploadFromUrl: "Von einer URL hochladen" @@ -591,6 +595,8 @@ smtpSecure: "FÃŧr SMTP-Verbindungen implizit SSL/TLS verwenden" smtpSecureInfo: "Schalte dies aus, falls du STARTTLS verwendest" testEmail: "Email-Versand testen" wordMute: "Wort-Stummschaltung" +regexpError: "Regular Expression error" +regexpErrorDescription: "Error in the regular expression on line {line} in your {tab} word mutes:" instanceMute: "Instanzstummschaltungen" userSaysSomething: "{name} hat etwas gesagt" makeActive: "Aktivieren" @@ -820,6 +826,13 @@ leaveGroupConfirm: "MÃļchtest du \"{name}\" wirklich verlassen?" useDrawerReactionPickerForMobile: "Auf mobilen Geräten ausfahrbare Reaktionsauswahl anzeigen" welcomeBackWithName: "Willkommen zurÃŧck, {name}" clickToFinishEmailVerification: "DrÃŧcke bitte auf [{ok}], um die Email-Bestätigung abzuschließen." +overridedDeviceKind: "Gerätetyp" +smartphone: "Smartphone" +tablet: "Tablet" +auto: "Automatisch" +themeColor: "Instanzfarbe" +size: "GrÃļße" +numberOfColumn: "Spaltenanzahl" _emailUnavailable: used: "Diese Email-Adresse wird bereits verwendet" format: "Das Format dieser Email-Adresse ist ungÃŧltig" @@ -1256,8 +1269,8 @@ _exportOrImport: excludeMutingUsers: "Stummgeschaltete Benutzer aussortieren" excludeInactiveUsers: "Inaktive Benutzer aussortieren" _charts: - federationInstancesIncDec: "Unterschied in der Anzahl von fÃļrderierenden Instanzen" - federationInstancesTotal: "Anzahl aller fÃļderierenden Instanzen" + federation: "FÃļderation" + apRequest: "Anfragen" usersIncDec: "Unterschied in der Anzahl von Benutzern" usersTotal: "Anzahl aller Benutzer" activeUsers: "Aktive Benutzer" diff --git a/locales/en-US.yml b/locales/en-US.yml index 6bbe84821..53434d7e6 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -141,6 +141,8 @@ flagAsBot: "Mark this account as a bot" flagAsBotDescription: "Enable this option if this account is controlled by a program. If enabled, it will act as a flag for other developers to prevent endless interaction chains with other bots and adjust Misskey's internal systems to treat this account as a bot." flagAsCat: "Mark this account as a cat" flagAsCatDescription: "Enable this option to mark this account as a cat." +flagShowTimelineReplies: "Show replies in timeline" +flagShowTimelineRepliesDescription: "Shows replies of users to notes of other users in the timeline if turned on." autoAcceptFollowed: "Automatically approve follow requests from users you're following" addAccount: "Add account" loginFailed: "Failed to sign in" @@ -235,6 +237,8 @@ resetAreYouSure: "Really reset?" saved: "Saved" messaging: "Chat" upload: "Upload" +keepOriginalUploading: "Keep original image" +keepOriginalUploadingDescription: "Saves the originally uploaded image as-is. If turned off, a version to display on the web will be generated on upload." fromDrive: "From Drive" fromUrl: "From URL" uploadFromUrl: "Upload from a URL" @@ -820,6 +824,13 @@ leaveGroupConfirm: "Are you sure you want to leave \"{name}\"?" useDrawerReactionPickerForMobile: "Display reaction picker as drawer on mobile" welcomeBackWithName: "Welcome back, {name}" clickToFinishEmailVerification: "Please click [{ok}] to complete email verification." +overridedDeviceKind: "Device type" +smartphone: "Smartphone" +tablet: "Tablet" +auto: "Auto" +themeColor: "Theme Color" +size: "Size" +numberOfColumn: "Number of columns" _emailUnavailable: used: "This email address is already being used" format: "The format of this email address is invalid" @@ -1256,8 +1267,8 @@ _exportOrImport: excludeMutingUsers: "Exclude muted users" excludeInactiveUsers: "Exclude inactive users" _charts: - federationInstancesIncDec: "Difference in # of federating instances" - federationInstancesTotal: "Total # of federating instances" + federation: "Federation" + apRequest: "Requests" usersIncDec: "Difference in # of users" usersTotal: "Total # of users" activeUsers: "Active users" diff --git a/locales/eo-UY.yml b/locales/eo-UY.yml index 0689834a1..062bf85aa 100644 --- a/locales/eo-UY.yml +++ b/locales/eo-UY.yml @@ -9,7 +9,7 @@ username: "Uzantnomo" password: "Pasvorto" forgotPassword: "Ĉu vi forgesis pasvorton?" fetchingAsApObject: "Informpetado de la Fediversoâ€Ļ" -ok: "OK" +ok: "Bone" gotIt: "Kompreni" cancel: "Nuligi" enterUsername: "Entajpu uzantnomon" @@ -65,6 +65,8 @@ files: "Dosieroj" download: "Elŝuti" driveFileDeleteConfirm: "Ĉu vi certas, ke vi volas forviŝi la dosieron \"{name}\"? Tio ankaÅ­ forviŝos la notojn kiuj citas ĝin." unfollowConfirm: "Ĉu vi certas, ke vi volas ĉesi sekvi {name}?" +exportRequested: "Vi petis elporton. Ĝi povas bezoni longan tempon. ElportaÄĩo estos aldonita al disko post elportado." +importRequested: "Vi petis enportadon. Ĝi povas bezoni longan tempon. " lists: "Listoj" noLists: "Neniu listo" note: "Noti" @@ -73,11 +75,14 @@ following: "Sekvata" followers: "Sekvantoj" followsYou: "Sekvas vin" createList: "Krei liston" -manageLists: "Bonteni liston" +manageLists: "Bonteni la listojn" error: "Eraro" somethingHappened: "Problemo okazis" retry: "Provi denove" +pageLoadError: "Fuŝiĝis enlegi paĝon." +pageLoadErrorDescription: "Ordinare tio okazas pro la retkondiĉo aÅ­ la staplo de retumilo.\nPurigu la staplon, aÅ­ refaru poste. " serverIsDead: "La servilo ne respondas. Vole atendu iom kaj penu denove." +youShouldUpgradeClient: "Por montri ĉi paĝon, bonvolu enlegi refoje kaj uzi klienton novversian." enterListName: "Entajpu nomon de la listo" privacy: "Privateco" makeFollowManuallyApprove: "Eksekvi vin devas peti al vi" @@ -132,6 +137,8 @@ settingGuide: "Agordaj rekomendoj" cacheRemoteFiles: "Stapli forajn dosierojn" flagAsBot: "Marki kiel esti uzanto de roboto" flagAsCat: "Marki kiel esti kato" +flagAsCatDescription: "Flagu por montri ke la konton havas kato." +flagShowTimelineReplies: "Montri respondon de notoj en templinio." autoAcceptFollowed: "AÅ­tomate akcepti la peton de sekvado far uzantoj kiujn vi sekvas" addAccount: "Aldoni konton" loginFailed: "Saluto malsukcesis" @@ -178,6 +185,7 @@ noUsers: "Neniu uzanto" editProfile: "Redakti profilon" noteDeleteConfirm: "Ĉu vi certas ke vi volas forviŝi la noton?" pinLimitExceeded: "Vi ne povas alpingli pli" +intro: "La instalado de Misskey finiĝis! Volu krei administran konton." done: "Fini" processing: "Prilaboradoâ€Ļ" preview: "AntaÅ­montro" @@ -216,6 +224,7 @@ resetAreYouSure: "Ĉu vi certas restarigi?" saved: "Konservita" messaging: "Retbabili" upload: "Alŝuti" +keepOriginalUploading: "Konservi la originalan bildon" fromDrive: "De la disko" fromUrl: "De URL" uploadFromUrl: "Alŝuti de URL" @@ -326,6 +335,7 @@ antennaExcludeKeywords: "Krom ĉefterminoj" notifyAntenna: "Oni sciigos novajn notojn" withFileAntenna: "Nur kun aldonaÄĩo" enableServiceworker: "Aktivigi ServiceWorker" +caseSensitive: "Distingi usklecon" withReplies: "Inkluzive respondoj" connectedTo: "Sekva konto estas konektita" notesAndReplies: "Kun respondoj" @@ -363,6 +373,7 @@ notFound: "Ne trovita" uploadFolder: "Dosierujo implicita por alŝuto" cacheClear: "Malplenigi staplon" markAsReadAllNotifications: "Marki ĉiujn sciigojn kiel legita" +markAsReadAllUnreadNotes: "Marki ĉiujn afiŝojn kiel legita" markAsReadAllTalkMessages: "Marki ĉiujn retbabiladojn kiel legita" help: "Manlibro de uzado" inputMessageHere: "Entajpu mesaĝon tie" @@ -385,6 +396,7 @@ next: "Sekve" retype: "Retajpu" noteOf: "Noto de {user}" inviteToGroup: "Inviti al grupo" +maxNoteTextLength: "Limnombro de leteroj en noto" quoteAttached: "Kun citaÄĩo" quoteQuestion: "Ĉu vi volas aldoni citaÄĩon?" noMessagesYet: "AnkoraÅ­ neniu mesaĝo" @@ -393,6 +405,7 @@ onlyOneFileCanBeAttached: "Oni povas aldoni nur unu dosieron po mesaĝo." signinRequired: "Bonvolu saluti" invitations: "Inviti" invitationCode: "Kodo de invito" +checking: "kontrolante..." available: "Disposabla" unavailable: "Ne disponebla" usernameInvalidFormat: "La uzantnomo povas enhavi minusklajn kaj majusklajn literojn, numerojn, nur kaj '_'." @@ -404,6 +417,7 @@ strongPassword: "Forta pasvorto" passwordMatched: "Konforma" passwordNotMatched: "Nekonforma" signinWith: "Saluti kun {x}" +signinFailed: "Fuŝiĝis ensaluti. Bonvolu kontroli uzantnomon kaj pasvorton." or: "AÅ­" language: "Lingvo" uiLanguage: "Lingvo de fasado" @@ -430,6 +444,7 @@ total: "Entute" appearance: "EksteraÄĩo" clientSettings: "Agordoj de kliento" accountSettings: "Agordoj de konto" +promote: "Reklamata" numberOfDays: "Nombro de tagoj" hideThisNote: "Kaŝi la noton" showFeaturedNotesInTimeline: "Montri en via templinio notojn de la tendenco" @@ -465,18 +480,20 @@ scratchpad: "Malneta redaktilo" output: "Elmeto" script: "Skripto" disablePagesScript: "Malebligi AiScript en la paĝoj" +updateRemoteUser: "Aktualigi informon de foraj uzantoj" deleteAllFiles: "Forviŝi ĉiujn dosierojn" deleteAllFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn dosierojn?" removeAllFollowing: "Ĉesi sekvi ĉiujn sekvatojn" userSuspended: "La uzanto estas flostigita." userSilenced: "La uzanto estas mutigita." +yourAccountSuspendedTitle: "La konto estas frostigita." menu: "Menuo" addItem: "Aldoni novaÄĩon" deletedNote: "Forviŝita noto" invisibleNote: "Malpublikigita noto" enableInfiniteScroll: "Ebligi infinitan rulumon" visibility: "Videbleco" -poll: "Balotujo" +poll: "Enketo" useCw: "Kaŝi enhavo" enablePlayer: "Vidigi la filmeton" disablePlayer: "Malfermi la filmeton" @@ -499,6 +516,7 @@ generateAccessToken: "Generi aÅ­tentikigan pecon" permission: "Permesoj" enableAll: "Ebligi ĉiujn" disableAll: "Malebligi ĉiujn" +tokenRequested: "Alirpermeso al konto" notificationType: "Tipo de sciigoj" edit: "Redakti" emailServer: "Retpoŝta servilo" @@ -521,7 +539,7 @@ overview: "Resumo" logs: "Protokoloj" delayed: "Prokrasto " database: "Datumbazo" -channel: "Kanalo" +channel: "Kanaloj" create: "Krei" notificationSetting: "Agordoj de sciigoj" useGlobalSetting: "Oni uzas malloka agordo" @@ -530,6 +548,7 @@ regenerateLoginToken: "Regeneri la aÅ­tentikigan pecon" fileIdOrUrl: "Dosiera identigilo aÅ­ URL" behavior: "Konduto" sample: "Ekzemplo" +reporter: "Informanto" send: "Sendi" openInNewTab: "Malfermi en nova langeto" editTheseSettingsMayBreakAccount: "Redakti tiujn agordojn povas damaĝi vian konton." @@ -543,6 +562,7 @@ createNew: "Krei novan" optional: "Opciaj" public: "Publika" i18nInfo: "Misskey estas tradukata en diversaj lingvoj de volontuloj. Oni povas kontribui ĉe {link}." +manageAccessTokens: "Bonteni la aÅ­tentikigajn pecojn" accountInfo: "Kontaj Informoj" notesCount: "La nombro de notoj" repliesCount: "La nombro de respondoj senditaj" @@ -553,6 +573,8 @@ followingCount: "La nombro de sekvatoj" followersCount: "La nombro de sekvantoj" sentReactionsCount: "La nombro de la reagoj senditaj" receivedReactionsCount: "La nombro de la reagoj ricevitaj" +pollVotesCount: "Nombro de voĉdonado" +pollVotedCount: "La nombro de la voĉoj ricevitaj en siaj enketoj" yes: "Jes" no: "Ne" driveFilesCount: "La nombro de la dosieroj sur la disko" @@ -587,6 +609,7 @@ createdAt: "Kreita je" updatedAt: "Laste ĝisdatigita" saveConfirm: "Ĉu vi konservas la ŝanĝon?" deleteConfirm: "Ĉu certas forviŝi?" +invalidValue: "Nevalida valoro" closeAccount: "Forigi konton" currentVersion: "La aktuala versio" latestVersion: "La plej nova versio" @@ -596,7 +619,7 @@ inUse: "Uzata" editCode: "Redakti kodon" receiveAnnouncementFromInstance: "Ricevi informojn sciigintajn de la nodo" emailNotification: "Sciigoj per retpoŝto" -inChannelSearch: "Serĉi en kanalo" +inChannelSearch: "Serĉi en la kanalo" useReactionPickerForContextMenu: "Dekstre-klaki por malfermi la elektilon de reagoj" typingUsers: "{users} nun skribasâ€Ļ" clear: "Vakigi" @@ -608,14 +631,18 @@ userInfo: "Informoj de uzanto" unknown: "Nekonata" online: "Surkonektita" offline: "Forkonektita" +notRecommended: "Evitindaj" instanceBlocking: "Bloki specifajn nodojn" selectAccount: "Elekti konton" user: "Uzantoj" administration: "Bontenado" accounts: "Kontoj" +configure: "Agordi" recentPosts: "Novaj afiŝoj" +popularPosts: "Plej viditaj" shareWithNote: "Kundividi en noto" ads: "ReklamaÄĩo" +expiration: "Limtempo" memo: "Memorigilo" high: "Alta" middle: "Meza" @@ -623,18 +650,25 @@ low: "Malalta" emailNotConfiguredWarning: "Vi ne agordis retpoŝtadreso." customCss: "Personecigita CSS" global: "Malloka" +squareAvatars: "Montri bildsimbolon kiel kvadrata" sent: "Sendi" received: "Ricevita" searchResult: "Serĉorezultoj" hashtags: "Kradvorto" troubleshooting: "Problemsolvi" learnMore: "Lernu pli" +misskeyUpdated: "Misskey ĝisdatiĝis!" +whatIsNew: "Montri novaÄĩojn" translate: "Traduki" translatedFrom: "Tradukita el {x}" +accountDeletionInProgress: "La konto estas forviŝanta." +resolved: "Solvita" +unresolved: "Nesolvita" breakFollow: "Ĉesigi la sekvadon al vi" itsOn: "Ŝaltita" emailRequiredForSignup: "Registri konton devas konformi retpoŝtadreson" unread: "Nelegita" +filter: "Filtrilo" controlPanel: "Ŝaltpodio" manageAccounts: "Bonteni la kontojn" classic: "Klasika" @@ -644,10 +678,15 @@ ffVisibility: "Videbleco de viaj sekvatoj/sekvantoj" ffVisibilityDescription: "Oni permesas agordi tiuln kiuj povas vidi la homojn kiujn vi sekvas, kaj la homojn kiuj sekvas vin." continueThread: "Pli vidi la mesaĝaron" incorrectPassword: "Nevalida pasvorto" +voteConfirm: "Ĉu vi voĉdonas {choice}n?" +hide: "Kaŝi" leaveGroup: "Eliĝi el la grupo" leaveGroupConfirm: "Ĉu vi certas ke vi volas eliĝi el la grupo {name}?" welcomeBackWithName: "Bonrevenon, {name}!" clickToFinishEmailVerification: "Volu klaki [{ok}] por fini la konfirmon de vian retadreson" +smartphone: "Saĝtelefono" +tablet: "Platkomputilo" +auto: "AÅ­tomate" _emailUnavailable: used: "La retpoŝto jam estas uzita." format: "Nevalida formato." @@ -658,14 +697,18 @@ _ffVisibility: followers: "Nur al sekvantoj" private: "Malpublikigita" _signup: + almostThere: "PreskaÅ­ plenumita" emailAddressInfo: "Entajpu vian retpoŝton" _accountDelete: accountDelete: "Forigi konton" + requestAccountDelete: "Peti forviŝi konton" + started: "Forviŝado komenciĝis." _ad: back: "Nuligi" _forgotPassword: enterEmail: "Entajpu la retpoŝton kiun vi registrigis al via konto. Ligilo por restarigi pasvorton estos sendita al la retadreso." _gallery: + my: "Miaj afiŝoj" liked: "Ŝatitaj notoj" like: "Ŝati" _email: @@ -687,6 +730,7 @@ _aboutMisskey: allContributors: "Ĉiuj kontribuantoj" source: "Fontkodo" translation: "Traduki Misskey" + donate: "Mondonaci al Misskey" patrons: "Mecenatoj" _mfm: dummy: "Misskey evoluigas la mondon de Fediverso" @@ -724,6 +768,7 @@ _channel: owned: "Bontenitaj de vi" following: "Sekvado" usersCount: "{n} partoprenantoj" + notesCount: "{n} notoj" _menuDisplay: sideFull: "Flanko" sideIcon: "Flanko (bildsimbolo)" @@ -735,9 +780,15 @@ _wordMute: hard: "Per la servilo" mutedNotes: "Silentigitaj notoj" _theme: + explore: "Serĉi koloraron" + install: "Instali koloraron" manage: "Bonteni kolorarojn" code: "Kolorara kodo" description: "Priskribo" + installedThemes: "Instalita koloraro" + make: "Krei koloraron" + addConstant: "Aldoni konstanton" + constant: "Konstanto" defaultValue: "ImplicitaÄĩa valoro" color: "Koloro" func: "Funkcio" @@ -745,12 +796,14 @@ _theme: lighten: "Brileco" keys: bg: "Fono" + shadow: "Ombro" navBg: "Fono de flanka stango" link: "Ligilo" hashtag: "Kradvorto" mention: "Mencioj" mentionMe: "Mencio al vi" renote: "Plusendita" + infoBg: "Fono de informo" buttonBg: "Fono de butono" driveFolderBg: "Fono de dosierujo de la disko" messageBg: "Fono de la retbabilejo" @@ -823,6 +876,7 @@ _widgets: timeline: "Templinio" clock: "Horloĝo" activity: "Aktiveco" + photos: "Fotoj" federation: "FederaÄĩo" slideshow: "Bildoprezento" button: "Butono" @@ -830,15 +884,21 @@ _widgets: aichan: "Ai" _cw: show: "Vidi pli" + chars: "{count} literoj" files: "{count} dosiero(j)" _poll: - choiceN: "Balotilo {n}" - noMore: "Oni ne povas aldoni pli." - infinite: "Neniam" + choiceN: "Ebla voĉdono {n}" + noMore: "Oni ne povas aldoni pli" + canMultipleVote: "Permesi plurelekton" + expiration: "Limtempo" deadlineTime: "hor" - votesCount: "{n} balotiloj" - vote: "Baloti" - closed: "Oni jam balotis ĝin" + duration: "DaÅ­ro" + votesCount: "{n} voĉoj" + totalVotes: "Sume {n} voĉoj" + vote: "Voĉdoni" + showResult: "Vidi la rezultojn" + voted: "Voĉdonita" + closed: "Finita" _visibility: public: "Publika" publicDescription: "Publikigi al ĉiuj en la Fediverso" @@ -876,7 +936,7 @@ _exportOrImport: blockingList: "Blokitoj" userLists: "Listoj" _charts: - federationInstancesTotal: "La totala nombro de nodoj federantaj" + federation: "FederaÄĩo" usersTotal: "La totala nombro de la uzantoj" activeUsers: "La nombro de la uzantoj aktivaj" notesTotal: "La totala nombro de notoj" @@ -965,6 +1025,45 @@ _pages: _join: arg1: "Listoj" arg2: "apartigilo" + _add: + arg1: "A" + arg2: "B" + _subtract: + arg1: "A" + arg2: "B" + _multiply: + arg1: "A" + arg2: "B" + _divide: + arg1: "A" + arg2: "B" + _mod: + arg1: "A" + arg2: "B" + _eq: + arg1: "A" + arg2: "B" + _notEq: + arg1: "A" + arg2: "B" + _and: + arg1: "A" + arg2: "B" + _or: + arg1: "A" + arg2: "B" + _lt: + arg1: "A" + arg2: "B" + _gt: + arg1: "A" + arg2: "B" + _ltEq: + arg1: "A" + arg2: "B" + _gtEq: + arg1: "A" + arg2: "B" random: "Hazardo" _randomPick: arg1: "Listoj" @@ -1004,7 +1103,7 @@ _notification: youGotReply: "{name} respondis" youGotQuote: "{name} citis" youRenoted: "{name} plusendis" - youGotPoll: "{name} balotis" + youGotPoll: "{name} voĉdonis" youGotMessagingMessageFromUser: "{name} sendis al vi mesaĝon" youGotMessagingMessageFromGroup: "Oni sendis al la grupo {name} mesaĝon" youWereFollowed: "Eksekvis vin" @@ -1019,6 +1118,7 @@ _notification: renote: "Plusendoj" quote: "Citi" reaction: "Reagoj" + pollVote: "Voĉdonoj en balotoj" receiveFollowRequest: "Ricevi peton de sekvado" followRequestAccepted: "Akceptita peto de sekvado" groupInvited: "Invitita al grupo" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index a9339acf7..1e85e7d8c 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -1091,8 +1091,8 @@ _exportOrImport: blockingList: "Bloqueados" userLists: "Listas" _charts: - federationInstancesIncDec: "VariaciÃŗn de instancias federando" - federationInstancesTotal: "Total de instancias federando" + federation: "FederaciÃŗn" + apRequest: "Pedidos" usersIncDec: "VariaciÃŗn de usuarios" usersTotal: "Total de usuarios" activeUsers: "Cantidad de usuarios activos" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 58dd000cc..1deda414c 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -141,6 +141,7 @@ flagAsBot: "Ce compte est un robot" flagAsBotDescription: "Si ce compte est gÊrÊ de manière automatisÊe, choisissez cette option. Si elle est activÊe, elle agira comme un marqueur pour les autres dÊveloppeurs afin d'Êviter des chaÃŽnes d'interaction sans fin avec d'autres robots et d'ajuster les systèmes internes de Misskey pour traiter ce compte comme un robot." flagAsCat: "Ce compte est un chat" flagAsCatDescription: "Activer l'option \" Je suis un chat \" pour ce compte." +flagShowTimelineReplies: "Afficher les rÊponses dans le fil" autoAcceptFollowed: "Accepter automatiquement les demandes d’abonnement venant d’utilisateur¡rice¡s que vous suivez" addAccount: "Ajouter un compte" loginFailed: "Échec de la connexion" @@ -235,6 +236,7 @@ resetAreYouSure: "Voulez-vous rÊinitialiser ?" saved: "EnregistrÊ" messaging: "Discuter" upload: "TÊlÊverser" +keepOriginalUploading: "Garder l’image d’origine" fromDrive: "Depuis le Drive" fromUrl: "Depuis une URL" uploadFromUrl: "TÊlÊverser via une URL" @@ -743,6 +745,7 @@ notRecommended: "DÊconseillÊ" botProtection: "Protection contre les bots" instanceBlocking: "Instances bloquÊes" selectAccount: "SÊlectionner un compte" +switchAccount: "Changer de compte" enabled: "ActivÊ" disabled: "DÊsactivÊ" quickAction: "Actions rapides" @@ -803,11 +806,13 @@ makeReactionsPublic: "Rendre les rÊactions publiques" makeReactionsPublicDescription: "Ceci rendra la liste de toutes vos rÊactions donnÊes publique." classic: "Classique" muteThread: "Mettre ce thread en sourdine" +unmuteThread: "Ne plus masquer le fil" ffVisibility: "VisibilitÊ des abonnÊs/abonnements" ffVisibilityDescription: "Permet de configurer qui peut voir les personnes que tu suis et les personnes qui te suivent." continueThread: "Afficher la suite du fil" deleteAccountConfirm: "Votre compte sera supprimÊ. Êtes vous certain ?" incorrectPassword: "Le mot de passe est incorrect." +voteConfirm: "Confirmez-vous votre vote pour ÂĢ {choice} Âģ ?" hide: "Masquer" leaveGroup: "Quitter le groupe" leaveGroupConfirm: "Êtes vous sÃģr de vouloir quitter \"{name}\" ?" @@ -969,6 +974,8 @@ _wordMute: hard: "Strict" mutedNotes: "Notes filtrÊes" _instanceMute: + instanceMuteDescription2: "SÊparer avec de nouvelles lignes" + title: "Masque les notes venant des instances listÊes." heading: "Instances à mettre en sourdine" _theme: explore: "Explorer les thèmes" @@ -1241,10 +1248,11 @@ _exportOrImport: muteList: "Comptes masquÊs" blockingList: "Comptes bloquÊs" userLists: "Listes" + excludeMutingUsers: "Exclure les utilisateur¡rice¡s mis en sourdine" excludeInactiveUsers: "Exclure les utilisateur¡rice¡s inactifs" _charts: - federationInstancesIncDec: "Variation du nombre d'instances fÊdÊrÊes" - federationInstancesTotal: "Nombre total d'instances fÊdÊrÊes" + federation: "FÊdÊration" + apRequest: "RequÃĒtes" usersIncDec: "Variation du nombre d'utilisateur¡rice¡s" usersTotal: "Nombre des utilisateur¡rice¡s au total" activeUsers: "Nombre d'utilisateurices actif¡ve¡s" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index a1d52f6ef..be766e72c 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -106,6 +106,7 @@ clickToShow: "Klik untuk melihat" sensitive: "Konten sensitif" add: "Tambahkan" reaction: "Reaksi" +reactionSetting: "Reaksi untuk dimunculkan di bilah reaksi" reactionSettingDescription2: "Geser untuk memindah urutkan, klik untuk menghapus, tekan \"+\" untuk menambahkan" rememberNoteVisibility: "Ingat pengaturan visibilitas catatan" attachCancel: "Hapus lampiran" @@ -140,6 +141,8 @@ flagAsBot: "Atur akun ini sebagai Bot" flagAsBotDescription: "Jika akun ini dikendalikan oleh program, tetapkanlah opsi ini. Jika diaktifkan, ini akan berfungsi sebagai tanda bagi pengembang lain untuk mencegah interaksi berantai dengan bot lain dan menyesuaikan sistem internal Misskey untuk memperlakukan akun ini sebagai bot." flagAsCat: "Atur akun ini sebagai kucing" flagAsCatDescription: "Nyalakan tanda ini untuk menandai akun ini sebagai kucing." +flagShowTimelineReplies: "Tampilkan balasan di linimasa" +flagShowTimelineRepliesDescription: "Menampilkan balasan pengguna dari note pengguna lain di linimasa apabila dinyalakan." autoAcceptFollowed: "Setujui otomatis permintaan mengikuti dari pengguna yang kamu ikuti" addAccount: "Tambahkan akun" loginFailed: "Gagal untuk masuk" @@ -234,6 +237,8 @@ resetAreYouSure: "Yakin mau atur ulang?" saved: "Telah disimpan" messaging: "Pesan" upload: "Unggah" +keepOriginalUploading: "Simpan gambar asli" +keepOriginalUploadingDescription: "Simpan gambar yang diunggah sebagaimana gambar aslinya. Bila dimatikan, versi tampilan web akan dihasilkan pada saat diunggah." fromDrive: "Dari Drive" fromUrl: "Dari URL" uploadFromUrl: "Unggah dari URL" @@ -446,6 +451,7 @@ uiLanguage: "Bahasa antarmuka pengguna" groupInvited: "Telah diundang ke grup" aboutX: "Tentang {x}" useOsNativeEmojis: "Gunakan Emoji bawaan sistem operasi" +disableDrawer: "Jangan gunakan menu bergaya laci" youHaveNoGroups: "Kamu tidak memiliki grup" joinOrCreateGroup: "Bergabunglah dengan grup atau kamu dapat membuat grupmu sendiri." noHistory: "Tidak ada riwayat" @@ -589,6 +595,7 @@ smtpSecure: "Gunakan SSL/TLS implisit untuk koneksi SMTP" smtpSecureInfo: "Matikan ini ketika menggunakan STARTTLS" testEmail: "Tes pengiriman surel" wordMute: "Bisukan kata" +instanceMute: "Bisuka instansi" userSaysSomething: "{name} mengatakan sesuatu" makeActive: "Aktifkan" display: "Tampilkan" @@ -616,8 +623,11 @@ reportAbuse: "Laporkan" reportAbuseOf: "Laporkan {name}" fillAbuseReportDescription: "Mohon isi rincian laporan. Jika laporan ini mengenai catatan yang spesifik, mohon lampirkan serta URL catatan tersebut." abuseReported: "Laporan kamu telah dikirimkan. Terima kasih." +reporter: "Pelapor" reporteeOrigin: "Yang dilaporkan" reporterOrigin: "Pelapor" +forwardReport: "Teruskan laporan ke instansi luar" +forwardReportIsAnonymous: "Untuk melindungi privasi akun kamu, akun anonim dari sistem akan digunakan sebagai pelapor pada instansi luar." send: "Kirim" abuseMarkAsResolved: "Tandai laporan sebagai selesai" openInNewTab: "Buka di tab baru" @@ -679,6 +689,7 @@ center: "Tengah" wide: "Lebar" narrow: "Sempit" reloadToApplySetting: "Pengaturan ini akan diterapkan saat memuat halaman kembali. Apakah kamu ingin memuat halaman kembali sekarang?" +needReloadToApply: "Pengaturan ini hanya akan diterapkan setelah memuat ulang halaman." showTitlebar: "Tampilkan bilah judul" clearCache: "Hapus tembolok" onlineUsersCount: "{n} orang sedang daring" @@ -739,6 +750,7 @@ notRecommended: "Tidak disarankan" botProtection: "Perlindungan Bot" instanceBlocking: "Instansi yang diblokir" selectAccount: "Pilih akun" +switchAccount: "Ganti akun" enabled: "Aktif" disabled: "Nonaktif" quickAction: "Aksi cepat" @@ -787,6 +799,7 @@ pubSub: "Akun Pub/Sub" lastCommunication: "Komunikasi terakhir" resolved: "Selesai" unresolved: "Belum selesai" +breakFollow: "Batalkan mengikuti" itsOn: "Aktif" itsOff: "Nonaktif" emailRequiredForSignup: "Membutuhkan alamat surel untuk mendaftar" @@ -806,6 +819,15 @@ deleteAccountConfirm: "Akun akan dihapus. Apakah kamu yakin?" incorrectPassword: "Kata sandi salah." voteConfirm: "Konfirmasi suara kamu untuk ({choice})īŧŸ" hide: "Sembunyikan" +leaveGroup: "Keluar grup" +leaveGroupConfirm: "Apakah kamu yakin untuk keluar dari \"{name}\"?" +useDrawerReactionPickerForMobile: "Tampilkan bilah reaksi sebagai laci di ponsel" +welcomeBackWithName: "Selamat datang kembali, {name}." +clickToFinishEmailVerification: "Mohon klik [{ok}] untuk menyelesaikan verifikasi email." +overridedDeviceKind: "Tipe perangkat" +smartphone: "Ponsel" +tablet: "Tablet" +auto: "Otomatis" _emailUnavailable: used: "Alamat surel ini telah digunakan" format: "Format tidak valid." @@ -963,6 +985,11 @@ _wordMute: soft: "Lembut" hard: "Keras" mutedNotes: "Catatan yang dibisukan" +_instanceMute: + instanceMuteDescription: "Pengaturan ini akan membisukan note/renote apa saja dari instansi yang terdaftar, termasuk pengguna yang membalas pengguna lain dalam instansi yang dibisukan." + instanceMuteDescription2: "Pisah dengan baris baru" + title: "Sembunyikan note dari instansi terdaftar." + heading: "Daftar instansi yang akan dibisukan" _theme: explore: "Jelajahi tema" install: "Pasang tema" @@ -1234,9 +1261,11 @@ _exportOrImport: muteList: "Bisukan" blockingList: "Blokir" userLists: "Daftar" + excludeMutingUsers: "Kecualikan pengguna yang dibisukan" + excludeInactiveUsers: "Kecualikan pengguna tidak aktif" _charts: - federationInstancesIncDec: "Perbedaan jumlah # instansi yang memfederasi" - federationInstancesTotal: "Jumlah # instansi yang memfederasi" + federation: "Federasi" + apRequest: "Permintaan" usersIncDec: "Perbedaan dalam # pengguna" usersTotal: "Jumlah # pengguna" activeUsers: "Pengguna aktif" diff --git a/locales/index.js b/locales/index.js index 8350b3d9c..b271b79b7 100644 --- a/locales/index.js +++ b/locales/index.js @@ -34,6 +34,7 @@ const languages = [ 'pl-PL', 'pt-PT', 'ru-RU', + 'sk-SK', 'ug-CN', 'uk-UA', 'zh-CN', diff --git a/locales/it-IT.yml b/locales/it-IT.yml index d13e53625..c4ec4232a 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -1177,8 +1177,8 @@ _exportOrImport: blockingList: "Account bloccati" userLists: "Liste" _charts: - federationInstancesIncDec: "Variazione del numero di istanze federate" - federationInstancesTotal: "Numero totale di istanze federate" + federation: "Federazione" + apRequest: "Richieste" usersIncDec: "Variazione del numero di utenti" usersTotal: "Numero totale di utenti" activeUsers: "Numero di utenti attivi" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b3279d78b..90dc14815 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -141,6 +141,8 @@ flagAsBot: "BotとしãĻč¨­åŽš" flagAsBotDescription: "こぎã‚ĸã‚Ģã‚ĻãƒŗトがプログナムãĢよãŖãĻ運į”¨ã•ã‚Œã‚‹å ´åˆã¯ã€ã“ぎフナグをã‚ĒãƒŗãĢしぞす。ã‚ĒãƒŗãĢすると、反åŋœãŽé€ŖéŽ–ã‚’é˜˛ããŸã‚ãŽãƒ•ãƒŠã‚°ã¨ã—ãĻäģ–ぎ開į™ē者ãĢåŊšįĢ‹ãŖたり、MisskeyãŽã‚ˇã‚šãƒ†ãƒ ä¸Šã§ãŽæ‰ąã„ãŒBotãĢ合ãŖたもぎãĢãĒりぞす。" flagAsCat: "CatとしãĻč¨­åŽš" flagAsCatDescription: "こぎã‚ĸã‚Ģã‚ĻãƒŗトがįŒĢであることをį¤ēす場合は、こぎフナグをã‚ĒãƒŗãĢしぞす。" +flagShowTimelineReplies: "ã‚ŋイムナイãƒŗãĢノãƒŧトへぎčŋ”äŋĄã‚’襨į¤ēする" +flagShowTimelineRepliesDescription: "ã‚ĒãƒŗãĢすると、ã‚ŋイムナイãƒŗãĢãƒĻãƒŧã‚ļãƒŧぎノãƒŧトäģĨ外ãĢもそぎãƒĻãƒŧã‚ļãƒŧぎäģ–ぎノãƒŧトへぎčŋ”äŋĄã‚’襨į¤ēしぞす。" autoAcceptFollowed: "フりロãƒŧ中ãƒĻãƒŧã‚ļãƒŧからぎフりロãƒĒクをč‡Ē動æ‰ŋčĒ" addAccount: "ã‚ĸã‚Ģã‚ĻãƒŗトをčŋŊ加" loginFailed: "ログイãƒŗãĢå¤ąæ•—ã—ãžã—ãŸ" @@ -235,6 +237,8 @@ resetAreYouSure: "ãƒĒã‚ģットしぞすかīŧŸ" saved: "äŋå­˜ã—ぞした" messaging: "チãƒŖット" upload: "ã‚ĸップロãƒŧド" +keepOriginalUploading: "ã‚ĒãƒĒジナãƒĢį”ģ像をäŋæŒ" +keepOriginalUploadingDescription: "į”ģ像をã‚ĸップロãƒŧドする時ãĢã‚ĒãƒĒジナãƒĢį‰ˆã‚’äŋæŒã—ぞす。ã‚ĒフãĢするとã‚ĸップロãƒŧド時ãĢブナã‚Ļã‚ļでWebå…Ŧ開į”¨į”ģ像をį”Ÿæˆã—ぞす。" fromDrive: "ドナイブから" fromUrl: "URLから" uploadFromUrl: "URLã‚ĸップロãƒŧド" @@ -321,8 +325,6 @@ disablingTimelinesInfo: "これらぎã‚ŋイムナイãƒŗをį„ĄåŠšåŒ–しãĻも、 registration: "į™ģ録" enableRegistration: "čĒ°ã§ã‚‚æ–°čĻį™ģéŒ˛ã§ãã‚‹ã‚ˆã†ãĢする" invite: "招垅" -proxyRemoteFiles: "ãƒĒãƒĸãƒŧãƒˆãŽãƒ•ã‚Ąã‚¤ãƒĢã‚’ãƒ—ãƒ­ã‚­ã‚ˇã™ã‚‹" -proxyRemoteFilesDescription: "ã“ãŽč¨­åŽšã‚’æœ‰åŠšãĢすると、æœĒäŋå­˜ãžãŸã¯äŋå­˜åŽšé‡čļ…過で削除されたãƒĒãƒĸãƒŧãƒˆãƒ•ã‚Ąã‚¤ãƒĢをロãƒŧã‚ĢãƒĢã§ãƒ—ãƒ­ã‚­ã‚ˇã—ã€ã‚ĩムネイãƒĢもį”Ÿæˆã™ã‚‹ã‚ˆã†ãĢãĒりぞす。ã‚ĩãƒŧバãƒŧぎ゚トãƒŦãƒŧジãĢはåŊąéŸŋしぞせん、" driveCapacityPerLocalAccount: "ロãƒŧã‚ĢãƒĢãƒĻãƒŧã‚ļãƒŧã˛ã¨ã‚Šã‚ãŸã‚ŠãŽãƒ‰ãƒŠã‚¤ãƒ–åŽšé‡" driveCapacityPerRemoteAccount: "ãƒĒãƒĸãƒŧトãƒĻãƒŧã‚ļãƒŧã˛ã¨ã‚Šã‚ãŸã‚ŠãŽãƒ‰ãƒŠã‚¤ãƒ–åŽšé‡" inMb: "ãƒĄã‚Ŧバイト単äŊ" @@ -418,7 +420,6 @@ next: "æŦĄ" retype: "再å…Ĩ力" noteOf: "{user}ぎノãƒŧト" inviteToGroup: "グãƒĢãƒŧプãĢ招垅" -maxNoteTextLength: "ノãƒŧトぎ文字数åˆļ限" quoteAttached: "åŧ•į”¨äģ˜ã" quoteQuestion: "åŧ•į”¨ã¨ã—ãĻæˇģäģ˜ã—ぞすかīŧŸ" noMessagesYet: "ぞだチãƒŖットはありぞせん" @@ -591,6 +592,8 @@ smtpSecure: "SMTP æŽĨįļšãĢ暗éģ™įš„ãĒSSL/TLSをäŊŋį”¨ã™ã‚‹" smtpSecureInfo: "STARTTLSäŊŋį”¨æ™‚はã‚ĒフãĢしぞす。" testEmail: "配äŋĄãƒ†ã‚šãƒˆ" wordMute: "ワãƒŧドミãƒĨãƒŧト" +regexpError: "æ­ŖčĻčĄ¨įžã‚¨ãƒŠãƒŧ" +regexpErrorDescription: "{tab}ワãƒŧドミãƒĨãƒŧトぎ{line}行į›ŽãŽæ­ŖčĻčĄ¨įžãĢエナãƒŧがį™ēį”Ÿã—ぞした:" instanceMute: "イãƒŗã‚šã‚ŋãƒŗ゚ミãƒĨãƒŧト" userSaysSomething: "{name}がäŊ•ã‹ã‚’č¨€ã„ãžã—ãŸ" makeActive: "ã‚ĸクテã‚ŖブãĢする" @@ -820,6 +823,17 @@ leaveGroupConfirm: "「{name}」から抜けぞすかīŧŸ" useDrawerReactionPickerForMobile: "ãƒĸバイãƒĢデバイ゚ぎときドロワãƒŧã§čĄ¨į¤ē" welcomeBackWithName: "おかえりãĒさい、{name}さん" clickToFinishEmailVerification: "[{ok}]をæŠŧしãĻã€ãƒĄãƒŧãƒĢã‚ĸドãƒŦ゚ぎįĸēčĒã‚’厌äē†ã—ãĻください。" +overridedDeviceKind: "デバイ゚ã‚ŋイプ" +smartphone: "゚マãƒŧトフりãƒŗ" +tablet: "ã‚ŋブãƒŦット" +auto: "č‡Ē動" +themeColor: "テãƒŧマã‚Ģナãƒŧ" +size: "ã‚ĩイã‚ē" +numberOfColumn: "列ぎ数" +searchByGoogle: "ググる" +instanceDefaultLightTheme: "イãƒŗã‚šã‚ŋãƒŗ゚デフりãƒĢトぎナイトテãƒŧマ" +instanceDefaultDarkTheme: "イãƒŗã‚šã‚ŋãƒŗ゚デフりãƒĢトぎダãƒŧクテãƒŧマ" +instanceDefaultThemeDescription: "ã‚ĒブジェクトåŊĸåŧãŽãƒ†ãƒŧマã‚ŗãƒŧãƒ‰ã‚’č¨˜å…Ĩしぞす。" _emailUnavailable: used: "æ—ĸãĢäŊŋį”¨ã•ã‚ŒãĻいぞす" @@ -1278,7 +1292,7 @@ _profile: youCanIncludeHashtags: "ãƒãƒƒã‚ˇãƒĨã‚ŋグをåĢめることができぞす。" metadata: "čŋŊåŠ æƒ…å ą" metadataEdit: "čŋŊåŠ æƒ…å ąã‚’įˇ¨é›†" - metadataDescription: "プロフã‚ŖãƒŧãƒĢãĢčĄ¨ã¨ã—ãĻ4つぞでぎčŋŊåŠ æƒ…å ąã‚’čĄ¨į¤ēすることができぞす。" + metadataDescription: "プロフã‚ŖãƒŧãƒĢãĢčĄ¨ã¨ã—ãĻčŋŊåŠ æƒ…å ąã‚’čĄ¨į¤ēすることができぞす。" metadataLabel: "ナベãƒĢ" metadataContent: "内厚" changeAvatar: "ã‚ĸバã‚ŋãƒŧį”ģ像を変更" @@ -1294,8 +1308,8 @@ _exportOrImport: excludeInactiveUsers: "äŊŋわれãĻいãĒいã‚ĸã‚Ģã‚Ļãƒŗトを除外" _charts: - federationInstancesIncDec: "é€Ŗ合ぎåĸ—減" - federationInstancesTotal: "é€ŖåˆãŽåˆč¨ˆ" + federation: "é€Ŗ合" + apRequest: "ãƒĒクエ゚ト" usersIncDec: "ãƒĻãƒŧã‚ļãƒŧぎåĸ—減" usersTotal: "ãƒĻãƒŧã‚ļãƒŧãŽåˆč¨ˆ" activeUsers: "ã‚ĸクテã‚ŖブãƒĻãƒŧã‚ļãƒŧ数" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 45ab9684d..b5b4e7257 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -81,6 +81,8 @@ somethingHappened: "ãĒんかã‚ĸã‚Ģãƒŗことがčĩˇã“ãŖたで" retry: "もãŖãēんやるīŧŸ" pageLoadError: "ペãƒŧジぎčĒ­ãŋčžŧãŋãĢå¤ąæ•—ã—ãĻしもうたでâ€Ļ" pageLoadErrorDescription: "これは晎通、ネットワãƒŧクかブナã‚Ļã‚ļキãƒŖãƒƒã‚ˇãƒĨが原因やからね。キãƒŖãƒƒã‚ˇãƒĨをクãƒĒã‚ĸã™ã‚‹ã‹ã€ã‚‚ã†ãĄãŖとだけ垅ãŖãĻくれへんかīŧŸ" +serverIsDead: "The server is not responding. Please wait for a while before trying again." +youShouldUpgradeClient: "To display this page, please reload and use a new version client. " enterListName: "ãƒĒ゚ト名をå…ĨれãĻや" privacy: "ãƒ—ãƒŠã‚¤ãƒã‚ˇãƒŧ" makeFollowManuallyApprove: "č‡Ē分がčĒã‚ãŸäēēだけがこぎã‚ĸã‚Ģã‚ĻãƒŗトをフりロãƒŧできるようãĢする" @@ -104,6 +106,7 @@ clickToShow: "æŠŧしたらčĻ‹ãˆã‚‹ã§" sensitive: "ãĄã‚‡ãŖとã‚ĸã‚Ģãƒŗやつやで" add: "åĸ—やす" reaction: "ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗ" +reactionSetting: "Reaction that will be displayed in Picker. " reactionSettingDescription2: "ドナッグでä¸Ļãŗæ›ŋえ、クãƒĒックで削除、īŧ‹ã‚’æŠŧしãĻčŋŊ加やで。" rememberNoteVisibility: "å…Ŧ開į¯„å›˛čĻšãˆã¨ã„ãĻ" attachCancel: "ぎãŖけるぎやめる" @@ -138,6 +141,8 @@ flagAsBot: "Botやで" flagAsBotDescription: "もしこぎã‚ĸã‚Ģã‚ĻãƒŗトがプログナムãĢよãŖãĻ運į”¨ã•ã‚Œã‚‹ã‚“ã‚„ãŖたら、こぎフナグをã‚ĒãƒŗãĢしãĻたぎむで。ã‚ĒãƒŗãĢすると、反åŋœãŽé€ŖéŽ–ã‚’é˜˛ããŸã‚ãŽãƒ•ãƒŠã‚°ã¨ã—ãĻäģ–ぎ開į™ē者ãĢåŊšįĢ‹ãŖたり、MisskeyãŽã‚ˇã‚šãƒ†ãƒ ä¸Šã§ãŽæ‰ąã„ãŒBotãĢ合ãŖたもんãĢãĒるんやで。" flagAsCat: "Catやで" flagAsCatDescription: "ワãƒŦ、įŒĢãĄã‚ƒã‚“ãĒらこぎフナグをつけãĻãŋīŧŸ" +flagShowTimelineReplies: "It will display the reply to the note in the timeline. " +flagShowTimelineRepliesDescription: "It will display the reply to notes other than the user notes in the timeline when you turn it on. " autoAcceptFollowed: "フりロãƒŧしとるãƒĻãƒŧã‚ļãƒŧからぎフりロãƒŧãƒĒクエ゚トを勝手ãĢč¨ąå¯ã—ã¨ã" addAccount: "ã‚ĸã‚Ģã‚ĻãƒŗトをčŋŊ加" loginFailed: "ログイãƒŗãĢå¤ąæ•—ã—ãĻしもうたâ€Ļ" @@ -232,6 +237,8 @@ resetAreYouSure: "ãƒĒã‚ģットしãĻええんīŧŸ" saved: "äŋå­˜ã—たでīŧ" messaging: "チãƒŖット" upload: "ã‚ĸップロãƒŧド" +keepOriginalUploading: "Retain the original image. " +keepOriginalUploadingDescription: "When uploading the clip, the original version will be retained. Turning it of then uploading will produce images for public use. " fromDrive: "ドナイブから" fromUrl: "URLから" uploadFromUrl: "URLã‚ĸップロãƒŧド" @@ -884,6 +891,8 @@ _exportOrImport: blockingList: "ブロック" userLists: "ãƒĒ゚ト" _charts: + federation: "é€Ŗ合" + apRequest: "ãƒĒクエ゚ト" usersTotal: "ãƒĻãƒŧã‚ļãƒŧãŽåˆč¨ˆ" activeUsers: "ã‚ĸクテã‚ŖブãƒĻãƒŧã‚ļãƒŧ数" notesIncDec: "ノãƒŧトぎåĸ—減" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 7451603a6..116e397ff 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -106,6 +106,7 @@ clickToShow: "클ëĻ­í•˜ė—Ŧ ëŗ´ę¸°" sensitive: "ė—´ëžŒėŖŧė˜" add: "ėļ”ę°€" reaction: "ëĻŦė•Ąė…˜" +reactionSetting: "ė„ íƒę¸°ė— 표ė‹œí•  ëĻŦė•Ąė…˜" reactionSettingDescription2: "끌ė–´ė„œ ėˆœė„œ ëŗ€ę˛Ŋ, 클ëĻ­í•´ė„œ ė‚­ė œ, īŧ‹ëĨŧ 눌ëŸŦė„œ ėļ”가할 ėˆ˜ ėžˆėŠĩ니다." rememberNoteVisibility: "ęŗĩ개 범ėœ„ëĨŧ 기ė–ĩ하기" attachCancel: "ė˛¨ëļ€ ėˇ¨ė†Œ" @@ -140,6 +141,8 @@ flagAsBot: "나는 봇ėž…니다" flagAsBotDescription: "ė´ ęŗ„ė •ė„ ėžë™í™”된 ėˆ˜ë‹¨ėœŧ로 ėš´ėšŠí•  ę˛Ŋėš°ė— 활ė„ąí™”í•´ ėŖŧė„¸ėš”. ė´ 플래그ëĨŧ 활ė„ąí™”하늴, 다ëĨ¸ 봇ė´ ė´ëĨŧ ė°¸ęŗ í•˜ė—Ŧ 봇 ëŧëĻŦė˜ ëŦ´í•œ ė—°ė‡„ 반ė‘ė„ 회í”ŧ하거나, ė´ ęŗ„ė •ė˜ ė‹œėŠ¤í…œ ėƒė—ė„œė˜ ėˇ¨ę¸‰ė´ Bot ėš´ė˜ė— ėĩœė í™”되는 등ė˜ ëŗ€í™”ę°€ ėƒęšë‹ˆë‹¤." flagAsCat: "나는 ęŗ ė–‘ė´ë‹¤ëƒĨ" flagAsCatDescription: "ė´ ęŗ„ė •ė´ ęŗ ė–‘ė´ëŧ늴 활ė„ąí™” 해ėŖŧė„¸ėš”." +flagShowTimelineReplies: "타ėž„ëŧė¸ė— 노트ė˜ ë‹ĩ글ė„ 표ė‹œí•˜ę¸°" +flagShowTimelineRepliesDescription: "ė´ ė„¤ė •ė„ 활ė„ąí™”하늴 타ėž„ëŧė¸ė— 다ëĨ¸ ėœ ė € 간ė˜ ë‹ĩ글ė„ 표ė‹œí•Šë‹ˆë‹¤." autoAcceptFollowed: "팔로ėš° ė¤‘ė¸ ėœ ė €ëĄœëļ€í„°ė˜ 팔로ėš° ėš”ė˛­ė„ ėžë™ ėˆ˜ëŊ" addAccount: "ęŗ„ė • ėļ”ę°€" loginFailed: "로그ė¸ė— ė‹¤íŒ¨í–ˆėŠĩ니다" @@ -234,6 +237,8 @@ resetAreYouSure: "ė´ˆę¸°í™” 하ė‹œę˛ ėŠĩ니까?" saved: "ė €ėžĨ하ė˜€ėŠĩ니다" messaging: "대화" upload: "ė—…ëĄœë“œ" +keepOriginalUploading: "ė›ëŗ¸ ė´ë¯¸ė§€ëĨŧ ėœ ė§€" +keepOriginalUploadingDescription: "ė´ë¯¸ė§€ëĨŧ ė—…ëĄœë“œí•  때ė— ė›ëŗ¸ė„ 그대로 ėœ ė§€í•Šë‹ˆë‹¤. 비활ė„ąí™”하늴 ė—…ëĄœë“œí•  때 브ëŧėš°ė €ė—ė„œ ė›š ęŗĩ개ėšŠ ė´ë¯¸ė§€ëĨŧ ėƒė„ąí•Šë‹ˆë‹¤." fromDrive: "드ëŧė´ë¸Œė—ė„œ" fromUrl: "URL로ëļ€í„°" uploadFromUrl: "URL ė—…ëĄœë“œ" @@ -446,6 +451,7 @@ uiLanguage: "UI 표ė‹œ ė–¸ė–´" groupInvited: "꡸ëŖšė— ė´ˆëŒ€ë˜ė—ˆėŠĩ니다" aboutX: "{x}ė— 대하ė—Ŧ" useOsNativeEmojis: "OS 기ëŗ¸ ė´ëĒ¨ė§€ëĨŧ ė‚ŦėšŠ" +disableDrawer: "드로ė–´ 메뉴ëĨŧ ė‚ŦėšŠí•˜ė§€ ė•Šę¸°" youHaveNoGroups: "꡸ëŖšė´ ė—†ėŠĩ니다" joinOrCreateGroup: "다ëĨ¸ ꡸ëŖšė˜ ė´ˆëŒ€ëĨŧ 받거나, ė§ė ‘ ėƒˆ ꡸ëŖšė„ 만들ė–´ ëŗ´ė„¸ėš”." noHistory: "기록ė´ ė—†ėŠĩ니다" @@ -617,8 +623,11 @@ reportAbuse: "ė‹ ęŗ " reportAbuseOf: "{name}ė„ ė‹ ęŗ í•˜ę¸°" fillAbuseReportDescription: "ė‹ ęŗ í•˜ë ¤ëŠ” ė´ėœ ëĨŧ ėžė„¸ížˆ ė•Œë ¤ėŖŧė„¸ėš”. 특ė • 게ė‹œëŦŧė„ ė‹ ęŗ í•  때ė—ëŠ” 게ė‹œëŦŧė˜ URL도 íŦ함해 ėŖŧė„¸ėš”." abuseReported: "ė‹ ęŗ ëĨŧ ëŗ´ëƒˆėŠĩ니다. ė‹ ęŗ í•´ ėŖŧė…”ė„œ 감ė‚Ŧ합니다." +reporter: "ė‹ ęŗ ėž" reporteeOrigin: "í”ŧė‹ ęŗ ėž" reporterOrigin: "ė‹ ęŗ ėž" +forwardReport: "ëĻŦëĒ¨íŠ¸ ė¸ėŠ¤í„´ėŠ¤ė—ë„ ė‹ ęŗ  내ėšŠ ëŗ´ë‚´ę¸°" +forwardReportIsAnonymous: "ëĻŦëĒ¨íŠ¸ ė¸ėŠ¤í„´ėŠ¤ė—ė„œëŠ” 나ė˜ ė •ëŗ´ëĨŧ ëŗŧ ėˆ˜ ė—†ėœŧ늰, ėĩëĒ…ė˜ ė‹œėŠ¤í…œ ęŗ„ė •ėœŧ로 표ė‹œëŠë‹ˆë‹¤." send: "ė „ė†Ą" abuseMarkAsResolved: "해결됨ėœŧ로 표ė‹œ" openInNewTab: "ėƒˆ 탭ė—ė„œ ė—´ę¸°" @@ -680,6 +689,7 @@ center: "가ėš´ë°" wide: "넓게" narrow: "ėĸę˛Œ" reloadToApplySetting: "ė´ ė„¤ė •ė„ ė ėšŠí•˜ë ¤ëŠ´ 페ė´ė§€ëĨŧ ėƒˆëĄœęŗ ėš¨í•´ė•ŧ 합니다. 바로 ėƒˆëĄœęŗ ėš¨í•˜ė‹œę˛ ėŠĩ니까?" +needReloadToApply: "ëŗ€ę˛Ŋ ė‚Ŧ항ė€ ėƒˆëĄœęŗ ėš¨í•˜ëŠ´ ė ėšŠëŠë‹ˆë‹¤." showTitlebar: "타ė´í‹€ 바ëĨŧ 표ė‹œí•˜ę¸°" clearCache: "ėēė‹œ 비ėš°ę¸°" onlineUsersCount: "{n}ëĒ…ė´ ė ‘ė† ė¤‘" @@ -740,6 +750,7 @@ notRecommended: "ėļ”ė˛œí•˜ė§€ ė•ŠėŒ" botProtection: "Bot ë°Šė–´" instanceBlocking: "ė¸ėŠ¤í„´ėŠ¤ ė°¨ë‹¨" selectAccount: "ęŗ„ė • ė„ íƒ" +switchAccount: "ęŗ„ė • 바꾸기" enabled: "활ė„ąí™”" disabled: "비활ė„ąí™”" quickAction: "ëš ëĨ¸ 동ėž‘" @@ -808,6 +819,15 @@ deleteAccountConfirm: "ęŗ„ė •ė´ ė‚­ė œë˜ęŗ  되돌ëĻ´ ėˆ˜ ė—†ę˛Œ 됩니다. incorrectPassword: "비밀번호가 ė˜Ŧ바ëĨ´ė§€ ė•ŠėŠĩ니다." voteConfirm: "\"{choice}\"ė— íˆŦ표하ė‹œę˛ ėŠĩ니까?" hide: "ėˆ¨ę¸°ę¸°" +leaveGroup: "꡸ëŖš 나가기" +leaveGroupConfirm: "\"{name}\"ė—ė„œ 나갈까ėš”?" +useDrawerReactionPickerForMobile: "ëĒ¨ë°”ėŧė—ė„œ 드로ė–´ 메뉴로 표ė‹œ" +welcomeBackWithName: "환ė˜í•Šë‹ˆë‹¤, {name}님" +clickToFinishEmailVerification: "[{ok}]ëĨŧ 눌ëŸŦ ė´ëŠ”ėŧ ė¸ėĻė„ ė™„ëŖŒí•˜ė„¸ėš”." +overridedDeviceKind: "ėžĨėš˜ ėœ í˜•" +smartphone: "ėŠ¤ë§ˆíŠ¸í°" +tablet: "태블ëĻŋ" +auto: "ėžë™" _emailUnavailable: used: "ė´ 메ėŧ ėŖŧė†ŒëŠ” ė‚ŦėšŠė¤‘ėž…니다" format: "형ė‹ė´ ė˜Ŧ바ëĨ´ė§€ ė•ŠėŠĩ니다" @@ -1244,8 +1264,8 @@ _exportOrImport: excludeMutingUsers: "뮤트한 ėœ ė € ė œė™¸í•˜ę¸°" excludeInactiveUsers: "휴면 ė¤‘ė¸ ęŗ„ė • ė œė™¸í•˜ę¸°" _charts: - federationInstancesIncDec: "ė—°í•Š ė¸ėŠ¤í„´ėŠ¤ ėˆ˜ ėĻę°" - federationInstancesTotal: "ė—°í•Š ė¸ėŠ¤í„´ėŠ¤ ėˆ˜ 합ęŗ„" + federation: "ė—°í•Š" + apRequest: "ėš”ė˛­" usersIncDec: "ėœ ė € ėˆ˜ ėĻę°" usersTotal: "ėœ ė € ėˆ˜ 합ęŗ„" activeUsers: "활ė„ą ėœ ė € ėˆ˜" diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index 386357f2d..38f9a88af 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -291,6 +291,8 @@ _exportOrImport: userLists: "Lijsten" excludeMutingUsers: "Negeer gedempte gebruikers" excludeInactiveUsers: "Negeer inactieve gebruikers" +_charts: + federation: "Federatie" _timelines: home: "Startpagina" _pages: diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 27772663b..0b57a3a46 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -1084,7 +1084,8 @@ _exportOrImport: blockingList: "Zablokuj" userLists: "Listy" _charts: - federationInstancesTotal: "Łącznie sfederowanych instancji" + federation: "Federacja" + apRequest: "Åģądania" usersTotal: "Łącznie # uÅŧytkownikÃŗw" activeUsers: "Aktywni uÅŧytkownicy" _instanceCharts: diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 7de9f8ff9..b29d2173c 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -235,6 +235,7 @@ resetAreYouSure: "На ŅĐ°ĐŧĐžĐŧ Đ´ĐĩĐģĐĩ ŅĐąŅ€ĐžŅĐ¸Ņ‚ŅŒ?" saved: "ĐĄĐžŅ…Ņ€Đ°ĐŊĐĩĐŊĐž" messaging: "ХООйŅ‰ĐĩĐŊиŅ" upload: "ЗаĐŗŅ€ŅƒĐˇĐ¸Ņ‚ŅŒ" +keepOriginalUploading: "ĐĄĐžŅ…Ņ€Đ°ĐŊиŅ‚ŅŒ иŅŅ…ОдĐŊĐžĐĩ иСОйŅ€Đ°ĐļĐĩĐŊиĐĩ" fromDrive: "ĐĄ ÂĢдиŅĐēĐ°Âģ" fromUrl: "По ŅŅŅ‹ĐģĐēĐĩ" uploadFromUrl: "ЗаĐŗŅ€ŅƒĐˇĐ¸Ņ‚ŅŒ ĐŋĐž ŅŅŅ‹ĐģĐēĐĩ" @@ -743,6 +744,7 @@ notRecommended: "НĐĩ Ņ€ĐĩĐēĐžĐŧĐĩĐŊĐ´ŅƒĐĩŅ‚ŅŅ" botProtection: "БоŅ‚ОСаŅ‰Đ¸Ņ‚Đ°" instanceBlocking: "БĐģĐžĐēиŅ€ĐžĐ˛ĐēĐ° иĐŊŅŅ‚Đ°ĐŊŅĐžĐ˛" selectAccount: "ВŅ‹ĐąĐĩŅ€Đ¸Ņ‚Đĩ ŅƒŅ‡Ņ‘Ņ‚ĐŊŅƒŅŽ СаĐŋиŅŅŒ" +switchAccount: "ĐĄĐŧĐĩĐŊиŅ‚ŅŒ ŅƒŅ‡Ņ‘Ņ‚ĐŊŅƒŅŽ СаĐŋиŅŅŒ" enabled: "ВĐēĐģ." disabled: "ОŅ‚ĐēĐģ." quickAction: "БŅ‹ŅŅ‚Ņ€ĐžĐĩ Đ´ĐĩĐšŅŅ‚виĐĩ" @@ -1249,8 +1251,8 @@ _exportOrImport: excludeMutingUsers: "За иŅĐēĐģŅŽŅ‡ĐĩĐŊиĐĩĐŧ СаĐŗĐģŅƒŅˆĐĩĐŊĐŊŅ‹Ņ… ĐŋĐžĐģŅŒĐˇĐžĐ˛Đ°Ņ‚ĐĩĐģĐĩĐš" excludeInactiveUsers: "БĐĩС ĐŊĐĩĐ°ĐēŅ‚ивĐŊŅ‹Ņ… ŅƒŅ‡Ņ‘Ņ‚ĐŊŅ‹Ņ… СаĐŋиŅĐĩĐš" _charts: - federationInstancesIncDec: "ИСĐŧĐĩĐŊĐĩĐŊиĐĩ вĐŊĐĩŅˆĐŊиŅ… ŅĐ˛ŅĐˇĐĩĐš" - federationInstancesTotal: "КоĐģиŅ‡ĐĩŅŅ‚вО вĐŊĐĩŅˆĐŊиŅ… ŅĐ˛ŅĐˇĐĩĐš" + federation: "ФĐĩĐ´ĐĩŅ€Đ°Ņ†Đ¸Ņ" + apRequest: "ЗаĐŋŅ€ĐžŅŅ‹" usersIncDec: "ИСĐŧĐĩĐŊĐĩĐŊиĐĩ Ņ‡Đ¸ŅĐģĐ° ĐŋĐžĐģŅŒĐˇĐžĐ˛Đ°Ņ‚ĐĩĐģĐĩĐš" usersTotal: "КоĐģиŅ‡ĐĩŅŅ‚вО ĐŋĐžĐģŅŒĐˇĐžĐ˛Đ°Ņ‚ĐĩĐģĐĩĐš" activeUsers: "АĐēŅ‚ивĐŊŅ‹Đĩ ĐŋĐžĐģŅŒĐˇĐžĐ˛Đ°Ņ‚ĐĩĐģи" diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml new file mode 100644 index 000000000..a501591a8 --- /dev/null +++ b/locales/sk-SK.yml @@ -0,0 +1,1641 @@ +--- +_lang_: "Slovenčina" +headlineMisskey: "SieÅĨ prepojenÃĄ poznÃĄmkami" +introMisskey: "Vitajte! Misskey je otvorenÃĄ a decentralizovanÃĄ mikroblogovacia sluÅžba.\n\"PoznÃĄmkami\" môŞete zdieÄžaÅĨ svoje myÅĄlienky so vÅĄetkÃŊmi okolo. 📡\nPomocou \"reakcií\" môŞete rÃŊchlo vyjadri svoje pocity o kaÅždÊho poznÃĄmkach. 👍\nPoďte objavovaÅĨ svet! 🚀" +monthAndDay: "{day}. {month}." +search: "HÄžadaÅĨ" +notifications: "OznÃĄmenia" +username: "Meno pouŞívateÄža" +password: "Heslo" +forgotPassword: "ZabudnutÊ heslo" +fetchingAsApObject: "Načítam Ãēdaje z Fediverzu" +ok: "OK" +gotIt: "Rozumiem!" +cancel: "ZruÅĄiÅĨ" +enterUsername: "Zadajte meno pouŞívateÄža" +renotedBy: "{user} preposlal/a" +noNotes: "ÅŊiadne poznÃĄmky" +noNotifications: "ÅŊiadne oznÃĄmenia" +instance: "InÅĄtancia" +settings: "Nastavenia" +basicSettings: "VÅĄeobecnÊ nastavenia" +otherSettings: "RozÅĄÃ­renÊ nastavenia" +openInWindow: "OtvoriÅĨ v novom okne" +profile: "Profil" +timeline: "ČasovÃĄ os" +noAccountDescription: "Tento pouŞívateÄž zatiaÄž nenapísal o sebe." +login: "PrihlÃĄsiÅĨ sa" +loggingIn: "Prebieha prihlasovanie" +logout: "OdhlÃĄsiÅĨ" +signup: "RegistrovaÅĨ" +uploading: "NahrÃĄvanie..." +save: "UloÅžiÅĨ" +users: "PouŞívatelia" +addUser: "PridaÅĨ pouŞívateÄža" +favorite: "PÃĄÄi sa mi" +favorites: "ObÄžÃēbenÊ" +unfavorite: "NepÃĄÄi sa mi" +favorited: "PridanÊ do obÄžÃēbenÃŊch" +alreadyFavorited: "UÅž je medzi obÄžÃēbenÃŊmi" +cantFavorite: "Nepodarilo sa pridaÅĨ medzi obÄžÃēbenÊ." +pin: "PripnÃēÅĨ" +unpin: "OdopnÃēÅĨ" +copyContent: "KopírovaÅĨ obsah" +copyLink: "KopírovaÅĨ odkaz" +delete: "OdstrÃĄniÅĨ" +deleteAndEdit: "OdstrÃĄniÅĨ a upraviÅĨ" +deleteAndEditConfirm: "Naozaj chcete odstrÃĄniÅĨ tÃēto poznÃĄmku a upraviÅĨ ju? Stratíte tÃŊm vÅĄetky reakcie a odpovede na ňu." +addToList: "PridaÅĨ do zoznamu" +sendMessage: "OdoslaÅĨ sprÃĄvu" +copyUsername: "KopírovaÅĨ meno pouŞívateÄža" +searchUser: "HÄžadaÅĨ pouŞívateÄžov" +reply: "OdpovedaÅĨ" +loadMore: "ZobraziÅĨ viac" +showMore: "ZobraziÅĨ viac" +youGotNewFollower: "MÃĄte novÊho sledujÃēceho" +receiveFollowRequest: "ÅŊiadosÅĨ o sledovanie prijatÃĄ" +followRequestAccepted: "ÅŊiadosÅĨ o sledovanie akceptovanÃĄ" +mention: "Zmienka" +mentions: "Zmienky" +directNotes: "Priame poznÃĄmky" +importAndExport: "Import a export" +import: "ImportovaÅĨ" +export: "ExportovaÅĨ" +files: "SÃēbor/y" +download: "StiahnuÅĨ" +driveFileDeleteConfirm: "Naozaj chcete odstrÃĄniÅĨ sÃēbor \"{name}\"? PoznÃĄmky s tÃŊmto sÃēborom sa odstrÃĄnia tieÅž." +unfollowConfirm: "Naozaj uÅž nechcete sledovaÅĨ {name}?" +exportRequested: "VyÅžiadali ste export. MôŞe to chvíĞu trvaÅĨ. Po skončení pribudne na vaÅĄom disku." +importRequested: "PoÅžiadali ste o export. MôŞe to chvíĞu trvaÅĨ." +lists: "Zoznamy" +noLists: "NemÃĄte Åžiadne zoznamy" +note: "PoznÃĄmka" +notes: "PoznÃĄmky" +following: "Sledujete" +followers: "SledujÃēci" +followsYou: "SledujÃē vÃĄs" +createList: "VytvoriÅĨ zoznam" +manageLists: "SpravovaÅĨ zoznamy" +error: "Chyba" +somethingHappened: "Ups. Niečo sa nepodarilo." +retry: "OpakovaÅĨ" +pageLoadError: "Nepodarilo sa načítaÅĨ strÃĄnku" +pageLoadErrorDescription: "Toto môŞe byÅĨ spôsobenÊ problÊmami so sieÅĨou alebo cachou prehliadača. SkÃēste vyčistiÅĨ cache a potom skÃēsiÅĨ znova po chvíli." +serverIsDead: "Tento server nereaguje. Prosím chvíĞu počkajte a skÃēste znova." +youShouldUpgradeClient: "Na pozretie tejto strÃĄnky prosím obnovte svojho klienta." +enterListName: "Zadajte nÃĄzov zoznamu" +privacy: "SÃēkromie" +makeFollowManuallyApprove: "ÅŊiadosti o sledovanie treba schvÃĄliÅĨ" +defaultNoteVisibility: "PredvolenÃĄ viditeÄžnosÅĨ" +follow: "SledovaÅĨ" +followRequest: "PoÅžiadaÅĨ o sledovanie" +followRequests: "ÅŊiadosti o sledovanie" +unfollow: "NesledovaÅĨ" +followRequestPending: "ÅŊiadosÅĨ o sledovanie čakÃĄ" +enterEmoji: "Zadajte emoji" +renote: "PreposlaÅĨ" +unrenote: "VrÃĄtiÅĨ preposlanie" +renoted: "PreposlanÊ." +cantRenote: "Tento príspevok sa nedÃĄ preposlaÅĨ." +cantReRenote: "Odpoveď nemôŞe byÅĨ odstrÃĄnenÃĄ." +quote: "CitovaÅĨ" +pinnedNote: "PripnutÊ poznÃĄmky" +pinned: "PripnÃēÅĨ" +you: "Vy" +clickToShow: "Kliknutím zobrazíte" +sensitive: "NSFW" +add: "PridaÅĨ" +reaction: "Reakcie" +reactionSetting: "Reakcie zobrazenÊ vo vÃŊbere reakcií" +reactionSettingDescription2: "Ťahaním preusporiadate, kliknutím odstrÃĄnite, Stlačením \"+\" pridÃĄte" +rememberNoteVisibility: "ZapamätaÅĨ nastavenia viditeÄžnosti poznÃĄmky" +attachCancel: "OdstrÃĄniÅĨ prílohu" +markAsSensitive: "OznačiÅĨ ako NSFW" +unmarkAsSensitive: "OdznačiÅĨ NSFW" +enterFileName: "Zadajte nÃĄzov sÃēboru" +mute: "VypnÃēÅĨ zvuk" +unmute: "ZapnÃēÅĨ zvuk" +block: "ZablokovaÅĨ" +unblock: "OdblokovaÅĨ" +suspend: "ZmraziÅĨ" +unsuspend: "OdmraziÅĨ" +blockConfirm: "Naozaj chcete zablokovaÅĨ tento Ãēčet?" +unblockConfirm: "Naozaj chcete odblokovaÅĨ tento Ãēčet?" +suspendConfirm: "Naozaj chcete zmraziÅĨ tento Ãēčet?" +unsuspendConfirm: "Naozaj chcete odmraziÅĨ tento Ãēčet?" +selectList: "Vyberte zoznam" +selectAntenna: "Vyberte antÊnu" +selectWidget: "Vyberte widget" +editWidgets: "UpraviÅĨ widget" +editWidgetsExit: "Hotovo" +customEmojis: "VlastnÊ emoji" +emoji: "Emoji" +emojis: "Emoji" +emojiName: "NÃĄzov emoji" +emojiUrl: "URL obrÃĄzku" +addEmoji: "PridaÅĨ emoji" +settingGuide: "OdporÃēčanÊ nastavenia" +cacheRemoteFiles: "Cachovanie vzdialenÃŊch sÃēborov" +cacheRemoteFilesDescription: "ZakÃĄzanie tohoto nastavenia spôsobí, Åže vzdialenÊ sÃēbory budÃē odkazovanÊ priamo, namiesto ukladania do cache. UÅĄetrí sa tak miesto na serveri, ale zvÃŊÅĄi sa dÃĄtovÃŊ tok, pretoÅže sa negenerujÃē miniatÃēry." +flagAsBot: "Tento Ãēčet je bot" +flagAsBotDescription: "Ak je tento Ãēčet ovlÃĄdanÃŊ programom, zaÅĄkrtnite tÃēto voÄžbu. Ostatní uvidia, Åže je to bot a zabrÃĄni nekonečnÃŊm interakciÃĄm s ďalÅĄÃ­mi botmi a upraví internÊ systÊmy Misskey, aby ho povaÅžoval za bota." +flagAsCat: "Tento Ãēčet je mačka" +flagAsCatDescription: "ZvoÄžte tÃēto voÄžbu, aby bol tento Ãēčet označenÃŊ ako mačka." +flagShowTimelineReplies: "ZobraziÅĨ odpovede na poznÃĄmky v časovej osi" +flagShowTimelineRepliesDescription: "Keď je zapnutÊ, na časovej osi sa zobrazia odpovede k poznÃĄmkam pouŞívateÄžov okrem samotnÃŊch poznÃĄmok." +autoAcceptFollowed: "Automaticky prijaÅĨ sledovanie od Ãēčtov, ktorÊ sledujete" +addAccount: "PridaÅĨ Ãēčet" +loginFailed: "PrihlÃĄsenie sa nepodarilo." +showOnRemote: "ZobraziÅĨ na vzdialenom serveri" +general: "VÅĄeobecnÊ" +wallpaper: "Tapeta" +setWallpaper: "NastaviÅĨ tapetu" +removeWallpaper: "OdstrÃĄniÅĨ tapetu" +searchWith: "HÄžadaÅĨ: {q}" +youHaveNoLists: "NemÃĄte Åžiadne zoznamy" +followConfirm: "Naozaj chcete sledovaÅĨ {name}?" +proxyAccount: "Proxy Ãēčet" +proxyAccountDescription: "Proxy Ãēčet je Ãēčet, ktorÃŊ za určitÃŊch podmienok sleduje pouŞívateÄžov na diaÄžku vaÅĄÃ­m menom. Napríklad keď pouŞívateÄž zaradí vzdialenÊho pouŞívateÄža do zoznamu, pokiaÄž nikto nesleduje pouŞívateÄža na zozname, aktivita nebude doručenÃĄ na server, takÅže namiesto toho bude pouŞívateÄža sledova proxy Ãēčet." +host: "Host" +selectUser: "Vyberte pouŞívateÄža" +recipient: "PrijímateÄž" +annotation: "KomentÃĄre" +federation: "FederÃĄcia" +instances: "InÅĄtancia" +registeredAt: "RegistrÃĄcia" +latestRequestSentAt: "PoslednÃĄ odoslanÃĄ poÅžiadavka" +latestRequestReceivedAt: "PoslednÃĄ prijatÃĄ poÅžiadavka" +latestStatus: "PoslednÃŊ status" +storageUsage: "VyuÅžitÊ ÃēloÅžisko" +charts: "Grafy" +perHour: "za hodinu" +perDay: "za deň" +stopActivityDelivery: "ZastaviÅĨ posielanie aktivít" +blockThisInstance: "BlokovaÅĨ tento server" +operations: "OperÃĄcie" +software: "SoftvÊr" +version: "Verzia" +metadata: "MetadÃĄta" +withNFiles: "{n} sÃēbor(ov)" +monitor: "Monitor" +jobQueue: "Fronta Ãēloh" +cpuAndMemory: "CPU a pamäÅĨ" +network: "SieÅĨ" +disk: "Disk" +instanceInfo: "InformÃĄcie o serveri" +statistics: "Å tatistiky" +clearQueue: "VyčistiÅĨ frontu" +clearQueueConfirmTitle: "Naozaj chcete zruÅĄiÅĨ vÅĄetky Ãēlohy vo fronte?" +clearQueueConfirmText: "VÅĄetky nedoručenÊ poznÃĄmky čakajÃēce vo fronte nebudÃē federovanÊ. Zvyčajne tÃĄto operÃĄcia nie je potrebnÃĄ." +clearCachedFiles: "VyprÃĄzdniÅĨ cache" +clearCachedFilesConfirm: "Naozaj chcete odstrÃĄniÅĨ vÅĄetky nacachovanÊ vzdialenÊ sÃēbory?" +blockedInstances: "BlokovanÊ servery" +blockedInstancesDescription: "Zoznam blokovanÃŊch serverov na riadkoch. BlokovanÊ servery nebudÃē môcÅĨ komunikovaÅĨ s tÃŊmto serverom." +muteAndBlock: "Umlčania a blokÃĄcie" +mutedUsers: "Umlčaní pouŞívatelia" +blockedUsers: "Blokovaní pouŞívatelia" +noUsers: "ÅŊiadni pouŞívatelia" +editProfile: "UpraviÅĨ profil" +noteDeleteConfirm: "Naozaj chcete odstrÃĄniÅĨ tÃēto poznÃĄmku?" +pinLimitExceeded: "ĎalÅĄie poznÃĄmky uÅž nemôŞete pripnÃēÅĨ." +intro: "InÅĄtalÃĄcia Misskey je dokončenÃĄ! Prosím vytvorte administrÃĄtora." +done: "Hotovo" +processing: "Pracujem..." +preview: "NÃĄhÄžad" +default: "PredvolenÊ" +noCustomEmojis: "ÅŊiadne emoji" +noJobs: "ÅŊiadne Ãēlohy" +federating: "FederÃĄcia" +blocked: "BlokovanÊ" +suspended: "ZmrazenÊ" +all: "VÅĄetko" +subscribing: "Odoberanie" +publishing: "Zverejňovanie" +notResponding: "NeodpovedÃĄ" +instanceFollowing: "Sledujem na serveri" +instanceFollowers: "SledujÃēci zo servera" +instanceUsers: "PouŞívatelia servera" +changePassword: "ZmeniÅĨ heslo" +security: "Zabezpečenie" +retypedNotMatch: "ZadanÊ vstupy nesÃēhlasia" +currentPassword: "AktuÃĄlne heslo" +newPassword: "NovÊ heslo" +newPasswordRetype: "NovÊ heslo (znovu)" +attachFile: "PriloÅžiÅĨ sÃēbor" +more: "Viac!" +featured: "ObÄžÃēbenÊ poznÃĄmky" +usernameOrUserId: "Meno pouŞívateÄža alebo ID pouŞívateÄža" +noSuchUser: "PouŞívateÄž sa nenaÅĄiel" +lookup: "VyhÄžadaÅĨ" +announcements: "Oznamy" +imageUrl: "URL obrÃĄzku" +remove: "OdstrÃĄniÅĨ" +removed: "OdstrÃĄnenÊ" +removeAreYouSure: "Naozaj chcete odstrÃĄniÅĨ \"{x}\"?" +deleteAreYouSure: "Naozaj chcete odstrÃĄniÅĨ \"{x}\"?" +resetAreYouSure: "Naozaj resetovaÅĨ?" +saved: "UloÅženÊ" +messaging: "Chat" +upload: "NahraÅĨ sÃēbor" +keepOriginalUploading: "ZachovaÅĨ pôvodnÃŊ obrÃĄzok" +keepOriginalUploadingDescription: "UloŞí pôvodnÃŊ obrÃĄzok ako je. Ak je vypnutÊ, verzia pre web sa vygeneruje pri nahratí." +fromDrive: "Z disku" +fromUrl: "Z URL" +uploadFromUrl: "NahraÅĨ z URL adresy" +uploadFromUrlDescription: "URL adresa nahrÃĄvanÊho sÃēboru" +uploadFromUrlRequested: "Upload vyÅžiadanÃŊ" +uploadFromUrlMayTakeTime: "NahrÃĄvanie môŞe nejakÃŊ čas trvaÅĨ." +explore: "ObjavovaÅĨ" +messageRead: "PrečítanÊ" +noMoreHistory: "To je vÅĄetko" +startMessaging: "ZačaÅĨ chat" +nUsersRead: "prečítanÊ {n} pouŞívateÄžmi" +agreeTo: "SÃēhlasím s {0}" +tos: "Podmienky pouŞívania" +start: "ZačaÅĨ" +home: "Domov" +remoteUserCaution: "Tieto informÃĄcie nemusia byÅĨ aktuÃĄlne, keďŞe pouŞívateÄž je na vzdialenom serveri." +activity: "Aktivita" +images: "ObrÃĄzky" +birthday: "DÃĄtum narodenia" +yearsOld: "{age} rokov" +registeredDate: "DÃĄtum registrÃĄcie" +location: "Lokalita" +theme: "TÊma" +themeForLightMode: "TÊma pri svetlom reÅžime" +themeForDarkMode: "TÊma pri tmavom reÅžime" +light: "SvetlÃĄ" +dark: "TmavÃĄ" +lightThemes: "SvetlÃĄ tÊma" +darkThemes: "TmavÃĄ tÊma" +syncDeviceDarkMode: "SynchronizovaÅĨ tmavÃē tÊmu s nastavení vÃĄÅĄho systÊmu" +drive: "Disk" +fileName: "NÃĄzov sÃēboru" +selectFile: "Vyberte sÃēbor" +selectFiles: "Vyberte sÃēbory" +selectFolder: "Vyberte priečinok" +selectFolders: "Vyberte priečinky" +renameFile: "PremenovaÅĨ sÃēbor" +folderName: "NÃĄzov priečinka" +createFolder: "VytvoriÅĨ priečinok" +renameFolder: "PremenovaÅĨ priečinok" +deleteFolder: "OdstrÃĄniÅĨ priečinok" +addFile: "PridaÅĨ sÃēbor" +emptyDrive: "VÃĄÅĄ disk je prÃĄzdny" +emptyFolder: "Tento priečinok je prÃĄzdny" +unableToDelete: "NedÃĄ sa odstrÃĄniÅĨ" +inputNewFileName: "Zadajte novÃŊ nÃĄzov" +inputNewDescription: "Zadajte novÃŊ popis" +inputNewFolderName: "Zadajte novÃŊ nÃĄzov priečinka" +circularReferenceFolder: "CieÄžovÃŊ priečinok je podpriečinkom priečinka, ktorÃŊ chcete presunÃēÅĨ." +hasChildFilesOrFolders: "NemôŞete odstrÃĄniÅĨ priečinok sÃē sÃēbormi." +copyUrl: "KopírovaÅĨ URL" +rename: "PremenovaÅĨ" +avatar: "Avatar" +banner: "BAnner" +nsfw: "NSFW" +whenServerDisconnected: "Keď sa stratí spojenie so serverom" +disconnectedFromServer: "Spojenie so serverom bolo preruÅĄenÊ" +reload: "ObnoviÅĨ" +doNothing: "IgnorovaÅĨ" +reloadConfirm: "Chcete obnoviÅĨ časovÃē os?" +watch: "SledovaÅĨ" +unwatch: "NesledovaÅĨ" +accept: "SÃēhlasím" +reject: "NesÃēhlasím" +normal: "NormÃĄlne" +instanceName: "NÃĄzov servera" +instanceDescription: "Popis servera" +maintainerName: "SprÃĄvca" +maintainerEmail: "E-mailovÃĄ adresa sprÃĄvcu" +tosUrl: "URL zmluvnÃŊch podmienok" +thisYear: "Rok" +thisMonth: "Mesiac" +today: "Dnes" +dayX: "{day}" +monthX: "{month}" +yearX: "{year}" +pages: "StrÃĄnky" +integration: "IntegrÃĄcia" +connectService: "PripojiÅĨ" +disconnectService: "OdpojiÅĨ" +enableLocalTimeline: "PovoliÅĨ lokÃĄlnu časovÃē os" +enableGlobalTimeline: "PovoliÅĨ globÃĄlnu časovÃē os" +disablingTimelinesInfo: "AdministrÃĄtori a moderÃĄtori majÃē vÅždy prístup ku vÅĄetkÃŊm časovÃŊm osiam, aj keď sÃē vypnutÊ." +registration: "RegistrÃĄcia" +enableRegistration: "PovoliÅĨ registrÃĄciu novÃŊch pouŞívateÄžov" +invite: "PozvaÅĨ" +proxyRemoteFiles: "Proxy vzdialenÃŊch sÃēborov" +proxyRemoteFilesDescription: "Ak je zapnutÊ, vzdialenÊ sÃēbory, ktorÊ nie sÃē uloÅženÊ lokÃĄlne alebo boli odstrÃĄnenÊ kvôli obmedzeniam ÃēloÅžiska, budÃē vyÅžiadanÊ cez proxy, vrÃĄtane generovani miniatÃēr. Neovplyvní to ÃēloÅžisko na serveri." +driveCapacityPerLocalAccount: "Kapacita disku pre pouŞívateÄža" +driveCapacityPerRemoteAccount: "Kapacita disku pre vzdialenÊho pouŞívateÄža" +inMb: "V megabajtoch" +iconUrl: "Favicon URL" +bannerUrl: "URL obrÃĄzku bannera" +backgroundImageUrl: "URL obrÃĄzku pozadia" +basicInfo: "ZÃĄkladnÊ informÃĄcie" +pinnedUsers: "Pripnutí pouŞívatelia" +pinnedUsersDescription: "Zoznam mien pouŞívateÄžov oddelenÃŊch riadkami, ktorÃŊ budÃē pripnutí v zÃĄloÅžke \"ObjavovaÅĨ\"." +pinnedPages: "PripnutÊ strÃĄnky" +pinnedPagesDescription: "Na kaÅždÃŊ riadok zadajte cesty strÃĄnok, ktorÊ chcete pripnÃēÅĨ na vrch strÃĄnky tohoto servera." +pinnedClipId: "ID pripnutÊho klipu" +pinnedNotes: "PripnutÊ poznÃĄmky" +hcaptcha: "hCaptcha" +enableHcaptcha: "ZapnÃēÅĨ hCaptchu" +hcaptchaSiteKey: "Site key" +hcaptchaSecretKey: "Secret key" +recaptcha: "reCAPTCHA" +enableRecaptcha: "ZapnÃēÅĨ ReCAPTCHA" +recaptchaSiteKey: "Site key" +recaptchaSecretKey: "Secret key" +avoidMultiCaptchaConfirm: "PouÅžitie viacerÃŊch Captcha systÊmov môŞe sposobiÅĨ problÊmy. Chcete radÅĄej vypnÃēÅĨ ostatnÊ Captcha systÊmy? MôŞete ich povoliÅĨ viacerÊ stlačení ZruÅĄiÅĨ." +antennas: "AntÊny" +manageAntennas: "SpravovaÅĨ antÊny" +name: "NÃĄzov" +antennaSource: "Zdroj antÊny" +antennaKeywords: "PočÃēvanÊ kÄžÃēčovÊ slovÃĄ" +antennaExcludeKeywords: "VylÃēčenÊ kÄžÃēčovÊ slovÃĄ" +antennaKeywordsDescription: "OddeÄžte medzerami pre podmienku AND alebo novÃŊmi riadkami pre podmienku OR." +notifyAntenna: "UpozorniÅĨ na novÊ poznÃĄmky" +withFileAntenna: "Len poznÃĄmky so sÃēbormi" +enableServiceworker: "PovoliÅĨ Service Worker" +antennaUsersDescription: "Zoznam pouŞívateÄžov jeden na riadok" +caseSensitive: "RozliÅĄuje malÊ a veÄžkÊ písmenÃĄ" +withReplies: "VrÃĄtane odpovedí" +connectedTo: "NasledujÃēce Ãēčty sÃē pripojenÊ" +notesAndReplies: "PoznÃĄmky a odpovede" +withFiles: "VrÃĄtane sÃēborov" +silence: "Ticho" +silenceConfirm: "Naozaj chcete utÃ­ÅĄiÅĨ tohoto pouŞívateÄža?" +unsilence: "VrÃĄtiÅĨ utÃ­ÅĄenie" +unsilenceConfirm: "Naozaj chcete vrÃĄtiÅĨ utÃ­ÅĄenie tohoto pouŞívateÄža?" +popularUsers: "PopulÃĄrni pouŞívatelia" +recentlyUpdatedUsers: "PouŞívatelia s najnovÅĄou aktivitou" +recentlyRegisteredUsers: "NajnovÅĄÃ­ pouŞívatelia" +recentlyDiscoveredUsers: "Naposledy objavení pouŞívatelia" +exploreUsersCount: "Existuje {count} pouŞívateÄžov" +exploreFediverse: "ObjavovaÅĨ Fediverzum" +popularTags: "PopulÃĄrne značky" +userList: "Zoznamy" +about: "InformÃĄcie" +aboutMisskey: "O Misskey" +administrator: "AdministrÃĄtor" +token: "Token" +twoStepAuthentication: "DvojfaktorovÃĄ autentifikÃĄcia" +moderator: "ModerÃĄtor" +nUsersMentioned: "{n} pouŞívateÄžov spomenulo" +securityKey: "BezpečnostnÃŊ kÄžÃēč" +securityKeyName: "NÃĄzov kÄžÃēča" +registerSecurityKey: "RegistrovaÅĨ bezpečnostnÃŊ kÄžÃēč" +lastUsed: "Naposledy pouÅžitÊ" +unregister: "OdregistrovaÅĨ" +passwordLessLogin: "NastaviÅĨ bezheslovÊ prihlÃĄsenie" +resetPassword: "ResetovaÅĨ heslo" +newPasswordIs: "NovÊ heslo je \"{password}\"" +reduceUiAnimation: "Menej UI animÃĄcií" +share: "ZdieÄžaÅĨ" +notFound: "NenÃĄjdenÊ" +notFoundDescription: "NenaÅĄla sa Åžiadna strÃĄnka na zadanej URL." +uploadFolder: "PredvolenÃŊ priečinok pre nahrÃĄvanie" +cacheClear: "VyčistiÅĨ cache" +markAsReadAllNotifications: "OznačiÅĨ vÅĄetky oznÃĄmenia ako prečítanÊ" +markAsReadAllUnreadNotes: "OznačiÅĨ vÅĄetky poznÃĄmky ako prečítanÊ" +markAsReadAllTalkMessages: "OznačiÅĨ vÅĄetky sprÃĄvy ako prečítanÊ" +help: "Pomoc" +inputMessageHere: "Sem napÃ­ÅĄte sprÃĄvu" +close: "ZavrieÅĨ" +group: "Skupina" +groups: "Skupiny" +createGroup: "VytvoriÅĨ skupinu" +ownedGroups: "VlastnenÊ skupiny" +joinedGroups: "Členstvo v skupinÃĄch" +invites: "PozvaÅĨ" +groupName: "NÃĄzov skupiny" +members: "Členovia" +transfer: "Presun" +messagingWithUser: "SÃēkromnÃŊ chat" +messagingWithGroup: "SkupinovÃŊ chat" +title: "Nadpis" +text: "Text" +enable: "PovoliÅĨ" +next: "ĎalÅĄÃ­" +retype: "Zadajte znovu" +noteOf: "PoznÃĄmky pouŞívateÄža {user}" +inviteToGroup: "PozvaÅĨ do skupiny" +maxNoteTextLength: "MaximÃĄlny počet znakov poznÃĄmky" +quoteAttached: "CitovanÊ" +quoteQuestion: "PripojiÅĨ ako citÃĄt?" +noMessagesYet: "ZatiaÄž Åžiadne sprÃĄvy" +newMessageExists: "MÃĄte novÃē sprÃĄvu" +onlyOneFileCanBeAttached: "Ku sprÃĄve môŞete priloÅžiÅĨ len jeden sÃēbor" +signinRequired: "PrihlÃĄste sa, prosím!" +invitations: "PozvaÅĨ" +invitationCode: "KÃŗd pozvÃĄnky" +checking: "Overujem..." +available: "DostupnÊ" +unavailable: "NedostupnÊ" +usernameInvalidFormat: "PovolenÊ sÃē písmenÃĄ, čísla a _." +tooShort: "PríliÅĄ krÃĄtke" +tooLong: "PríliÅĄ dlhÊ" +weakPassword: "SlabÊ heslo" +normalPassword: "DobrÊ heslo" +strongPassword: "SilnÊ heslo" +passwordMatched: "HeslÃĄ sÃē rovnakÊ" +passwordNotMatched: "HeslÃĄ nie sÃē rovnakÊ" +signinWith: "PrihlÃĄsiÅĨ sa pouÅžitím {x}" +signinFailed: "NedÃĄ sa prihlÃĄsiÅĨ. Skontrolujte prosím meno pouŞívateÄža a heslo." +tapSecurityKey: "Ťuknite na bezpečnostnÃŊ kÄžÃēč" +or: "Alebo" +language: "Jazyk" +uiLanguage: "Jazyk pouŞívateÄžskÊho prostredia" +groupInvited: "PozvaÅĨ do skupiny" +aboutX: "O {x}" +useOsNativeEmojis: "PouŞívaÅĨ natívne emoji z OS" +disableDrawer: "NepouŞívaÅĨ ÅĄuflíkovÊ menu" +youHaveNoGroups: "NemÃĄte Åžiadne skupiny" +joinOrCreateGroup: "PoÅžiadajte o pozvanie do existujÃēcej skupiny alebo vytvorte novÃē." +noHistory: "ÅŊiadna histÃŗria" +signinHistory: "HistÃŗria prihlÃĄsení" +disableAnimatedMfm: "VypnÃēÅĨ MFM s animÃĄciou" +doing: "Pracujem..." +category: "KategÃŗrie" +tags: "Značky" +docSource: "Zdroj tohoto dokumentu" +createAccount: "VytvoriÅĨ Ãēčet" +existingAccount: "ExistujÃēci Ãēčet" +regenerate: "PregenerovaÅĨ" +fontSize: "VeÄžkosÅĨ písma" +noFollowRequests: "NemÃĄte nijakÊ čakajÃēce Åžiadosti o sledovanie" +openImageInNewTab: "OtvoriÅĨ obrÃĄzok v novom tabe" +dashboard: "PrehÄžad" +local: "LokÃĄlne" +remote: "VzdialenÊ" +total: "Celkom" +weekOverWeekChanges: "MedzitÃŊÅždňovÊ zmeny" +dayOverDayChanges: "MedzidennÊ zmeny" +appearance: "VzhÄžad" +clientSettings: "Nastavenia klienta" +accountSettings: "Nastavenia Ãēčtu" +promotion: "PropagÃĄcia" +promote: "PropagovaÅĨ" +numberOfDays: "Počet dní" +hideThisNote: "SkryÅĨ tÃēto poznÃĄmku" +showFeaturedNotesInTimeline: "ZobraziÅĨ vÃŊznamnÊ poznÃĄmky v časovej osi" +objectStorage: "ObjektovÊ ÃēloÅžisko" +useObjectStorage: "PouÅžiÅĨ objektovÊ ÃēloÅžisko" +objectStorageBaseUrl: "ZÃĄkladnÃĄ URL" +objectStorageBaseUrlDesc: "URL pouÅžitÃĄ ako referencia. Zadajte URL svojho CDN alebo Proxy ak niektorÊ pouŞívate. S3: 'https://.s3.amazonaws.com', GCS: 'https://storage.googleapis.com/' atď." +objectStorageBucket: "Bucket" +objectStorageBucketDesc: "Prosím zadajte nÃĄzov bucketu od svojho poskytovateÄža." +objectStoragePrefix: "Prefix" +objectStoragePrefixDesc: "SÃēbory budÃē ukladanÊ do priečinkov pod tÃŊmto prefixom." +objectStorageEndpoint: "Endpoint" +objectStorageEndpointDesc: "Nechajte prÃĄzdne ak pouŞívate AWS S3, inak zadajte endpoint ako \"\" alebo \":\". ZÃĄleŞí to od sluÅžby, ktorÃē pouŞívate." +objectStorageRegion: "RegiÃŗn" +objectStorageRegionDesc: "Zadajte regiÃŗn ako 'xx-east-1'. Ak vaÅĄa sluÅžba nerozliÅĄuje regiÃŗny, nechajte prÃĄzdne alebo zadajte 'us-east-1'." +objectStorageUseSSL: "PouÅžiÅĨ SSL" +objectStorageUseSSLDesc: "Vypnite to ak nechcete pouÅžiÅĨ HTTPS na API spojenia." +objectStorageUseProxy: "PripÃĄjaÅĨ cez Proxy" +objectStorageUseProxyDesc: "Vypnite ak nechcete, aby spojenia na API iÅĄli cez Proxy" +objectStorageSetPublicRead: "Pri nahratí nastaviÅĨ \"public-read\"" +serverLogs: "Logy servera" +deleteAll: "OdstrÃĄniÅĨ vÅĄetko" +showFixedPostForm: "ZobraziÅĨ formulÃĄr na novÊ príspevky nad časovou osou" +newNoteRecived: "SÃē novÊ poznÃĄmky" +sounds: "Zvuky" +listen: "PočÃēvaÅĨ" +none: "ÅŊiadne" +showInPage: "ZobraziÅĨ v strÃĄnke" +popout: "Pop-out" +volume: "HlasitosÅĨ" +masterVolume: "CelkovÃĄ hlasitosÅĨ" +details: "Detaily" +chooseEmoji: "VybraÅĨ emoji" +unableToProcess: "OperÃĄciu sa nepodarilo dokončiÅĨ." +recentUsed: "Neposledy pouÅžitÊ" +install: "NainÅĄtalovaÅĨ" +uninstall: "OdinÅĄtalovaÅĨ" +installedApps: "AutorizovanÊ aplikÃĄcie" +nothing: "Nič tu nie je" +installedDate: "DÃĄtum autorizÃĄcie" +lastUsedDate: "Naposledy pouÅžitÊ" +state: "Status" +sort: "ZoradiÅĨ" +ascendingOrder: "Vzostupne" +descendingOrder: "Zostupne" +scratchpad: "ZÃĄpisník" +scratchpadDescription: "ZÃĄpisník poskytuje prostredia pre experimenty s AiScriptom. MôŞete písaÅĨ, spÃēÅĄÅĨaÅĨ a skÃēÅĄaÅĨ vysledky pri interakcii s Misskey." +output: "VÃŊstup" +script: "Skript" +disablePagesScript: "VypnÃēÅĨ AiScript na strÃĄnkach" +updateRemoteUser: "AktualizovaÅĨ informÃĄcie o vzdialenom Ãēčte" +deleteAllFiles: "OdstrÃĄniÅĨ vÅĄetky sÃēbory" +deleteAllFilesConfirm: "Naozaj chcete odstrÃĄniÅĨ vÅĄetky sÃēbory" +removeAllFollowing: "ZruÅĄiÅĨ sledovani vÅĄetkÃŊch pouŞívateÄžov" +removeAllFollowingDescription: "TÃŊmto zruÅĄÃ­te sledovanie vÅĄetkÃŊch pouŞívateÄžov z {host}. Spustite to prosím, keď server napríklad uÅž neexistuje." +userSuspended: "Tento pouŞívateÄž je zmrazenÃŊ." +userSilenced: "Tento pouŞívateÄž je umlčanÃŊ." +yourAccountSuspendedTitle: "Tento Ãēčet je zmrazenÃŊ" +yourAccountSuspendedDescription: "Tento Ãēčet bol zmrazenÃŊ, lebo poruÅĄoval zmluvnÊ podmienky. Kontaktujte administrÃĄtora ak chcete viac podrobností. Prosím nevytvÃĄrajte novÃŊ Ãēčet." +menu: "Menu" +divider: "OddeÄžovač" +addItem: "PridaÅĨ poloÅžku" +relays: "Prenos" +addRelay: "PridaÅĨ prenos" +inboxUrl: "Inbox URL" +addedRelays: "PridanÊ prenosy" +serviceworkerInfo: "Musí byÅĨ zapnutÊ pre push notifikÃĄcie." +deletedNote: "OdstrÃĄnenÊ príspevky" +invisibleNote: "SkrytÊ príspevky" +enableInfiniteScroll: "ZapnÃēÅĨ nekonečnÊ skrolovanie" +visibility: "ViditeÄžnosÅĨ" +poll: "Hlasovanie" +useCw: "SkryÅĨ obsah" +enablePlayer: "OtvoriÅĨ video prehrÃĄvač" +disablePlayer: "ZavrieÅĨ video prehrÃĄvač" +expandTweet: "RozÅĄÃ­riÅĨ tweet" +themeEditor: "Editor tÊm" +description: "Popis" +describeFile: "PridaÅĨ nadpis" +enterFileDescription: "Zadajte nadpis" +author: "Autor" +leaveConfirm: "MÃĄte neuloÅženÊ zmeny. Chcete ich zahodiÅĨ?" +manage: "AdministrÃĄcia" +plugins: "Pluginy" +deck: "Deck" +useBlurEffectForModal: "PouÅžiÅĨ efekt rozmazania na oknÃĄ" +useFullReactionPicker: "PouÅžiÅĨ plnÃē veÄžkosÅĨ vÃŊberu reakcií" +width: "Šírka" +height: "VÃŊÅĄka" +large: "VeÄžkÊ" +medium: "StrednÊ" +small: "MalÊ" +generateAccessToken: "VygenerovaÅĨ prístupovÃŊ token" +permission: "OprÃĄvnenia" +enableAll: "PovoliÅĨ vÅĄetko" +disableAll: "VypnÃēÅĨ vÅĄetko" +tokenRequested: "PovoliÅĨ prístup k Ãēčtu" +pluginTokenRequestedDescription: "Tento plugin bude môcÅĨ pouŞívaÅĨ oprÃĄvnenia nastavenÊ tu." +notificationType: "Typ oznÃĄmenia" +edit: "UpraviÅĨ" +useStarForReactionFallback: "PouÅžiÅĨ ★ keď emoji reakcie nie je znÃĄme" +emailServer: "Email server" +enableEmail: "ZapnÃēÅĨ email" +emailConfigInfo: "PouŞíva sa na overenie emaily pri registrÃĄcii alebo pri zabudnutí hesla" +email: "Email" +emailAddress: "EmailovÃĄ adresa" +smtpConfig: "Nastavenia SMTP servera" +smtpHost: "Host" +smtpPort: "Port" +smtpUser: "Meno pouŞívateÄža" +smtpPass: "Heslo" +emptyToDisableSmtpAuth: "Vynechaním mena hesla vypnete SMTP verifikÃĄciu" +smtpSecure: "PouÅžiÅĨ implicitnÊ SSL/TLS pre SMTP spojenia" +smtpSecureInfo: "Toto vypnite keď pouŞívate STARTTLS" +testEmail: "Doručenie testovacieho emailu" +wordMute: "StÃ­ÅĄenie slova" +regexpError: "Chyba v regulÃĄrnom vÃŊraze" +regexpErrorDescription: "Na riadku {line} sa vyskytla chyba v stÃ­ÅĄenom slove {tab}." +instanceMute: "StÃ­ÅĄenÊ servery" +userSaysSomething: "{name} niečo povedal/a" +makeActive: "AktivovaÅĨ" +display: "ZobraziÅĨ" +copy: "KopírovaÅĨ" +metrics: "Metriky" +overview: "PrehÄžad" +logs: "Logy" +delayed: "OneskorenÊ" +database: "DatabÃĄza" +channel: "KanÃĄly" +create: "VytvoriÅĨ" +notificationSetting: "Nastavenia oznÃĄmení" +notificationSettingDesc: "Vyberte typ oznÃĄmení na zobrazenie" +useGlobalSetting: "PouÅžiÅĨ globÃĄlne nastavenie" +useGlobalSettingDesc: "Ak je zapnutÊ, pouÅžijÃē sa oznÃĄmenia vÃĄÅĄho Ãēčtu. Ak je vypnutÊ, pouÅžijÃē sa jednotlivÊ nastavenia." +other: "Ostatní" +regenerateLoginToken: "PregenerovaÅĨ prihlasovací token" +regenerateLoginTokenDescription: "Pregeneruje token interne pouŞívanÃŊ počas prihlÃĄsenia. NormÃĄlne toto netreba robiÅĨ. Ak sa pregeneruje, vÅĄetky zariadenia sa odhlÃĄsia." +setMultipleBySeparatingWithSpace: "ViacerÊ poloÅžky oddeÄžte medzerami." +fileIdOrUrl: "ID alebo URL sÃēboru" +behavior: "SprÃĄvanie" +sample: "UkÃĄÅžka" +abuseReports: "NahlÃĄsenia" +reportAbuse: "NahlÃĄsiÅĨ" +reportAbuseOf: "NahlÃĄsiÅĨ {name}" +fillAbuseReportDescription: "Prosím vyplňte podrobnosti nahlÃĄsenia. Ak sa tÃŊka konkrÊtnej poznÃĄmky, prosím napÃ­ÅĄte jej URL." +abuseReported: "VaÅĄe nahlÃĄsenie je odoslanÊ. VeÄžmi pekne ďakujeme." +reporter: "NahlÃĄsil" +reporteeOrigin: "Pôvod nahlÃĄsenÊho" +reporterOrigin: "Pôvod nahlasovača" +forwardReport: "PreposlaÅĨ nahlÃĄsenie na server" +forwardReportIsAnonymous: "Namiesto vÃĄÅĄho Ãēčtu bude zobrazenÃŊ anonymnÃŊ systÊmovÃŊ Ãēčet na vzdialenom serveri ako autor nahlÃĄsenia." +send: "PoslaÅĨ" +abuseMarkAsResolved: "OznačiÅĨ nahlÃĄsenia ako vyrieÅĄenÊ" +openInNewTab: "OtvoriÅĨ v novom tabe" +openInSideView: "OtvoriÅĨ v bočnom paneli" +defaultNavigationBehaviour: "PredvolenÊ sprÃĄvanie navigÃĄcie" +editTheseSettingsMayBreakAccount: "Úpravou tÃŊchto nastavení si môŞete pokaziÅĨ Ãēčet." +instanceTicker: "InformÃĄcie servera o poznÃĄmkach" +waitingFor: "ČakÃĄ sa na {x}" +random: "NÃĄhodnÊ" +system: "SystÊm" +switchUi: "PrepnÃēÅĨ UI" +desktop: "Desktop" +clip: "Klip" +createNew: "VytvoriÅĨ novÃŊ" +optional: "VoliteÄžnÊ" +createNewClip: "VytvoriÅĨ novÃŊ klip" +public: "VerejnÊ" +i18nInfo: "Misskey je prekladanÃŊ do rôznych jazykov dobrovoÄžníkmi. PomôcÅĨ môŞete na {link}." +manageAccessTokens: "SpravovaÅĨ prístupovÊ tokeny" +accountInfo: "InformÃĄcie o Ãēčte" +notesCount: "Počet poznÃĄmok" +repliesCount: "Počet odoslanÃŊch odpovedí" +renotesCount: "Počet preposlanÃŊch poznÃĄmok" +repliedCount: "Počet odpovedí prijatÃŊch" +renotedCount: "Počet preposlaní prijatÃŊch" +followingCount: "Počet sledovanÃŊch Ãēčtov" +followersCount: "Počet sledujÃēcich" +sentReactionsCount: "Počet poslanÃŊch reakcií" +receivedReactionsCount: "Počet prijatÃŊch reakcií" +pollVotesCount: "Počet odoslanÃŊch hlasov" +pollVotedCount: "Počet prijatÃŊch hlasov" +yes: "Áno" +no: "Nie" +driveFilesCount: "Počet sÃēborov na disku" +driveUsage: "VyuÅžitÊ miesto na disku" +noCrawle: "OdmietaÅĨ indexovanie crawlerov" +noCrawleDescription: "PoÅžiadaÅĨ vyhÄžadÃĄvače, aby neindexovali vÃĄÅĄ profil, poznÃĄmky, strÃĄnky, atď." +lockedAccountInfo: "PokÃŊm nenastavíte viditeÄžnosÅĨ poznÃĄmok na \"Len pre sledujÃēcich\", vaÅĄe príspevky bude vidieÅĨ hocikto, aj keď vyÅžadujete manuÃĄlne potvrdenie sledovania." +alwaysMarkSensitive: "Predvolene označovaÅĨ ako NSFW" +loadRawImages: "NačítaÅĨ originÃĄlne obrÃĄzky namiesto miniatÃēr" +disableShowingAnimatedImages: "NeprehrÃĄvaÅĨ animovanÊ obrÃĄzky" +verificationEmailSent: "Odoslali sme overovací email. Overenie dokončíte kliknutím na odkaz v emaili." +notSet: "NenastavenÊ" +emailVerified: "Email overenÃŊ" +noteFavoritesCount: "Počet obÄžÃēbenÃŊch poznÃĄmok" +pageLikesCount: "Počet obÄžÃēbenÃŊch strÃĄnok" +pageLikedCount: "Počet prijatÃŊch \"pÃĄÄi sa mi\"" +contact: "Kontakt" +useSystemFont: "PouÅžiÅĨ predvolenÊ systÊmovÊ písmo" +clips: "Klip" +experimentalFeatures: "ExperimentÃĄlne funkcie" +developer: "VÃŊvojÃĄr" +makeExplorable: "SpraviÅĨ Ãēčet viditeÄžnÃŊ v \"ObjavovaÅĨ\"" +makeExplorableDescription: "Ak toto vypnete, vÃĄÅĄ Ãēčet sa nezobrazí v sekcii \"Objavovat\"." +showGapBetweenNotesInTimeline: "ZobraziÅĨ medzeru medzi príspevkami časovej osi." +duplicate: "DuplikovaÅĨ" +left: "NaÄžavo" +center: "Stred" +wide: "Å iroko" +narrow: "Úzko" +reloadToApplySetting: "Toto nastavenia sa prejaví aÅž po obnovení strÃĄnky. ObnoviÅĨ teraz?" +needReloadToApply: "Toto nastavenie sa prejaví aÅž po obnovení strÃĄnky." +showTitlebar: "ZobraziÅĨ riadok s nadpisom" +clearCache: "VyprÃĄzdniÅĨ cache" +onlineUsersCount: "{n} pouŞívateÄžov je online" +nUsers: "{n} pouŞívateÄžov" +nNotes: "{n} poznÃĄmok" +sendErrorReports: "PoslaÅĨ nahlÃĄsenie chyby" +sendErrorReportsDescription: "Keď je zapnutÊ, v prípade problÊmu sa odoÅĄlÃē podrobnÊ informÃĄcie o chybe do Misskey. PomôŞete tak zvÃŊÅĄiÅĨ kvalitu Misskey.\nTieto informÃĄcie zahŕňajÃē verziu vÃĄÅĄho OS, pouÅžitÃŊ prehliadač, histÃŗriu aktivít, atď." +myTheme: "Moja tÊma" +backgroundColor: "Pozadie" +accentColor: "Akcent" +textColor: "Text" +saveAs: "UloÅžiÅĨ ako..." +advanced: "RozÅĄÃ­renÊ" +value: "Hodnoty" +createdAt: "VytvorenÊ" +updatedAt: "UpravenÊ" +saveConfirm: "UloÅžiÅĨ zmeny?" +deleteConfirm: "Naozaj odstrÃĄniÅĨ?" +invalidValue: "NesprÃĄvna hodnota." +registry: "Register" +closeAccount: "ZavrieÅĨ Ãēčet" +currentVersion: "AktuÃĄlna verzia" +latestVersion: "NajnovÅĄia verzia" +youAreRunningUpToDateClient: "PouŞívate najnovÅĄiu verziu vÃĄÅĄho klienta." +newVersionOfClientAvailable: "Je dostupnÃĄ novÅĄia verzia vÃĄÅĄho klienta." +usageAmount: "VyuÅžitie" +capacity: "Kapacita" +inUse: "PouÅžitÊ" +editCode: "UpraviÅĨ kÃŗd" +apply: "PouÅžiÅĨ" +receiveAnnouncementFromInstance: "PrijaÅĨ notifikÃĄcie z tohoto servera" +emailNotification: "EmailovÊ upozornenia" +publish: "ZverejniÅĨ" +inChannelSearch: "HÄžadaÅĨ v kanÃĄli" +useReactionPickerForContextMenu: "OtvoriÅĨ vÃŊber reakcií na pravÃŊ klik" +typingUsers: "{users} pÃ­ÅĄe/u" +jumpToSpecifiedDate: "SkočiÅĨ na konkrÊtny dÃĄtum" +showingPastTimeline: "PrÃĄve vidíte starÃē časovÃē os" +clear: "VrÃĄtiÅĨ" +markAllAsRead: "OznačiÅĨ vÅĄetko ako prečítanÊ" +goBack: "SpäÅĨ" +unlikeConfirm: "Naozaj odstrÃĄniÅĨ vÃĄÅĄ like?" +fullView: "PlnÃŊ pohÄžad" +quitFullView: "ZavrieÅĨ plnÃŊ pohÄžad" +addDescription: "PridaÅĨ popis" +userPagePinTip: "Tu môŞete zobraziÅĨ poznÃĄmky zvolením \"PripnÃēÅĨ na profil\" z menu jednotlivÃŊch poznÃĄmok." +notSpecifiedMentionWarning: "TÃĄto poznÃĄmka obsahuje spomenutÃŊch pouŞívateÄžov, ktorí nie sÃē medzi adresÃĄtmi." +info: "InformÃĄcie" +userInfo: "InformÃĄcie o pouŞívateÄžovi" +unknown: "NeznÃĄme" +onlineStatus: "Online status" +hideOnlineStatus: "SkryÅĨ online status" +hideOnlineStatusDescription: "Skrytie vÃĄÅĄho online statusu zníŞi pohodlnosÅĨ niektorÃŊch funkcií ako napríklad vyhÄžadÃĄvanie." +online: "Online" +active: "Aktívny" +offline: "Offline" +notRecommended: "NeodporÃēčanÊ" +botProtection: "Bot ochrana" +instanceBlocking: "BlokovanÊ servery" +selectAccount: "Vyberte Ãēčet" +switchAccount: "PrepnÃēt Ãēčet" +enabled: "ZapnutÊ" +disabled: "VypnutÊ" +quickAction: "RÃŊchle akcie" +user: "PouŞívatelia" +administration: "Spravovanie" +accounts: "Účty" +switch: "PrepnÃēÅĨ" +noMaintainerInformationWarning: "InformÃĄcie sprÃĄvcu nie sÃē nastavenÊ." +noBotProtectionWarning: "Ochrana proti botom nie je nastavenÃĄ." +configure: "KonfigurovaÅĨ" +postToGallery: "VytvoriÅĨ novÃŊ príspevok v galÊrii" +gallery: "GalÊria" +recentPosts: "NajnovÅĄie príspevky" +popularPosts: "PopulÃĄrne príspevky" +shareWithNote: "ZdieÄžaÅĨ s poznÃĄmkou" +ads: "Reklamy" +expiration: "UkončiÅĨ hlasovanie" +memo: "Memo" +priority: "Priorita" +high: "VysokÃĄ" +middle: "StrednÊ" +low: "MÃĄlo" +emailNotConfiguredWarning: "Nie je nastavenÃĄ emailovÃĄ adresa." +ratio: "Pomer" +previewNoteText: "ZobraziÅĨ nÃĄhÄžad" +customCss: "VlastnÊ CSS" +customCssWarn: "Toto nastavenie by sa malo pouŞívaÅĨ iba ak viete čo robíte. Zadanie nesprÃĄvnych hodnôt môŞe spôsobiÅĨ nenormÃĄlne sprÃĄvanie klienta." +global: "GlobÃĄlne" +squareAvatars: "ZobrazovaÅĨ ÅĄtvorcovÊ avatary" +sent: "PoslaÅĨ" +received: "PrijatÊ" +searchResult: "VÃŊsledky hÄžadania" +hashtags: "Hashtagy" +troubleshooting: "RieÅĄenie problÊmov" +useBlurEffect: "PouŞívaÅĨ efekty rozmazania v UI" +learnMore: "ZistiÅĨ viac" +misskeyUpdated: "Misskey sa aktualizoval!" +whatIsNew: "Čo je novÊ?" +translate: "PreloÅžiÅĨ" +translatedFrom: "PreloÅženÊ z {x}" +accountDeletionInProgress: "Odstraňovanie Ãēčtu prebieha" +usernameInfo: "Meno, ktorÊ odliÅĄuje vÃĄÅĄ Ãēčet od ostatnÃŊch na tomto serveri. MôŞete pouÅžiÅĨ abecedu (a~z, A~Z), čísla (0~9) alebo podtrÅžník (_). PouŞívateÄžskÊ menÃĄ sa nedajÃē neskôr zmeniÅĨ." +aiChanMode: "Ai reÅžim" +keepCw: "NechaÅĨ varovania obsahu" +pubSub: "Pub/Sub Ãēčty" +lastCommunication: "PoslednÃĄ komunikÃĄcia" +resolved: "VyrieÅĄenÊ" +unresolved: "NevyrieÅĄenÊ" +breakFollow: "NesledovaÅĨ" +itsOn: "ZapnutÊ" +itsOff: "VypnutÊ" +emailRequiredForSignup: "RegistrÃĄcia vyÅžaduje emailovÃē adresu" +unread: "NeprečítanÊ" +filter: "Filter" +controlPanel: "OvlÃĄdací panel" +manageAccounts: "SprÃĄva Ãēčtov" +makeReactionsPublic: "Reakcie sÃē verejnÊ" +makeReactionsPublicDescription: "Toto spraví vÅĄetky vaÅĄe minulÊ reakcie viditeÄžnÊ verejnosti." +classic: "Klasika" +muteThread: "ZtÃ­ÅĄiÅĨ vlÃĄkno" +unmuteThread: "ZruÅĄiÅĨ stÃ­ÅĄenie vlÃĄkna" +ffVisibility: "ViditeÄžnosÅĨ sledujÃēcich/sledovanÃŊch" +ffVisibilityDescription: "UmoŞňuje nastaviÅĨ kto vidí koho sledujete a kto vÃĄs sleduje." +continueThread: "ZobraziÅĨ pokračovanie vlÃĄkna" +deleteAccountConfirm: "Toto nezvrÃĄtiteÄžne vymaÅže vÃĄÅĄ Ãēčet. PokračovaÅĨ?" +incorrectPassword: "NesprÃĄvne heslo." +voteConfirm: "Potvrdzujete svoj hlas za \"{choice}\"?" +hide: "SkryÅĨ" +leaveGroup: "OpustiÅĨ skupiny" +leaveGroupConfirm: "Naozaj chcete opustiÅĨ \"{name}\"?" +useDrawerReactionPickerForMobile: "ZobraziÅĨ vÃŊber reakcií ako ÅĄuflík na mobile" +welcomeBackWithName: "Vitajte späÅĨ, {name}" +clickToFinishEmailVerification: "Kliknutím na [{ok}] dokončíte overeniu emailu." +overridedDeviceKind: "Typ zariadenia" +smartphone: "SmartfÃŗn" +tablet: "Tablet" +auto: "Automaticky" +themeColor: "Farba tÊmy" +size: "VeÄžkosÅĨ" +numberOfColumn: "Počet stÄēpcov" +_emailUnavailable: + used: "TÃĄto emailovÃĄ adresa sa uÅž pouŞíva" + format: "FormÃĄt emailovej adresy je nesprÃĄvny" + disposable: "JednorÃĄzovÊ emailovÊ adresy sa nemôŞu pouŞívaÅĨ." + mx: "Tento emailovÃŊ server nefunguje." + smtp: "Tento emailovÃŊ server neodpovedÃĄ." +_ffVisibility: + public: "ZverejniÅĨ" + followers: "Len viditeÄžní sledujÃēci" + private: "SÃēkromnÊ" +_signup: + almostThere: "Skoro na konci" + emailAddressInfo: "Prosím zadajte svoju emailovÃē adresu!" + emailSent: "Na vaÅĄu emailovÃē adresu ({email}) sme odoslali email. Vytvorenie Ãēčtu dokončíte kliknutím na odkaz v emaili." +_accountDelete: + accountDelete: "OdstrÃĄniÅĨ Ãēčet" + mayTakeTime: "KeďŞe odstrÃĄnenie Ãēčtu je nÃĄročnÃŊ proces, môŞe to nejakÃŊ čas trvaÅĨ. ZÃĄleŞí koÄžko obsahu ste vytvorili a koÄžko sÃēborov ste nahrali." + sendEmail: "Po odstrÃĄnení Ãēčtu vÃĄm poÅĄleme email na emailovÃē adresu zadanÃē pri registrÃĄcii tohoto Ãēčtu." + requestAccountDelete: "PoÅžiadaÅĨ o zmazanie Ãēčtu" + started: "Odstraňovanie začalo." + inProgress: "Odstraňovanie prebieha" +_ad: + back: "SpäÅĨ" + reduceFrequencyOfThisAd: "TÃēto reklamu zobrazovaÅĨ menej" +_forgotPassword: + enterEmail: "Zadajte emailovÃē adresu, ktorÃē ste pouÅžili pri registrÃĄcii. PoÅĄleme vÃĄm na ňu odkaz, cez ktorÃŊ si môŞete obnoviÅĨ heslo." + ifNoEmail: "Ak ste pri registrÃĄcii nepouÅžili email, prosím kontaktujte administrÃĄtora." + contactAdmin: "Tento server nepodporuje pouŞívanie emailovÃŊch adries, prosím kontaktuje administrÃĄtor, ktorÃŊ vÃĄm resetuje heslo." +_gallery: + my: "Moja galÊria" + liked: "ObÄžÃēbenÊ príspevky" + like: "PÃĄÄi sa mi" + unlike: "NepÃĄÄi sa mi" +_email: + _follow: + title: "MÃĄte novÊho sledujÃēceho" + _receiveFollowRequest: + title: "Dostali ste ÅžiadosÅĨ o sledovanie" +_plugin: + install: "InÅĄtalova pluginy" + installWarn: "Prosím neinÅĄtalujte nedôveryhodnÊ pluginy." + manage: "Spravovanie pluginov" +_registry: + scope: "OblasÅĨ" + key: "KÄžÃēč" + keys: "KÄžÃēče" + domain: "DomÊna" + createKey: "VytvoriÅĨ kÄžÃēč" +_aboutMisskey: + about: "Misskey je open-source softvÊr, ktorÃŊ vyvíja syuilo od 2014." + contributors: "Hlavní prispievatelia" + allContributors: "VÅĄetci prispievatelia" + source: "ZdrojovÃŊ kÃŗd" + translation: "PreloÅžiÅĨ Misskey" + donate: "PodporiÅĨ Misskey" + morePatrons: "Takisto oceňujeme podporu mnoÃŊch ďalÅĄÃ­ch, ktorí tu nie sÃē uvedení. Ďakujeme! đŸĨ°" + patrons: "Prispievatelia" +_nsfw: + respect: "SkryÅĨ NSFW mÊdiÃĄ" + ignore: "NeskrÃŊvaÅĨ NSFW mÊdiÃĄ" + force: "SkryÅĨ vÅĄetky mÊdiÃĄ" +_mfm: + cheatSheet: "MFM Cheatsheet" + intro: "MFM je Misskey exkluzívny značkovací jazyk, ktorÃŊ sa dÃĄ pouŞívaÅĨ na viacerÃŊch miestach. Tu môŞete vidieÅĨ zoznam vÅĄetkej dostupnej MFM syntaxe." + dummy: "Misskey rozÅĄiruje svet Fediverza" + mention: "Zmienka" + mentionDescription: "PouŞívateÄža spomeniete pouŞítím zavinÃĄÄa a mena pouŞívateÄža" + hashtag: "Hashtag" + hashtagDescription: "MôŞete zadaÅĨ hashtag pouÅžitím mrieÅžky a textu" + url: "URL" + urlDescription: "URL sa dajÃē zobraziÅĨ." + link: "Odkaz" + linkDescription: "JednotlivÊ časti texty sa dajÃē zobraziÅĨ ako URL." + bold: "TučnÊ" + boldDescription: "ZvÃŊrazní písmenÃĄ tÃŊm, Åže budÃē tučnejÅĄie." + small: "MalÊ" + smallDescription: "Zobrazí obsah malÃŊ a tenkÃŊ." + center: "VystrediÅĨ prvky" + centerDescription: "Zobrazí obsah v strede" + inlineCode: "KÃŗd (inline)" + inlineCodeDescription: "Zobrazí kÃŗd so zvÃŊraznením syntaxe." + blockCode: "KÃŗd (blok)" + blockCodeDescription: "Zobrazí viacriadkovÃŊ kÃŗd so zvÃŊraznením syntaxe v bloku." + inlineMath: "Vzorec (inline)" + inlineMathDescription: "Zobrazí matematickÃŊ vzorec (KaTeX) v riadku." + blockMath: "Vzorec (blok)" + blockMathDescription: "Zobrazí viacriadkovÃŊ matematickÃŊ vzorec (KaTeX) v bloku" + quote: "CitovaÅĨ" + quoteDescription: "Zobrazí obsah ako citÃĄt." + emoji: "VlastnÊ emoji" + emojiDescription: "Pridaním dvojbodiek pred a za nÃĄzov vlastnej emoji, sa dÃĄ zobraziÅĨ vlastnÃĄ emoji." + search: "HÄžadaÅĨ" + searchDescription: "Zobrazí vyhÄžadÃĄvacie pole so zadanÃŊm textom." + flip: "PreklopiÅĨ" + flipDescription: "Preklopí obsah horizontÃĄlne alebo vertikÃĄlne" + jelly: "AnimÃĄcia (ÅželÊ)" + jellyDescription: "Obsah sa bude hÃŊbaÅĨ ako ÅželÊ." + tada: "AnimÃĄcia (tadÃĄ)" + tadaDescription: "Obsah sa bude hÃŊbaÅĨ ako Tada!" + jump: "AnimÃĄcia (skok)" + jumpDescription: "Obsah skočí." + bounce: "AnimÃĄcia (odraz)" + bounceDescription: "Obsah sa bude odrÃĄÅžaÅĨ." + shake: "AnimÃĄcia (trasenie)" + shakeDescription: "Obsah sa bude triasÅĨ." + twitch: "AnimÃĄcia (myknutie)" + twitchDescription: "Obsahu dÃĄ animÃĄciu silnÊho trasenia." + spin: "AnimÃĄcia (rotÃĄcia)" + spinDescription: "Obsahu pridÃĄ otÃĄÄajÃēcu animÃĄciu." + x2: "VeÄžkÃŊ" + x2Description: "Zobrazí obsah vÃ¤ÄÅĄÃ­." + x3: "VeÄžmi veÄžkÃŊ" + x3Description: "Zobrazí obsah eÅĄte vÃ¤ÄÅĄÃ­." + x4: "NeuveriteÄžne veÄžkÃŊ" + x4Description: "Zobrazí obsah eÅĄte viac veÄžkÃŊ neÅž veÄžmi veÄžkÃŊ." + blur: "Rozmazanie" + blurDescription: "TÃŊmto efektom môŞe byÅĨ obsah rozmazanÃŊ. Zaostrí sa keď ned neho príde kurzor." + font: "Písmo" + fontDescription: "Nastaví písmo, ktorÃŊm sa zobrazí text." + rainbow: "DÃēha" + rainbowDescription: "Zobrazí obsah vo farbÃĄch dÃēhy." + sparkle: "Trblietky" + sparkleDescription: "Obsahu dodÃĄ trblietajÃēci efekt." + rotate: "OtÃĄÄaÅĨ" + rotateDescription: "Otočí obsah o určitÃŊ uhol." +_instanceTicker: + none: "Nikdy nezobrazovaÅĨ" + remote: "ZobraziÅĨ pre vzdialenÃŊch pouŞívateÄžov" + always: "ZobraziÅĨ vÅždy" +_serverDisconnectedBehavior: + reload: "Automaticky obnoviÅĨ" + dialog: "ZobraziÅĨ okno s varovaním" + quiet: "ZobraziÅĨ neruÅĄivÊ varovanie" +_channel: + create: "VytvoriÅĨ kanÃĄl" + edit: "UpraviÅĨ kanÃĄl" + setBanner: "NastaviÅĨ banner" + removeBanner: "OdstrÃĄniÅĨ banner" + featured: "Trendy" + owned: "VlastnenÊ" + following: "SledovanÊ" + usersCount: "{n} Ãēčastníkov" + notesCount: "{n} poznÃĄmok" +_menuDisplay: + sideFull: "Strana" + sideIcon: "Strana (Ikony)" + top: "Hore" + hide: "SkryÅĨ" +_wordMute: + muteWords: "UmlčanÊ slovÃĄ" + muteWordsDescription: "Medzerami oddeÄžte pre podmienku AND a novÃŊmi riadkami pre podmienku OR." + muteWordsDescription2: "RegulÃĄrne vÃŊrazy sa pouÅžijÃē keď pouÅžijete okolo lomítka." + softDescription: "Skryje poznÃĄmky z časovej osi, ktorÊ spÄēňajÃē podmienky." + hardDescription: "ZabrÃĄni poznÃĄmky spÄēňajÃēce mnoÅžinu podmienok, aby boli pridanÊ do časovej osi. NavyÅĄe tieto poznÃĄmky nepribudnÃē v časovej osi ani keď sa podmienky zmenia." + soft: "MäkkÊ" + hard: "TvrdÊ" + mutedNotes: "UmlčanÊ poznÃĄmky" +_instanceMute: + instanceMuteDescription: "Toto umlčí vÅĄetky poznÃĄmky/preposlania zo zoznamu serverov, vrÃĄtane tÃŊch, na ktorÊ pouŞívatelia odpovedajÃē z umlčanÊho servera." + instanceMuteDescription2: "OddeÄžte novÃŊmi riadkami" + title: "Skryje poznÃĄmky z uvedenÃŊch serverov." + heading: "Zoznam umlčanÃŊch inÅĄtancií" +_theme: + explore: "ObjavovaÅĨ tÊmy" + install: "NainÅĄtalovaÅĨ tÊmu" + manage: "SpravovaÅĨ tÊmy" + code: "KÃŗd tÊmy" + description: "Popis" + installed: "{name} je nainÅĄtalovanÃĄ" + installedThemes: "NainÅĄtalovanÊ tÊmy" + builtinThemes: "VstavanÊ tÊmy" + alreadyInstalled: "TÃĄto tÊma je uÅž nainÅĄtalovanÃĄ" + invalid: "FormÃĄt tejto tÊmy je nesprÃĄvny" + make: "VytvoriÅĨ tÊmu" + base: "ZÃĄklad" + addConstant: "PridaÅĨ konÅĄtantu" + constant: "KonÅĄtanta" + defaultValue: "PredvolenÃĄ hodnota" + color: "Farba" + refProp: "Odkaz na vlastnosÅĨ" + refConst: "Odkaz na konÅĄtantu" + key: "KÄžÃēč" + func: "Funkcie" + funcKind: "Typ funkcie" + argument: "Argument" + basedProp: "OdkazovanÃĄ vlastnosÅĨ" + alpha: "PriehÄžadnosÅĨ" + darken: "StmaviÅĨ" + lighten: "ZosvetliÅĨ" + inputConstantName: "Zadajte nÃĄzov tejto konÅĄtanty" + importInfo: "Ak sem zadÃĄte kÃŗd tÊmy, môŞete ju importovaÅĨ do editora tÊm." + deleteConstantConfirm: "Naozaj chcete odstrÃĄniÅĨ konÅĄtantu {const}?" + keys: + accent: "Akcent" + bg: "Pozadie" + fg: "Text" + focus: "Fokus" + indicator: "IndikÃĄtor" + panel: "Panel" + shadow: "Tieň" + header: "Hlavička" + navBg: "Pozadie bočnÊho panela" + navFg: "Text bočnÊho panela" + navHoverFg: "Text bočnÊho panela (pod kurzorom)" + navActive: "Text bočnÊho panela (aktívny)" + navIndicator: "IndikÃĄtor bočnÊho panela" + link: "Odkaz" + hashtag: "Hashtag" + mention: "Zmienka" + mentionMe: "Zmienky (mňa)" + renote: "PreposlaÅĨ" + modalBg: "Pozadie modÃĄlu" + divider: "OddeÄžovač" + scrollbarHandle: "RÃēčka scrollbaru" + scrollbarHandleHover: "RÃēčka scrollbaru (pod kurzorom)" + dateLabelFg: "Text dÃĄtovÊho popisku" + infoBg: "Pozadie informÃĄcií" + infoFg: "InformačnÃŊ text" + infoWarnBg: "Pozadie varovania" + infoWarnFg: "Text varovania" + cwBg: "CW pozadie tlačidla" + cwFg: "CW text tlačidla" + cwHoverBg: "CW pozadie tlačidla (pod kurzorom)" + toastBg: "Pozadie upozornenia" + toastFg: "Text upozornenia" + buttonBg: "Pozadie tlačidla" + buttonHoverBg: "Pozadie tlačidla (pod kurzorom)" + inputBorder: "Okraj vstupnÊho poÄža" + listItemHoverBg: "Pozadie poloÅžky zoznamu (pod kurzorom)" + driveFolderBg: "Pozadie priečinu disku" + wallpaperOverlay: "Vrstvenie pozadia" + badge: "Odznak" + messageBg: "Pozadie chatu" + accentDarken: "Akcent (stmavenÊ)" + accentLighten: "Akcent (zosvetlenÊ)" + fgHighlighted: "ZvÃŊraznenÃŊ text" +_sfx: + note: "PoznÃĄmky" + noteMy: "VlastnÃĄ poznÃĄmka" + notification: "OznÃĄmenia" + chat: "Chat" + chatBg: "Chat (pozadie)" + antenna: "AntÊny" + channel: "Upozornenia kanÃĄla" +_ago: + unknown: "NeznÃĄme" + future: "BudÃēcnosÅĨ" + justNow: "Teraz" + secondsAgo: "pred {n} sekundami" + minutesAgo: "pred {n} minÃētami" + hoursAgo: "pred {n} hodinami" + daysAgo: "pred {n} dňami" + weeksAgo: "pred {n} tÃŊÅždňami" + monthsAgo: "pred {n} mesiacmi" + yearsAgo: "pred {n} rokmi" +_time: + second: "s" + minute: "min" + hour: "hod" + day: "dní" +_tutorial: + title: "Ako pouŞívaÅĨ Misskey" + step1_1: "Vitajte!" + step1_2: "TÃĄto strÃĄnka sa volÃĄ \"časovÃĄ os\". Zobrazuje chronologicky zoradenÊ \"poznÃĄmky\" od Äžudí, ktorÃŊch sledujete." + step1_3: "VaÅĄa časovÃĄ os je teraz prÃĄzdna pretoÅže ste nepridali Åžiadne poznÃĄmky ani nikoho zatiaÄž nesledujete." + step2_1: "Podˇme dokončiÅĨ nastavenia vÃĄÅĄho profilu pred napísaním poznÃĄmky alebo sledovaním niekoho." + step2_2: "Poskytnutím informÃĄcií o vÃĄs uÄžahčíte ostatnÃŊm, či chcÃē vidieÅĨ alebo sledovaÅĨ vaÅĄe poznÃĄmky." + step3_1: "Dokončili ste nastavovanie svojho profilu?" + step3_2: "Poďme vyskÃēÅĄaÅĨ napísaÅĨ poznÃĄmku. MôŞete to spraviÅĨ stlačením ikony ceruzky na vrchu obrazovky." + step3_3: "Vyplňte polia a stlačte tlačítko vpravo hore." + step3_4: "NemÃĄte čo povedaÅĨ? SkÃēste \"len si nastavujem môj msky\"!" + step4_1: "Napísali ste svoju prvÃē poznÃĄmku?" + step4_2: "HurÃĄ! Teraz by vaÅĄa prvÃĄ poznÃĄmka mala byÅĨ na vaÅĄej časovej osi." + step5_1: "Teraz skÃēsme oÅživiÅĨ časovÃē os sledovaním nejakÃŊch Äžudí." + step5_2: "{featured} zobrazí populÃĄrne poznÃĄmku na tomto serveri. {explore} môŞete objavovaÅĨ populÃĄrnych pouŞívateÄžov. SkÃēste tam nÃĄjsÅĨ Äžudí, ktorÃŊch by ste radi sledovali!" + step5_3: "Ak chcete sledovaÅĨ ďalÅĄÃ­ch pouŞívateÄžov, kliknite na ich ikonu a stlačte tlačidlo \"SledovaÅĨ\" na ich profile." + step5_4: "Ak mÃĄ niektorÃŊ pouŞívateÄž ikonu zÃĄmku vedÄža svojho mena, znamenÃĄ to, Åže môŞe trvaÅĨ určitÃŊ čas, kÃŊm danÃŊ pouŞívateÄž schvÃĄli vaÅĄu ÅžiadosÅĨ o sledovanie." + step6_1: "Teraz by ste mali vidieÅĨ poznÃĄmky ďalÅĄÃ­ch pouŞívateÄžov na svojej časovej osi." + step6_2: "MôŞete daÅĨ \"reakcie\" na poznÃĄmky ďalÅĄÃ­ch Äžudí ako rÃŊchlu odpoveď." + step6_3: "Reakciu pridÃĄte kliknutím na \"+\" niekoho poznÃĄmke a vybratím emoji, ktorou chcete reagovaÅĨ." + step7_1: "Gralujeme! Dokončili ste zÃĄkladnÊho sprievodcu Misskey." + step7_2: "Ak sa chcete naučiÅĨ viac o Misskey, skÃēste sekciu {help}." + step7_3: "A teraz, veÄža ÅĄÅĨastia, bavte sa s Misskey! 🚀" +_2fa: + alreadyRegistered: "UÅž ste zaregistrovali 2-faktorovÊ autentifikačnÊ zariadenie." + registerDevice: "RegistrovaÅĨ novÊ zariadenie" + registerKey: "RegistrovaÅĨ bezpečnostnÃŊ kÄžÃēč" + step1: "Najprv si nainÅĄtalujte autentifikačnÃē aplikÃĄciu (napríklad {a} alebo {b}) na svoje zariadenie." + step2: "Potom, naskenujte QR kÃŗd zobrazenÃŊ na obrazovke." + step3: "Nastavenie dokončíte zadaním tokenu z vaÅĄej aplikÃĄcie." + step4: "Od teraz, vÅĄetky ďalÅĄie prihlÃĄsenia budÃē vyÅžadovaÅĨ prihlasovací token." + securityKeyInfo: "Okrem odtlačku prsta alebo PIN autentifikÃĄcie si môŞete nastaviÅĨ autentifikÃĄciu cez hardvÊrovÃŊ bezpečnostnÃŊ kÄžÃēč podporujÃēci FIDO2 a tak eÅĄte viac zabezpečiÅĨ svoj Ãēčet." +_permissions: + "read:account": "VidieÅĨ informÃĄcie o vaÅĄom Ãēčte" + "write:account": "UpraviÅĨ informÃĄcie o vaÅĄom Ãēčte" + "read:blocks": "VidieÅĨ zoznam blokovanÃŊch pouŞívateÄžov" + "write:blocks": "UpraviÅĨ zoznam blokovanÃŊch pouŞívateÄžov" + "read:drive": "Prístup k sÃēborom a priečinkom na disku" + "write:drive": "UpraviÅĨ alebo odstrÃĄniÅĨ sÃēbory a priečinky na disku" + "read:favorites": "VidieÅĨ vÃĄÅĄ zoznam obÄžÃēbenÃŊch" + "write:favorites": "UpraviÅĨ vÃĄÅĄ zoznam obÄžÃēbenÃŊch" + "read:following": "VidieÅĨ koho sledujete" + "write:following": "SledovaÅĨ alebo nesledovaÅĨ ďalÅĄie Ãēčty" + "read:messaging": "VidieÅĨ vaÅĄe chaty" + "write:messaging": "PísaÅĨ alebo odstraňovaÅĨ sprÃĄvy v chate" + "read:mutes": "VidieÅĨ vÃĄÅĄ zoznam stÃ­ÅĄenÃŊch pouŞívateÄžov" + "write:mutes": "UpravovaÅĨ zoznam stÃ­ÅĄenÃŊch pouŞívateÄžov" + "write:notes": "PísaÅĨ alebo odstrÃĄniÅĨ poznÃĄmky" + "read:notifications": "VidieÅĨ vaÅĄe oznÃĄmenia" + "write:notifications": "PracovaÅĨ s vaÅĄimi notifikÃĄciami" + "read:reactions": "VidieÅĨ vaÅĄe reakcie" + "write:reactions": "UpravovaÅĨ vaÅĄe reakcie" + "write:votes": "HlasovaÅĨ v hlasovaniach" + "read:pages": "VidieÅĨ vaÅĄe strÃĄnky" + "write:pages": "UpraviÅĨ alebo odstrÃĄniÅĨ vaÅĄe strÃĄnky" + "read:page-likes": "VidieÅĨ vaÅĄe pÃĄÄiky na strÃĄnkach" + "write:page-likes": "UpraviÅĨ pÃĄÄiky na strÃĄnkach" + "read:user-groups": "VidieÅĨ vaÅĄe skupiny" + "write:user-groups": "UpraviÅĨ alebo odstrÃĄniÅĨ vaÅĄe skupiny" + "read:channels": "ČítaÅĨ vaÅĄe kanÃĄly" + "write:channels": "UpravovaÅĨ vaÅĄe kanÃĄly" + "read:gallery": "VidieÅĨ vaÅĄu galÊriu" + "write:gallery": "UpravovaÅĨ vaÅĄu galÊriu" + "read:gallery-likes": "VidieÅĨ zoznam obÄžÃēbenÃŊch príspevkov z galÊrie" + "write:gallery-likes": "UpraviÅĨ zoznam obÄžÃēbenÃŊch príspevov z galÊrie" +_auth: + shareAccess: "Prajete si povoliÅĨ \"{name}\", aby mal prístup k tomuto Ãēčtu?" + shareAccessAsk: "Naozaj chcete povoliÅĨ tejto aplikÃĄcii prístup k tomuto Ãēčtu?" + permissionAsk: "TÃĄto aplikÃĄcia vyÅžaduje nasledujÃēce nastavenia" + pleaseGoBack: "Prosím prejdite späÅĨ na aplikÃĄciu" + callback: "Vraciam sa späÅĨ na aplikÃĄciu" + denied: "Prístup zamietnutÃŊ" +_antennaSources: + all: "VÅĄetky poznÃĄmky" + homeTimeline: "PoznÃĄmky od sledovanÊho pouŞívateÄža" + users: "PoznÃĄmky od konkrÊtneho pouŞívateÄža" + userList: "PoznÃĄmky od pouŞívateÄžov v zozname" + userGroup: "PoznÃĄmky od pouŞívateÄžov z konkrÊtnej skupiny." +_weekday: + sunday: "NedeÄža" + monday: "Pondelok" + tuesday: "Utorok" + wednesday: "Streda" + thursday: "Å tvrtok" + friday: "Piatok" + saturday: "Sobota" +_widgets: + memo: "PrilepenÊ poznÃĄmky" + notifications: "OznÃĄmenia" + timeline: "ČasovÃĄ os" + calendar: "KalendÃĄr" + trends: "Trendy" + clock: "Hodiny" + rss: "RSS čítačka" + activity: "Aktivita" + photos: "Fotky" + digitalClock: "DigitÃĄlne hodiny" + federation: "FederÃĄcia" + postForm: "NapísaÅĨ poznÃĄmku" + slideshow: "PrezentÃĄcia" + button: "Tlačidlo" + onlineUsers: "Online pouŞívatelia" + jobQueue: "Fronta Ãēloh" + serverMetric: "Metriky servera" + aiscript: "Konzola AiScript" + aichan: "Ai" +_cw: + hide: "SkryÅĨ" + show: "ZobraziÅĨ viac" + chars: "{count} znakov" + files: "{count} sÃēbor/ov" +_poll: + noOnlyOneChoice: "Treba aspoň dve voÄžby" + choiceN: "VoÄžba {n}" + noMore: "NemôŞete pridaÅĨ viac volieb" + canMultipleVote: "PovoliÅĨ hlasovaÅĨ za viac volieb." + expiration: "UkončiÅĨ hlasovanie" + infinite: "Nikdy" + at: "KonkrÊtny dÃĄtum..." + after: "UkončiÅĨ po..." + deadlineDate: "DÃĄtum ukončenia" + deadlineTime: "hod" + duration: "Trvanie" + votesCount: "{n} hlasov" + totalVotes: "{n} hlasov celkom" + vote: "HlasovaÅĨ" + showResult: "VidieÅĨ vÃŊsledky hlasovania" + voted: "ZahlasovanÊ" + closed: "Skončilo" + remainingDays: "zostÃĄva {d} dní {h} hodín" + remainingHours: "zostÃĄva {h} hodín {m} minÃēt" + remainingMinutes: "zostÃĄva {m} minÃēt {s} sekÃēnd" + remainingSeconds: "zostÃĄva {s} sekÃēnd" +_visibility: + public: "VerejnÊ" + publicDescription: "VaÅĄa poznÃĄmku bude viditeÄžnÃĄ vÅĄetkÃŊm pouŞívateÄžom" + home: "Domov" + homeDescription: "PridaÅĨ iba na domÃĄcu časovÃē os" + followers: "SledujÃēci" + followersDescription: "ViditeÄžnÊ iba tÃŊm, ktorí vÃĄs sledujÃē" + specified: "Priame" + specifiedDescription: "ViditeÄžnÊ iba pre konkrÊtnych pouŞívateÄžov" + localOnly: "Iba lokÃĄlne" + localOnlyDescription: "VzdialenÃŊ pouŞívatelia nebudÃē vidieÅĨ" +_postForm: + replyPlaceholder: "Odpoveď na tÃēto poznÃĄmku..." + quotePlaceholder: "Citovanie tejto poznÃĄmky..." + channelPlaceholder: "PoslaÅĨ do kanÃĄla..." + _placeholders: + a: "Čo mÃĄte v plÃĄne?" + b: "Čo sa deje?" + c: "O čom rozmÃŊÅĄÄžaÅĄ?" + d: "Čo chcete povedaÅĨ?" + e: "Začnite písaÅĨ..." + f: "ČakÃĄ sa na písanie..." +_profile: + name: "NÃĄzov" + username: "Meno pouŞívateÄža" + description: "Bio" + youCanIncludeHashtags: "Vo svojom bio môŞete maÅĨ aj hashtagy." + metadata: "DodatočnÊ informÃĄcie" + metadataEdit: "UpraviÅĨ dodatočnÊ informÃĄcie" + metadataDescription: "Vo svojom profile môŞete uviesÅĨ aÅž ÅĄtyri dodatočnÊ informačnÊ polia." + metadataLabel: "Popisok" + metadataContent: "Obsah" + changeAvatar: "ZmeniÅĨ avatara" + changeBanner: "ZmeniÅĨ banner" +_exportOrImport: + allNotes: "VÅĄetky poznÃĄmky" + followingList: "Sledujete" + muteList: "VypnÃēÅĨ zvuk" + blockingList: "ZablokovaÅĨ" + userLists: "Zoznamy" + excludeMutingUsers: "VylÃēčiÅĨ stÃ­ÅĄenÃŊch pouŞívateÄžov" + excludeInactiveUsers: "VylÃēčiÅĨ neaktívnych pouŞívateÄžov" +_charts: + federation: "FederÃĄcia" + apRequest: "ÅŊiadosti" + usersIncDec: "Rozdiel v počte pouŞívateÄžov" + usersTotal: "CelkovÃŊ počet pouŞívateÄžov" + activeUsers: "Aktívni pouŞívatelia" + notesIncDec: "Rozdiel v počte poznÃĄmok" + localNotesIncDec: "Rozdiel v počte lokÃĄlnych poznÃĄmok" + remoteNotesIncDec: "Rozdiel v počte vzdialenÃŊch poznÃĄmok" + notesTotal: "CelkovÃŊ počet poznÃĄmok" + filesIncDec: "Rozdiel v počte sÃēborov" + filesTotal: "CelkovÃŊ počet sÃēborov" + storageUsageIncDec: "Rozdiel vyuÅžitÊho ÃēloÅžiska" + storageUsageTotal: "CelkovÊ vyuÅžitÊ ÃēloÅžisko" +_instanceCharts: + requests: "ÅŊiadosti" + users: "Rozdiel v počte pouŞívateÄžov" + usersTotal: "Celkom spolu počet pouŞívateÄžov" + notes: "Rozdiel v počte poznÃĄmok" + notesTotal: "Celkom spolu počet poznÃĄmok" + ff: "Rozdiel v počte sledovanÃŊch/sledujÃēcich" + ffTotal: "Celkom spolu počet sledovanÃŊch / sledujÃēcich" + cacheSize: "Rozdiel vo veÄžkosti cache" + cacheSizeTotal: "Celkom spolu veÄžkosÅĨ cache" + files: "Rozdiel v počte sÃēborov" + filesTotal: "Celkom spolu počet sÃēborov" +_timelines: + home: "Domov" + local: "LokÃĄlne" + social: "SociÃĄlne" + global: "GlobÃĄlne" +_pages: + newPage: "VytvoriÅĨ novÃē strÃĄnku" + editPage: "UpraviÅĨ tÃēto strÃĄnku" + readPage: "Zobrazenie zdroja aktívne" + created: "StrÃĄnka ÃēspeÅĄne vytvorenÃĄ" + updated: "StrÃĄnka ÃēspeÅĄne upravenÃĄ" + deleted: "StrÃĄnka ÃēspeÅĄne odstrÃĄnenÃĄ" + pageSetting: "Nastavenia strÃĄnky" + nameAlreadyExists: "ZadanÃĄ URL strÃĄnku uÅž existuje" + invalidNameTitle: "ZadanÃĄ URL strÃĄnku je nesprÃĄvna" + invalidNameText: "Uistite sa, Åže nadpis strÃĄnky nie je prÃĄzdny" + editThisPage: "UpraviÅĨ tÃēto strÃĄnku" + viewSource: "UkÃĄzaÅĨ zdroj" + viewPage: "UkÃĄzaÅĨ vaÅĄe strÃĄnky" + like: "PÃĄÄi sa mi" + unlike: "NepÃĄÄi sa mi" + my: "Moje strÃĄnky" + liked: "ObÄžÃēbenÊ strÃĄnky" + featured: "VÃŊznačnÊ" + inspector: "InÅĄpektor" + contents: "Obsah" + content: "Blok strÃĄnky" + variables: "PremennÊ" + title: "Nadpis" + url: "URL strÃĄnky" + summary: "Zhrnutie strÃĄnky" + alignCenter: "VystrediÅĨ prvky" + hideTitleWhenPinned: "SkryÅĨ nadpis strÃĄnky keď je pripnutÃĄ na profil" + font: "Písmo" + fontSerif: "PätkovÊ" + fontSansSerif: "BezpätkovÊ" + eyeCatchingImageSet: "NastaviÅĨ miniatÃēru" + eyeCatchingImageRemove: "OdstrÃĄniÅĨ miniatÃēru" + chooseBlock: "PridaÅĨ blok" + selectType: "Vyberte typ" + enterVariableName: "Zadajte meno premennej" + variableNameIsAlreadyUsed: "Meno premennej s uÅž pouŞíva" + contentBlocks: "Obsah" + inputBlocks: "Vstup" + specialBlocks: "Å peciÃĄlne" + blocks: + text: "Text" + textarea: "TextovÊ pole" + section: "Sekcia" + image: "ObrÃĄzky" + button: "Tlačidlo" + if: "Ak" + _if: + variable: "PremennÊ" + post: "NapísaÅĨ poznÃĄmku" + _post: + text: "Obsah" + attachCanvasImage: "Príspevok s obrÃĄzkom na plÃĄtne" + canvasId: "ID plÃĄtna" + textInput: "TextovÃŊ vstup" + _textInput: + name: "Meno premennej" + text: "Nadpis" + default: "PredvolenÃĄ hodnota" + textareaInput: "ViacriadkovÃŊ textovÃŊ vstup" + _textareaInput: + name: "Meno premennej" + text: "Nadpis" + default: "PredvolenÃĄ hodnota" + numberInput: "ČíselnÃŊ vstup" + _numberInput: + name: "Meno premennej" + text: "Nadpis" + default: "PredvolenÃĄ hodnota" + canvas: "PlÃĄtno" + _canvas: + id: "ID plÃĄtna" + width: "Šírka" + height: "VÃŊÅĄka" + note: "VloÅženÃĄ poznÃĄmka" + _note: + id: "ID poznÃĄmky" + idDescription: "Alebo môŞete vloÅžiÅĨ URL poznÃĄmky sem" + detailed: "PodrobnÃŊ pohÄžad" + switch: "PrepnÃēÅĨ" + _switch: + name: "Meno premennej" + text: "Nadpis" + default: "PredvolenÃĄ hodnota" + counter: "Počítadlo" + _counter: + name: "Meno premennej" + text: "Nadpis" + inc: "PripočítaÅĨ" + _button: + text: "Nadpis" + colored: "FarebnÊ" + action: "OperÃĄcia po stlačení tlačidla" + _action: + dialog: "ZobraziÅĨ dialÃŗg" + _dialog: + content: "Obsah" + resetRandom: "ResetovaÅĨ zdroj nÃĄhodnosti" + pushEvent: "PoslaÅĨ udalosÅĨ" + _pushEvent: + event: "NÃĄzov udalosti" + message: "ZobrazenÃĄ sprÃĄva po aktivÃĄcii" + variable: "OdoslanÃĄ premennÃĄ" + no-variable: "ÅŊiadne" + callAiScript: "SpustiÅĨ AiScript" + _callAiScript: + functionName: "NÃĄzov funkcie" + radioButton: "MoÅžnosÅĨ" + _radioButton: + name: "Meno premennej" + title: "Nadpis" + values: "Zoznam moÅžností oddelenÊ novÃŊmi riadkami" + default: "PredvolenÃĄ hodnota" + script: + categories: + flow: "Riadenie behu" + logical: "LogickÃĄ operÃĄcia" + operation: "VÃŊpočet" + comparison: "Porovnanie" + random: "NÃĄhodnÊ" + value: "Hodnoty" + fn: "Funkcie" + text: "TextovÊ operÃĄcie" + convert: "TransformÃĄcie" + list: "Zoznamy" + blocks: + text: "Text" + multiLineText: "Text (viacriadkovÃŊ)" + textList: "Zoznam textov" + _textList: + info: "OddeÄžte kaÅždÃē poloÅžku novÃŊm riadkom" + strLen: "DÄēÅžka textu" + _strLen: + arg1: "Text" + strPick: "VybraÅĨ znak" + _strPick: + arg1: "Text" + arg2: "Pozícia znaku" + strReplace: "NÃĄhradnÃŊ text" + _strReplace: + arg1: "Text" + arg2: "NahradenÃŊ text" + arg3: "NahradiÅĨ s" + strReverse: "OtočiÅĨ text" + _strReverse: + arg1: "Text" + join: "SpojiÅĨ texty" + _join: + arg1: "Zoznamy" + arg2: "OddeÄžovač" + add: "PridaÅĨ" + _add: + arg1: "A" + arg2: "B" + subtract: "OdčítaÅĨ" + _subtract: + arg1: "A" + arg2: "B" + multiply: "NÃĄsobiÅĨ" + _multiply: + arg1: "A" + arg2: "B" + divide: "DeliÅĨ" + _divide: + arg1: "A" + arg2: "B" + mod: "ZvyÅĄok po delení" + _mod: + arg1: "A" + arg2: "B" + round: "ZaokrÃēhliÅĨ" + _round: + arg1: "Číslo" + eq: "A a B sa rovnajÃē" + _eq: + arg1: "A" + arg2: "B" + notEq: "A a B sa nerovnajÃē" + _notEq: + arg1: "A" + arg2: "B" + and: "A a zÃĄroveň B" + _and: + arg1: "A" + arg2: "B" + or: "A alebo B" + _or: + arg1: "A" + arg2: "B" + lt: "< A je menÅĄie ako B" + _lt: + arg1: "A" + arg2: "B" + gt: "> A je vÃ¤ÄÅĄie ako B" + _gt: + arg1: "A" + arg2: "B" + ltEq: "<= A je menÅĄie alebo rovnÊ B" + _ltEq: + arg1: "A" + arg2: "B" + gtEq: ">= A je vÃ¤ÄÅĄie alebo rovnÊ B" + _gtEq: + arg1: "A" + arg2: "B" + if: "Vetva" + _if: + arg1: "Ak" + arg2: "Potom" + arg3: "Inak" + not: "Opak" + _not: + arg1: "Opak" + random: "NÃĄhodnÊ" + _random: + arg1: "PravdepodobnosÅĨ" + rannum: "NÃĄhodnÊ číslo" + _rannum: + arg1: "MinimÃĄlna hodnota" + arg2: "MaximÃĄlna hodnota" + randomPick: "NÃĄhodnÃŊ vÃŊber zo zoznamu" + _randomPick: + arg1: "Zoznam" + dailyRandom: "NÃĄhodne (zmení sa raz denne pre kaÅždÊho pouŞívateÄža)" + _dailyRandom: + arg1: "PravdepodobnosÅĨ" + dailyRannum: "NÃĄhodnÊ číslo (Mení sa denne pre kaÅždÊho pouŞívateÄža)" + _dailyRannum: + arg1: "MinimÃĄlna hodnota" + arg2: "MaximÃĄlna hodnota" + dailyRandomPick: "NÃĄhodnÃŊ vÃŊber zo zoznamu (Mení sa denne pre kaÅždÊho pouŞívateÄža)" + _dailyRandomPick: + arg1: "Zoznam" + seedRandom: "NÃĄhodne (so seedom)" + _seedRandom: + arg1: "Seed" + arg2: "PravdepodobnosÅĨ" + seedRannum: "NÃĄhodnÊ číslo (so seedom)" + _seedRannum: + arg1: "Seed" + arg2: "MinimÃĄlna hodnota" + arg3: "MaximÃĄlna hodnota" + seedRandomPick: "NÃĄhodnÃŊ vÃŊber zo zoznamu (so seedom)" + _seedRandomPick: + arg1: "Seed" + arg2: "Zoznam" + DRPWPM: "NÃĄhodnÃŊ vÃŊber z vÃĄÅženÊho zoznamu (Mení sa denne pre kaÅždÊho pouŞívateÄža)" + _DRPWPM: + arg1: "Zoznam textov" + pick: "VybraÅĨ zo zoznamu" + _pick: + arg1: "Zoznam" + arg2: "Pozícia" + listLen: "ZískaÅĨ dÄēÅžku zoznamu" + _listLen: + arg1: "Zoznam" + number: "Číslo" + stringToNumber: "Text na číslo" + _stringToNumber: + arg1: "Text" + numberToString: "Číslo na text" + _numberToString: + arg1: "Číslo" + splitStrByLine: "Rozdelí text po riadkoch" + _splitStrByLine: + arg1: "Text" + ref: "PremennÊ" + aiScriptVar: "AiScript premennÃĄ" + fn: "Funkcie" + _fn: + slots: "Sloty" + slots-info: "OddeÄžte kaÅždÃŊ slot novÃŊm riadkom" + arg1: "VÃŊstup" + for: "For cyklus" + _for: + arg1: "Počet opakovaní" + arg2: "Akcia" + typeError: "Slot {slot} akceptuje hodnoty typu \"{expect}\", ale dodanÃĄ hodnota je typu \"{actual}\"!" + thereIsEmptySlot: "Slot {slot} je prÃĄzdny!" + types: + string: "Text" + number: "Číslo" + boolean: "Boolean" + array: "Zoznamy" + stringArray: "Zoznam textov" + emptySlot: "PrÃĄzdny slot" + enviromentVariables: "PremennÊ prostredia" + pageVariables: "PremennÊ strÃĄnky" + argVariables: "VstupnÊ sloty" +_relayStatus: + requesting: "ČakÃĄ sa" + accepted: "AkceptovanÊ" + rejected: "OdmietnutÊ" +_notification: + fileUploaded: "SÃēbor sa ÃēspeÅĄne nahral" + youGotMention: "{name} vÃĄs spomenul/a" + youGotReply: "{name} vÃĄm odpovedal/a" + youGotQuote: "{name} vÃĄs citoval/a" + youRenoted: "{name} preposlal/a vaÅĄu poznÃĄmku" + youGotPoll: "{name} hlasoval/a" + youGotMessagingMessageFromUser: "{name} vÃĄm poslal/a sprÃĄvu" + youGotMessagingMessageFromGroup: "PriÅĄla sprÃĄva do skupiny {name}" + youWereFollowed: "MÃĄte novÊho sledujÃēceho" + youReceivedFollowRequest: "Dostali ste ÅžiadosÅĨ o sledovanie" + yourFollowRequestAccepted: "VaÅĄa ÅžiadosÅĨ o sledovanie bola prijatÃĄ" + youWereInvitedToGroup: "PozvaÅĨ do skupiny" + _types: + all: "VÅĄetky" + follow: "Sledujete" + mention: "Zmienka" + reply: "Odpovede" + renote: "PreposlaÅĨ" + quote: "CitovaÅĨ" + reaction: "Reakcie" + pollVote: "Hlasy v hlasovaniach" + receiveFollowRequest: "DoručenÊ Åžiadosti o sledovanie" + followRequestAccepted: "SchvÃĄlenÊ Åžiadosti o sledovanie" + groupInvited: "PozvÃĄnky do skupín" + app: "OznÃĄmenia z prepojenÃŊch aplikÃĄcií" +_deck: + alwaysShowMainColumn: "VÅždy zobraziÅĨ v hlavnom stÄēpci" + columnAlign: "ZarovnaÅĨ stÄēpce" + columnMargin: "Rozostup medzi stÄēpcami" + columnHeaderHeight: "VÃŊÅĄka hlavičky stÄēpca" + addColumn: "PridaÅĨ stÄēpec" + swapLeft: "VymeniÅĨ vÄžavo" + swapRight: "VymeniÅĨ vpravo" + swapUp: "VymeniÅĨ hore" + swapDown: "VymeniÅĨ s nasledujÃēcim" + stackLeft: "PriloÅžiÅĨ do ÄžavÊho stÄēpca" + popRight: "VybraÅĨ napravo" + profile: "Profil" + _columns: + main: "HlavnÃŊ" + widgets: "Widgety" + notifications: "OznÃĄmenia" + tl: "ČasovÃĄ os" + antenna: "AntÊny" + list: "Zoznam" + mentions: "Zmienky" + direct: "Priame poznÃĄmky" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 2dd605601..588df8d32 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -1038,7 +1038,8 @@ _exportOrImport: blockingList: "ЗабĐģĐžĐēŅƒĐ˛Đ°Ņ‚и" userLists: "ĐĄĐŋиŅĐēи" _charts: - federationInstancesTotal: "ЗаĐŗĐ°ĐģŅŒĐŊĐ° ĐēŅ–ĐģŅŒĐēŅ–ŅŅ‚ŅŒ Ņ„ĐĩĐ´ĐĩŅ€Đ°Ņ‚ивĐŊиŅ… Ņ–ĐŊŅŅ‚Đ°ĐŊŅŅ–в" + federation: "ФĐĩĐ´Ņ–вĐĩŅ€Ņ" + apRequest: "ЗаĐŋиŅ‚и" usersTotal: "ЗаĐŗĐ°ĐģŅŒĐŊĐ° ĐēŅ–ĐģŅŒĐēŅ–ŅŅ‚ŅŒ ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Ņ–в" activeUsers: "АĐēŅ‚ивĐŊŅ– ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Ņ–" notesTotal: "ЗаĐŗĐ°ĐģŅŒĐŊĐ° ĐēŅ–ĐģŅŒĐēŅ–ŅŅ‚ŅŒ ĐŊĐžŅ‚Đ°Ņ‚ĐžĐē" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 5815c92f4..86d3fb5cd 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -141,6 +141,8 @@ flagAsBot: "čŋ™æ˜¯ä¸€ä¸Ēæœē器äēēč´Ļåˇ" flagAsBotDescription: "åĻ‚æžœæ­¤å¸æˆˇį”ąį¨‹åēæŽ§åˆļīŧŒč¯ˇå¯į”¨æ­¤éĄšã€‚启į”¨åŽīŧŒæ­¤æ ‡åŋ—可äģĨ帎劊å…ļäģ–åŧ€å‘äēēå‘˜é˜˛æ­ĸæœē器äēē之间äē§į”Ÿæ— é™äē’动įš„čĄŒä¸ēīŧŒåšļ莊Misskeyįš„内部įŗģįģŸå°†æ­¤å¸æˆˇč¯†åˆĢä¸ēæœē器äēē。" flagAsCat: "将čŋ™ä¸Ēč´ĻæˆˇčŽžåŽšä¸ē一åĒįŒĢ" flagAsCatDescription: "åĻ‚果您æƒŗčĄ¨æ˜Žæ­¤å¸æˆˇæ˜¯ä¸€åĒįŒĢīŧŒč¯ˇæ‰“åŧ€æ­¤æ ‡åŋ—。" +flagShowTimelineReplies: "在æ—ļ间įēŋ上昞į¤ē帖子įš„回复" +flagShowTimelineRepliesDescription: "启į”¨æ—ļīŧŒæ—ļ间įēŋ除äē†æ˜žį¤ēį”¨æˆˇįš„帖子外īŧŒčŋ˜äŧšæ˜žį¤ēå…ļäģ–į”¨æˆˇå¯šå¸–子įš„回复。" autoAcceptFollowed: "č‡ĒåŠ¨å…čŽ¸å…ŗæŗ¨" addAccount: "æˇģ加č´Ļæˆˇ" loginFailed: "į™ģåŊ•å¤ąč´Ĩ" @@ -235,6 +237,8 @@ resetAreYouSure: "æĸ复éģ˜čŽ¤čŽžįŊŽīŧŸ" saved: "åˇ˛äŋå­˜" messaging: "čŠå¤Š" upload: "æœŦ地上äŧ " +keepOriginalUploading: "äŋį•™åŽŸå›ž" +keepOriginalUploadingDescription: "上äŧ å›žį‰‡æ—ļäŋį•™åŽŸå§‹å›žį‰‡ã€‚å…ŗ闭æ—ļīŧŒæĩč§ˆå™¨äŧšåœ¨ä¸Šäŧ æ—ļį”Ÿæˆä¸€åŧ į”¨äēŽweb发布įš„回į‰‡ã€‚" fromDrive: "äģŽįŊ‘į›˜ä¸­" fromUrl: "äģŽ URL" uploadFromUrl: "äģŽįŊ‘址上äŧ " @@ -591,6 +595,8 @@ smtpSecure: "在 SMTP čŋžæŽĨ中äŊŋį”¨éšåŧ SSL / TLS" smtpSecureInfo: "äŊŋį”¨STARTTLSæ—ļå…ŗ闭。" testEmail: "邮äģļ发送æĩ‹č¯•" wordMute: "æ–‡å­—åąč”Ŋ" +regexpError: "æ­Ŗåˆ™čĄ¨čžžåŧé”™č¯¯" +regexpErrorDescription: "{tab} åąč”Ŋ文字įš„įŦŦ {line} 行įš„æ­Ŗåˆ™čĄ¨čžžåŧæœ‰é”™č¯¯īŧš" instanceMute: "厞䞋įš„åąč”Ŋ" userSaysSomething: "{name}č¯´äē†äģ€äšˆ" makeActive: "启į”¨" @@ -619,8 +625,11 @@ reportAbuse: "丞æŠĨ" reportAbuseOf: "丞æŠĨ{name}" fillAbuseReportDescription: "č¯ˇåĄĢ写丞æŠĨįš„č¯Ļįģ†åŽŸå› ã€‚åĻ‚果有寚斚发įš„帖子īŧŒč¯ˇåŒæ—ļåĄĢ写URL地址。" abuseReported: "å†…åŽšåˇ˛å‘é€ã€‚æ„Ÿč°ĸ您įš„æŠĨ告。" +reporter: "æŠĨå‘Šč€…" reporteeOrigin: "丞æŠĨæĨæē" reporterOrigin: "丞æŠĨ者æĨæē" +forwardReport: "将æŠĨ告čŊŦ发įģ™čŋœį¨‹åŽžäž‹" +forwardReportIsAnonymous: "在čŋœį¨‹åŽžäž‹ä¸Šæ˜žį¤ēįš„æŠĨå‘Šč€…æ˜¯åŒŋ名įš„įŗģįģŸč´ĻåˇīŧŒč€Œä¸æ˜¯æ‚¨įš„č´Ļåˇã€‚" send: "发送" abuseMarkAsResolved: "处į†åŽŒæ¯•" openInNewTab: "在新标į­žéĄĩ中打åŧ€" @@ -817,6 +826,13 @@ leaveGroupConfirm: "įĄŽåŽšįĻģåŧ€ã€Œ{name}」īŧŸ" useDrawerReactionPickerForMobile: "在į§ģåŠ¨čŽžå¤‡ä¸ŠäŊŋį”¨æŠŊåą‰æ˜žį¤ē" welcomeBackWithName: "æŦĸčŋŽå›žæĨīŧŒ{name}" clickToFinishEmailVerification: "į‚šå‡ģ [{ok}] 厌成į”ĩ子邎äģļåœ°å€čŽ¤č¯ã€‚" +overridedDeviceKind: "čŽžå¤‡įąģ型" +smartphone: "æ™ēčƒŊ手æœē" +tablet: "åšŗæŋ" +auto: "č‡Ē动" +themeColor: "ä¸ģéĸ˜éĸœč‰˛" +size: "大小" +numberOfColumn: "列数" _emailUnavailable: used: "åˇ˛įģčĸĢäŊŋį”¨čŋ‡" format: "无效įš„æ ŧåŧ" @@ -944,7 +960,7 @@ _mfm: rotateDescription: "旋čŊŦ指厚įš„角åēĻ。" _instanceTicker: none: "不昞į¤ē" - remote: "昞į¤ēįģ™čŋœį¨‹į”¨æˆˇ" + remote: "äģ…昞į¤ēčŋœį¨‹į”¨æˆˇįš„" always: "始įģˆæ˜žį¤ē" _serverDisconnectedBehavior: reload: "č‡Ē动重čŊŊ" @@ -1253,8 +1269,8 @@ _exportOrImport: excludeMutingUsers: "æŽ’é™¤åąč”Ŋį”¨æˆˇ" excludeInactiveUsers: "排除不æ´ģ衃į”¨æˆˇ" _charts: - federationInstancesIncDec: "č”åˆīŧšåĸžåŠ /减少" - federationInstancesTotal: "č”åˆæ€ģ数" + federation: "č”åˆ" + apRequest: "č¯ˇæą‚" usersIncDec: "į”¨æˆˇæ•°é‡īŧšåĸžåŠ /减少" usersTotal: "į”¨æˆˇæ€ģ数" activeUsers: "æ´ģ衃į”¨æˆˇæ•°" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 798398a6a..b10871ec1 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1114,6 +1114,8 @@ _exportOrImport: blockingList: "封鎖" userLists: "清喎" _charts: + federation: "įĢ™å°č¯é‚Ļ" + apRequest: "čĢ‹æą‚" usersIncDec: "äŊŋį”¨č€…åĸ—減" usersTotal: "äŊŋį”¨č€…åˆå…ą" activeUsers: "æ´ģčēäŊŋį”¨č€…" diff --git a/package.json b/package.json index d94567298..68421f0e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "12.102.1", + "version": "12.107.0", "codename": "indigo", "repository": { "type": "git", @@ -42,11 +42,9 @@ "js-yaml": "4.1.0" }, "devDependencies": { - "@redocly/openapi-core": "1.0.0-beta.79", - "@types/fluent-ffmpeg": "2.1.20", - "@typescript-eslint/parser": "5.10.0", + "@typescript-eslint/parser": "5.12.0", "cross-env": "7.0.3", - "cypress": "9.3.1", + "cypress": "9.5.0", "start-server-and-test": "1.14.0", "typescript": "4.5.5" } diff --git a/packages/backend/.mocharc.json b/packages/backend/.mocharc.json index 278a5b310..26628066e 100644 --- a/packages/backend/.mocharc.json +++ b/packages/backend/.mocharc.json @@ -1,6 +1,9 @@ { "extension": ["ts","js","cjs","mjs"], - "require": ["ts-node/register", "tsconfig-paths/register"], + "node-option": [ + "experimental-specifier-resolution=node", + "loader=./test/loader.js" + ], "slow": 1000, "timeout": 35000, "exit": true diff --git a/packages/backend/@types/langmap.d.ts b/packages/backend/@types/langmap.d.ts deleted file mode 100644 index a0f99028a..000000000 --- a/packages/backend/@types/langmap.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -declare module 'langmap' { - type Lang = { - nativeName: string; - englishName: string; - }; - - const langmap: { [lang: string]: Lang }; - - export = langmap; -} diff --git a/packages/backend/migration/1000000000000-Init.js b/packages/backend/migration/1000000000000-Init.js index 19b216600..1140be7e8 100644 --- a/packages/backend/migration/1000000000000-Init.js +++ b/packages/backend/migration/1000000000000-Init.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class Init1000000000000 { + + +export class Init1000000000000 { async up(queryRunner) { await queryRunner.query(`CREATE TYPE "log_level_enum" AS ENUM('error', 'warning', 'info', 'success', 'debug')`); await queryRunner.query(`CREATE TABLE "log" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "domain" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "level" "log_level_enum" NOT NULL, "worker" character varying(8) NOT NULL, "machine" character varying(128) NOT NULL, "message" character varying(1024) NOT NULL, "data" jsonb NOT NULL DEFAULT '{}', CONSTRAINT "PK_350604cbdf991d5930d9e618fbd" PRIMARY KEY ("id"))`); @@ -480,4 +480,3 @@ class Init1000000000000 { await queryRunner.query(`DROP TYPE "log_level_enum"`); } } -exports.Init1000000000000 = Init1000000000000; diff --git a/packages/backend/migration/1556348509290-Pages.js b/packages/backend/migration/1556348509290-Pages.js index d69d17258..50caa2ce9 100644 --- a/packages/backend/migration/1556348509290-Pages.js +++ b/packages/backend/migration/1556348509290-Pages.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class Pages1556348509290 { + + +export class Pages1556348509290 { async up(queryRunner) { await queryRunner.query(`CREATE TYPE "page_visibility_enum" AS ENUM('public', 'followers', 'specified')`); await queryRunner.query(`CREATE TABLE "page" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "title" character varying(256) NOT NULL, "name" character varying(256) NOT NULL, "summary" character varying(256), "alignCenter" boolean NOT NULL, "font" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "eyeCatchingImageId" character varying(32), "content" jsonb NOT NULL DEFAULT '[]', "variables" jsonb NOT NULL DEFAULT '[]', "visibility" "page_visibility_enum" NOT NULL, "visibleUserIds" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], CONSTRAINT "PK_742f4117e065c5b6ad21b37ba1f" PRIMARY KEY ("id"))`); @@ -26,4 +26,3 @@ class Pages1556348509290 { await queryRunner.query(`DROP TYPE "page_visibility_enum"`); } } -exports.Pages1556348509290 = Pages1556348509290; diff --git a/packages/backend/migration/1556746559567-UserProfile.js b/packages/backend/migration/1556746559567-UserProfile.js index 3a082b882..50a9d1a8b 100644 --- a/packages/backend/migration/1556746559567-UserProfile.js +++ b/packages/backend/migration/1556746559567-UserProfile.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class UserProfile1556746559567 { + + +export class UserProfile1556746559567 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "githubId" TYPE VARCHAR(64) USING "githubId"::VARCHAR(64)`); await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "discordExpiresDate" TYPE VARCHAR(64) USING "discordExpiresDate"::VARCHAR(64)`); @@ -11,4 +11,3 @@ class UserProfile1556746559567 { await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "discordExpiresDate" TYPE INTEGER USING NULL`); } } -exports.UserProfile1556746559567 = UserProfile1556746559567; diff --git a/packages/backend/migration/1557476068003-PinnedUsers.js b/packages/backend/migration/1557476068003-PinnedUsers.js index c5e7fe748..d9cce2543 100644 --- a/packages/backend/migration/1557476068003-PinnedUsers.js +++ b/packages/backend/migration/1557476068003-PinnedUsers.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class PinnedUsers1557476068003 { + + +export class PinnedUsers1557476068003 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "meta" ADD "pinnedUsers" character varying(256) array NOT NULL DEFAULT '{}'::varchar[]`); } @@ -8,4 +8,3 @@ class PinnedUsers1557476068003 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "pinnedUsers"`); } } -exports.PinnedUsers1557476068003 = PinnedUsers1557476068003; diff --git a/packages/backend/migration/1557761316509-AddSomeUrls.js b/packages/backend/migration/1557761316509-AddSomeUrls.js index f6a7b409c..ab8736f7c 100644 --- a/packages/backend/migration/1557761316509-AddSomeUrls.js +++ b/packages/backend/migration/1557761316509-AddSomeUrls.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class AddSomeUrls1557761316509 { + + +export class AddSomeUrls1557761316509 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "meta" ADD "ToSUrl" character varying(512)`); await queryRunner.query(`ALTER TABLE "meta" ADD "repositoryUrl" character varying(512) NOT NULL DEFAULT 'https://github.com/misskey-dev/misskey'`); @@ -12,4 +12,3 @@ class AddSomeUrls1557761316509 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "ToSUrl"`); } } -exports.AddSomeUrls1557761316509 = AddSomeUrls1557761316509; diff --git a/packages/backend/migration/1557932705754-ObjectStorageSetting.js b/packages/backend/migration/1557932705754-ObjectStorageSetting.js index d798ac5ca..19a0b9d5c 100644 --- a/packages/backend/migration/1557932705754-ObjectStorageSetting.js +++ b/packages/backend/migration/1557932705754-ObjectStorageSetting.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class ObjectStorageSetting1557932705754 { + + +export class ObjectStorageSetting1557932705754 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "meta" ADD "useObjectStorage" boolean NOT NULL DEFAULT false`); await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageBucket" character varying(512)`); @@ -26,4 +26,3 @@ class ObjectStorageSetting1557932705754 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "useObjectStorage"`); } } -exports.ObjectStorageSetting1557932705754 = ObjectStorageSetting1557932705754; diff --git a/packages/backend/migration/1558072954435-PageLike.js b/packages/backend/migration/1558072954435-PageLike.js index 703843497..31b08418a 100644 --- a/packages/backend/migration/1558072954435-PageLike.js +++ b/packages/backend/migration/1558072954435-PageLike.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class PageLike1558072954435 { + + +export class PageLike1558072954435 { async up(queryRunner) { await queryRunner.query(`CREATE TABLE "page_like" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "pageId" character varying(32) NOT NULL, CONSTRAINT "PK_813f034843af992d3ae0f43c64c" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE INDEX "IDX_0e61efab7f88dbb79c9166dbb4" ON "page_like" ("userId") `); @@ -18,4 +18,3 @@ class PageLike1558072954435 { await queryRunner.query(`DROP TABLE "page_like"`); } } -exports.PageLike1558072954435 = PageLike1558072954435; diff --git a/packages/backend/migration/1558103093633-UserGroup.js b/packages/backend/migration/1558103093633-UserGroup.js index 9c1e51128..b670b31c3 100644 --- a/packages/backend/migration/1558103093633-UserGroup.js +++ b/packages/backend/migration/1558103093633-UserGroup.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class UserGroup1558103093633 { + + +export class UserGroup1558103093633 { async up(queryRunner) { await queryRunner.query(`CREATE TABLE "user_group" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "name" character varying(256) NOT NULL, "userId" character varying(32) NOT NULL, "isPrivate" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_3c29fba6fe013ec8724378ce7c9" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE INDEX "IDX_20e30aa35180e317e133d75316" ON "user_group" ("createdAt") `); @@ -36,4 +36,3 @@ class UserGroup1558103093633 { await queryRunner.query(`DROP TABLE "user_group"`); } } -exports.UserGroup1558103093633 = UserGroup1558103093633; diff --git a/packages/backend/migration/1558257926829-UserGroupInvite.js b/packages/backend/migration/1558257926829-UserGroupInvite.js index e8a575e74..e48bd3a7f 100644 --- a/packages/backend/migration/1558257926829-UserGroupInvite.js +++ b/packages/backend/migration/1558257926829-UserGroupInvite.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class UserGroupInvite1558257926829 { + + +export class UserGroupInvite1558257926829 { async up(queryRunner) { await queryRunner.query(`CREATE TABLE "user_group_invite" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "userGroupId" character varying(32) NOT NULL, CONSTRAINT "PK_3893884af0d3a5f4d01e7921a97" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE INDEX "IDX_1039988afa3bf991185b277fe0" ON "user_group_invite" ("userId") `); @@ -20,4 +20,3 @@ class UserGroupInvite1558257926829 { await queryRunner.query(`DROP TABLE "user_group_invite"`); } } -exports.UserGroupInvite1558257926829 = UserGroupInvite1558257926829; diff --git a/packages/backend/migration/1558266512381-UserListJoining.js b/packages/backend/migration/1558266512381-UserListJoining.js index b31f7bd3d..3398aed13 100644 --- a/packages/backend/migration/1558266512381-UserListJoining.js +++ b/packages/backend/migration/1558266512381-UserListJoining.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class UserListJoining1558266512381 { + + +export class UserListJoining1558266512381 { async up(queryRunner) { await queryRunner.query(`CREATE UNIQUE INDEX "IDX_90f7da835e4c10aca6853621e1" ON "user_list_joining" ("userId", "userListId") `); } @@ -8,4 +8,3 @@ class UserListJoining1558266512381 { await queryRunner.query(`DROP INDEX "IDX_90f7da835e4c10aca6853621e1"`); } } -exports.UserListJoining1558266512381 = UserListJoining1558266512381; diff --git a/packages/backend/migration/1561706992953-webauthn.js b/packages/backend/migration/1561706992953-webauthn.js index f05054f55..b007ffef1 100644 --- a/packages/backend/migration/1561706992953-webauthn.js +++ b/packages/backend/migration/1561706992953-webauthn.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class webauthn1561706992953 { + + +export class webauthn1561706992953 { async up(queryRunner) { await queryRunner.query(`CREATE TABLE "attestation_challenge" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "challenge" character varying(64) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "registrationChallenge" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_d0ba6786e093f1bcb497572a6b5" PRIMARY KEY ("id", "userId"))`); await queryRunner.query(`CREATE INDEX "IDX_f1a461a618fa1755692d0e0d59" ON "attestation_challenge" ("userId") `); @@ -24,4 +24,3 @@ class webauthn1561706992953 { await queryRunner.query(`DROP TABLE "attestation_challenge"`); } } -exports.webauthn1561706992953 = webauthn1561706992953; diff --git a/packages/backend/migration/1561873850023-ChartIndexes.js b/packages/backend/migration/1561873850023-ChartIndexes.js index 559cb70cb..3ce53567f 100644 --- a/packages/backend/migration/1561873850023-ChartIndexes.js +++ b/packages/backend/migration/1561873850023-ChartIndexes.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class ChartIndexes1561873850023 { + + +export class ChartIndexes1561873850023 { async up(queryRunner) { await queryRunner.query(`CREATE INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc" ON "__chart__active_users" ("date") `); await queryRunner.query(`CREATE INDEX "IDX_15e91a03aeeac9dbccdf43fc06" ON "__chart__active_users" ("span") `); @@ -196,4 +196,3 @@ class ChartIndexes1561873850023 { await queryRunner.query(`DROP INDEX "IDX_8cb40cfc8f3c28261e6f887b03"`); } } -exports.ChartIndexes1561873850023 = ChartIndexes1561873850023; diff --git a/packages/backend/migration/1562422242907-PasswordLessLogin.js b/packages/backend/migration/1562422242907-PasswordLessLogin.js index bed879ade..b73c7db4d 100644 --- a/packages/backend/migration/1562422242907-PasswordLessLogin.js +++ b/packages/backend/migration/1562422242907-PasswordLessLogin.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class PasswordLessLogin1562422242907 { + + +export class PasswordLessLogin1562422242907 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "user_profile" ADD COLUMN "usePasswordLessLogin" boolean DEFAULT false NOT NULL`); } @@ -8,4 +8,3 @@ class PasswordLessLogin1562422242907 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "usePasswordLessLogin"`); } } -exports.PasswordLessLogin1562422242907 = PasswordLessLogin1562422242907; diff --git a/packages/backend/migration/1562444565093-PinnedPage.js b/packages/backend/migration/1562444565093-PinnedPage.js index f0aac3a4b..9a999a915 100644 --- a/packages/backend/migration/1562444565093-PinnedPage.js +++ b/packages/backend/migration/1562444565093-PinnedPage.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class PinnedPage1562444565093 { + + +export class PinnedPage1562444565093 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "user_profile" ADD "pinnedPageId" character varying(32)`); await queryRunner.query(`ALTER TABLE "user_profile" ADD CONSTRAINT "UQ_6dc44f1ceb65b1e72bacef2ca27" UNIQUE ("pinnedPageId")`); @@ -12,4 +12,3 @@ class PinnedPage1562444565093 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "pinnedPageId"`); } } -exports.PinnedPage1562444565093 = PinnedPage1562444565093; diff --git a/packages/backend/migration/1562448332510-PageTitleHideOption.js b/packages/backend/migration/1562448332510-PageTitleHideOption.js index 238b74226..8fc78d202 100644 --- a/packages/backend/migration/1562448332510-PageTitleHideOption.js +++ b/packages/backend/migration/1562448332510-PageTitleHideOption.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class PageTitleHideOption1562448332510 { + + +export class PageTitleHideOption1562448332510 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "page" ADD "hideTitleWhenPinned" boolean NOT NULL DEFAULT false`); } @@ -8,4 +8,3 @@ class PageTitleHideOption1562448332510 { await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "hideTitleWhenPinned"`); } } -exports.PageTitleHideOption1562448332510 = PageTitleHideOption1562448332510; diff --git a/packages/backend/migration/1562869971568-ModerationLog.js b/packages/backend/migration/1562869971568-ModerationLog.js index c8953c513..dd66d16ee 100644 --- a/packages/backend/migration/1562869971568-ModerationLog.js +++ b/packages/backend/migration/1562869971568-ModerationLog.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class ModerationLog1562869971568 { + + +export class ModerationLog1562869971568 { async up(queryRunner) { await queryRunner.query(`CREATE TABLE "moderation_log" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "type" character varying(128) NOT NULL, "info" jsonb NOT NULL, CONSTRAINT "PK_d0adca6ecfd068db83e4526cc26" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE INDEX "IDX_a08ad074601d204e0f69da9a95" ON "moderation_log" ("userId") `); @@ -12,4 +12,3 @@ class ModerationLog1562869971568 { await queryRunner.query(`DROP TABLE "moderation_log"`); } } -exports.ModerationLog1562869971568 = ModerationLog1562869971568; diff --git a/packages/backend/migration/1563757595828-UsedUsername.js b/packages/backend/migration/1563757595828-UsedUsername.js index 0e59fdd45..8972df297 100644 --- a/packages/backend/migration/1563757595828-UsedUsername.js +++ b/packages/backend/migration/1563757595828-UsedUsername.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class UsedUsername1563757595828 { + + +export class UsedUsername1563757595828 { async up(queryRunner) { await queryRunner.query(`CREATE TABLE "used_username" ("username" character varying(128) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_78fd79d2d24c6ac2f4cc9a31a5d" PRIMARY KEY ("username"))`); } @@ -8,4 +8,3 @@ class UsedUsername1563757595828 { await queryRunner.query(`DROP TABLE "used_username"`); } } -exports.UsedUsername1563757595828 = UsedUsername1563757595828; diff --git a/packages/backend/migration/1565634203341-room.js b/packages/backend/migration/1565634203341-room.js index 49ca5ea50..679940f24 100644 --- a/packages/backend/migration/1565634203341-room.js +++ b/packages/backend/migration/1565634203341-room.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class room1565634203341 { + + +export class room1565634203341 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "user_profile" ADD "room" jsonb NOT NULL DEFAULT '{}'`); } @@ -8,4 +8,3 @@ class room1565634203341 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "room"`); } } -exports.room1565634203341 = room1565634203341; diff --git a/packages/backend/migration/1571220798684-CustomEmojiCategory.js b/packages/backend/migration/1571220798684-CustomEmojiCategory.js index c67c437de..37c07366e 100644 --- a/packages/backend/migration/1571220798684-CustomEmojiCategory.js +++ b/packages/backend/migration/1571220798684-CustomEmojiCategory.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class CustomEmojiCategory1571220798684 { + + +export class CustomEmojiCategory1571220798684 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "emoji" ADD "category" character varying(128)`, undefined); } @@ -8,4 +8,3 @@ class CustomEmojiCategory1571220798684 { await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "category"`, undefined); } } -exports.CustomEmojiCategory1571220798684 = CustomEmojiCategory1571220798684; diff --git a/packages/backend/migration/1572760203493-nodeinfo.js b/packages/backend/migration/1572760203493-nodeinfo.js index a3ca5d718..54d5f914a 100644 --- a/packages/backend/migration/1572760203493-nodeinfo.js +++ b/packages/backend/migration/1572760203493-nodeinfo.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class nodeinfo1572760203493 { + + +export class nodeinfo1572760203493 { async up(queryRunner) { await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "system"`, undefined); await queryRunner.query(`ALTER TABLE "instance" ADD "softwareName" character varying(64) DEFAULT null`, undefined); @@ -24,4 +24,3 @@ class nodeinfo1572760203493 { await queryRunner.query(`ALTER TABLE "instance" ADD "system" character varying(64)`, undefined); } } -exports.nodeinfo1572760203493 = nodeinfo1572760203493; diff --git a/packages/backend/migration/1576269851876-TalkFederationId.js b/packages/backend/migration/1576269851876-TalkFederationId.js index 63a8f8a9a..35861d571 100644 --- a/packages/backend/migration/1576269851876-TalkFederationId.js +++ b/packages/backend/migration/1576269851876-TalkFederationId.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class TalkFederationId1576269851876 { + + +export class TalkFederationId1576269851876 { constructor() { this.name = 'TalkFederationId1576269851876'; } @@ -11,4 +11,3 @@ class TalkFederationId1576269851876 { await queryRunner.query(`ALTER TABLE "messaging_message" DROP COLUMN "uri"`, undefined); } } -exports.TalkFederationId1576269851876 = TalkFederationId1576269851876; diff --git a/packages/backend/migration/1576869585998-ProxyRemoteFiles.js b/packages/backend/migration/1576869585998-ProxyRemoteFiles.js index 867ae3d6e..d6d134be4 100644 --- a/packages/backend/migration/1576869585998-ProxyRemoteFiles.js +++ b/packages/backend/migration/1576869585998-ProxyRemoteFiles.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class ProxyRemoteFiles1576869585998 { + + +export class ProxyRemoteFiles1576869585998 { constructor() { this.name = 'ProxyRemoteFiles1576869585998'; } @@ -11,4 +11,3 @@ class ProxyRemoteFiles1576869585998 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyRemoteFiles"`, undefined); } } -exports.ProxyRemoteFiles1576869585998 = ProxyRemoteFiles1576869585998; diff --git a/packages/backend/migration/1579267006611-v12.js b/packages/backend/migration/1579267006611-v12.js index ccc524773..7f6318a19 100644 --- a/packages/backend/migration/1579267006611-v12.js +++ b/packages/backend/migration/1579267006611-v12.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v121579267006611 { + + +export class v121579267006611 { constructor() { this.name = 'v121579267006611'; } @@ -31,4 +31,3 @@ class v121579267006611 { await queryRunner.query(`DROP TABLE "announcement"`, undefined); } } -exports.v121579267006611 = v121579267006611; diff --git a/packages/backend/migration/1579270193251-v12-2.js b/packages/backend/migration/1579270193251-v12-2.js index 7f67645aa..c51ce6306 100644 --- a/packages/backend/migration/1579270193251-v12-2.js +++ b/packages/backend/migration/1579270193251-v12-2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v1221579270193251 { + + +export class v1221579270193251 { constructor() { this.name = 'v1221579270193251'; } @@ -11,4 +11,3 @@ class v1221579270193251 { await queryRunner.query(`ALTER TABLE "announcement_read" DROP COLUMN "createdAt"`, undefined); } } -exports.v1221579270193251 = v1221579270193251; diff --git a/packages/backend/migration/1579282808087-v12-3.js b/packages/backend/migration/1579282808087-v12-3.js index 80fa234a5..aeb4f5a87 100644 --- a/packages/backend/migration/1579282808087-v12-3.js +++ b/packages/backend/migration/1579282808087-v12-3.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v1231579282808087 { + + +export class v1231579282808087 { constructor() { this.name = 'v1231579282808087'; } @@ -11,4 +11,3 @@ class v1231579282808087 { await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "updatedAt"`, undefined); } } -exports.v1231579282808087 = v1231579282808087; diff --git a/packages/backend/migration/1579544426412-v12-4.js b/packages/backend/migration/1579544426412-v12-4.js index ef2b804f5..f1e093413 100644 --- a/packages/backend/migration/1579544426412-v12-4.js +++ b/packages/backend/migration/1579544426412-v12-4.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v1241579544426412 { + + +export class v1241579544426412 { constructor() { this.name = 'v1241579544426412'; } @@ -13,4 +13,3 @@ class v1241579544426412 { await queryRunner.query(`ALTER TABLE "notification" DROP COLUMN "followRequestId"`, undefined); } } -exports.v1241579544426412 = v1241579544426412; diff --git a/packages/backend/migration/1579977526288-v12-5.js b/packages/backend/migration/1579977526288-v12-5.js index 1d2ed0966..6d2b5c584 100644 --- a/packages/backend/migration/1579977526288-v12-5.js +++ b/packages/backend/migration/1579977526288-v12-5.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v1251579977526288 { + + +export class v1251579977526288 { constructor() { this.name = 'v1251579977526288'; } @@ -51,4 +51,3 @@ class v1251579977526288 { await queryRunner.query(`DROP TABLE "clip"`, undefined); } } -exports.v1251579977526288 = v1251579977526288; diff --git a/packages/backend/migration/1579993013959-v12-6.js b/packages/backend/migration/1579993013959-v12-6.js index e6c3a40a3..3941c1391 100644 --- a/packages/backend/migration/1579993013959-v12-6.js +++ b/packages/backend/migration/1579993013959-v12-6.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v1261579993013959 { + + +export class v1261579993013959 { constructor() { this.name = 'v1261579993013959'; } @@ -15,4 +15,3 @@ class v1261579993013959 { await queryRunner.query(`ALTER TABLE "antenna" ADD "hasNewNote" boolean NOT NULL DEFAULT false`, undefined); } } -exports.v1261579993013959 = v1261579993013959; diff --git a/packages/backend/migration/1580069531114-v12-7.js b/packages/backend/migration/1580069531114-v12-7.js index 7915603b8..4b4790cb7 100644 --- a/packages/backend/migration/1580069531114-v12-7.js +++ b/packages/backend/migration/1580069531114-v12-7.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v1271580069531114 { + + +export class v1271580069531114 { constructor() { this.name = 'v1271580069531114'; } @@ -21,4 +21,3 @@ class v1271580069531114 { await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "users"`, undefined); } } -exports.v1271580069531114 = v1271580069531114; diff --git a/packages/backend/migration/1580148575182-v12-8.js b/packages/backend/migration/1580148575182-v12-8.js index 43fbc70e4..cc30200c1 100644 --- a/packages/backend/migration/1580148575182-v12-8.js +++ b/packages/backend/migration/1580148575182-v12-8.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v1281580148575182 { + + +export class v1281580148575182 { constructor() { this.name = 'v1281580148575182'; } @@ -13,4 +13,3 @@ class v1281580148575182 { await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_ec5c201576192ba8904c345c5cc" FOREIGN KEY ("appId") REFERENCES "app"("id") ON DELETE SET NULL ON UPDATE NO ACTION`, undefined); } } -exports.v1281580148575182 = v1281580148575182; diff --git a/packages/backend/migration/1580154400017-v12-9.js b/packages/backend/migration/1580154400017-v12-9.js index f47611868..3715798f1 100644 --- a/packages/backend/migration/1580154400017-v12-9.js +++ b/packages/backend/migration/1580154400017-v12-9.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v1291580154400017 { + + +export class v1291580154400017 { constructor() { this.name = 'v1291580154400017'; } @@ -11,4 +11,3 @@ class v1291580154400017 { await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "withReplies"`, undefined); } } -exports.v1291580154400017 = v1291580154400017; diff --git a/packages/backend/migration/1580276619901-v12-10.js b/packages/backend/migration/1580276619901-v12-10.js index 301d0ceb9..d5decb882 100644 --- a/packages/backend/migration/1580276619901-v12-10.js +++ b/packages/backend/migration/1580276619901-v12-10.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v12101580276619901 { + + +export class v12101580276619901 { constructor() { this.name = 'v12101580276619901'; } @@ -16,4 +16,3 @@ class v12101580276619901 { await queryRunner.query(`ALTER TABLE "notification" ADD "type" character varying(32) NOT NULL`, undefined); } } -exports.v12101580276619901 = v12101580276619901; diff --git a/packages/backend/migration/1580331224276-v12-11.js b/packages/backend/migration/1580331224276-v12-11.js index fb5124baa..129720adb 100644 --- a/packages/backend/migration/1580331224276-v12-11.js +++ b/packages/backend/migration/1580331224276-v12-11.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v12111580331224276 { + + +export class v12111580331224276 { constructor() { this.name = 'v12111580331224276'; } @@ -15,4 +15,3 @@ class v12111580331224276 { await queryRunner.query(`ALTER TABLE "instance" ADD "isMarkedAsClosed" boolean NOT NULL DEFAULT false`, undefined); } } -exports.v12111580331224276 = v12111580331224276; diff --git a/packages/backend/migration/1580508795118-v12-12.js b/packages/backend/migration/1580508795118-v12-12.js index eb70ba3ce..c5cec23a3 100644 --- a/packages/backend/migration/1580508795118-v12-12.js +++ b/packages/backend/migration/1580508795118-v12-12.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v12121580508795118 { + + +export class v12121580508795118 { constructor() { this.name = 'v12121580508795118'; } @@ -43,4 +43,3 @@ class v12121580508795118 { await queryRunner.query(`ALTER TABLE "user_profile" ADD "twitter" boolean NOT NULL DEFAULT false`, undefined); } } -exports.v12121580508795118 = v12121580508795118; diff --git a/packages/backend/migration/1580543501339-v12-13.js b/packages/backend/migration/1580543501339-v12-13.js index 7dae7178b..2fa490392 100644 --- a/packages/backend/migration/1580543501339-v12-13.js +++ b/packages/backend/migration/1580543501339-v12-13.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v12131580543501339 { + + +export class v12131580543501339 { constructor() { this.name = 'v12131580543501339'; } @@ -11,4 +11,3 @@ class v12131580543501339 { await queryRunner.query(`DROP INDEX "IDX_NOTE_TAGS"`, undefined); } } -exports.v12131580543501339 = v12131580543501339; diff --git a/packages/backend/migration/1580864313253-v12-14.js b/packages/backend/migration/1580864313253-v12-14.js index b1939c51b..a3756ad02 100644 --- a/packages/backend/migration/1580864313253-v12-14.js +++ b/packages/backend/migration/1580864313253-v12-14.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class v12141580864313253 { + + +export class v12141580864313253 { constructor() { this.name = 'v12141580864313253'; } @@ -17,4 +17,3 @@ class v12141580864313253 { await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "proxyAccountId" TO "proxyAccount"`, undefined); } } -exports.v12141580864313253 = v12141580864313253; diff --git a/packages/backend/migration/1581526429287-user-group-invitation.js b/packages/backend/migration/1581526429287-user-group-invitation.js index 80946c94a..181b0aba8 100644 --- a/packages/backend/migration/1581526429287-user-group-invitation.js +++ b/packages/backend/migration/1581526429287-user-group-invitation.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userGroupInvitation1581526429287 { + + +export class userGroupInvitation1581526429287 { constructor() { this.name = 'userGroupInvitation1581526429287'; } @@ -35,4 +35,3 @@ class userGroupInvitation1581526429287 { await queryRunner.query(`DROP TABLE "user_group_invitation"`, undefined); } } -exports.userGroupInvitation1581526429287 = userGroupInvitation1581526429287; diff --git a/packages/backend/migration/1581695816408-user-group-antenna.js b/packages/backend/migration/1581695816408-user-group-antenna.js index 307b5b057..267b58cd9 100644 --- a/packages/backend/migration/1581695816408-user-group-antenna.js +++ b/packages/backend/migration/1581695816408-user-group-antenna.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userGroupAntenna1581695816408 { + + +export class userGroupAntenna1581695816408 { constructor() { this.name = 'userGroupAntenna1581695816408'; } @@ -25,4 +25,3 @@ class userGroupAntenna1581695816408 { await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "userGroupJoiningId"`, undefined); } } -exports.userGroupAntenna1581695816408 = userGroupAntenna1581695816408; diff --git a/packages/backend/migration/1581708415836-drive-user-folder-id-index.js b/packages/backend/migration/1581708415836-drive-user-folder-id-index.js index 8029ef139..43c2ce6ce 100644 --- a/packages/backend/migration/1581708415836-drive-user-folder-id-index.js +++ b/packages/backend/migration/1581708415836-drive-user-folder-id-index.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class driveUserFolderIdIndex1581708415836 { + + +export class driveUserFolderIdIndex1581708415836 { constructor() { this.name = 'driveUserFolderIdIndex1581708415836'; } @@ -11,4 +11,3 @@ class driveUserFolderIdIndex1581708415836 { await queryRunner.query(`DROP INDEX "IDX_55720b33a61a7c806a8215b825"`, undefined); } } -exports.driveUserFolderIdIndex1581708415836 = driveUserFolderIdIndex1581708415836; diff --git a/packages/backend/migration/1581979837262-promo.js b/packages/backend/migration/1581979837262-promo.js index d2c5bac17..4813a5f48 100644 --- a/packages/backend/migration/1581979837262-promo.js +++ b/packages/backend/migration/1581979837262-promo.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class promo1581979837262 { + + +export class promo1581979837262 { constructor() { this.name = 'promo1581979837262'; } @@ -25,4 +25,3 @@ class promo1581979837262 { await queryRunner.query(`DROP TABLE "promo_note"`, undefined); } } -exports.promo1581979837262 = promo1581979837262; diff --git a/packages/backend/migration/1582019042083-featured-injecttion.js b/packages/backend/migration/1582019042083-featured-injecttion.js index 9779e2a08..7f8790b01 100644 --- a/packages/backend/migration/1582019042083-featured-injecttion.js +++ b/packages/backend/migration/1582019042083-featured-injecttion.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class featuredInjecttion1582019042083 { + + +export class featuredInjecttion1582019042083 { constructor() { this.name = 'featuredInjecttion1582019042083'; } @@ -11,4 +11,3 @@ class featuredInjecttion1582019042083 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "injectFeaturedNote"`, undefined); } } -exports.featuredInjecttion1582019042083 = featuredInjecttion1582019042083; diff --git a/packages/backend/migration/1582210532752-antenna-exclude.js b/packages/backend/migration/1582210532752-antenna-exclude.js index cc095b4b5..ff8d7b80d 100644 --- a/packages/backend/migration/1582210532752-antenna-exclude.js +++ b/packages/backend/migration/1582210532752-antenna-exclude.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class antennaExclude1582210532752 { + + +export class antennaExclude1582210532752 { constructor() { this.name = 'antennaExclude1582210532752'; } @@ -11,4 +11,3 @@ class antennaExclude1582210532752 { await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "excludeKeywords"`, undefined); } } -exports.antennaExclude1582210532752 = antennaExclude1582210532752; diff --git a/packages/backend/migration/1582875306439-note-reaction-length.js b/packages/backend/migration/1582875306439-note-reaction-length.js index bdee1ef14..e99501f01 100644 --- a/packages/backend/migration/1582875306439-note-reaction-length.js +++ b/packages/backend/migration/1582875306439-note-reaction-length.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class noteReactionLength1582875306439 { + + +export class noteReactionLength1582875306439 { constructor() { this.name = 'noteReactionLength1582875306439'; } @@ -11,4 +11,3 @@ class noteReactionLength1582875306439 { await queryRunner.query(`ALTER TABLE "note_reaction" ALTER COLUMN "reaction" TYPE character varying(128)`, undefined); } } -exports.noteReactionLength1582875306439 = noteReactionLength1582875306439; diff --git a/packages/backend/migration/1585361548360-miauth.js b/packages/backend/migration/1585361548360-miauth.js index c1a695dd2..e59aa3b6e 100644 --- a/packages/backend/migration/1585361548360-miauth.js +++ b/packages/backend/migration/1585361548360-miauth.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class miauth1585361548360 { + + +export class miauth1585361548360 { constructor() { this.name = 'miauth1585361548360'; } @@ -33,4 +33,3 @@ class miauth1585361548360 { await queryRunner.query(`ALTER TABLE "access_token" DROP COLUMN "lastUsedAt"`, undefined); } } -exports.miauth1585361548360 = miauth1585361548360; diff --git a/packages/backend/migration/1585385921215-custom-notification.js b/packages/backend/migration/1585385921215-custom-notification.js index 7f94c741a..c3ddb2be1 100644 --- a/packages/backend/migration/1585385921215-custom-notification.js +++ b/packages/backend/migration/1585385921215-custom-notification.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class customNotification1585385921215 { + + +export class customNotification1585385921215 { constructor() { this.name = 'customNotification1585385921215'; } @@ -45,4 +45,3 @@ class customNotification1585385921215 { await queryRunner.query(`ALTER TABLE "notification" DROP COLUMN "customBody"`, undefined); } } -exports.customNotification1585385921215 = customNotification1585385921215; diff --git a/packages/backend/migration/1585772678853-ap-url.js b/packages/backend/migration/1585772678853-ap-url.js index f7c1f87b8..5fb809ff5 100644 --- a/packages/backend/migration/1585772678853-ap-url.js +++ b/packages/backend/migration/1585772678853-ap-url.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class apUrl1585772678853 { + + +export class apUrl1585772678853 { constructor() { this.name = 'apUrl1585772678853'; } @@ -11,4 +11,3 @@ class apUrl1585772678853 { await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "url"`, undefined); } } -exports.apUrl1585772678853 = apUrl1585772678853; diff --git a/packages/backend/migration/1586624197029-AddObjectStorageUseProxy.js b/packages/backend/migration/1586624197029-AddObjectStorageUseProxy.js index 9fcef0c90..e13bb217e 100644 --- a/packages/backend/migration/1586624197029-AddObjectStorageUseProxy.js +++ b/packages/backend/migration/1586624197029-AddObjectStorageUseProxy.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class AddObjectStorageUseProxy1586624197029 { + + +export class AddObjectStorageUseProxy1586624197029 { constructor() { this.name = 'AddObjectStorageUseProxy1586624197029'; } @@ -11,4 +11,3 @@ class AddObjectStorageUseProxy1586624197029 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageUseProxy"`, undefined); } } -exports.AddObjectStorageUseProxy1586624197029 = AddObjectStorageUseProxy1586624197029; diff --git a/packages/backend/migration/1586641139527-remote-reaction.js b/packages/backend/migration/1586641139527-remote-reaction.js index a9d362474..5b23103a1 100644 --- a/packages/backend/migration/1586641139527-remote-reaction.js +++ b/packages/backend/migration/1586641139527-remote-reaction.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class remoteReaction1586641139527 { + + +export class remoteReaction1586641139527 { constructor() { this.name = 'remoteReaction1586641139527'; } @@ -11,4 +11,3 @@ class remoteReaction1586641139527 { await queryRunner.query(`ALTER TABLE "note_reaction" ALTER COLUMN "reaction" TYPE character varying(130)`, undefined); } } -exports.remoteReaction1586641139527 = remoteReaction1586641139527; diff --git a/packages/backend/migration/1586708940386-pageAiScript.js b/packages/backend/migration/1586708940386-pageAiScript.js index 089ff6e27..eed616c11 100644 --- a/packages/backend/migration/1586708940386-pageAiScript.js +++ b/packages/backend/migration/1586708940386-pageAiScript.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class pageAiScript1586708940386 { + + +export class pageAiScript1586708940386 { constructor() { this.name = 'pageAiScript1586708940386'; } @@ -11,4 +11,3 @@ class pageAiScript1586708940386 { await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "script"`, undefined); } } -exports.pageAiScript1586708940386 = pageAiScript1586708940386; diff --git a/packages/backend/migration/1588044505511-hCaptcha.js b/packages/backend/migration/1588044505511-hCaptcha.js index 9b2524afb..a33dbd713 100644 --- a/packages/backend/migration/1588044505511-hCaptcha.js +++ b/packages/backend/migration/1588044505511-hCaptcha.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class hCaptcha1588044505511 { + + +export class hCaptcha1588044505511 { constructor() { this.name = 'hCaptcha1588044505511'; } @@ -15,4 +15,3 @@ class hCaptcha1588044505511 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableHcaptcha"`, undefined); } } -exports.hCaptcha1588044505511 = hCaptcha1588044505511; diff --git a/packages/backend/migration/1589023282116-pubRelay.js b/packages/backend/migration/1589023282116-pubRelay.js index f03384a51..48a1028d3 100644 --- a/packages/backend/migration/1589023282116-pubRelay.js +++ b/packages/backend/migration/1589023282116-pubRelay.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class pubRelay1589023282116 { + + +export class pubRelay1589023282116 { constructor() { this.name = 'pubRelay1589023282116'; } @@ -15,4 +15,3 @@ class pubRelay1589023282116 { await queryRunner.query(`DROP TYPE "relay_status_enum"`, undefined); } } -exports.pubRelay1589023282116 = pubRelay1589023282116; diff --git a/packages/backend/migration/1595075960584-blurhash.js b/packages/backend/migration/1595075960584-blurhash.js index 3bd9c46f1..f24d3722c 100644 --- a/packages/backend/migration/1595075960584-blurhash.js +++ b/packages/backend/migration/1595075960584-blurhash.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class blurhash1595075960584 { + + +export class blurhash1595075960584 { constructor() { this.name = 'blurhash1595075960584'; } @@ -11,4 +11,3 @@ class blurhash1595075960584 { await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "blurhash"`); } } -exports.blurhash1595075960584 = blurhash1595075960584; diff --git a/packages/backend/migration/1595077605646-blurhash-for-avatar-banner.js b/packages/backend/migration/1595077605646-blurhash-for-avatar-banner.js index c2a9c9756..f18f6f972 100644 --- a/packages/backend/migration/1595077605646-blurhash-for-avatar-banner.js +++ b/packages/backend/migration/1595077605646-blurhash-for-avatar-banner.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class blurhashForAvatarBanner1595077605646 { + + +export class blurhashForAvatarBanner1595077605646 { constructor() { this.name = 'blurhashForAvatarBanner1595077605646'; } @@ -17,4 +17,3 @@ class blurhashForAvatarBanner1595077605646 { await queryRunner.query(`ALTER TABLE "user" ADD "avatarColor" character varying(32)`); } } -exports.blurhashForAvatarBanner1595077605646 = blurhashForAvatarBanner1595077605646; diff --git a/packages/backend/migration/1595676934834-instance-icon-url.js b/packages/backend/migration/1595676934834-instance-icon-url.js index 21ae26c55..df9d8199b 100644 --- a/packages/backend/migration/1595676934834-instance-icon-url.js +++ b/packages/backend/migration/1595676934834-instance-icon-url.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class instanceIconUrl1595676934834 { + + +export class instanceIconUrl1595676934834 { constructor() { this.name = 'instanceIconUrl1595676934834'; } @@ -11,4 +11,3 @@ class instanceIconUrl1595676934834 { await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "iconUrl"`); } } -exports.instanceIconUrl1595676934834 = instanceIconUrl1595676934834; diff --git a/packages/backend/migration/1595771249699-word-mute.js b/packages/backend/migration/1595771249699-word-mute.js index 0dd3a5556..e8e4ac838 100644 --- a/packages/backend/migration/1595771249699-word-mute.js +++ b/packages/backend/migration/1595771249699-word-mute.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class wordMute1595771249699 { + + +export class wordMute1595771249699 { constructor() { this.name = 'wordMute1595771249699'; } @@ -27,4 +27,3 @@ class wordMute1595771249699 { await queryRunner.query(`DROP TABLE "muted_note"`); } } -exports.wordMute1595771249699 = wordMute1595771249699; diff --git a/packages/backend/migration/1595782306083-word-mute2.js b/packages/backend/migration/1595782306083-word-mute2.js index 29c707e95..ab1e40a04 100644 --- a/packages/backend/migration/1595782306083-word-mute2.js +++ b/packages/backend/migration/1595782306083-word-mute2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class wordMute21595782306083 { + + +export class wordMute21595782306083 { constructor() { this.name = 'wordMute21595782306083'; } @@ -15,4 +15,3 @@ class wordMute21595782306083 { await queryRunner.query(`DROP TYPE "muted_note_reason_enum"`); } } -exports.wordMute21595782306083 = wordMute21595782306083; diff --git a/packages/backend/migration/1596548170836-channel.js b/packages/backend/migration/1596548170836-channel.js index bce812d5e..242db7d45 100644 --- a/packages/backend/migration/1596548170836-channel.js +++ b/packages/backend/migration/1596548170836-channel.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class channel1596548170836 { + + +export class channel1596548170836 { constructor() { this.name = 'channel1596548170836'; } @@ -55,4 +55,3 @@ class channel1596548170836 { await queryRunner.query(`DROP TABLE "channel"`); } } -exports.channel1596548170836 = channel1596548170836; diff --git a/packages/backend/migration/1596786425167-channel2.js b/packages/backend/migration/1596786425167-channel2.js index 160c73b06..4b17048fe 100644 --- a/packages/backend/migration/1596786425167-channel2.js +++ b/packages/backend/migration/1596786425167-channel2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class channel21596786425167 { + + +export class channel21596786425167 { constructor() { this.name = 'channel21596786425167'; } @@ -11,4 +11,3 @@ class channel21596786425167 { await queryRunner.query(`ALTER TABLE "channel_following" DROP COLUMN "readCursor"`); } } -exports.channel21596786425167 = channel21596786425167; diff --git a/packages/backend/migration/1597230137744-objectStorageSetPublicRead.js b/packages/backend/migration/1597230137744-objectStorageSetPublicRead.js index d208c425e..07283e31d 100644 --- a/packages/backend/migration/1597230137744-objectStorageSetPublicRead.js +++ b/packages/backend/migration/1597230137744-objectStorageSetPublicRead.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class objectStorageSetPublicRead1597230137744 { + + +export class objectStorageSetPublicRead1597230137744 { constructor() { this.name = 'objectStorageSetPublicRead1597230137744'; } @@ -11,4 +11,3 @@ class objectStorageSetPublicRead1597230137744 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageSetPublicRead"`); } } -exports.objectStorageSetPublicRead1597230137744 = objectStorageSetPublicRead1597230137744; diff --git a/packages/backend/migration/1597236229720-IncludingNotificationTypes.js b/packages/backend/migration/1597236229720-IncludingNotificationTypes.js index 0efbf2fe5..f498fa7d9 100644 --- a/packages/backend/migration/1597236229720-IncludingNotificationTypes.js +++ b/packages/backend/migration/1597236229720-IncludingNotificationTypes.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class IncludingNotificationTypes1597236229720 { + + +export class IncludingNotificationTypes1597236229720 { constructor() { this.name = 'IncludingNotificationTypes1597236229720'; } @@ -13,4 +13,3 @@ class IncludingNotificationTypes1597236229720 { await queryRunner.query(`DROP TYPE "user_profile_includingnotificationtypes_enum"`); } } -exports.IncludingNotificationTypes1597236229720 = IncludingNotificationTypes1597236229720; diff --git a/packages/backend/migration/1597385880794-add-sensitive-index.js b/packages/backend/migration/1597385880794-add-sensitive-index.js index 69fd394b0..8c5c040ba 100644 --- a/packages/backend/migration/1597385880794-add-sensitive-index.js +++ b/packages/backend/migration/1597385880794-add-sensitive-index.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class addSensitiveIndex1597385880794 { + + +export class addSensitiveIndex1597385880794 { constructor() { this.name = 'addSensitiveIndex1597385880794'; } @@ -11,4 +11,3 @@ class addSensitiveIndex1597385880794 { await queryRunner.query(`DROP INDEX "IDX_a7eba67f8b3fa27271e85d2e26"`); } } -exports.addSensitiveIndex1597385880794 = addSensitiveIndex1597385880794; diff --git a/packages/backend/migration/1597459042300-channel-unread.js b/packages/backend/migration/1597459042300-channel-unread.js index 629aa6009..3157ab779 100644 --- a/packages/backend/migration/1597459042300-channel-unread.js +++ b/packages/backend/migration/1597459042300-channel-unread.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class channelUnread1597459042300 { + + +export class channelUnread1597459042300 { constructor() { this.name = 'channelUnread1597459042300'; } @@ -24,4 +24,3 @@ class channelUnread1597459042300 { await queryRunner.query(`ALTER TABLE "channel_following" ADD "readCursor" TIMESTAMP WITH TIME ZONE NOT NULL`); } } -exports.channelUnread1597459042300 = channelUnread1597459042300; diff --git a/packages/backend/migration/1597893996136-ChannelNoteIdDescIndex.js b/packages/backend/migration/1597893996136-ChannelNoteIdDescIndex.js index 770ac1887..2bd8aee35 100644 --- a/packages/backend/migration/1597893996136-ChannelNoteIdDescIndex.js +++ b/packages/backend/migration/1597893996136-ChannelNoteIdDescIndex.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class ChannelNoteIdDescIndex1597893996136 { + + +export class ChannelNoteIdDescIndex1597893996136 { constructor() { this.name = 'ChannelNoteIdDescIndex1597893996136'; } @@ -13,4 +13,3 @@ class ChannelNoteIdDescIndex1597893996136 { await queryRunner.query(`CREATE INDEX "IDX_f22169eb10657bded6d875ac8f" ON "note" ("channelId") `); } } -exports.ChannelNoteIdDescIndex1597893996136 = ChannelNoteIdDescIndex1597893996136; diff --git a/packages/backend/migration/1600353287890-mutingNotificationTypes.js b/packages/backend/migration/1600353287890-mutingNotificationTypes.js index d39a6f2e4..ed3eb7d14 100644 --- a/packages/backend/migration/1600353287890-mutingNotificationTypes.js +++ b/packages/backend/migration/1600353287890-mutingNotificationTypes.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class mutingNotificationTypes1600353287890 { + + +export class mutingNotificationTypes1600353287890 { constructor() { this.name = 'mutingNotificationTypes1600353287890'; } @@ -17,4 +17,3 @@ class mutingNotificationTypes1600353287890 { await queryRunner.query(`ALTER TABLE "user_profile" ADD "includingNotificationTypes" "user_profile_includingnotificationtypes_enum" array`); } } -exports.mutingNotificationTypes1600353287890 = mutingNotificationTypes1600353287890; diff --git a/packages/backend/migration/1603094348345-refine-abuse-user-report.js b/packages/backend/migration/1603094348345-refine-abuse-user-report.js index b01a5d80a..4918032a2 100644 --- a/packages/backend/migration/1603094348345-refine-abuse-user-report.js +++ b/packages/backend/migration/1603094348345-refine-abuse-user-report.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class refineAbuseUserReport1603094348345 { + + +export class refineAbuseUserReport1603094348345 { constructor() { this.name = 'refineAbuseUserReport1603094348345'; } @@ -29,4 +29,3 @@ class refineAbuseUserReport1603094348345 { await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_d049123c413e68ca52abe734203" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); } } -exports.refineAbuseUserReport1603094348345 = refineAbuseUserReport1603094348345; diff --git a/packages/backend/migration/1603095701770-refine-abuse-user-report2.js b/packages/backend/migration/1603095701770-refine-abuse-user-report2.js index 32b4e0bd2..64e92672f 100644 --- a/packages/backend/migration/1603095701770-refine-abuse-user-report2.js +++ b/packages/backend/migration/1603095701770-refine-abuse-user-report2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class refineAbuseUserReport21603095701770 { + + +export class refineAbuseUserReport21603095701770 { constructor() { this.name = 'refineAbuseUserReport21603095701770'; } @@ -17,4 +17,3 @@ class refineAbuseUserReport21603095701770 { await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "targetUserHost"`); } } -exports.refineAbuseUserReport21603095701770 = refineAbuseUserReport21603095701770; diff --git a/packages/backend/migration/1603776877564-instance-theme-color.js b/packages/backend/migration/1603776877564-instance-theme-color.js index 315305f53..92440d3f6 100644 --- a/packages/backend/migration/1603776877564-instance-theme-color.js +++ b/packages/backend/migration/1603776877564-instance-theme-color.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class instanceThemeColor1603776877564 { + + +export class instanceThemeColor1603776877564 { constructor() { this.name = 'instanceThemeColor1603776877564'; } @@ -11,4 +11,3 @@ class instanceThemeColor1603776877564 { await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "themeColor"`); } } -exports.instanceThemeColor1603776877564 = instanceThemeColor1603776877564; diff --git a/packages/backend/migration/1603781553011-instance-favicon.js b/packages/backend/migration/1603781553011-instance-favicon.js index 451989f91..f607c49ff 100644 --- a/packages/backend/migration/1603781553011-instance-favicon.js +++ b/packages/backend/migration/1603781553011-instance-favicon.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class instanceFavicon1603781553011 { + + +export class instanceFavicon1603781553011 { constructor() { this.name = 'instanceFavicon1603781553011'; } @@ -11,4 +11,3 @@ class instanceFavicon1603781553011 { await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "faviconUrl"`); } } -exports.instanceFavicon1603781553011 = instanceFavicon1603781553011; diff --git a/packages/backend/migration/1604821689616-delete-auto-watch.js b/packages/backend/migration/1604821689616-delete-auto-watch.js index 9d972dd3f..4706e8bae 100644 --- a/packages/backend/migration/1604821689616-delete-auto-watch.js +++ b/packages/backend/migration/1604821689616-delete-auto-watch.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class deleteAutoWatch1604821689616 { + + +export class deleteAutoWatch1604821689616 { constructor() { this.name = 'deleteAutoWatch1604821689616'; } @@ -11,4 +11,3 @@ class deleteAutoWatch1604821689616 { await queryRunner.query(`ALTER TABLE "user_profile" ADD "autoWatch" boolean NOT NULL DEFAULT false`); } } -exports.deleteAutoWatch1604821689616 = deleteAutoWatch1604821689616; diff --git a/packages/backend/migration/1605408848373-clip-description.js b/packages/backend/migration/1605408848373-clip-description.js index acbe2b0c8..edd5505b3 100644 --- a/packages/backend/migration/1605408848373-clip-description.js +++ b/packages/backend/migration/1605408848373-clip-description.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class clipDescription1605408848373 { + + +export class clipDescription1605408848373 { constructor() { this.name = 'clipDescription1605408848373'; } @@ -11,4 +11,3 @@ class clipDescription1605408848373 { await queryRunner.query(`ALTER TABLE "clip" DROP COLUMN "description"`); } } -exports.clipDescription1605408848373 = clipDescription1605408848373; diff --git a/packages/backend/migration/1605408971051-comments.js b/packages/backend/migration/1605408971051-comments.js index 6e5dacbb6..400efd5e7 100644 --- a/packages/backend/migration/1605408971051-comments.js +++ b/packages/backend/migration/1605408971051-comments.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class comments1605408971051 { + + +export class comments1605408971051 { constructor() { this.name = 'comments1605408971051'; } @@ -431,4 +431,3 @@ class comments1605408971051 { await queryRunner.query(`COMMENT ON COLUMN "log"."createdAt" IS NULL`); } } -exports.comments1605408971051 = comments1605408971051; diff --git a/packages/backend/migration/1605585339718-instance-pinned-pages.js b/packages/backend/migration/1605585339718-instance-pinned-pages.js index 8d2357276..56ccd44c8 100644 --- a/packages/backend/migration/1605585339718-instance-pinned-pages.js +++ b/packages/backend/migration/1605585339718-instance-pinned-pages.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class instancePinnedPages1605585339718 { + + +export class instancePinnedPages1605585339718 { constructor() { this.name = 'instancePinnedPages1605585339718'; } @@ -11,4 +11,3 @@ class instancePinnedPages1605585339718 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "pinnedPages"`); } } -exports.instancePinnedPages1605585339718 = instancePinnedPages1605585339718; diff --git a/packages/backend/migration/1605965516823-instance-images.js b/packages/backend/migration/1605965516823-instance-images.js index f078428ba..710c75981 100644 --- a/packages/backend/migration/1605965516823-instance-images.js +++ b/packages/backend/migration/1605965516823-instance-images.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class instanceImages1605965516823 { + + +export class instanceImages1605965516823 { constructor() { this.name = 'instanceImages1605965516823'; } @@ -13,4 +13,3 @@ class instanceImages1605965516823 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "backgroundImageUrl"`); } } -exports.instanceImages1605965516823 = instanceImages1605965516823; diff --git a/packages/backend/migration/1606191203881-no-crawle.js b/packages/backend/migration/1606191203881-no-crawle.js index 2c5fdaed2..b9ada4354 100644 --- a/packages/backend/migration/1606191203881-no-crawle.js +++ b/packages/backend/migration/1606191203881-no-crawle.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class noCrawle1606191203881 { + + +export class noCrawle1606191203881 { constructor() { this.name = 'noCrawle1606191203881'; } @@ -13,4 +13,3 @@ class noCrawle1606191203881 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "noCrawle"`); } } -exports.noCrawle1606191203881 = noCrawle1606191203881; diff --git a/packages/backend/migration/1607151207216-instance-pinned-clip.js b/packages/backend/migration/1607151207216-instance-pinned-clip.js index 3bd479296..9a4195e74 100644 --- a/packages/backend/migration/1607151207216-instance-pinned-clip.js +++ b/packages/backend/migration/1607151207216-instance-pinned-clip.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class instancePinnedClip1607151207216 { + + +export class instancePinnedClip1607151207216 { constructor() { this.name = 'instancePinnedClip1607151207216'; } @@ -11,4 +11,3 @@ class instancePinnedClip1607151207216 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "pinnedClipId"`); } } -exports.instancePinnedClip1607151207216 = instancePinnedClip1607151207216; diff --git a/packages/backend/migration/1607353487793-isExplorable.js b/packages/backend/migration/1607353487793-isExplorable.js index 3ddd0cb32..d9f1ff4c6 100644 --- a/packages/backend/migration/1607353487793-isExplorable.js +++ b/packages/backend/migration/1607353487793-isExplorable.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class isExplorable1607353487793 { + + +export class isExplorable1607353487793 { constructor() { this.name = 'isExplorable1607353487793'; } @@ -15,4 +15,3 @@ class isExplorable1607353487793 { await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isExplorable"`); } } -exports.isExplorable1607353487793 = isExplorable1607353487793; diff --git a/packages/backend/migration/1610277136869-registry.js b/packages/backend/migration/1610277136869-registry.js index a7b5af84b..184c062dd 100644 --- a/packages/backend/migration/1610277136869-registry.js +++ b/packages/backend/migration/1610277136869-registry.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class registry1610277136869 { + + +export class registry1610277136869 { constructor() { this.name = 'registry1610277136869'; } @@ -19,4 +19,3 @@ class registry1610277136869 { await queryRunner.query(`DROP TABLE "registry_item"`); } } -exports.registry1610277136869 = registry1610277136869; diff --git a/packages/backend/migration/1610277585759-registry2.js b/packages/backend/migration/1610277585759-registry2.js index aa1417e18..591bafae3 100644 --- a/packages/backend/migration/1610277585759-registry2.js +++ b/packages/backend/migration/1610277585759-registry2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class registry21610277585759 { + + +export class registry21610277585759 { constructor() { this.name = 'registry21610277585759'; } @@ -13,4 +13,3 @@ class registry21610277585759 { await queryRunner.query(`ALTER TABLE "registry_item" DROP COLUMN "value"`); } } -exports.registry21610277585759 = registry21610277585759; diff --git a/packages/backend/migration/1610283021566-registry3.js b/packages/backend/migration/1610283021566-registry3.js index 7089cee1f..e0289f17e 100644 --- a/packages/backend/migration/1610283021566-registry3.js +++ b/packages/backend/migration/1610283021566-registry3.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class registry31610283021566 { + + +export class registry31610283021566 { constructor() { this.name = 'registry31610283021566'; } @@ -11,4 +11,3 @@ class registry31610283021566 { await queryRunner.query(`ALTER TABLE "registry_item" ALTER COLUMN "value" SET NOT NULL`); } } -exports.registry31610283021566 = registry31610283021566; diff --git a/packages/backend/migration/1611354329133-followersUri.js b/packages/backend/migration/1611354329133-followersUri.js index e944da73a..669ddb480 100644 --- a/packages/backend/migration/1611354329133-followersUri.js +++ b/packages/backend/migration/1611354329133-followersUri.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class followersUri1611354329133 { + + +export class followersUri1611354329133 { constructor() { this.name = 'followersUri1611354329133'; } @@ -13,4 +13,3 @@ class followersUri1611354329133 { await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "followersUri"`); } } -exports.followersUri1611354329133 = followersUri1611354329133; diff --git a/packages/backend/migration/1611397665007-gallery.js b/packages/backend/migration/1611397665007-gallery.js index 9cf73cbcf..f49b2df46 100644 --- a/packages/backend/migration/1611397665007-gallery.js +++ b/packages/backend/migration/1611397665007-gallery.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class gallery1611397665007 { + + +export class gallery1611397665007 { constructor() { this.name = 'gallery1611397665007'; } @@ -37,4 +37,3 @@ class gallery1611397665007 { await queryRunner.query(`DROP TABLE "gallery_post"`); } } -exports.gallery1611397665007 = gallery1611397665007; diff --git a/packages/backend/migration/1611547387175-objectStorageS3ForcePathStyle.js b/packages/backend/migration/1611547387175-objectStorageS3ForcePathStyle.js index 50a618994..e4d3c0e8e 100644 --- a/packages/backend/migration/1611547387175-objectStorageS3ForcePathStyle.js +++ b/packages/backend/migration/1611547387175-objectStorageS3ForcePathStyle.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class objectStorageS3ForcePathStyle1611547387175 { + + +export class objectStorageS3ForcePathStyle1611547387175 { constructor() { this.name = 'objectStorageS3ForcePathStyle1611547387175'; } @@ -11,4 +11,3 @@ class objectStorageS3ForcePathStyle1611547387175 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageS3ForcePathStyle"`); } } -exports.objectStorageS3ForcePathStyle1611547387175 = objectStorageS3ForcePathStyle1611547387175; diff --git a/packages/backend/migration/1612619156584-announcement-email.js b/packages/backend/migration/1612619156584-announcement-email.js index bbd04679b..bcc718d1c 100644 --- a/packages/backend/migration/1612619156584-announcement-email.js +++ b/packages/backend/migration/1612619156584-announcement-email.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class announcementEmail1612619156584 { + + +export class announcementEmail1612619156584 { constructor() { this.name = 'announcementEmail1612619156584'; } @@ -11,4 +11,3 @@ class announcementEmail1612619156584 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "receiveAnnouncementEmail"`); } } -exports.announcementEmail1612619156584 = announcementEmail1612619156584; diff --git a/packages/backend/migration/1613155914446-emailNotificationTypes.js b/packages/backend/migration/1613155914446-emailNotificationTypes.js index 30fa4924b..cd49924d2 100644 --- a/packages/backend/migration/1613155914446-emailNotificationTypes.js +++ b/packages/backend/migration/1613155914446-emailNotificationTypes.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class emailNotificationTypes1613155914446 { + + +export class emailNotificationTypes1613155914446 { constructor() { this.name = 'emailNotificationTypes1613155914446'; } @@ -11,4 +11,3 @@ class emailNotificationTypes1613155914446 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "emailNotificationTypes"`); } } -exports.emailNotificationTypes1613155914446 = emailNotificationTypes1613155914446; diff --git a/packages/backend/migration/1613181457597-user-lang.js b/packages/backend/migration/1613181457597-user-lang.js index f6be7cdab..d2cd06848 100644 --- a/packages/backend/migration/1613181457597-user-lang.js +++ b/packages/backend/migration/1613181457597-user-lang.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userLang1613181457597 { + + +export class userLang1613181457597 { constructor() { this.name = 'userLang1613181457597'; } @@ -11,4 +11,3 @@ class userLang1613181457597 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "lang"`); } } -exports.userLang1613181457597 = userLang1613181457597; diff --git a/packages/backend/migration/1613503367223-use-bigint-for-driveUsage.js b/packages/backend/migration/1613503367223-use-bigint-for-driveUsage.js index 91956ad78..f2e2c5d35 100644 --- a/packages/backend/migration/1613503367223-use-bigint-for-driveUsage.js +++ b/packages/backend/migration/1613503367223-use-bigint-for-driveUsage.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class useBigintForDriveUsage1613503367223 { + + +export class useBigintForDriveUsage1613503367223 { constructor() { this.name = 'useBigintForDriveUsage1613503367223'; } @@ -12,4 +12,3 @@ class useBigintForDriveUsage1613503367223 { await queryRunner.query(`ALTER TABLE "instance" ADD "driveUsage" integer NOT NULL DEFAULT 0`); } } -exports.useBigintForDriveUsage1613503367223 = useBigintForDriveUsage1613503367223; diff --git a/packages/backend/migration/1615965918224-chart-v2.js b/packages/backend/migration/1615965918224-chart-v2.js index 95f44879b..86fa5b0c0 100644 --- a/packages/backend/migration/1615965918224-chart-v2.js +++ b/packages/backend/migration/1615965918224-chart-v2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class chartV21615965918224 { + + +export class chartV21615965918224 { constructor() { this.name = 'chartV21615965918224'; } @@ -214,4 +214,3 @@ class chartV21615965918224 { await queryRunner.query(`CREATE INDEX "IDX_15e91a03aeeac9dbccdf43fc06" ON "__chart__active_users" ("span") `); } } -exports.chartV21615965918224 = chartV21615965918224; diff --git a/packages/backend/migration/1615966519402-chart-v2-2.js b/packages/backend/migration/1615966519402-chart-v2-2.js index 85a83df1a..c62f1b875 100644 --- a/packages/backend/migration/1615966519402-chart-v2-2.js +++ b/packages/backend/migration/1615966519402-chart-v2-2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class chartV221615966519402 { + + +export class chartV221615966519402 { constructor() { this.name = 'chartV221615966519402'; } @@ -19,4 +19,3 @@ class chartV221615966519402 { await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___local_users"`); } } -exports.chartV221615966519402 = chartV221615966519402; diff --git a/packages/backend/migration/1618637372000-user-last-active-date.js b/packages/backend/migration/1618637372000-user-last-active-date.js index 03fc011e4..6c77ace46 100644 --- a/packages/backend/migration/1618637372000-user-last-active-date.js +++ b/packages/backend/migration/1618637372000-user-last-active-date.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userLastActiveDate1618637372000 { + + +export class userLastActiveDate1618637372000 { constructor() { this.name = 'userLastActiveDate1618637372000'; } @@ -13,4 +13,3 @@ class userLastActiveDate1618637372000 { await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "lastActiveDate"`); } } -exports.userLastActiveDate1618637372000 = userLastActiveDate1618637372000; diff --git a/packages/backend/migration/1618639857000-user-hide-online-status.js b/packages/backend/migration/1618639857000-user-hide-online-status.js index 0b1e34100..e63c8ae11 100644 --- a/packages/backend/migration/1618639857000-user-hide-online-status.js +++ b/packages/backend/migration/1618639857000-user-hide-online-status.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userHideOnlineStatus1618639857000 { + + +export class userHideOnlineStatus1618639857000 { constructor() { this.name = 'userHideOnlineStatus1618639857000'; } @@ -11,4 +11,3 @@ class userHideOnlineStatus1618639857000 { await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "hideOnlineStatus"`); } } -exports.userHideOnlineStatus1618639857000 = userHideOnlineStatus1618639857000; diff --git a/packages/backend/migration/1619942102890-password-reset.js b/packages/backend/migration/1619942102890-password-reset.js index 9505be4b8..922d225dc 100644 --- a/packages/backend/migration/1619942102890-password-reset.js +++ b/packages/backend/migration/1619942102890-password-reset.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class passwordReset1619942102890 { + + +export class passwordReset1619942102890 { constructor() { this.name = 'passwordReset1619942102890'; } @@ -17,4 +17,3 @@ class passwordReset1619942102890 { await queryRunner.query(`DROP TABLE "password_reset_request"`); } } -exports.passwordReset1619942102890 = passwordReset1619942102890; diff --git a/packages/backend/migration/1620019354680-ad.js b/packages/backend/migration/1620019354680-ad.js index 655629bc3..c96d2bfb3 100644 --- a/packages/backend/migration/1620019354680-ad.js +++ b/packages/backend/migration/1620019354680-ad.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class ad1620019354680 { + + +export class ad1620019354680 { constructor() { this.name = 'ad1620019354680'; } @@ -15,4 +15,3 @@ class ad1620019354680 { await queryRunner.query(`DROP TABLE "ad"`); } } -exports.ad1620019354680 = ad1620019354680; diff --git a/packages/backend/migration/1620364649428-ad2.js b/packages/backend/migration/1620364649428-ad2.js index 7f2213f6a..db1c3e1de 100644 --- a/packages/backend/migration/1620364649428-ad2.js +++ b/packages/backend/migration/1620364649428-ad2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class ad21620364649428 { + + +export class ad21620364649428 { constructor() { this.name = 'ad21620364649428'; } @@ -11,4 +11,3 @@ class ad21620364649428 { await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "ratio"`); } } -exports.ad21620364649428 = ad21620364649428; diff --git a/packages/backend/migration/1621479946000-add-note-indexes.js b/packages/backend/migration/1621479946000-add-note-indexes.js index 1bf9827f6..dcf97fa4d 100644 --- a/packages/backend/migration/1621479946000-add-note-indexes.js +++ b/packages/backend/migration/1621479946000-add-note-indexes.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class addNoteIndexes1621479946000 { + + +export class addNoteIndexes1621479946000 { constructor() { this.name = 'addNoteIndexes1621479946000'; } @@ -13,4 +13,3 @@ class addNoteIndexes1621479946000 { await queryRunner.query(`DROP INDEX "IDX_NOTE_VISIBLE_USER_IDS"`, undefined); } } -exports.addNoteIndexes1621479946000 = addNoteIndexes1621479946000; diff --git a/packages/backend/migration/1622679304522-user-profile-description-length.js b/packages/backend/migration/1622679304522-user-profile-description-length.js index 237870d6c..22f6c1c5d 100644 --- a/packages/backend/migration/1622679304522-user-profile-description-length.js +++ b/packages/backend/migration/1622679304522-user-profile-description-length.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userProfileDescriptionLength1622679304522 { + + +export class userProfileDescriptionLength1622679304522 { constructor() { this.name = 'userProfileDescriptionLength1622679304522'; } @@ -11,4 +11,3 @@ class userProfileDescriptionLength1622679304522 { await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "description" TYPE character varying(1024)`, undefined); } } -exports.userProfileDescriptionLength1622679304522 = userProfileDescriptionLength1622679304522; diff --git a/packages/backend/migration/1622681548499-log-message-length.js b/packages/backend/migration/1622681548499-log-message-length.js index cb2ad288b..ac16c0e1b 100644 --- a/packages/backend/migration/1622681548499-log-message-length.js +++ b/packages/backend/migration/1622681548499-log-message-length.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class logMessageLength1622681548499 { + + +export class logMessageLength1622681548499 { constructor() { this.name = 'logMessageLength1622681548499'; } @@ -11,4 +11,3 @@ class logMessageLength1622681548499 { await queryRunner.query(`ALTER TABLE "log" ALTER COLUMN "message" TYPE character varying(1024)`, undefined); } } -exports.logMessageLength1622681548499 = logMessageLength1622681548499; diff --git a/packages/backend/migration/1626509500668-fix-remote-file-proxy.js b/packages/backend/migration/1626509500668-fix-remote-file-proxy.js new file mode 100644 index 000000000..30c562007 --- /dev/null +++ b/packages/backend/migration/1626509500668-fix-remote-file-proxy.js @@ -0,0 +1,22 @@ + + +export class fixRemoteFileProxy1626509500668 { + constructor() { + this.name = 'fixRemoteFileProxy1626509500668'; + } + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarUrl"`); + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerUrl"`); + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarBlurhash"`); + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerBlurhash"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyRemoteFiles"`); + } + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "proxyRemoteFiles" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "user" ADD "bannerBlurhash" character varying(128)`); + await queryRunner.query(`ALTER TABLE "user" ADD "avatarBlurhash" character varying(128)`); + await queryRunner.query(`ALTER TABLE "user" ADD "bannerUrl" character varying(512)`); + await queryRunner.query(`ALTER TABLE "user" ADD "avatarUrl" character varying(512)`); + } +} + diff --git a/packages/backend/migration/1629004542760-chart-reindex.js b/packages/backend/migration/1629004542760-chart-reindex.js index 927ea312e..a7d459276 100644 --- a/packages/backend/migration/1629004542760-chart-reindex.js +++ b/packages/backend/migration/1629004542760-chart-reindex.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class chartReindex1629004542760 { + + +export class chartReindex1629004542760 { constructor() { this.name = 'chartReindex1629004542760'; } @@ -179,4 +179,3 @@ class chartReindex1629004542760 { await queryRunner.query(`CREATE INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc" ON "__chart__active_users" ("date") `); } } -exports.chartReindex1629004542760 = chartReindex1629004542760; diff --git a/packages/backend/migration/1629024377804-deepl-integration.js b/packages/backend/migration/1629024377804-deepl-integration.js index a2bd3b188..19c49ffcd 100644 --- a/packages/backend/migration/1629024377804-deepl-integration.js +++ b/packages/backend/migration/1629024377804-deepl-integration.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class deeplIntegration1629024377804 { + + +export class deeplIntegration1629024377804 { constructor() { this.name = 'deeplIntegration1629024377804'; } @@ -11,4 +11,3 @@ class deeplIntegration1629024377804 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "deeplAuthKey"`); } } -exports.deeplIntegration1629024377804 = deeplIntegration1629024377804; diff --git a/packages/backend/migration/1629288472000-fix-channel-userId.js b/packages/backend/migration/1629288472000-fix-channel-userId.js index d0e8baa06..02a1199b0 100644 --- a/packages/backend/migration/1629288472000-fix-channel-userId.js +++ b/packages/backend/migration/1629288472000-fix-channel-userId.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class fixChannelUserId1629288472000 { + + +export class fixChannelUserId1629288472000 { constructor() { this.name = 'fixChannelUserId1629288472000'; } @@ -11,4 +11,3 @@ class fixChannelUserId1629288472000 { await queryRunner.query(`ALTER TABLE "channel" ALTER COLUMN "userId" SET NOT NULL;`); } } -exports.fixChannelUserId1629288472000 = fixChannelUserId1629288472000; diff --git a/packages/backend/migration/1629512953000-user-is-deleted.js b/packages/backend/migration/1629512953000-user-is-deleted.js index 008390719..a7848d569 100644 --- a/packages/backend/migration/1629512953000-user-is-deleted.js +++ b/packages/backend/migration/1629512953000-user-is-deleted.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class isUserDeleted1629512953000 { + + +export class isUserDeleted1629512953000 { constructor() { this.name = 'isUserDeleted1629512953000'; } @@ -12,4 +12,3 @@ class isUserDeleted1629512953000 { await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isDeleted"`); } } -exports.isUserDeleted1629512953000 = isUserDeleted1629512953000; diff --git a/packages/backend/migration/1629778475000-deepl-integration2.js b/packages/backend/migration/1629778475000-deepl-integration2.js index 50365f4bb..699f06c76 100644 --- a/packages/backend/migration/1629778475000-deepl-integration2.js +++ b/packages/backend/migration/1629778475000-deepl-integration2.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class deeplIntegration21629778475000 { + + +export class deeplIntegration21629778475000 { constructor() { this.name = 'deeplIntegration21629778475000'; } @@ -11,4 +11,3 @@ class deeplIntegration21629778475000 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "deeplIsPro"`); } } -exports.deeplIntegration21629778475000 = deeplIntegration21629778475000; diff --git a/packages/backend/migration/1629833361000-AddShowTLReplies.js b/packages/backend/migration/1629833361000-AddShowTLReplies.js new file mode 100644 index 000000000..5d4c938a7 --- /dev/null +++ b/packages/backend/migration/1629833361000-AddShowTLReplies.js @@ -0,0 +1,14 @@ + + +export class addShowTLReplies1629833361000 { + constructor() { + this.name = 'addShowTLReplies1629833361000'; + } + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "showTimelineReplies" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`COMMENT ON COLUMN "user"."showTimelineReplies" IS 'Whether to show users replying to other users in the timeline.'`); + } + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "showTimelineReplies"`); + } +} diff --git a/packages/backend/migration/1629968054000_userInstanceBlocks.js b/packages/backend/migration/1629968054000_userInstanceBlocks.js index 5703ff0b0..1f202d9f6 100644 --- a/packages/backend/migration/1629968054000_userInstanceBlocks.js +++ b/packages/backend/migration/1629968054000_userInstanceBlocks.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userInstanceBlocks1629968054000 { + + +export class userInstanceBlocks1629968054000 { constructor() { this.name = 'userInstanceBlocks1629968054000'; } @@ -12,4 +12,3 @@ class userInstanceBlocks1629968054000 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "mutedInstances"`); } } -exports.userInstanceBlocks1629968054000 = userInstanceBlocks1629968054000; diff --git a/packages/backend/migration/1633068642000-email-required-for-signup.js b/packages/backend/migration/1633068642000-email-required-for-signup.js index 9793cac00..d592f3ca2 100644 --- a/packages/backend/migration/1633068642000-email-required-for-signup.js +++ b/packages/backend/migration/1633068642000-email-required-for-signup.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class emailRequiredForSignup1633068642000 { + + +export class emailRequiredForSignup1633068642000 { constructor() { this.name = 'emailRequiredForSignup1633068642000'; } @@ -11,4 +11,3 @@ class emailRequiredForSignup1633068642000 { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "emailRequiredForSignup"`); } } -exports.emailRequiredForSignup1633068642000 = emailRequiredForSignup1633068642000; diff --git a/packages/backend/migration/1633071909016-user-pending.js b/packages/backend/migration/1633071909016-user-pending.js index 92a513994..17cf5c11b 100644 --- a/packages/backend/migration/1633071909016-user-pending.js +++ b/packages/backend/migration/1633071909016-user-pending.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userPending1633071909016 { + + +export class userPending1633071909016 { constructor() { this.name = 'userPending1633071909016'; } @@ -13,4 +13,3 @@ class userPending1633071909016 { await queryRunner.query(`DROP TABLE "user_pending"`); } } -exports.userPending1633071909016 = userPending1633071909016; diff --git a/packages/backend/migration/1634486652000-user-public-reactions.js b/packages/backend/migration/1634486652000-user-public-reactions.js index 1447abe6a..e74112249 100644 --- a/packages/backend/migration/1634486652000-user-public-reactions.js +++ b/packages/backend/migration/1634486652000-user-public-reactions.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class userPublicReactions1634486652000 { + + +export class userPublicReactions1634486652000 { constructor() { this.name = 'userPublicReactions1634486652000'; } @@ -11,4 +11,3 @@ class userPublicReactions1634486652000 { await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "publicReactions"`); } } -exports.userPublicReactions1634486652000 = userPublicReactions1634486652000; diff --git a/packages/backend/migration/1634902659689-delete-log.js b/packages/backend/migration/1634902659689-delete-log.js index b2162519f..555a0020c 100644 --- a/packages/backend/migration/1634902659689-delete-log.js +++ b/packages/backend/migration/1634902659689-delete-log.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class deleteLog1634902659689 { + + +export class deleteLog1634902659689 { constructor() { this.name = 'deleteLog1634902659689'; } @@ -10,4 +10,3 @@ class deleteLog1634902659689 { async down(queryRunner) { } } -exports.deleteLog1634902659689 = deleteLog1634902659689; diff --git a/packages/backend/migration/1635500777168-note-thread-mute.js b/packages/backend/migration/1635500777168-note-thread-mute.js index 1e0195274..a790cace3 100644 --- a/packages/backend/migration/1635500777168-note-thread-mute.js +++ b/packages/backend/migration/1635500777168-note-thread-mute.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class noteThreadMute1635500777168 { + + +export class noteThreadMute1635500777168 { constructor() { this.name = 'noteThreadMute1635500777168'; } @@ -23,4 +23,3 @@ class noteThreadMute1635500777168 { await queryRunner.query(`DROP TABLE "note_thread_muting"`); } } -exports.noteThreadMute1635500777168 = noteThreadMute1635500777168; diff --git a/packages/backend/migration/1636197624383-ff-visibility.js b/packages/backend/migration/1636197624383-ff-visibility.js index 9e8d5a3dc..89028f3c2 100644 --- a/packages/backend/migration/1636197624383-ff-visibility.js +++ b/packages/backend/migration/1636197624383-ff-visibility.js @@ -1,6 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class ffVisibility1636197624383 { + + +export class ffVisibility1636197624383 { constructor() { this.name = 'ffVisibility1636197624383'; } @@ -13,4 +13,3 @@ class ffVisibility1636197624383 { await queryRunner.query(`DROP TYPE "public"."user_profile_ffvisibility_enum"`); } } -exports.ffVisibility1636197624383 = ffVisibility1636197624383; diff --git a/packages/backend/migration/1636697408073-remove-via-mobile.js b/packages/backend/migration/1636697408073-remove-via-mobile.js index bb5157cf1..36e96fd21 100644 --- a/packages/backend/migration/1636697408073-remove-via-mobile.js +++ b/packages/backend/migration/1636697408073-remove-via-mobile.js @@ -1,6 +1,6 @@ -const { MigrationInterface, QueryRunner } = require("typeorm"); -module.exports = class removeViaMobile1636697408073 { + +export class removeViaMobile1636697408073 { name = 'removeViaMobile1636697408073' async up(queryRunner) { diff --git a/packages/backend/migration/1637320813000-forwarded-report.js b/packages/backend/migration/1637320813000-forwarded-report.js index 4056f7b5f..1e39bd5c3 100644 --- a/packages/backend/migration/1637320813000-forwarded-report.js +++ b/packages/backend/migration/1637320813000-forwarded-report.js @@ -1,6 +1,6 @@ -const { QueryRunner } = require('typeorm'); -module.exports = class forwardedReport1637320813000 { + +export class forwardedReport1637320813000 { name = 'forwardedReport1637320813000'; async up(queryRunner) { diff --git a/packages/backend/migration/1639325650583-chart-v3.js b/packages/backend/migration/1639325650583-chart-v3.js index b9d8814c6..e2a4e920c 100644 --- a/packages/backend/migration/1639325650583-chart-v3.js +++ b/packages/backend/migration/1639325650583-chart-v3.js @@ -1,6 +1,6 @@ -const { MigrationInterface, QueryRunner } = require("typeorm"); -module.exports = class chartV31639325650583 { + +export class chartV31639325650583 { name = 'chartV31639325650583' async up(queryRunner) { diff --git a/packages/backend/migration/1642611822809-emoji-url.js b/packages/backend/migration/1642611822809-emoji-url.js index f229c403f..d38f8cc08 100644 --- a/packages/backend/migration/1642611822809-emoji-url.js +++ b/packages/backend/migration/1642611822809-emoji-url.js @@ -1,6 +1,6 @@ -const { MigrationInterface, QueryRunner } = require("typeorm"); -module.exports = class emojiUrl1642611822809 { + +export class emojiUrl1642611822809 { name = 'emojiUrl1642611822809' async up(queryRunner) { diff --git a/packages/backend/migration/1642613870898-drive-file-webpublic-type.js b/packages/backend/migration/1642613870898-drive-file-webpublic-type.js index e10c2ac2d..15434f7d0 100644 --- a/packages/backend/migration/1642613870898-drive-file-webpublic-type.js +++ b/packages/backend/migration/1642613870898-drive-file-webpublic-type.js @@ -1,6 +1,6 @@ -const { MigrationInterface, QueryRunner } = require("typeorm"); -module.exports = class driveFileWebpublicType1642613870898 { + +export class driveFileWebpublicType1642613870898 { name = 'driveFileWebpublicType1642613870898' async up(queryRunner) { diff --git a/packages/backend/migration/1643963705770-chart-v4.js b/packages/backend/migration/1643963705770-chart-v4.js new file mode 100644 index 000000000..8b320c2b4 --- /dev/null +++ b/packages/backend/migration/1643963705770-chart-v4.js @@ -0,0 +1,63 @@ + + +export class chartV41643963705770 { + name = 'chartV41643963705770' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__instance" DROP COLUMN "___drive_totalUsage"`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" DROP COLUMN "___drive_totalUsage"`); + await queryRunner.query(`ALTER TABLE "__chart__drive" DROP COLUMN "___local_totalCount"`); + await queryRunner.query(`ALTER TABLE "__chart__drive" DROP COLUMN "___local_totalSize"`); + await queryRunner.query(`ALTER TABLE "__chart__drive" DROP COLUMN "___remote_totalCount"`); + await queryRunner.query(`ALTER TABLE "__chart__drive" DROP COLUMN "___remote_totalSize"`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" DROP COLUMN "___local_totalCount"`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" DROP COLUMN "___local_totalSize"`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" DROP COLUMN "___remote_totalCount"`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" DROP COLUMN "___remote_totalSize"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___local_users" bigint NOT NULL DEFAULT 0`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___remote_users" bigint NOT NULL DEFAULT 0`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___local_users" bigint NOT NULL DEFAULT 0`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___remote_users" bigint NOT NULL DEFAULT 0`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "___local_users" bigint NOT NULL DEFAULT 0`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "___remote_users" bigint NOT NULL DEFAULT 0`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ADD "___local_users" bigint NOT NULL DEFAULT 0`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ADD "___remote_users" bigint NOT NULL DEFAULT 0`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ADD "___remote_users" character varying array NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ADD "___local_users" character varying array NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "___remote_users" character varying array NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "___local_users" character varying array NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___remote_users" character varying array NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___local_users" character varying array NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___remote_users" character varying array NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___local_users" character varying array NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ADD "___remote_totalSize" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ADD "___remote_totalCount" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ADD "___local_totalSize" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ADD "___local_totalCount" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ADD "___remote_totalSize" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ADD "___remote_totalCount" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ADD "___local_totalSize" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ADD "___local_totalCount" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ADD "___drive_totalUsage" bigint NOT NULL`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ADD "___drive_totalUsage" bigint NOT NULL`); + } +} diff --git a/packages/backend/migration/1643966656277-chart-v5.js b/packages/backend/migration/1643966656277-chart-v5.js new file mode 100644 index 000000000..df84002f7 --- /dev/null +++ b/packages/backend/migration/1643966656277-chart-v5.js @@ -0,0 +1,27 @@ + + +export class chartV51643966656277 { + name = 'chartV51643966656277' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___local_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___remote_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___local_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___remote_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "unique_temp___local_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "unique_temp___remote_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ADD "unique_temp___local_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ADD "unique_temp___remote_users" character varying array NOT NULL DEFAULT '{}'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" DROP COLUMN "unique_temp___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" DROP COLUMN "unique_temp___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "unique_temp___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "unique_temp___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___local_users"`); + } +} diff --git a/packages/backend/migration/1643967331284-chart-v6.js b/packages/backend/migration/1643967331284-chart-v6.js new file mode 100644 index 000000000..119198f4a --- /dev/null +++ b/packages/backend/migration/1643967331284-chart-v6.js @@ -0,0 +1,343 @@ + + +export class chartV61643967331284 { + name = 'chartV61643967331284' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_normal" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_reply" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_renote" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_normal" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_reply" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_renote" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_normal" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_reply" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_renote" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_normal" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_reply" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_renote" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___incomingRequests" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___outgoingRequests" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___totalTime" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___incomingBytes" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___outgoingBytes" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___incomingRequests" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___outgoingRequests" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___totalTime" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___incomingBytes" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___outgoingBytes" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_failed" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_succeeded" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_received" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_normal" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_reply" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_renote" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_totalFiles" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_incFiles" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_decFiles" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_incUsage" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_decUsage" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_failed" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_succeeded" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_received" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_normal" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_reply" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_renote" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_totalFiles" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_incFiles" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_decFiles" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_incUsage" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_decUsage" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_normal" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_reply" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_renote" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_normal" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_reply" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_renote" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_incCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_incSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_decCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_decSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_incCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_incSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_decCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_decSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_incCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_incSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_decCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_decSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_incCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_incSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_decCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_decSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ALTER COLUMN "___local_count" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ALTER COLUMN "___remote_count" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_reaction" ALTER COLUMN "___local_count" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_reaction" ALTER COLUMN "___remote_count" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_total" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_inc" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_dec" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___totalCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___totalSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___incCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___incSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___decCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___decSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___totalCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___totalSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___incCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___incSize" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___decCount" SET DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___decSize" SET DEFAULT '0'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___decSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___decCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___incSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___incCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___totalSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___totalCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___decSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___decCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___incSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___incCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___totalSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___totalCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_reaction" ALTER COLUMN "___remote_count" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_reaction" ALTER COLUMN "___local_count" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ALTER COLUMN "___remote_count" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ALTER COLUMN "___local_count" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_decSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_decCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_incSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_incCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_decSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_decCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_incSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_incCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_decSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_decCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_incSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_incCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_decSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_decCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_incSize" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_incCount" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_renote" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_reply" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_normal" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_renote" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_reply" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_normal" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_decUsage" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_incUsage" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_decFiles" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_incFiles" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_totalFiles" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_renote" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_reply" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_normal" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_received" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_succeeded" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_failed" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_decUsage" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_incUsage" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_decFiles" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_incFiles" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_totalFiles" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_renote" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_reply" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_normal" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_received" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_succeeded" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_failed" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___outgoingBytes" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___incomingBytes" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___totalTime" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___outgoingRequests" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___incomingRequests" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___outgoingBytes" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___incomingBytes" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___totalTime" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___outgoingRequests" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___incomingRequests" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_renote" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_reply" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_normal" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_renote" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_reply" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_normal" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_renote" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_reply" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_normal" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_renote" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_reply" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_normal" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_total" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_dec" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_inc" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_total" DROP DEFAULT`); + } +} diff --git a/packages/backend/migration/1644010796173-convert-hard-mutes.js b/packages/backend/migration/1644010796173-convert-hard-mutes.js new file mode 100644 index 000000000..207a759b8 --- /dev/null +++ b/packages/backend/migration/1644010796173-convert-hard-mutes.js @@ -0,0 +1,65 @@ +import RE2 from 're2'; + + +export class convertHardMutes1644010796173 { + name = 'convertHardMutes1644010796173' + + async up(queryRunner) { + let entries = await queryRunner.query(`SELECT "userId", "mutedWords" FROM "user_profile" WHERE "userHost" IS NULL`); + for(let i = 0; i < entries.length; i++) { + let words = entries[i].mutedWords + .map(line => { + if (typeof line === 'string') return []; + const regexp = line.join(" ").match(/^\/(.+)\/(.*)$/); + if (regexp) { + // convert regexp's + try { + new RE2(regexp[1], regexp[2]); + return `/${regexp[1]}/${regexp[2]}`; + } catch (err) { + // invalid regex, ignore it + return []; + } + } else { + // remove empty segments + return line.filter(x => x !== ''); + } + }) + // remove empty lines + .filter(x => !(Array.isArray(x) && x.length === 0)); + + await queryRunner.connection.createQueryBuilder() + .update('user_profile') + .set({ + mutedWords: words + }) + .where('userId = :id', { id: entries[i].userId }) + .execute(); + } + } + + async down(queryRunner) { + let entries = await queryRunner.query(`SELECT "userId", "mutedWords" FROM "user_profile"`); + for(let i = 0; i < entries.length; i++) { + let words = entries[i].mutedWords + .map(line => { + if (Array.isArray(line)) { + return line; + } else { + // do not split regex at spaces again + return [line]; + } + }) + // remove empty lines + .filter(x => !(Array.isArray(x) && x.length === 0)); + + await queryRunner.connection.createQueryBuilder() + .update('user_profile') + .set({ + mutedWords: words + }) + .where('userId = :id', { id: entries[i].userId }) + .execute(); + } + } +} diff --git a/packages/backend/migration/1644058404077-chart-v7.js b/packages/backend/migration/1644058404077-chart-v7.js new file mode 100644 index 000000000..f05ad003d --- /dev/null +++ b/packages/backend/migration/1644058404077-chart-v7.js @@ -0,0 +1,501 @@ + + +export class chartV71644058404077 { + name = 'chartV71644058404077' + + async up(queryRunner) { + await queryRunner.query(`UPDATE "__chart__federation" SET "___instance_total"=2147483647 WHERE "___instance_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__federation" SET "___instance_inc"=32767 WHERE "___instance_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__federation" SET "___instance_dec"=32767 WHERE "___instance_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__federation" SET "___instance_total"=2147483647 WHERE "___instance_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__federation" SET "___instance_inc"=32767 WHERE "___instance_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__federation" SET "___instance_dec"=32767 WHERE "___instance_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___local_total"=2147483647 WHERE "___local_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___local_inc"=2147483647 WHERE "___local_inc" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___local_dec"=2147483647 WHERE "___local_dec" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___local_diffs_normal"=2147483647 WHERE "___local_diffs_normal" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___local_diffs_reply"=2147483647 WHERE "___local_diffs_reply" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___local_diffs_renote"=2147483647 WHERE "___local_diffs_renote" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___remote_total"=2147483647 WHERE "___remote_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___remote_inc"=2147483647 WHERE "___remote_inc" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___remote_dec"=2147483647 WHERE "___remote_dec" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___remote_diffs_normal"=2147483647 WHERE "___remote_diffs_normal" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___remote_diffs_reply"=2147483647 WHERE "___remote_diffs_reply" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__notes" SET "___remote_diffs_renote"=2147483647 WHERE "___remote_diffs_renote" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___local_total"=2147483647 WHERE "___local_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___local_inc"=2147483647 WHERE "___local_inc" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___local_dec"=2147483647 WHERE "___local_dec" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___local_diffs_normal"=2147483647 WHERE "___local_diffs_normal" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___local_diffs_reply"=2147483647 WHERE "___local_diffs_reply" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___local_diffs_renote"=2147483647 WHERE "___local_diffs_renote" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___remote_total"=2147483647 WHERE "___remote_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___remote_inc"=2147483647 WHERE "___remote_inc" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___remote_dec"=2147483647 WHERE "___remote_dec" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___remote_diffs_normal"=2147483647 WHERE "___remote_diffs_normal" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___remote_diffs_reply"=2147483647 WHERE "___remote_diffs_reply" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__notes" SET "___remote_diffs_renote"=2147483647 WHERE "___remote_diffs_renote" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__users" SET "___local_total"=2147483647 WHERE "___local_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__users" SET "___local_inc"=32767 WHERE "___local_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__users" SET "___local_dec"=32767 WHERE "___local_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__users" SET "___remote_total"=2147483647 WHERE "___remote_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__users" SET "___remote_inc"=32767 WHERE "___remote_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__users" SET "___remote_dec"=32767 WHERE "___remote_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__users" SET "___local_total"=2147483647 WHERE "___local_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__users" SET "___local_inc"=32767 WHERE "___local_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__users" SET "___local_dec"=32767 WHERE "___local_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__users" SET "___remote_total"=2147483647 WHERE "___remote_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__users" SET "___remote_inc"=32767 WHERE "___remote_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__users" SET "___remote_dec"=32767 WHERE "___remote_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__network" SET "___incomingRequests"=2147483647 WHERE "___incomingRequests" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__network" SET "___outgoingRequests"=2147483647 WHERE "___outgoingRequests" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__network" SET "___totalTime"=2147483647 WHERE "___totalTime" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__network" SET "___incomingBytes"=2147483647 WHERE "___incomingBytes" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__network" SET "___outgoingBytes"=2147483647 WHERE "___outgoingBytes" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__network" SET "___incomingRequests"=2147483647 WHERE "___incomingRequests" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__network" SET "___outgoingRequests"=2147483647 WHERE "___outgoingRequests" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__network" SET "___totalTime"=2147483647 WHERE "___totalTime" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__network" SET "___incomingBytes"=2147483647 WHERE "___incomingBytes" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__network" SET "___outgoingBytes"=2147483647 WHERE "___outgoingBytes" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___requests_failed"=32767 WHERE "___requests_failed" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___requests_succeeded"=32767 WHERE "___requests_succeeded" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___requests_received"=32767 WHERE "___requests_received" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___notes_total"=2147483647 WHERE "___notes_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___notes_inc"=2147483647 WHERE "___notes_inc" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___notes_dec"=2147483647 WHERE "___notes_dec" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___notes_diffs_normal"=2147483647 WHERE "___notes_diffs_normal" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___notes_diffs_reply"=2147483647 WHERE "___notes_diffs_reply" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___notes_diffs_renote"=2147483647 WHERE "___notes_diffs_renote" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___users_total"=2147483647 WHERE "___users_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___users_inc"=32767 WHERE "___users_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___users_dec"=32767 WHERE "___users_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___following_total"=2147483647 WHERE "___following_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___following_inc"=32767 WHERE "___following_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___following_dec"=32767 WHERE "___following_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___followers_total"=2147483647 WHERE "___followers_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___followers_inc"=32767 WHERE "___followers_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___followers_dec"=32767 WHERE "___followers_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___drive_totalFiles"=2147483647 WHERE "___drive_totalFiles" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___drive_incFiles"=2147483647 WHERE "___drive_incFiles" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___drive_decFiles"=2147483647 WHERE "___drive_decFiles" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___drive_incUsage"=2147483647 WHERE "___drive_incUsage" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__instance" SET "___drive_decUsage"=2147483647 WHERE "___drive_decUsage" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___requests_failed"=32767 WHERE "___requests_failed" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___requests_succeeded"=32767 WHERE "___requests_succeeded" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___requests_received"=32767 WHERE "___requests_received" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___notes_total"=2147483647 WHERE "___notes_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___notes_inc"=2147483647 WHERE "___notes_inc" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___notes_dec"=2147483647 WHERE "___notes_dec" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___notes_diffs_normal"=2147483647 WHERE "___notes_diffs_normal" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___notes_diffs_reply"=2147483647 WHERE "___notes_diffs_reply" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___notes_diffs_renote"=2147483647 WHERE "___notes_diffs_renote" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___users_total"=2147483647 WHERE "___users_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___users_inc"=32767 WHERE "___users_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___users_dec"=32767 WHERE "___users_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___following_total"=2147483647 WHERE "___following_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___following_inc"=32767 WHERE "___following_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___following_dec"=32767 WHERE "___following_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___followers_total"=2147483647 WHERE "___followers_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___followers_inc"=32767 WHERE "___followers_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___followers_dec"=32767 WHERE "___followers_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___drive_totalFiles"=2147483647 WHERE "___drive_totalFiles" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___drive_incFiles"=2147483647 WHERE "___drive_incFiles" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___drive_decFiles"=2147483647 WHERE "___drive_decFiles" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___drive_incUsage"=2147483647 WHERE "___drive_incUsage" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__instance" SET "___drive_decUsage"=2147483647 WHERE "___drive_decUsage" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__per_user_notes" SET "___total"=2147483647 WHERE "___total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__per_user_notes" SET "___inc"=32767 WHERE "___inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_notes" SET "___dec"=32767 WHERE "___dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_notes" SET "___diffs_normal"=32767 WHERE "___diffs_normal" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_notes" SET "___diffs_reply"=32767 WHERE "___diffs_reply" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_notes" SET "___diffs_renote"=32767 WHERE "___diffs_renote" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_notes" SET "___total"=2147483647 WHERE "___total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__per_user_notes" SET "___inc"=32767 WHERE "___inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_notes" SET "___dec"=32767 WHERE "___dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_notes" SET "___diffs_normal"=32767 WHERE "___diffs_normal" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_notes" SET "___diffs_reply"=32767 WHERE "___diffs_reply" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_notes" SET "___diffs_renote"=32767 WHERE "___diffs_renote" > 32767`); + await queryRunner.query(`UPDATE "__chart__drive" SET "___local_incCount"=2147483647 WHERE "___local_incCount" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__drive" SET "___local_incSize"=2147483647 WHERE "___local_incSize" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__drive" SET "___local_decCount"=2147483647 WHERE "___local_decCount" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__drive" SET "___local_decSize"=2147483647 WHERE "___local_decSize" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__drive" SET "___remote_incCount"=2147483647 WHERE "___remote_incCount" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__drive" SET "___remote_incSize"=2147483647 WHERE "___remote_incSize" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__drive" SET "___remote_decCount"=2147483647 WHERE "___remote_decCount" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__drive" SET "___remote_decSize"=2147483647 WHERE "___remote_decSize" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__drive" SET "___local_incCount"=2147483647 WHERE "___local_incCount" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__drive" SET "___local_incSize"=2147483647 WHERE "___local_incSize" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__drive" SET "___local_decCount"=2147483647 WHERE "___local_decCount" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__drive" SET "___local_decSize"=2147483647 WHERE "___local_decSize" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__drive" SET "___remote_incCount"=2147483647 WHERE "___remote_incCount" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__drive" SET "___remote_incSize"=2147483647 WHERE "___remote_incSize" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__drive" SET "___remote_decCount"=2147483647 WHERE "___remote_decCount" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__drive" SET "___remote_decSize"=2147483647 WHERE "___remote_decSize" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__per_user_reaction" SET "___local_count"=32767 WHERE "___local_count" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_reaction" SET "___remote_count"=32767 WHERE "___remote_count" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_reaction" SET "___local_count"=32767 WHERE "___local_count" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_reaction" SET "___remote_count"=32767 WHERE "___remote_count" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___local_followings_total"=2147483647 WHERE "___local_followings_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___local_followings_inc"=32767 WHERE "___local_followings_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___local_followings_dec"=32767 WHERE "___local_followings_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___local_followers_total"=2147483647 WHERE "___local_followers_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___local_followers_inc"=32767 WHERE "___local_followers_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___local_followers_dec"=32767 WHERE "___local_followers_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___remote_followings_total"=2147483647 WHERE "___remote_followings_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___remote_followings_inc"=32767 WHERE "___remote_followings_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___remote_followings_dec"=32767 WHERE "___remote_followings_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___remote_followers_total"=2147483647 WHERE "___remote_followers_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___remote_followers_inc"=32767 WHERE "___remote_followers_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart__per_user_following" SET "___remote_followers_dec"=32767 WHERE "___remote_followers_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___local_followings_total"=2147483647 WHERE "___local_followings_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___local_followings_inc"=32767 WHERE "___local_followings_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___local_followings_dec"=32767 WHERE "___local_followings_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___local_followers_total"=2147483647 WHERE "___local_followers_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___local_followers_inc"=32767 WHERE "___local_followers_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___local_followers_dec"=32767 WHERE "___local_followers_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___remote_followings_total"=2147483647 WHERE "___remote_followings_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___remote_followings_inc"=32767 WHERE "___remote_followings_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___remote_followings_dec"=32767 WHERE "___remote_followings_dec" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___remote_followers_total"=2147483647 WHERE "___remote_followers_total" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___remote_followers_inc"=32767 WHERE "___remote_followers_inc" > 32767`); + await queryRunner.query(`UPDATE "__chart_day__per_user_following" SET "___remote_followers_dec"=32767 WHERE "___remote_followers_dec" > 32767`); + await queryRunner.query(`TRUNCATE TABLE "__chart__per_user_drive"`); + await queryRunner.query(`TRUNCATE TABLE "__chart_day__per_user_drive"`); + + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_total" TYPE integer USING "___instance_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_inc" TYPE smallint USING "___instance_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_dec" TYPE smallint USING "___instance_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_total" TYPE integer USING "___instance_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_inc" TYPE smallint USING "___instance_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_dec" TYPE smallint USING "___instance_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_total" TYPE integer USING "___local_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_inc" TYPE integer USING "___local_inc"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_dec" TYPE integer USING "___local_dec"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_normal" TYPE integer USING "___local_diffs_normal"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_reply" TYPE integer USING "___local_diffs_reply"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_renote" TYPE integer USING "___local_diffs_renote"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_total" TYPE integer USING "___remote_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_inc" TYPE integer USING "___remote_inc"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_dec" TYPE integer USING "___remote_dec"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_normal" TYPE integer USING "___remote_diffs_normal"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_reply" TYPE integer USING "___remote_diffs_reply"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_renote" TYPE integer USING "___remote_diffs_renote"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_total" TYPE integer USING "___local_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_inc" TYPE integer USING "___local_inc"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_dec" TYPE integer USING "___local_dec"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_normal" TYPE integer USING "___local_diffs_normal"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_reply" TYPE integer USING "___local_diffs_reply"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_renote" TYPE integer USING "___local_diffs_renote"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_total" TYPE integer USING "___remote_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_inc" TYPE integer USING "___remote_inc"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_dec" TYPE integer USING "___remote_dec"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_normal" TYPE integer USING "___remote_diffs_normal"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_reply" TYPE integer USING "___remote_diffs_reply"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_renote" TYPE integer USING "___remote_diffs_renote"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_total" TYPE integer USING "___local_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_inc" TYPE smallint USING "___local_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_dec" TYPE smallint USING "___local_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_total" TYPE integer USING "___remote_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_inc" TYPE smallint USING "___remote_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_dec" TYPE smallint USING "___remote_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_total" TYPE integer USING "___local_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_inc" TYPE smallint USING "___local_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_dec" TYPE smallint USING "___local_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_total" TYPE integer USING "___remote_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_inc" TYPE smallint USING "___remote_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_dec" TYPE smallint USING "___remote_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___incomingRequests" TYPE integer USING "___incomingRequests"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___outgoingRequests" TYPE integer USING "___outgoingRequests"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___totalTime" TYPE integer USING "___totalTime"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___incomingBytes" TYPE integer USING "___incomingBytes"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___outgoingBytes" TYPE integer USING "___outgoingBytes"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___incomingRequests" TYPE integer USING "___incomingRequests"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___outgoingRequests" TYPE integer USING "___outgoingRequests"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___totalTime" TYPE integer USING "___totalTime"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___incomingBytes" TYPE integer USING "___incomingBytes"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___outgoingBytes" TYPE integer USING "___outgoingBytes"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_failed" TYPE smallint USING "___requests_failed"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_succeeded" TYPE smallint USING "___requests_succeeded"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_received" TYPE smallint USING "___requests_received"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_total" TYPE integer USING "___notes_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_inc" TYPE integer USING "___notes_inc"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_dec" TYPE integer USING "___notes_dec"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_normal" TYPE integer USING "___notes_diffs_normal"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_reply" TYPE integer USING "___notes_diffs_reply"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_renote" TYPE integer USING "___notes_diffs_renote"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_total" TYPE integer USING "___users_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_inc" TYPE smallint USING "___users_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_dec" TYPE smallint USING "___users_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_total" TYPE integer USING "___following_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_inc" TYPE smallint USING "___following_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_dec" TYPE smallint USING "___following_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_total" TYPE integer USING "___followers_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_inc" TYPE smallint USING "___followers_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_dec" TYPE smallint USING "___followers_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_totalFiles" TYPE integer USING "___drive_totalFiles"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_incFiles" TYPE integer USING "___drive_incFiles"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_decFiles" TYPE integer USING "___drive_decFiles"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_incUsage" TYPE integer USING "___drive_incUsage"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_decUsage" TYPE integer USING "___drive_decUsage"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_failed" TYPE smallint USING "___requests_failed"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_succeeded" TYPE smallint USING "___requests_succeeded"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_received" TYPE smallint USING "___requests_received"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_total" TYPE integer USING "___notes_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_inc" TYPE integer USING "___notes_inc"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_dec" TYPE integer USING "___notes_dec"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_normal" TYPE integer USING "___notes_diffs_normal"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_reply" TYPE integer USING "___notes_diffs_reply"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_renote" TYPE integer USING "___notes_diffs_renote"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_total" TYPE integer USING "___users_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_inc" TYPE smallint USING "___users_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_dec" TYPE smallint USING "___users_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_total" TYPE integer USING "___following_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_inc" TYPE smallint USING "___following_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_dec" TYPE smallint USING "___following_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_total" TYPE integer USING "___followers_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_inc" TYPE smallint USING "___followers_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_dec" TYPE smallint USING "___followers_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_totalFiles" TYPE integer USING "___drive_totalFiles"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_incFiles" TYPE integer USING "___drive_incFiles"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_decFiles" TYPE integer USING "___drive_decFiles"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_incUsage" TYPE integer USING "___drive_incUsage"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_decUsage" TYPE integer USING "___drive_decUsage"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___total" TYPE integer USING "___total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___inc" TYPE smallint USING "___inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___dec" TYPE smallint USING "___dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_normal" TYPE smallint USING "___diffs_normal"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_reply" TYPE smallint USING "___diffs_reply"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_renote" TYPE smallint USING "___diffs_renote"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___total" TYPE integer USING "___total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___inc" TYPE smallint USING "___inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___dec" TYPE smallint USING "___dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_normal" TYPE smallint USING "___diffs_normal"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_reply" TYPE smallint USING "___diffs_reply"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_renote" TYPE smallint USING "___diffs_renote"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_incCount" TYPE integer USING "___local_incCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_incSize" TYPE integer USING "___local_incSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_decCount" TYPE integer USING "___local_decCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_decSize" TYPE integer USING "___local_decSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_incCount" TYPE integer USING "___remote_incCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_incSize" TYPE integer USING "___remote_incSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_decCount" TYPE integer USING "___remote_decCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_decSize" TYPE integer USING "___remote_decSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_incCount" TYPE integer USING "___local_incCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_incSize" TYPE integer USING "___local_incSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_decCount" TYPE integer USING "___local_decCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_decSize" TYPE integer USING "___local_decSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_incCount" TYPE integer USING "___remote_incCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_incSize" TYPE integer USING "___remote_incSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_decCount" TYPE integer USING "___remote_decCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_decSize" TYPE integer USING "___remote_decSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ALTER COLUMN "___local_count" TYPE smallint USING "___local_count"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ALTER COLUMN "___remote_count" TYPE smallint USING "___remote_count"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_reaction" ALTER COLUMN "___local_count" TYPE smallint USING "___local_count"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_reaction" ALTER COLUMN "___remote_count" TYPE smallint USING "___remote_count"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_total" TYPE integer USING "___local_followings_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_inc" TYPE smallint USING "___local_followings_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_dec" TYPE smallint USING "___local_followings_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_total" TYPE integer USING "___local_followers_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_inc" TYPE smallint USING "___local_followers_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_dec" TYPE smallint USING "___local_followers_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_total" TYPE integer USING "___remote_followings_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_inc" TYPE smallint USING "___remote_followings_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_dec" TYPE smallint USING "___remote_followings_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_total" TYPE integer USING "___remote_followers_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_inc" TYPE smallint USING "___remote_followers_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_dec" TYPE smallint USING "___remote_followers_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_total" TYPE integer USING "___local_followings_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_inc" TYPE smallint USING "___local_followings_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_dec" TYPE smallint USING "___local_followings_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_total" TYPE integer USING "___local_followers_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_inc" TYPE smallint USING "___local_followers_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_dec" TYPE smallint USING "___local_followers_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_total" TYPE integer USING "___remote_followings_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_inc" TYPE smallint USING "___remote_followings_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_dec" TYPE smallint USING "___remote_followings_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_total" TYPE integer USING "___remote_followers_total"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_inc" TYPE smallint USING "___remote_followers_inc"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_dec" TYPE smallint USING "___remote_followers_dec"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___totalCount" TYPE integer USING "___totalCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___totalSize" TYPE integer USING "___totalSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___incCount" TYPE smallint USING "___incCount"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___incSize" TYPE integer USING "___incSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___decCount" TYPE smallint USING "___decCount"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___decSize" TYPE integer USING "___decSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___totalCount" TYPE integer USING "___totalCount"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___totalSize" TYPE integer USING "___totalSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___incCount" TYPE smallint USING "___incCount"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___incSize" TYPE integer USING "___incSize"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___decCount" TYPE smallint USING "___decCount"::smallint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___decSize" TYPE integer USING "___decSize"::integer`); + } + + async down(queryRunner) { + + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_total" TYPE bigint USING "___instance_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_inc" TYPE bigint USING "___instance_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ALTER COLUMN "___instance_dec" TYPE bigint USING "___instance_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_total" TYPE bigint USING "___instance_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_inc" TYPE bigint USING "___instance_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ALTER COLUMN "___instance_dec" TYPE bigint USING "___instance_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_total" TYPE bigint USING "___local_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_inc" TYPE bigint USING "___local_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_dec" TYPE bigint USING "___local_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_normal" TYPE bigint USING "___local_diffs_normal"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_reply" TYPE bigint USING "___local_diffs_reply"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___local_diffs_renote" TYPE bigint USING "___local_diffs_renote"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_total" TYPE bigint USING "___remote_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_inc" TYPE bigint USING "___remote_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_dec" TYPE bigint USING "___remote_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_normal" TYPE bigint USING "___remote_diffs_normal"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_reply" TYPE bigint USING "___remote_diffs_reply"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ALTER COLUMN "___remote_diffs_renote" TYPE bigint USING "___remote_diffs_renote"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_total" TYPE bigint USING "___local_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_inc" TYPE bigint USING "___local_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_dec" TYPE bigint USING "___local_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_normal" TYPE bigint USING "___local_diffs_normal"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_reply" TYPE bigint USING "___local_diffs_reply"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___local_diffs_renote" TYPE bigint USING "___local_diffs_renote"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_total" TYPE bigint USING "___remote_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_inc" TYPE bigint USING "___remote_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_dec" TYPE bigint USING "___remote_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_normal" TYPE bigint USING "___remote_diffs_normal"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_reply" TYPE bigint USING "___remote_diffs_reply"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ALTER COLUMN "___remote_diffs_renote" TYPE bigint USING "___remote_diffs_renote"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_total" TYPE bigint USING "___local_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_inc" TYPE bigint USING "___local_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___local_dec" TYPE bigint USING "___local_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_total" TYPE bigint USING "___remote_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_inc" TYPE bigint USING "___remote_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__users" ALTER COLUMN "___remote_dec" TYPE bigint USING "___remote_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_total" TYPE bigint USING "___local_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_inc" TYPE bigint USING "___local_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___local_dec" TYPE bigint USING "___local_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_total" TYPE bigint USING "___remote_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_inc" TYPE bigint USING "___remote_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__users" ALTER COLUMN "___remote_dec" TYPE bigint USING "___remote_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___incomingRequests" TYPE bigint USING "___incomingRequests"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___outgoingRequests" TYPE bigint USING "___outgoingRequests"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___totalTime" TYPE bigint USING "___totalTime"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___incomingBytes" TYPE bigint USING "___incomingBytes"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__network" ALTER COLUMN "___outgoingBytes" TYPE bigint USING "___outgoingBytes"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___incomingRequests" TYPE bigint USING "___incomingRequests"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___outgoingRequests" TYPE bigint USING "___outgoingRequests"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___totalTime" TYPE bigint USING "___totalTime"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___incomingBytes" TYPE bigint USING "___incomingBytes"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__network" ALTER COLUMN "___outgoingBytes" TYPE bigint USING "___outgoingBytes"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_failed" TYPE bigint USING "___requests_failed"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_succeeded" TYPE bigint USING "___requests_succeeded"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___requests_received" TYPE bigint USING "___requests_received"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_total" TYPE bigint USING "___notes_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_inc" TYPE bigint USING "___notes_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_dec" TYPE bigint USING "___notes_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_normal" TYPE bigint USING "___notes_diffs_normal"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_reply" TYPE bigint USING "___notes_diffs_reply"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___notes_diffs_renote" TYPE bigint USING "___notes_diffs_renote"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_total" TYPE bigint USING "___users_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_inc" TYPE bigint USING "___users_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___users_dec" TYPE bigint USING "___users_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_total" TYPE bigint USING "___following_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_inc" TYPE bigint USING "___following_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___following_dec" TYPE bigint USING "___following_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_total" TYPE bigint USING "___followers_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_inc" TYPE bigint USING "___followers_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___followers_dec" TYPE bigint USING "___followers_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_totalFiles" TYPE bigint USING "___drive_totalFiles"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_incFiles" TYPE bigint USING "___drive_incFiles"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_decFiles" TYPE bigint USING "___drive_decFiles"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_incUsage" TYPE bigint USING "___drive_incUsage"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ALTER COLUMN "___drive_decUsage" TYPE bigint USING "___drive_decUsage"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_failed" TYPE bigint USING "___requests_failed"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_succeeded" TYPE bigint USING "___requests_succeeded"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___requests_received" TYPE bigint USING "___requests_received"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_total" TYPE bigint USING "___notes_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_inc" TYPE bigint USING "___notes_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_dec" TYPE bigint USING "___notes_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_normal" TYPE bigint USING "___notes_diffs_normal"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_reply" TYPE bigint USING "___notes_diffs_reply"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___notes_diffs_renote" TYPE bigint USING "___notes_diffs_renote"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_total" TYPE bigint USING "___users_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_inc" TYPE bigint USING "___users_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___users_dec" TYPE bigint USING "___users_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_total" TYPE bigint USING "___following_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_inc" TYPE bigint USING "___following_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___following_dec" TYPE bigint USING "___following_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_total" TYPE bigint USING "___followers_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_inc" TYPE bigint USING "___followers_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___followers_dec" TYPE bigint USING "___followers_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_totalFiles" TYPE bigint USING "___drive_totalFiles"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_incFiles" TYPE bigint USING "___drive_incFiles"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_decFiles" TYPE bigint USING "___drive_decFiles"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_incUsage" TYPE bigint USING "___drive_incUsage"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ALTER COLUMN "___drive_decUsage" TYPE bigint USING "___drive_decUsage"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___total" TYPE bigint USING "___total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___inc" TYPE bigint USING "___inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___dec" TYPE bigint USING "___dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_normal" TYPE bigint USING "___diffs_normal"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_reply" TYPE bigint USING "___diffs_reply"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ALTER COLUMN "___diffs_renote" TYPE bigint USING "___diffs_renote"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___total" TYPE bigint USING "___total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___inc" TYPE bigint USING "___inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___dec" TYPE bigint USING "___dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_normal" TYPE bigint USING "___diffs_normal"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_reply" TYPE bigint USING "___diffs_reply"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ALTER COLUMN "___diffs_renote" TYPE bigint USING "___diffs_renote"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_incCount" TYPE bigint USING "___local_incCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_incSize" TYPE bigint USING "___local_incSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_decCount" TYPE bigint USING "___local_decCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___local_decSize" TYPE bigint USING "___local_decSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_incCount" TYPE bigint USING "___remote_incCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_incSize" TYPE bigint USING "___remote_incSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_decCount" TYPE bigint USING "___remote_decCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__drive" ALTER COLUMN "___remote_decSize" TYPE bigint USING "___remote_decSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_incCount" TYPE bigint USING "___local_incCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_incSize" TYPE bigint USING "___local_incSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_decCount" TYPE bigint USING "___local_decCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___local_decSize" TYPE bigint USING "___local_decSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_incCount" TYPE bigint USING "___remote_incCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_incSize" TYPE bigint USING "___remote_incSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_decCount" TYPE bigint USING "___remote_decCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__drive" ALTER COLUMN "___remote_decSize" TYPE bigint USING "___remote_decSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ALTER COLUMN "___local_count" TYPE bigint USING "___local_count"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ALTER COLUMN "___remote_count" TYPE bigint USING "___remote_count"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_reaction" ALTER COLUMN "___local_count" TYPE bigint USING "___local_count"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_reaction" ALTER COLUMN "___remote_count" TYPE bigint USING "___remote_count"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_total" TYPE bigint USING "___local_followings_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_inc" TYPE bigint USING "___local_followings_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followings_dec" TYPE bigint USING "___local_followings_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_total" TYPE bigint USING "___local_followers_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_inc" TYPE bigint USING "___local_followers_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___local_followers_dec" TYPE bigint USING "___local_followers_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_total" TYPE bigint USING "___remote_followings_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_inc" TYPE bigint USING "___remote_followings_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followings_dec" TYPE bigint USING "___remote_followings_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_total" TYPE bigint USING "___remote_followers_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_inc" TYPE bigint USING "___remote_followers_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ALTER COLUMN "___remote_followers_dec" TYPE bigint USING "___remote_followers_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_total" TYPE bigint USING "___local_followings_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_inc" TYPE bigint USING "___local_followings_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followings_dec" TYPE bigint USING "___local_followings_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_total" TYPE bigint USING "___local_followers_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_inc" TYPE bigint USING "___local_followers_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___local_followers_dec" TYPE bigint USING "___local_followers_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_total" TYPE bigint USING "___remote_followings_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_inc" TYPE bigint USING "___remote_followings_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followings_dec" TYPE bigint USING "___remote_followings_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_total" TYPE bigint USING "___remote_followers_total"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_inc" TYPE bigint USING "___remote_followers_inc"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_following" ALTER COLUMN "___remote_followers_dec" TYPE bigint USING "___remote_followers_dec"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___totalCount" TYPE bigint USING "___totalCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___totalSize" TYPE bigint USING "___totalSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___incCount" TYPE bigint USING "___incCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___incSize" TYPE bigint USING "___incSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___decCount" TYPE bigint USING "___decCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ALTER COLUMN "___decSize" TYPE bigint USING "___decSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___totalCount" TYPE bigint USING "___totalCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___totalSize" TYPE bigint USING "___totalSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___incCount" TYPE bigint USING "___incCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___incSize" TYPE bigint USING "___incSize"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___decCount" TYPE bigint USING "___decCount"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_drive" ALTER COLUMN "___decSize" TYPE bigint USING "___decSize"::bigint`); + } +} diff --git a/packages/backend/migration/1644059847460-chart-v8.js b/packages/backend/migration/1644059847460-chart-v8.js new file mode 100644 index 000000000..a5339c0eb --- /dev/null +++ b/packages/backend/migration/1644059847460-chart-v8.js @@ -0,0 +1,25 @@ + + +export class chartV81644059847460 { + name = 'chartV81644059847460' + + async up(queryRunner) { + await queryRunner.query(`UPDATE "__chart__active_users" SET "___local_users"=2147483647 WHERE "___local_users" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__active_users" SET "___remote_users"=2147483647 WHERE "___remote_users" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__active_users" SET "___local_users"=2147483647 WHERE "___local_users" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__active_users" SET "___remote_users"=2147483647 WHERE "___remote_users" > 2147483647`); + + await queryRunner.query(`ALTER TABLE "__chart__active_users" ALTER COLUMN "___local_users" TYPE integer USING "___local_users"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ALTER COLUMN "___remote_users" TYPE integer USING "___remote_users"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ALTER COLUMN "___local_users" TYPE integer USING "___local_users"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ALTER COLUMN "___remote_users" TYPE integer USING "___remote_users"::integer`); + } + + async down(queryRunner) { + + await queryRunner.query(`ALTER TABLE "__chart__active_users" ALTER COLUMN "___local_users" TYPE bigint USING "___local_users"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ALTER COLUMN "___remote_users" TYPE bigint USING "___remote_users"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ALTER COLUMN "___local_users" TYPE bigint USING "___local_users"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ALTER COLUMN "___remote_users" TYPE bigint USING "___remote_users"::bigint`); + } +} diff --git a/packages/backend/migration/1644060125705-chart-v9.js b/packages/backend/migration/1644060125705-chart-v9.js new file mode 100644 index 000000000..da35d4231 --- /dev/null +++ b/packages/backend/migration/1644060125705-chart-v9.js @@ -0,0 +1,25 @@ + + +export class chartV91644060125705 { + name = 'chartV91644060125705' + + async up(queryRunner) { + await queryRunner.query(`UPDATE "__chart__hashtag" SET "___local_users"=2147483647 WHERE "___local_users" > 2147483647`); + await queryRunner.query(`UPDATE "__chart__hashtag" SET "___remote_users"=2147483647 WHERE "___remote_users" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__hashtag" SET "___local_users"=2147483647 WHERE "___local_users" > 2147483647`); + await queryRunner.query(`UPDATE "__chart_day__hashtag" SET "___remote_users"=2147483647 WHERE "___remote_users" > 2147483647`); + + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ALTER COLUMN "___local_users" TYPE integer USING "___local_users"::integer`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ALTER COLUMN "___remote_users" TYPE integer USING "___remote_users"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ALTER COLUMN "___local_users" TYPE integer USING "___local_users"::integer`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ALTER COLUMN "___remote_users" TYPE integer USING "___remote_users"::integer`); + } + + async down(queryRunner) { + + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ALTER COLUMN "___local_users" TYPE bigint USING "___local_users"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart__hashtag" ALTER COLUMN "___remote_users" TYPE bigint USING "___remote_users"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ALTER COLUMN "___local_users" TYPE bigint USING "___local_users"::bigint`); + await queryRunner.query(`ALTER TABLE "__chart_day__hashtag" ALTER COLUMN "___remote_users" TYPE bigint USING "___remote_users"::bigint`); + } +} diff --git a/packages/backend/migration/1644073149413-chart-v10.js b/packages/backend/migration/1644073149413-chart-v10.js new file mode 100644 index 000000000..7260bbeca --- /dev/null +++ b/packages/backend/migration/1644073149413-chart-v10.js @@ -0,0 +1,35 @@ + + +export class chartV101644073149413 { + name = 'chartV101644073149413' + + async up(queryRunner) { + await queryRunner.query(`CREATE TABLE "__chart__ap_request" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "___deliverFailed" integer NOT NULL DEFAULT '0', "___deliverSucceeded" integer NOT NULL DEFAULT '0', "___inboxReceived" integer NOT NULL DEFAULT '0', CONSTRAINT "UQ_e56f4beac5746d44bc3e19c80d0" UNIQUE ("date"), CONSTRAINT "PK_56a25cd447c7ee08876b3baf8d8" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e56f4beac5746d44bc3e19c80d" ON "__chart__ap_request" ("date") `); + await queryRunner.query(`CREATE TABLE "__chart_day__ap_request" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "___deliverFailed" integer NOT NULL DEFAULT '0', "___deliverSucceeded" integer NOT NULL DEFAULT '0', "___inboxReceived" integer NOT NULL DEFAULT '0', CONSTRAINT "UQ_a848f66d6cec11980a5dd595822" UNIQUE ("date"), CONSTRAINT "PK_9318b49daee320194e23f712e69" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a848f66d6cec11980a5dd59582" ON "__chart_day__ap_request" ("date") `); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "unique_temp___deliveredInstances" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___deliveredInstances" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "unique_temp___inboxInstances" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___inboxInstances" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "unique_temp___deliveredInstances" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___deliveredInstances" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "unique_temp___inboxInstances" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___inboxInstances" smallint NOT NULL DEFAULT '0'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___inboxInstances"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "unique_temp___inboxInstances"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___deliveredInstances"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "unique_temp___deliveredInstances"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___inboxInstances"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "unique_temp___inboxInstances"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___deliveredInstances"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "unique_temp___deliveredInstances"`); + await queryRunner.query(`DROP INDEX "public"."IDX_a848f66d6cec11980a5dd59582"`); + await queryRunner.query(`DROP TABLE "__chart_day__ap_request"`); + await queryRunner.query(`DROP INDEX "public"."IDX_e56f4beac5746d44bc3e19c80d"`); + await queryRunner.query(`DROP TABLE "__chart__ap_request"`); + } +} diff --git a/packages/backend/migration/1644095659741-chart-v11.js b/packages/backend/migration/1644095659741-chart-v11.js new file mode 100644 index 000000000..309fff1d9 --- /dev/null +++ b/packages/backend/migration/1644095659741-chart-v11.js @@ -0,0 +1,91 @@ + + +export class chartV111644095659741 { + name = 'chartV111644095659741' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___local_users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___remote_users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___users" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___notedUsers" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___notedUsers" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___registeredWithinWeek" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___registeredWithinWeek" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___registeredWithinMonth" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___registeredWithinMonth" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___registeredWithinYear" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___registeredWithinYear" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___registeredOutsideWeek" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___registeredOutsideWeek" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___registeredOutsideMonth" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___registeredOutsideMonth" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___registeredOutsideYear" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___registeredOutsideYear" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___users" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___notedUsers" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___notedUsers" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___registeredWithinWeek" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___registeredWithinWeek" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___registeredWithinMonth" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___registeredWithinMonth" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___registeredWithinYear" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___registeredWithinYear" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___registeredOutsideWeek" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___registeredOutsideWeek" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___registeredOutsideMonth" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___registeredOutsideMonth" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___registeredOutsideYear" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___registeredOutsideYear" smallint NOT NULL DEFAULT '0'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___registeredOutsideYear"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___registeredOutsideYear"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___registeredOutsideMonth"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___registeredOutsideMonth"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___registeredOutsideWeek"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___registeredOutsideWeek"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___registeredWithinYear"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___registeredWithinYear"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___registeredWithinMonth"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___registeredWithinMonth"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___registeredWithinWeek"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___registeredWithinWeek"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___notedUsers"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___notedUsers"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___registeredOutsideYear"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___registeredOutsideYear"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___registeredOutsideMonth"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___registeredOutsideMonth"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___registeredOutsideWeek"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___registeredOutsideWeek"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___registeredWithinYear"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___registeredWithinYear"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___registeredWithinMonth"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___registeredWithinMonth"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___registeredWithinWeek"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___registeredWithinWeek"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___notedUsers"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___notedUsers"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___remote_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___local_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___remote_users" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___local_users" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___remote_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___local_users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___remote_users" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___local_users" integer NOT NULL DEFAULT '0'`); + } +} diff --git a/packages/backend/migration/1644328606241-chart-v12.js b/packages/backend/migration/1644328606241-chart-v12.js new file mode 100644 index 000000000..c3c7e44f9 --- /dev/null +++ b/packages/backend/migration/1644328606241-chart-v12.js @@ -0,0 +1,27 @@ + + +export class chartV121644328606241 { + name = 'chartV121644328606241' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__notes" ADD "___local_diffs_withFile" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__notes" ADD "___remote_diffs_withFile" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ADD "___local_diffs_withFile" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" ADD "___remote_diffs_withFile" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__instance" ADD "___notes_diffs_withFile" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" ADD "___notes_diffs_withFile" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ADD "___diffs_withFile" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ADD "___diffs_withFile" smallint NOT NULL DEFAULT '0'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" DROP COLUMN "___diffs_withFile"`); + await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" DROP COLUMN "___diffs_withFile"`); + await queryRunner.query(`ALTER TABLE "__chart_day__instance" DROP COLUMN "___notes_diffs_withFile"`); + await queryRunner.query(`ALTER TABLE "__chart__instance" DROP COLUMN "___notes_diffs_withFile"`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" DROP COLUMN "___remote_diffs_withFile"`); + await queryRunner.query(`ALTER TABLE "__chart_day__notes" DROP COLUMN "___local_diffs_withFile"`); + await queryRunner.query(`ALTER TABLE "__chart__notes" DROP COLUMN "___remote_diffs_withFile"`); + await queryRunner.query(`ALTER TABLE "__chart__notes" DROP COLUMN "___local_diffs_withFile"`); + } +} diff --git a/packages/backend/migration/1644331238153-chart-v13.js b/packages/backend/migration/1644331238153-chart-v13.js new file mode 100644 index 000000000..639f7b4e2 --- /dev/null +++ b/packages/backend/migration/1644331238153-chart-v13.js @@ -0,0 +1,19 @@ + + +export class chartV131644331238153 { + name = 'chartV131644331238153' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "unique_temp___stalled" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___stalled" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "unique_temp___stalled" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___stalled" smallint NOT NULL DEFAULT '0'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___stalled"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "unique_temp___stalled"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___stalled"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "unique_temp___stalled"`); + } +} diff --git a/packages/backend/migration/1644344266289-chart-v14.js b/packages/backend/migration/1644344266289-chart-v14.js new file mode 100644 index 000000000..a0d9cfc38 --- /dev/null +++ b/packages/backend/migration/1644344266289-chart-v14.js @@ -0,0 +1,47 @@ + + +export class chartV141644344266289 { + name = 'chartV141644344266289' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___users"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___notedUsers"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___notedUsers"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___users"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___notedUsers"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___notedUsers"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___readWrite" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___read" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___read" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___write" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___write" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___readWrite" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___read" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___read" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___write" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___write" smallint NOT NULL DEFAULT '0'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___write"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___write"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___read"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "unique_temp___read"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" DROP COLUMN "___readWrite"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___write"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___write"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___read"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique_temp___read"`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___readWrite"`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___notedUsers" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___notedUsers" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "___users" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__active_users" ADD "unique_temp___users" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___notedUsers" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___notedUsers" character varying array NOT NULL DEFAULT '{}'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___users" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique_temp___users" character varying array NOT NULL DEFAULT '{}'`); + } +} diff --git a/packages/backend/migration/1644395759931-instance-theme-color.js b/packages/backend/migration/1644395759931-instance-theme-color.js new file mode 100644 index 000000000..8f335ad21 --- /dev/null +++ b/packages/backend/migration/1644395759931-instance-theme-color.js @@ -0,0 +1,13 @@ + + +export class instanceThemeColor1644395759931 { + name = 'instanceThemeColor1644395759931' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "themeColor" character varying(512)`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "themeColor"`); + } +} diff --git a/packages/backend/migration/1644481657998-chart-v15.js b/packages/backend/migration/1644481657998-chart-v15.js new file mode 100644 index 000000000..b50ca87c4 --- /dev/null +++ b/packages/backend/migration/1644481657998-chart-v15.js @@ -0,0 +1,31 @@ + + +export class chartV151644481657998 { + name = 'chartV151644481657998' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___instance_total"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___instance_inc"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___instance_dec"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___instance_total"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___instance_inc"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___instance_dec"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___sub" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___pub" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___sub" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___pub" smallint NOT NULL DEFAULT '0'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___pub"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___sub"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___pub"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___sub"`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___instance_dec" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___instance_inc" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___instance_total" integer NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___instance_dec" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___instance_inc" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___instance_total" integer NOT NULL DEFAULT '0'`); + } +} diff --git a/packages/backend/migration/1644551208096-following-indexes.js b/packages/backend/migration/1644551208096-following-indexes.js new file mode 100644 index 000000000..276473ff6 --- /dev/null +++ b/packages/backend/migration/1644551208096-following-indexes.js @@ -0,0 +1,15 @@ + + +export class followingIndexes1644551208096 { + name = 'followingIndexes1644551208096' + + async up(queryRunner) { + await queryRunner.query(`CREATE INDEX "IDX_4ccd2239268ebbd1b35e318754" ON "following" ("followerHost") `); + await queryRunner.query(`CREATE INDEX "IDX_fcdafee716dfe9c3b5fde90f30" ON "following" ("followeeHost") `); + } + + async down(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_fcdafee716dfe9c3b5fde90f30"`); + await queryRunner.query(`DROP INDEX "public"."IDX_4ccd2239268ebbd1b35e318754"`); + } +} diff --git a/packages/backend/migration/1645340161439-remove-max-note-text-length.js b/packages/backend/migration/1645340161439-remove-max-note-text-length.js new file mode 100644 index 000000000..c88cb70bf --- /dev/null +++ b/packages/backend/migration/1645340161439-remove-max-note-text-length.js @@ -0,0 +1,13 @@ + + +export class removeMaxNoteTextLength1645340161439 { + name = 'removeMaxNoteTextLength1645340161439' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "maxNoteTextLength"`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "maxNoteTextLength" integer NOT NULL DEFAULT '500'`); + } +} diff --git a/packages/backend/migration/1645599900873-federation-chart-pubsub.js b/packages/backend/migration/1645599900873-federation-chart-pubsub.js new file mode 100644 index 000000000..fd7cb6d5a --- /dev/null +++ b/packages/backend/migration/1645599900873-federation-chart-pubsub.js @@ -0,0 +1,15 @@ + + +export class federationChartPubsub1645599900873 { + name = 'federationChartPubsub1645599900873' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___pubsub" smallint NOT NULL DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___pubsub" smallint NOT NULL DEFAULT '0'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___pubsub"`); + await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___pubsub"`); + } +} diff --git a/packages/backend/migration/1646143552768-instance-default-theme.js b/packages/backend/migration/1646143552768-instance-default-theme.js new file mode 100644 index 000000000..029354fd9 --- /dev/null +++ b/packages/backend/migration/1646143552768-instance-default-theme.js @@ -0,0 +1,13 @@ +export class instanceDefaultTheme1646143552768 { + name = 'instanceDefaultTheme1646143552768' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "defaultLightTheme" character varying(8192)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "defaultDarkTheme" character varying(8192)`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "defaultDarkTheme"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "defaultLightTheme"`); + } +} diff --git a/packages/backend/ormconfig.js b/packages/backend/ormconfig.js index 524181cb8..b8150f701 100644 --- a/packages/backend/ormconfig.js +++ b/packages/backend/ormconfig.js @@ -1,7 +1,7 @@ -const config = require('./built/config').default; -const entities = require('./built/db/postgre').entities; +import config from './built/config/index.js'; +import { entities } from './built/db/postgre.js'; -module.exports = { +export default { type: 'postgres', host: config.db.host, port: config.db.port, diff --git a/packages/backend/package.json b/packages/backend/package.json index 3d3a901f3..3bc7051b1 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,7 @@ { "main": "./index.js", "private": true, + "type": "module", "scripts": { "init": "npm run migrate", "build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json", @@ -18,15 +19,13 @@ "@elastic/elasticsearch": "7.11.0", "@koa/cors": "3.1.0", "@koa/multer": "3.0.0", - "@koa/router": "9.0.1", - "@sinonjs/fake-timers": "7.1.2", + "@koa/router": "10.1.1", + "@sinonjs/fake-timers": "9.1.0", "@syuilo/aiscript": "0.11.1", "@types/bcryptjs": "2.4.2", - "@types/bull": "3.15.7", + "@types/bull": "3.15.8", "@types/cbor": "6.0.0", - "@types/dateformat": "3.0.1", "@types/escape-regexp": "0.0.1", - "@types/glob": "7.2.0", "@types/is-url": "1.2.30", "@types/js-yaml": "4.0.5", "@types/jsdom": "16.2.14", @@ -42,8 +41,8 @@ "@types/koa__cors": "3.1.1", "@types/koa__multer": "2.0.4", "@types/koa__router": "8.0.11", - "@types/mocha": "8.2.3", - "@types/node": "17.0.10", + "@types/mocha": "9.1.0", + "@types/node": "17.0.19", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.4", "@types/oauth": "0.9.1", @@ -56,56 +55,54 @@ "@types/ratelimiter": "3.4.3", "@types/redis": "4.0.11", "@types/rename": "1.0.4", - "@types/request-stats": "3.0.0", "@types/sanitize-html": "2.6.2", - "@types/seedrandom": "2.4.28", + "@types/seedrandom": "3.0.1", "@types/sharp": "0.29.5", - "@types/sinonjs__fake-timers": "6.0.4", + "@types/sinonjs__fake-timers": "8.1.1", "@types/speakeasy": "2.0.7", "@types/throttle-debounce": "2.1.0", "@types/tinycolor2": "1.4.3", "@types/tmp": "0.2.3", "@types/uuid": "8.3.4", "@types/web-push": "3.3.2", - "@types/webpack": "5.28.0", - "@types/webpack-stream": "3.2.12", - "@types/websocket": "1.0.4", - "@types/ws": "8.2.2", - "@typescript-eslint/eslint-plugin": "5.10.0", - "@typescript-eslint/parser": "5.10.0", + "@types/websocket": "1.0.5", + "@types/ws": "8.2.3", + "@typescript-eslint/eslint-plugin": "5.12.1", + "@typescript-eslint/parser": "5.12.1", "abort-controller": "3.0.0", + "ajv": "8.10.0", "archiver": "5.3.0", "autobind-decorator": "2.4.0", "autwh": "0.1.0", - "aws-sdk": "2.1061.0", + "aws-sdk": "2.1079.0", "bcryptjs": "2.4.3", - "blurhash": "1.1.4", - "broadcast-channel": "4.9.0", - "bull": "4.2.1", + "blurhash": "1.1.5", + "broadcast-channel": "4.10.0", + "bull": "4.6.2", "cacheable-lookup": "6.0.4", "cafy": "15.2.1", "cbor": "8.1.0", - "chalk": "4.1.2", + "chalk": "5.0.0", + "chalk-template": "0.3.1", "cli-highlight": "2.1.11", + "color-convert": "2.0.1", "content-disposition": "0.5.4", - "crc-32": "1.2.0", - "dateformat": "4.5.1", + "date-fns": "2.28.0", "deep-email-validator": "0.1.21", "escape-regexp": "0.0.1", - "eslint": "8.7.0", + "eslint": "8.9.0", "eslint-plugin-import": "2.25.4", "eventemitter3": "4.0.7", "feed": "4.2.2", "file-type": "16.5.3", "fluent-ffmpeg": "2.1.2", - "glob": "7.2.0", "got": "11.8.2", "hpagent": "0.1.2", "http-signature": "1.3.6", "ip-cidr": "3.0.4", "is-svg": "4.3.2", "js-yaml": "4.1.0", - "jsdom": "16.7.0", + "jsdom": "19.0.0", "json5": "2.2.0", "json5-loader": "4.0.1", "jsonld": "5.2.0", @@ -119,22 +116,21 @@ "koa-send": "5.0.1", "koa-slow": "2.1.0", "koa-views": "7.0.2", - "langmap": "0.0.16", "mfm-js": "0.21.0", "mime-types": "2.1.34", - "misskey-js": "0.0.13", - "mocha": "8.4.0", + "misskey-js": "0.0.14", + "mocha": "9.2.1", "ms": "3.0.0-canary.1", "multer": "1.4.4", "nested-property": "4.0.0", - "node-fetch": "2.6.1", + "node-fetch": "2.6.7", "nodemailer": "6.7.2", "os-utils": "0.0.14", "parse5": "6.0.1", - "pg": "8.7.1", + "pg": "8.7.3", "portscanner": "2.2.0", "private-ip": "2.3.3", - "probe-image-size": "7.2.2", + "probe-image-size": "7.2.3", "promise-limit": "2.7.0", "pug": "3.0.2", "punycode": "2.1.1", @@ -142,47 +138,46 @@ "qrcode": "1.5.0", "random-seed": "0.3.0", "ratelimiter": "3.4.1", - "re2": "1.17.3", + "re2": "1.17.4", "redis": "3.1.2", "redis-lock": "0.1.4", "reflect-metadata": "0.1.13", "rename": "1.0.4", - "request-stats": "3.0.0", "require-all": "3.0.0", "rndstr": "1.0.0", "s-age": "1.1.2", - "sanitize-html": "2.6.1", + "sanitize-html": "2.7.0", "seedrandom": "3.0.5", - "sharp": "0.29.3", + "sharp": "0.30.1", "speakeasy": "2.0.0", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", "style-loader": "3.3.1", "summaly": "2.5.0", "syslog-pro": "1.0.0", - "systeminformation": "5.9.9", + "systeminformation": "5.11.4", "throttle-debounce": "3.0.1", "tinycolor2": "1.4.2", "tmp": "0.2.1", "ts-loader": "9.2.6", - "ts-node": "10.4.0", + "ts-node": "10.5.0", "tsc-alias": "1.4.1", "tsconfig-paths": "3.12.0", "twemoji-parser": "13.1.0", - "typeorm": "0.2.41", + "typeorm": "0.2.44", "typescript": "4.5.5", "ulid": "2.3.0", "unzipper": "0.10.11", "uuid": "8.3.2", "web-push": "3.4.5", "websocket": "1.0.34", - "ws": "8.4.2", + "ws": "8.5.0", "xev": "2.0.1" }, "devDependencies": { - "@redocly/openapi-core": "1.0.0-beta.79", + "@redocly/openapi-core": "1.0.0-beta.83", "@types/fluent-ffmpeg": "2.1.20", "cross-env": "7.0.3", - "execa": "6.0.0" + "execa": "6.1.0" } } diff --git a/packages/backend/@types/hcaptcha.d.ts b/packages/backend/src/@types/hcaptcha.d.ts similarity index 100% rename from packages/backend/@types/hcaptcha.d.ts rename to packages/backend/src/@types/hcaptcha.d.ts diff --git a/packages/backend/@types/http-signature.d.ts b/packages/backend/src/@types/http-signature.d.ts similarity index 100% rename from packages/backend/@types/http-signature.d.ts rename to packages/backend/src/@types/http-signature.d.ts diff --git a/packages/backend/@types/jsrsasign.d.ts b/packages/backend/src/@types/jsrsasign.d.ts similarity index 100% rename from packages/backend/@types/jsrsasign.d.ts rename to packages/backend/src/@types/jsrsasign.d.ts diff --git a/packages/backend/@types/koa-json-body.d.ts b/packages/backend/src/@types/koa-json-body.d.ts similarity index 100% rename from packages/backend/@types/koa-json-body.d.ts rename to packages/backend/src/@types/koa-json-body.d.ts diff --git a/packages/backend/@types/koa-slow.d.ts b/packages/backend/src/@types/koa-slow.d.ts similarity index 100% rename from packages/backend/@types/koa-slow.d.ts rename to packages/backend/src/@types/koa-slow.d.ts diff --git a/packages/backend/@types/os-utils.d.ts b/packages/backend/src/@types/os-utils.d.ts similarity index 100% rename from packages/backend/@types/os-utils.d.ts rename to packages/backend/src/@types/os-utils.d.ts diff --git a/packages/backend/@types/package.json.d.ts b/packages/backend/src/@types/package.json.d.ts similarity index 100% rename from packages/backend/@types/package.json.d.ts rename to packages/backend/src/@types/package.json.d.ts diff --git a/packages/backend/@types/probe-image-size.d.ts b/packages/backend/src/@types/probe-image-size.d.ts similarity index 95% rename from packages/backend/@types/probe-image-size.d.ts rename to packages/backend/src/@types/probe-image-size.d.ts index 665edcf2e..11bb6c620 100644 --- a/packages/backend/@types/probe-image-size.d.ts +++ b/packages/backend/src/@types/probe-image-size.d.ts @@ -1,5 +1,5 @@ declare module 'probe-image-size' { - import { ReadStream } from 'fs'; + import { ReadStream } from 'node:fs'; type ProbeOptions = { retries: 1; diff --git a/packages/backend/src/boot/index.ts b/packages/backend/src/boot/index.ts index 1723c32dd..5bb20a729 100644 --- a/packages/backend/src/boot/index.ts +++ b/packages/backend/src/boot/index.ts @@ -1,18 +1,18 @@ -import * as cluster from 'cluster'; -import * as chalk from 'chalk'; -import Xev from 'xev'; +import cluster from 'node:cluster'; +import chalk from 'chalk'; +import { default as Xev } from 'xev'; -import Logger from '@/services/logger'; -import { envOption } from '../env'; +import Logger from '@/services/logger.js'; +import { envOption } from '../env.js'; // for typeorm import 'reflect-metadata'; -import { masterMain } from './master'; -import { workerMain } from './worker'; +import { masterMain } from './master.js'; +import { workerMain } from './worker.js'; const logger = new Logger('core', 'cyan'); const clusterLogger = logger.createSubLogger('cluster', 'orange', false); -const ev = new Xev(); +const ev = new Xev.default(); /** * Init process diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index eeb7017cb..1c909dff1 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -1,22 +1,22 @@ -import * as fs from 'fs'; -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; -import * as os from 'os'; -import * as cluster from 'cluster'; -import * as chalk from 'chalk'; +import * as fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; +import * as os from 'node:os'; +import cluster from 'node:cluster'; +import chalk from 'chalk'; +import chalkTemplate from 'chalk-template'; import * as portscanner from 'portscanner'; import { getConnection } from 'typeorm'; -import Logger from '@/services/logger'; -import loadConfig from '@/config/load'; -import { Config } from '@/config/types'; -import { lessThan } from '@/prelude/array'; -import { envOption } from '../env'; -import { showMachineInfo } from '@/misc/show-machine-info'; -import { initDb } from '../db/postgre'; +import Logger from '@/services/logger.js'; +import loadConfig from '@/config/load.js'; +import { Config } from '@/config/types.js'; +import { lessThan } from '@/prelude/array.js'; +import { envOption } from '../env.js'; +import { showMachineInfo } from '@/misc/show-machine-info.js'; +import { initDb } from '../db/postgre.js'; -//const _filename = fileURLToPath(import.meta.url); -const _filename = __filename; +const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8')); @@ -24,22 +24,24 @@ const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json const logger = new Logger('core', 'cyan'); const bootLogger = logger.createSubLogger('boot', 'magenta', false); +const themeColor = chalk.hex('#86b300'); + function greet() { if (!envOption.quiet) { //#region Misskey logo const v = `v${meta.version}`; - console.log(' _____ _ _ '); - console.log(' | |_|___ ___| |_ ___ _ _ '); - console.log(' | | | | |_ -|_ -| \'_| -_| | |'); - console.log(' |_|_|_|_|___|___|_,_|___|_ |'); - console.log(' ' + chalk.gray(v) + (' |___|\n'.substr(v.length))); + console.log(themeColor(' _____ _ _ ')); + console.log(themeColor(' | |_|___ ___| |_ ___ _ _ ')); + console.log(themeColor(' | | | | |_ -|_ -| \'_| -_| | |')); + console.log(themeColor(' |_|_|_|_|___|___|_,_|___|_ |')); + console.log(' ' + chalk.gray(v) + themeColor(' |___|\n'.substr(v.length))); //#endregion console.log(' Misskey is an open-source decentralized microblogging platform.'); - console.log(chalk.keyword('orange')(' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo')); + console.log(chalk.rgb(255, 136, 0)(' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo')); console.log(''); - console.log(chalk`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`); + console.log(chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`); } bootLogger.info('Welcome to Misskey!'); @@ -80,9 +82,9 @@ export async function masterMain() { bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true); if (!envOption.noDaemons) { - require('../daemons/server-stats').default(); - require('../daemons/queue-stats').default(); - require('../daemons/janitor').default(); + import('../daemons/server-stats.js').then(x => x.default()); + import('../daemons/queue-stats.js').then(x => x.default()); + import('../daemons/janitor.js').then(x => x.default()); } } diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts index 362fa3f26..8038e2563 100644 --- a/packages/backend/src/boot/worker.ts +++ b/packages/backend/src/boot/worker.ts @@ -1,5 +1,5 @@ -import * as cluster from 'cluster'; -import { initDb } from '../db/postgre'; +import cluster from 'node:cluster'; +import { initDb } from '../db/postgre.js'; /** * Init worker process @@ -8,10 +8,10 @@ export async function workerMain() { await initDb(); // start server - await require('../server').default(); + await import('../server/index.js').then(x => x.default()); // start job queue - require('../queue').default(); + import('../queue/index.js').then(x => x.default()); if (cluster.isWorker) { // Send a 'ready' message to parent process diff --git a/packages/backend/src/config/index.ts b/packages/backend/src/config/index.ts index 7bfdca461..3e53b0003 100644 --- a/packages/backend/src/config/index.ts +++ b/packages/backend/src/config/index.ts @@ -1,3 +1,3 @@ -import load from './load'; +import load from './load.js'; export default load(); diff --git a/packages/backend/src/config/load.ts b/packages/backend/src/config/load.ts index 1b5457cdb..7f765463e 100644 --- a/packages/backend/src/config/load.ts +++ b/packages/backend/src/config/load.ts @@ -2,14 +2,13 @@ * Config loader */ -import * as fs from 'fs'; -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; +import * as fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; import * as yaml from 'js-yaml'; -import { Source, Mixin } from './types'; +import { Source, Mixin } from './types.js'; -//const _filename = fileURLToPath(import.meta.url); -const _filename = __filename; +const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); /** diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts index e3ca6c1ab..7a1b83c99 100644 --- a/packages/backend/src/config/types.ts +++ b/packages/backend/src/config/types.ts @@ -62,6 +62,7 @@ export type Source = { }; mediaProxy?: string; + proxyRemoteFiles?: boolean; signToActivityPubGet?: boolean; }; diff --git a/packages/backend/src/const.ts b/packages/backend/src/const.ts index b00bd8165..6d3b9559e 100644 --- a/packages/backend/src/const.ts +++ b/packages/backend/src/const.ts @@ -1,3 +1,5 @@ +export const MAX_NOTE_TEXT_LENGTH = 3000; + export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days diff --git a/packages/backend/src/daemons/janitor.ts b/packages/backend/src/daemons/janitor.ts index 115c1fe38..f2a1bfcc2 100644 --- a/packages/backend/src/daemons/janitor.ts +++ b/packages/backend/src/daemons/janitor.ts @@ -1,7 +1,7 @@ // TODO: æļˆã—たい const interval = 30 * 60 * 1000; -import { AttestationChallenges } from '@/models/index'; +import { AttestationChallenges } from '@/models/index.js'; import { LessThan } from 'typeorm'; /** diff --git a/packages/backend/src/daemons/queue-stats.ts b/packages/backend/src/daemons/queue-stats.ts index 5faa16ee4..bfef11054 100644 --- a/packages/backend/src/daemons/queue-stats.ts +++ b/packages/backend/src/daemons/queue-stats.ts @@ -1,7 +1,7 @@ -import Xev from 'xev'; -import { deliverQueue, inboxQueue } from '../queue/queues'; +import { default as Xev } from 'xev'; +import { deliverQueue, inboxQueue } from '../queue/queues.js'; -const ev = new Xev(); +const ev = new Xev.default(); const interval = 10000; diff --git a/packages/backend/src/daemons/server-stats.ts b/packages/backend/src/daemons/server-stats.ts index 47c46042e..327305ccc 100644 --- a/packages/backend/src/daemons/server-stats.ts +++ b/packages/backend/src/daemons/server-stats.ts @@ -1,8 +1,8 @@ -import * as si from 'systeminformation'; -import Xev from 'xev'; +import si from 'systeminformation'; +import { default as Xev } from 'xev'; import * as osUtils from 'os-utils'; -const ev = new Xev(); +const ev = new Xev.default(); const interval = 2000; @@ -36,8 +36,8 @@ export default function() { tx: round(Math.max(0, netStats.tx_sec)), }, fs: { - r: round(Math.max(0, fsStats.rIO_sec)), - w: round(Math.max(0, fsStats.wIO_sec)), + r: round(Math.max(0, fsStats.rIO_sec ?? 0)), + w: round(Math.max(0, fsStats.wIO_sec ?? 0)), }, }; ev.emit('serverStats', stats); @@ -51,9 +51,9 @@ export default function() { } // CPU STAT -function cpuUsage() { +function cpuUsage(): Promise { return new Promise((res, rej) => { - osUtils.cpuUsage((cpuUsage: number) => { + osUtils.cpuUsage((cpuUsage) => { res(cpuUsage); }); }); diff --git a/packages/backend/src/db/elasticsearch.ts b/packages/backend/src/db/elasticsearch.ts index 60a4061d4..d98c5d180 100644 --- a/packages/backend/src/db/elasticsearch.ts +++ b/packages/backend/src/db/elasticsearch.ts @@ -1,5 +1,5 @@ import * as elasticsearch from '@elastic/elasticsearch'; -import config from '@/config/index'; +import config from '@/config/index.js'; const index = { settings: { diff --git a/packages/backend/src/db/logger.ts b/packages/backend/src/db/logger.ts index 62f90555a..22f4c6b1b 100644 --- a/packages/backend/src/db/logger.ts +++ b/packages/backend/src/db/logger.ts @@ -1,3 +1,3 @@ -import Logger from '@/services/logger'; +import Logger from '@/services/logger.js'; export const dbLogger = new Logger('db'); diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts index 69336c2a4..c1f7245bc 100644 --- a/packages/backend/src/db/postgre.ts +++ b/packages/backend/src/db/postgre.ts @@ -1,78 +1,78 @@ // https://github.com/typeorm/typeorm/issues/2400 -const types = require('pg').types; -types.setTypeParser(20, Number); +import pg from 'pg'; +pg.types.setTypeParser(20, Number); import { createConnection, Logger, getConnection } from 'typeorm'; import * as highlight from 'cli-highlight'; -import config from '@/config/index'; +import config from '@/config/index.js'; -import { dbLogger } from './logger'; +import { dbLogger } from './logger.js'; -import { User } from '@/models/entities/user'; -import { DriveFile } from '@/models/entities/drive-file'; -import { DriveFolder } from '@/models/entities/drive-folder'; -import { AccessToken } from '@/models/entities/access-token'; -import { App } from '@/models/entities/app'; -import { PollVote } from '@/models/entities/poll-vote'; -import { Note } from '@/models/entities/note'; -import { NoteReaction } from '@/models/entities/note-reaction'; -import { NoteWatching } from '@/models/entities/note-watching'; -import { NoteThreadMuting } from '@/models/entities/note-thread-muting'; -import { NoteUnread } from '@/models/entities/note-unread'; -import { Notification } from '@/models/entities/notification'; -import { Meta } from '@/models/entities/meta'; -import { Following } from '@/models/entities/following'; -import { Instance } from '@/models/entities/instance'; -import { Muting } from '@/models/entities/muting'; -import { SwSubscription } from '@/models/entities/sw-subscription'; -import { Blocking } from '@/models/entities/blocking'; -import { UserList } from '@/models/entities/user-list'; -import { UserListJoining } from '@/models/entities/user-list-joining'; -import { UserGroup } from '@/models/entities/user-group'; -import { UserGroupJoining } from '@/models/entities/user-group-joining'; -import { UserGroupInvitation } from '@/models/entities/user-group-invitation'; -import { Hashtag } from '@/models/entities/hashtag'; -import { NoteFavorite } from '@/models/entities/note-favorite'; -import { AbuseUserReport } from '@/models/entities/abuse-user-report'; -import { RegistrationTicket } from '@/models/entities/registration-tickets'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { Signin } from '@/models/entities/signin'; -import { AuthSession } from '@/models/entities/auth-session'; -import { FollowRequest } from '@/models/entities/follow-request'; -import { Emoji } from '@/models/entities/emoji'; -import { UserNotePining } from '@/models/entities/user-note-pining'; -import { Poll } from '@/models/entities/poll'; -import { UserKeypair } from '@/models/entities/user-keypair'; -import { UserPublickey } from '@/models/entities/user-publickey'; -import { UserProfile } from '@/models/entities/user-profile'; -import { UserSecurityKey } from '@/models/entities/user-security-key'; -import { AttestationChallenge } from '@/models/entities/attestation-challenge'; -import { Page } from '@/models/entities/page'; -import { PageLike } from '@/models/entities/page-like'; -import { GalleryPost } from '@/models/entities/gallery-post'; -import { GalleryLike } from '@/models/entities/gallery-like'; -import { ModerationLog } from '@/models/entities/moderation-log'; -import { UsedUsername } from '@/models/entities/used-username'; -import { Announcement } from '@/models/entities/announcement'; -import { AnnouncementRead } from '@/models/entities/announcement-read'; -import { Clip } from '@/models/entities/clip'; -import { ClipNote } from '@/models/entities/clip-note'; -import { Antenna } from '@/models/entities/antenna'; -import { AntennaNote } from '@/models/entities/antenna-note'; -import { PromoNote } from '@/models/entities/promo-note'; -import { PromoRead } from '@/models/entities/promo-read'; -import { envOption } from '../env'; -import { Relay } from '@/models/entities/relay'; -import { MutedNote } from '@/models/entities/muted-note'; -import { Channel } from '@/models/entities/channel'; -import { ChannelFollowing } from '@/models/entities/channel-following'; -import { ChannelNotePining } from '@/models/entities/channel-note-pining'; -import { RegistryItem } from '@/models/entities/registry-item'; -import { Ad } from '@/models/entities/ad'; -import { PasswordResetRequest } from '@/models/entities/password-reset-request'; -import { UserPending } from '@/models/entities/user-pending'; +import { User } from '@/models/entities/user.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { DriveFolder } from '@/models/entities/drive-folder.js'; +import { AccessToken } from '@/models/entities/access-token.js'; +import { App } from '@/models/entities/app.js'; +import { PollVote } from '@/models/entities/poll-vote.js'; +import { Note } from '@/models/entities/note.js'; +import { NoteReaction } from '@/models/entities/note-reaction.js'; +import { NoteWatching } from '@/models/entities/note-watching.js'; +import { NoteThreadMuting } from '@/models/entities/note-thread-muting.js'; +import { NoteUnread } from '@/models/entities/note-unread.js'; +import { Notification } from '@/models/entities/notification.js'; +import { Meta } from '@/models/entities/meta.js'; +import { Following } from '@/models/entities/following.js'; +import { Instance } from '@/models/entities/instance.js'; +import { Muting } from '@/models/entities/muting.js'; +import { SwSubscription } from '@/models/entities/sw-subscription.js'; +import { Blocking } from '@/models/entities/blocking.js'; +import { UserList } from '@/models/entities/user-list.js'; +import { UserListJoining } from '@/models/entities/user-list-joining.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { UserGroupJoining } from '@/models/entities/user-group-joining.js'; +import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js'; +import { Hashtag } from '@/models/entities/hashtag.js'; +import { NoteFavorite } from '@/models/entities/note-favorite.js'; +import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; +import { RegistrationTicket } from '@/models/entities/registration-tickets.js'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import { Signin } from '@/models/entities/signin.js'; +import { AuthSession } from '@/models/entities/auth-session.js'; +import { FollowRequest } from '@/models/entities/follow-request.js'; +import { Emoji } from '@/models/entities/emoji.js'; +import { UserNotePining } from '@/models/entities/user-note-pining.js'; +import { Poll } from '@/models/entities/poll.js'; +import { UserKeypair } from '@/models/entities/user-keypair.js'; +import { UserPublickey } from '@/models/entities/user-publickey.js'; +import { UserProfile } from '@/models/entities/user-profile.js'; +import { UserSecurityKey } from '@/models/entities/user-security-key.js'; +import { AttestationChallenge } from '@/models/entities/attestation-challenge.js'; +import { Page } from '@/models/entities/page.js'; +import { PageLike } from '@/models/entities/page-like.js'; +import { GalleryPost } from '@/models/entities/gallery-post.js'; +import { GalleryLike } from '@/models/entities/gallery-like.js'; +import { ModerationLog } from '@/models/entities/moderation-log.js'; +import { UsedUsername } from '@/models/entities/used-username.js'; +import { Announcement } from '@/models/entities/announcement.js'; +import { AnnouncementRead } from '@/models/entities/announcement-read.js'; +import { Clip } from '@/models/entities/clip.js'; +import { ClipNote } from '@/models/entities/clip-note.js'; +import { Antenna } from '@/models/entities/antenna.js'; +import { AntennaNote } from '@/models/entities/antenna-note.js'; +import { PromoNote } from '@/models/entities/promo-note.js'; +import { PromoRead } from '@/models/entities/promo-read.js'; +import { envOption } from '../env.js'; +import { Relay } from '@/models/entities/relay.js'; +import { MutedNote } from '@/models/entities/muted-note.js'; +import { Channel } from '@/models/entities/channel.js'; +import { ChannelFollowing } from '@/models/entities/channel-following.js'; +import { ChannelNotePining } from '@/models/entities/channel-note-pining.js'; +import { RegistryItem } from '@/models/entities/registry-item.js'; +import { Ad } from '@/models/entities/ad.js'; +import { PasswordResetRequest } from '@/models/entities/password-reset-request.js'; +import { UserPending } from '@/models/entities/user-pending.js'; -import { entities as charts } from '@/services/chart/entities'; +import { entities as charts } from '@/services/chart/entities.js'; const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); diff --git a/packages/backend/src/db/redis.ts b/packages/backend/src/db/redis.ts index 9fc2b6241..934604145 100644 --- a/packages/backend/src/db/redis.ts +++ b/packages/backend/src/db/redis.ts @@ -1,5 +1,5 @@ import * as redis from 'redis'; -import config from '@/config/index'; +import config from '@/config/index.js'; export function createConnection() { return redis.createClient( diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 5e4e377ab..bd9c0098b 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -2,10 +2,12 @@ * Misskey Entry Point! */ +import { EventEmitter } from 'node:events'; +import boot from './boot/index.js'; + Error.stackTraceLimit = Infinity; +EventEmitter.defaultMaxListeners = 128; -require('events').EventEmitter.defaultMaxListeners = 128; - -import boot from './boot/index'; - -boot(); +boot().catch(err => { + console.error(err); +}); diff --git a/packages/backend/src/mfm/from-html.ts b/packages/backend/src/mfm/from-html.ts index fc6d3b306..623cb0e71 100644 --- a/packages/backend/src/mfm/from-html.ts +++ b/packages/backend/src/mfm/from-html.ts @@ -1,13 +1,11 @@ import * as parse5 from 'parse5'; -import treeAdapter = require('parse5/lib/tree-adapters/default'); -import { URL } from 'url'; +import treeAdapter from 'parse5/lib/tree-adapters/default.js'; +import { URL } from 'node:url'; const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/; const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/; -export function fromHtml(html: string, hashtagNames?: string[]): string | null { - if (html == null) return null; - +export function fromHtml(html: string, hashtagNames?: string[]): string { const dom = parse5.parseFragment(html); let text = ''; diff --git a/packages/backend/src/mfm/to-html.ts b/packages/backend/src/mfm/to-html.ts index b16c6b95e..5b382063e 100644 --- a/packages/backend/src/mfm/to-html.ts +++ b/packages/backend/src/mfm/to-html.ts @@ -1,8 +1,8 @@ import { JSDOM } from 'jsdom'; import * as mfm from 'mfm-js'; -import config from '@/config/index'; -import { intersperse } from '@/prelude/array'; -import { IMentionedRemoteUsers } from '@/models/entities/note'; +import config from '@/config/index.js'; +import { intersperse } from '@/prelude/array.js'; +import { IMentionedRemoteUsers } from '@/models/entities/note.js'; export function toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) { if (nodes == null) { diff --git a/packages/backend/src/misc/acct.ts b/packages/backend/src/misc/acct.ts new file mode 100644 index 000000000..c32cee86c --- /dev/null +++ b/packages/backend/src/misc/acct.ts @@ -0,0 +1,14 @@ +export type Acct = { + username: string; + host: string | null; +}; + +export function parse(acct: string): Acct { + if (acct.startsWith('@')) acct = acct.substr(1); + const split = acct.split('@', 2); + return { username: split[0], host: split[1] || null }; +} + +export function toString(acct: Acct): string { + return acct.host == null ? acct.username : `${acct.username}@${acct.host}`; +} diff --git a/packages/backend/src/misc/antenna-cache.ts b/packages/backend/src/misc/antenna-cache.ts index a23eeb45e..dcf96c161 100644 --- a/packages/backend/src/misc/antenna-cache.ts +++ b/packages/backend/src/misc/antenna-cache.ts @@ -1,6 +1,6 @@ -import { Antennas } from '@/models/index'; -import { Antenna } from '@/models/entities/antenna'; -import { subsdcriber } from '../db/redis'; +import { Antennas } from '@/models/index.js'; +import { Antenna } from '@/models/entities/antenna.js'; +import { subsdcriber } from '../db/redis.js'; let antennasFetched = false; let antennas: Antenna[] = []; diff --git a/packages/backend/src/misc/app-lock.ts b/packages/backend/src/misc/app-lock.ts index a32b60061..b5089cc6a 100644 --- a/packages/backend/src/misc/app-lock.ts +++ b/packages/backend/src/misc/app-lock.ts @@ -1,6 +1,6 @@ -import { redisClient } from '../db/redis'; -import { promisify } from 'util'; -import * as redisLock from 'redis-lock'; +import { redisClient } from '../db/redis.js'; +import { promisify } from 'node:util'; +import redisLock from 'redis-lock'; /** * Retry delay (ms) for lock acquisition diff --git a/packages/backend/src/misc/before-shutdown.ts b/packages/backend/src/misc/before-shutdown.ts index 33abf5fb4..93ac7a1f3 100644 --- a/packages/backend/src/misc/before-shutdown.ts +++ b/packages/backend/src/misc/before-shutdown.ts @@ -24,14 +24,14 @@ const SHUTDOWN_TIMEOUT = 15000; * down the process. * @type {BeforeShutdownListener[]} */ -const shutdownListeners = []; +const shutdownListeners: ((signalOrEvent: string) => void)[] = []; /** * Listen for signals and execute given `fn` function once. * @param {string[]} signals System signals to listen to. * @param {function(string)} fn Function to execute on shutdown. */ -const processOnce = (signals, fn) => { +const processOnce = (signals: string[], fn: (signalOrEvent: string) => void) => { for (const sig of signals) { process.once(sig, fn); } @@ -41,7 +41,7 @@ const processOnce = (signals, fn) => { * Sets a forced shutdown mechanism that will exit the process after `timeout` milliseconds. * @param {number} timeout Time to wait before forcing shutdown (milliseconds) */ -const forceExitAfter = timeout => () => { +const forceExitAfter = (timeout: number) => () => { setTimeout(() => { // Force shutdown after timeout console.warn(`Could not close resources gracefully after ${timeout}ms: forcing shutdown`); @@ -55,7 +55,7 @@ const forceExitAfter = timeout => () => { * be logged out as a warning, but won't prevent other callbacks from executing. * @param {string} signalOrEvent The exit signal or event name received on the process. */ -async function shutdownHandler(signalOrEvent) { +async function shutdownHandler(signalOrEvent: string) { if (process.env.NODE_ENV === 'test') return process.exit(0); console.warn(`Shutting down: received [${signalOrEvent}] signal`); @@ -64,7 +64,9 @@ async function shutdownHandler(signalOrEvent) { try { await listener(signalOrEvent); } catch (err) { - console.warn(`A shutdown handler failed before completing with: ${err.message || err}`); + if (err instanceof Error) { + console.warn(`A shutdown handler failed before completing with: ${err.message || err}`); + } } } @@ -78,7 +80,7 @@ async function shutdownHandler(signalOrEvent) { * @param {BeforeShutdownListener} listener The shutdown listener to register. * @returns {BeforeShutdownListener} Echoes back the supplied `listener`. */ -export function beforeShutdown(listener) { +export function beforeShutdown(listener: () => void) { shutdownListeners.push(listener); return listener; } diff --git a/packages/backend/src/misc/captcha.ts b/packages/backend/src/misc/captcha.ts index 41a986d78..293cbdcd3 100644 --- a/packages/backend/src/misc/captcha.ts +++ b/packages/backend/src/misc/captcha.ts @@ -1,7 +1,7 @@ import fetch from 'node-fetch'; -import { URLSearchParams } from 'url'; -import { getAgentByUrl } from './fetch'; -import config from '@/config/index'; +import { URLSearchParams } from 'node:url'; +import { getAgentByUrl } from './fetch.js'; +import config from '@/config/index.js'; export async function verifyRecaptcha(secret: string, response: string) { const result = await getCaptchaResponse('https://www.recaptcha.net/recaptcha/api/siteverify', secret, response).catch(e => { diff --git a/packages/backend/src/misc/check-hit-antenna.ts b/packages/backend/src/misc/check-hit-antenna.ts index 3c39a337f..ceb74d690 100644 --- a/packages/backend/src/misc/check-hit-antenna.ts +++ b/packages/backend/src/misc/check-hit-antenna.ts @@ -1,10 +1,10 @@ -import { Antenna } from '@/models/entities/antenna'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; -import { UserListJoinings, UserGroupJoinings } from '@/models/index'; -import { getFullApAccount } from './convert-host'; -import * as Acct from 'misskey-js/built/acct'; -import { Packed } from './schema'; +import { Antenna } from '@/models/entities/antenna.js'; +import { Note } from '@/models/entities/note.js'; +import { User } from '@/models/entities/user.js'; +import { UserListJoinings, UserGroupJoinings } from '@/models/index.js'; +import { getFullApAccount } from './convert-host.js'; +import * as Acct from '@/misc/acct.js'; +import { Packed } from './schema.js'; /** * noteUserFollowers / antennaUserFollowing ã¯ãŠãĄã‚‰ã‹ä¸€æ–šãŒæŒ‡åŽšã•ã‚ŒãĻいればよい diff --git a/packages/backend/src/misc/check-word-mute.ts b/packages/backend/src/misc/check-word-mute.ts index e2e871dd2..588dc79e5 100644 --- a/packages/backend/src/misc/check-word-mute.ts +++ b/packages/backend/src/misc/check-word-mute.ts @@ -1,6 +1,6 @@ -const RE2 = require('re2'); -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; +import RE2 from 're2'; +import { Note } from '@/models/entities/note.js'; +import { User } from '@/models/entities/user.js'; type NoteLike = { userId: Note['userId']; @@ -11,26 +11,31 @@ type UserLike = { id: User['id']; }; -export async function checkWordMute(note: NoteLike, me: UserLike | null | undefined, mutedWords: string[][]): Promise { +export async function checkWordMute(note: NoteLike, me: UserLike | null | undefined, mutedWords: Array): Promise { // č‡Ē分č‡ĒčēĢ if (me && (note.userId === me.id)) return false; - const words = mutedWords - // Clean up - .map(xs => xs.filter(x => x !== '')) - .filter(xs => xs.length > 0); - - if (words.length > 0) { + if (mutedWords.length > 0) { if (note.text == null) return false; - const matched = words.some(and => - and.every(keyword => { - const regexp = keyword.match(/^\/(.+)\/(.*)$/); - if (regexp) { + const matched = mutedWords.some(filter => { + if (Array.isArray(filter)) { + return filter.every(keyword => note.text!.includes(keyword)); + } else { + // represents RegExp + const regexp = filter.match(/^\/(.+)\/(.*)$/); + + // This should never happen due to input sanitisation. + if (!regexp) return false; + + try { return new RE2(regexp[1], regexp[2]).test(note.text!); + } catch (err) { + // This should never happen due to input sanitisation. + return false; } - return note.text!.includes(keyword); - })); + } + }); if (matched) return true; } diff --git a/packages/backend/src/misc/content-disposition.ts b/packages/backend/src/misc/content-disposition.ts index 9df7ed468..b2aec471d 100644 --- a/packages/backend/src/misc/content-disposition.ts +++ b/packages/backend/src/misc/content-disposition.ts @@ -1,4 +1,4 @@ -const cd = require('content-disposition'); +import cd from 'content-disposition'; export function contentDisposition(type: 'inline' | 'attachment', filename: string): string { const fallback = filename.replace(/[^\w.-]/g, '_'); diff --git a/packages/backend/src/misc/convert-host.ts b/packages/backend/src/misc/convert-host.ts index 6e9f6ed3e..7eb940a7e 100644 --- a/packages/backend/src/misc/convert-host.ts +++ b/packages/backend/src/misc/convert-host.ts @@ -1,6 +1,6 @@ -import { URL } from 'url'; -import config from '@/config/index'; -import { toASCII } from 'punycode/'; +import { URL } from 'node:url'; +import config from '@/config/index.js'; +import { toASCII } from 'punycode'; export function getFullApAccount(username: string, host: string | null) { return host ? `${username}@${toPuny(host)}` : `${username}@${toPuny(config.host)}`; diff --git a/packages/backend/src/misc/count-same-renotes.ts b/packages/backend/src/misc/count-same-renotes.ts index 662876118..b7f8ce90c 100644 --- a/packages/backend/src/misc/count-same-renotes.ts +++ b/packages/backend/src/misc/count-same-renotes.ts @@ -1,4 +1,4 @@ -import { Notes } from '@/models/index'; +import { Notes } from '@/models/index.js'; export async function countSameRenotes(userId: string, renoteId: string, excludeNoteId: string | undefined): Promise { // 指厚したãƒĻãƒŧã‚ļãƒŧぎ指厚したノãƒŧトぎãƒĒノãƒŧトがいくつあるか数える diff --git a/packages/backend/src/misc/detect-url-mime.ts b/packages/backend/src/misc/detect-url-mime.ts index 274c29173..cd143cf2f 100644 --- a/packages/backend/src/misc/detect-url-mime.ts +++ b/packages/backend/src/misc/detect-url-mime.ts @@ -1,6 +1,6 @@ -import { createTemp } from './create-temp'; -import { downloadUrl } from './download-url'; -import { detectType } from './get-file-info'; +import { createTemp } from './create-temp.js'; +import { downloadUrl } from './download-url.js'; +import { detectType } from './get-file-info.js'; export async function detectUrlMime(url: string) { const [path, cleanup] = await createTemp(); diff --git a/packages/backend/src/misc/download-text-file.ts b/packages/backend/src/misc/download-text-file.ts index e8e23cc12..c62c70ee3 100644 --- a/packages/backend/src/misc/download-text-file.ts +++ b/packages/backend/src/misc/download-text-file.ts @@ -1,8 +1,8 @@ -import * as fs from 'fs'; -import * as util from 'util'; -import Logger from '@/services/logger'; -import { createTemp } from './create-temp'; -import { downloadUrl } from './download-url'; +import * as fs from 'node:fs'; +import * as util from 'node:util'; +import Logger from '@/services/logger.js'; +import { createTemp } from './create-temp.js'; +import { downloadUrl } from './download-url.js'; const logger = new Logger('download-text-file'); diff --git a/packages/backend/src/misc/download-url.ts b/packages/backend/src/misc/download-url.ts index 8e1f7b9e2..21eee57b3 100644 --- a/packages/backend/src/misc/download-url.ts +++ b/packages/backend/src/misc/download-url.ts @@ -1,13 +1,13 @@ -import * as fs from 'fs'; -import * as stream from 'stream'; -import * as util from 'util'; +import * as fs from 'node:fs'; +import * as stream from 'node:stream'; +import * as util from 'node:util'; import got, * as Got from 'got'; -import { httpAgent, httpsAgent, StatusError } from './fetch'; -import config from '@/config/index'; -import * as chalk from 'chalk'; -import Logger from '@/services/logger'; +import { httpAgent, httpsAgent, StatusError } from './fetch.js'; +import config from '@/config/index.js'; +import chalk from 'chalk'; +import Logger from '@/services/logger.js'; import * as IPCIDR from 'ip-cidr'; -const PrivateIp = require('private-ip'); +import PrivateIp from 'private-ip'; const pipeline = util.promisify(stream.pipeline); @@ -38,7 +38,9 @@ export async function downloadUrl(url: string, path: string): Promise { https: httpsAgent, }, http2: false, // default - retry: 0, + retry: { + limit: 0, + }, }).on('response', (res: Got.Response) => { if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !config.proxy && res.ip) { if (isPrivateIp(res.ip)) { @@ -75,7 +77,7 @@ export async function downloadUrl(url: string, path: string): Promise { logger.succ(`Download finished: ${chalk.cyan(url)}`); } -function isPrivateIp(ip: string) { +function isPrivateIp(ip: string): boolean { for (const net of config.allowedPrivateNetworks || []) { const cidr = new IPCIDR(net); if (cidr.contains(ip)) { diff --git a/packages/backend/src/misc/emoji-regex.ts b/packages/backend/src/misc/emoji-regex.ts index 8b07fbd8f..ca224971c 100644 --- a/packages/backend/src/misc/emoji-regex.ts +++ b/packages/backend/src/misc/emoji-regex.ts @@ -1,3 +1,4 @@ -const twemojiRegex = require('twemoji-parser/dist/lib/regex').default; +import twemoji from 'twemoji-parser/dist/lib/regex.js'; +const twemojiRegex = twemoji.default; export const emojiRegex = new RegExp(`(${twemojiRegex.source})`); diff --git a/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts b/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts index b29ce281b..a0319d8dd 100644 --- a/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts +++ b/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts @@ -1,5 +1,5 @@ import * as mfm from 'mfm-js'; -import { unique } from '@/prelude/array'; +import { unique } from '@/prelude/array.js'; export function extractCustomEmojisFromMfm(nodes: mfm.MfmNode[]): string[] { const emojiNodes = mfm.extract(nodes, (node) => { diff --git a/packages/backend/src/misc/extract-hashtags.ts b/packages/backend/src/misc/extract-hashtags.ts index b0a74df21..0b0418eef 100644 --- a/packages/backend/src/misc/extract-hashtags.ts +++ b/packages/backend/src/misc/extract-hashtags.ts @@ -1,5 +1,5 @@ import * as mfm from 'mfm-js'; -import { unique } from '@/prelude/array'; +import { unique } from '@/prelude/array.js'; export function extractHashtags(nodes: mfm.MfmNode[]): string[] { const hashtagNodes = mfm.extract(nodes, (node) => node.type === 'hashtag'); diff --git a/packages/backend/src/misc/fetch-meta.ts b/packages/backend/src/misc/fetch-meta.ts index b7b055d18..9f85d3d1d 100644 --- a/packages/backend/src/misc/fetch-meta.ts +++ b/packages/backend/src/misc/fetch-meta.ts @@ -1,4 +1,4 @@ -import { Meta } from '@/models/entities/meta'; +import { Meta } from '@/models/entities/meta.js'; import { getConnection } from 'typeorm'; let cache: Meta; diff --git a/packages/backend/src/misc/fetch-proxy-account.ts b/packages/backend/src/misc/fetch-proxy-account.ts index e0eedea4c..ed8a4c794 100644 --- a/packages/backend/src/misc/fetch-proxy-account.ts +++ b/packages/backend/src/misc/fetch-proxy-account.ts @@ -1,6 +1,6 @@ -import { fetchMeta } from './fetch-meta'; -import { ILocalUser } from '@/models/entities/user'; -import { Users } from '@/models/index'; +import { fetchMeta } from './fetch-meta.js'; +import { ILocalUser } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; export async function fetchProxyAccount(): Promise { const meta = await fetchMeta(); diff --git a/packages/backend/src/misc/fetch.ts b/packages/backend/src/misc/fetch.ts index baebab192..47a5cd471 100644 --- a/packages/backend/src/misc/fetch.ts +++ b/packages/backend/src/misc/fetch.ts @@ -3,8 +3,8 @@ import * as https from 'https'; import CacheableLookup from 'cacheable-lookup'; import fetch from 'node-fetch'; import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent'; -import config from '@/config/index'; -import { URL } from 'url'; +import config from '@/config/index.js'; +import { URL } from 'node:url'; export async function getJson(url: string, accept = 'application/json, */*', timeout = 10000, headers?: Record) { const res = await getResponse({ diff --git a/packages/backend/src/misc/gen-id.ts b/packages/backend/src/misc/gen-id.ts index b1b542dc4..fcf476857 100644 --- a/packages/backend/src/misc/gen-id.ts +++ b/packages/backend/src/misc/gen-id.ts @@ -1,9 +1,9 @@ import { ulid } from 'ulid'; -import { genAid } from './id/aid'; -import { genMeid } from './id/meid'; -import { genMeidg } from './id/meidg'; -import { genObjectId } from './id/object-id'; -import config from '@/config/index'; +import { genAid } from './id/aid.js'; +import { genMeid } from './id/meid.js'; +import { genMeidg } from './id/meidg.js'; +import { genObjectId } from './id/object-id.js'; +import config from '@/config/index.js'; const metohd = config.id.toLowerCase(); diff --git a/packages/backend/src/misc/gen-identicon.ts b/packages/backend/src/misc/gen-identicon.ts index 5cedd7afa..9b30e5dbd 100644 --- a/packages/backend/src/misc/gen-identicon.ts +++ b/packages/backend/src/misc/gen-identicon.ts @@ -3,9 +3,9 @@ * https://en.wikipedia.org/wiki/Identicon */ +import { WriteStream } from 'node:fs'; import * as p from 'pureimage'; -import * as gen from 'random-seed'; -import { WriteStream } from 'fs'; +import gen from 'random-seed'; const size = 256; // px const n = 5; // resolution @@ -39,7 +39,7 @@ const sideN = Math.floor(n / 2); */ export function genIdenticon(seed: string, stream: WriteStream): Promise { const rand = gen.create(seed); - const canvas = p.make(size, size); + const canvas = p.make(size, size, undefined); const ctx = canvas.getContext('2d'); ctx.fillStyle = bg; diff --git a/packages/backend/src/misc/gen-key-pair.ts b/packages/backend/src/misc/gen-key-pair.ts index 9db6b2a3e..e2ad59850 100644 --- a/packages/backend/src/misc/gen-key-pair.ts +++ b/packages/backend/src/misc/gen-key-pair.ts @@ -1,5 +1,5 @@ -import * as crypto from 'crypto'; -import * as util from 'util'; +import * as crypto from 'node:crypto'; +import * as util from 'node:util'; const generateKeyPair = util.promisify(crypto.generateKeyPair); diff --git a/packages/backend/src/misc/get-file-info.ts b/packages/backend/src/misc/get-file-info.ts index 361cdd295..48a5b40cc 100644 --- a/packages/backend/src/misc/get-file-info.ts +++ b/packages/backend/src/misc/get-file-info.ts @@ -1,11 +1,11 @@ -import * as fs from 'fs'; -import * as crypto from 'crypto'; -import * as stream from 'stream'; -import * as util from 'util'; -import * as fileType from 'file-type'; +import * as fs from 'node:fs'; +import * as crypto from 'node:crypto'; +import * as stream from 'node:stream'; +import * as util from 'node:util'; +import fileType from 'file-type'; import isSvg from 'is-svg'; -import * as probeImageSize from 'probe-image-size'; -import * as sharp from 'sharp'; +import probeImageSize from 'probe-image-size'; +import sharp from 'sharp'; import { encode } from 'blurhash'; const pipeline = util.promisify(stream.pipeline); diff --git a/packages/backend/src/misc/get-note-summary.ts b/packages/backend/src/misc/get-note-summary.ts index d7273d1c5..93783873d 100644 --- a/packages/backend/src/misc/get-note-summary.ts +++ b/packages/backend/src/misc/get-note-summary.ts @@ -1,4 +1,4 @@ -import { Packed } from './schema'; +import { Packed } from './schema.js'; /** * 投į¨ŋã‚’čĄ¨ã™æ–‡å­—åˆ—ã‚’å–åž—ã—ãžã™ã€‚ diff --git a/packages/backend/src/misc/id/aid.ts b/packages/backend/src/misc/id/aid.ts index 2bcde90bf..87e688826 100644 --- a/packages/backend/src/misc/id/aid.ts +++ b/packages/backend/src/misc/id/aid.ts @@ -1,7 +1,7 @@ // AID // é•ˇã•8ぎ[2000åš´1月1æ—ĨからぎįĩŒéŽãƒŸãƒĒį§’ã‚’base36でエãƒŗã‚ŗãƒŧドしたもぎ] + é•ˇã•2ぎ[ノイã‚ē文字列] -import * as crypto from 'crypto'; +import * as crypto from 'node:crypto'; const TIME2000 = 946684800000; let counter = crypto.randomBytes(2).readUInt16LE(0); diff --git a/packages/backend/src/misc/is-duplicate-key-value-error.ts b/packages/backend/src/misc/is-duplicate-key-value-error.ts index 23d8ceb1b..04ff191e4 100644 --- a/packages/backend/src/misc/is-duplicate-key-value-error.ts +++ b/packages/backend/src/misc/is-duplicate-key-value-error.ts @@ -1,3 +1,3 @@ -export function isDuplicateKeyValueError(e: Error): boolean { - return e.message.startsWith('duplicate key value'); +export function isDuplicateKeyValueError(e: unknown | Error): boolean { + return (e as any).message && (e as Error).message.startsWith('duplicate key value'); } diff --git a/packages/backend/src/misc/is-instance-muted.ts b/packages/backend/src/misc/is-instance-muted.ts index 2e1785b51..a74ba524e 100644 --- a/packages/backend/src/misc/is-instance-muted.ts +++ b/packages/backend/src/misc/is-instance-muted.ts @@ -1,4 +1,4 @@ -import { Packed } from "./schema"; +import { Packed } from './schema.js'; export function isInstanceMuted(note: Packed<'Note'>, mutedInstances: Set): boolean { if (mutedInstances.has(note?.user?.host ?? '')) return true; diff --git a/packages/backend/src/misc/is-quote.ts b/packages/backend/src/misc/is-quote.ts index 2b57f036a..779f548b0 100644 --- a/packages/backend/src/misc/is-quote.ts +++ b/packages/backend/src/misc/is-quote.ts @@ -1,4 +1,4 @@ -import { Note } from '@/models/entities/note'; +import { Note } from '@/models/entities/note.js'; export default function(note: Note): boolean { return note.renoteId != null && (note.text != null || note.hasPoll || (note.fileIds != null && note.fileIds.length > 0)); diff --git a/packages/backend/src/misc/keypair-store.ts b/packages/backend/src/misc/keypair-store.ts index c018013b7..3d505c0ab 100644 --- a/packages/backend/src/misc/keypair-store.ts +++ b/packages/backend/src/misc/keypair-store.ts @@ -1,7 +1,7 @@ -import { UserKeypairs } from '@/models/index'; -import { User } from '@/models/entities/user'; -import { UserKeypair } from '@/models/entities/user-keypair'; -import { Cache } from './cache'; +import { UserKeypairs } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; +import { UserKeypair } from '@/models/entities/user-keypair.js'; +import { Cache } from './cache.js'; const cache = new Cache(Infinity); diff --git a/packages/backend/src/misc/langmap.ts b/packages/backend/src/misc/langmap.ts new file mode 100644 index 000000000..5ee85e6c0 --- /dev/null +++ b/packages/backend/src/misc/langmap.ts @@ -0,0 +1,666 @@ +// TODO: sharedãĢįŊŽã„ãĻフロãƒŗトエãƒŗドぎとįĩąåˆã—たい +export const langmap = { + 'ach': { + nativeName: 'Lwo', + }, + 'ady': { + nativeName: 'АдŅ‹ĐŗŅĐąĐˇŅ', + }, + 'af': { + nativeName: 'Afrikaans', + }, + 'af-NA': { + nativeName: 'Afrikaans (Namibia)', + }, + 'af-ZA': { + nativeName: 'Afrikaans (South Africa)', + }, + 'ak': { + nativeName: 'TɕÉĨi', + }, + 'ar': { + nativeName: 'اŲ„ØšØąØ¨ŲŠØŠ', + }, + 'ar-AR': { + nativeName: 'اŲ„ØšØąØ¨ŲŠØŠ', + }, + 'ar-MA': { + nativeName: 'اŲ„ØšØąØ¨ŲŠØŠ', + }, + 'ar-SA': { + nativeName: 'اŲ„ØšØąØ¨ŲŠØŠ (اŲ„ØŗØšŲˆØ¯ŲŠØŠ)', + }, + 'ay-BO': { + nativeName: 'Aymar aru', + }, + 'az': { + nativeName: 'Azərbaycan dili', + }, + 'az-AZ': { + nativeName: 'Azərbaycan dili', + }, + 'be-BY': { + nativeName: 'БĐĩĐģĐ°Ņ€ŅƒŅĐēĐ°Ņ', + }, + 'bg': { + nativeName: 'БŅŠĐģĐŗĐ°Ņ€ŅĐēи', + }, + 'bg-BG': { + nativeName: 'БŅŠĐģĐŗĐ°Ņ€ŅĐēи', + }, + 'bn': { + nativeName: 'āĻŦāĻžāĻ‚āĻ˛āĻž', + }, + 'bn-IN': { + nativeName: 'āĻŦāĻžāĻ‚āĻ˛āĻž (āĻ­āĻžāĻ°āĻ¤)', + }, + 'bn-BD': { + nativeName: 'āĻŦāĻžāĻ‚āĻ˛āĻž(āĻŦāĻžāĻ‚āĻ˛āĻžāĻĻā§‡āĻļ)', + }, + 'br': { + nativeName: 'Brezhoneg', + }, + 'bs-BA': { + nativeName: 'Bosanski', + }, + 'ca': { + nativeName: 'Català', + }, + 'ca-ES': { + nativeName: 'Català', + }, + 'cak': { + nativeName: 'Maya Kaqchikel', + }, + 'ck-US': { + nativeName: 'áŖáŽŗᎊ (tsalagi)', + }, + 'cs': { + nativeName: 'ČeÅĄtina', + }, + 'cs-CZ': { + nativeName: 'ČeÅĄtina', + }, + 'cy': { + nativeName: 'Cymraeg', + }, + 'cy-GB': { + nativeName: 'Cymraeg', + }, + 'da': { + nativeName: 'Dansk', + }, + 'da-DK': { + nativeName: 'Dansk', + }, + 'de': { + nativeName: 'Deutsch', + }, + 'de-AT': { + nativeName: 'Deutsch (Österreich)', + }, + 'de-DE': { + nativeName: 'Deutsch (Deutschland)', + }, + 'de-CH': { + nativeName: 'Deutsch (Schweiz)', + }, + 'dsb': { + nativeName: 'DolnoserbÅĄÄ‡ina', + }, + 'el': { + nativeName: 'ΕÎģÎģΡÎŊΚÎēÎŦ', + }, + 'el-GR': { + nativeName: 'ΕÎģÎģΡÎŊΚÎēÎŦ', + }, + 'en': { + nativeName: 'English', + }, + 'en-GB': { + nativeName: 'English (UK)', + }, + 'en-AU': { + nativeName: 'English (Australia)', + }, + 'en-CA': { + nativeName: 'English (Canada)', + }, + 'en-IE': { + nativeName: 'English (Ireland)', + }, + 'en-IN': { + nativeName: 'English (India)', + }, + 'en-PI': { + nativeName: 'English (Pirate)', + }, + 'en-SG': { + nativeName: 'English (Singapore)', + }, + 'en-UD': { + nativeName: 'English (Upside Down)', + }, + 'en-US': { + nativeName: 'English (US)', + }, + 'en-ZA': { + nativeName: 'English (South Africa)', + }, + 'en@pirate': { + nativeName: 'English (Pirate)', + }, + 'eo': { + nativeName: 'Esperanto', + }, + 'eo-EO': { + nativeName: 'Esperanto', + }, + 'es': { + nativeName: 'EspaÃąol', + }, + 'es-AR': { + nativeName: 'EspaÃąol (Argentine)', + }, + 'es-419': { + nativeName: 'EspaÃąol (LatinoamÊrica)', + }, + 'es-CL': { + nativeName: 'EspaÃąol (Chile)', + }, + 'es-CO': { + nativeName: 'EspaÃąol (Colombia)', + }, + 'es-EC': { + nativeName: 'EspaÃąol (Ecuador)', + }, + 'es-ES': { + nativeName: 'EspaÃąol (EspaÃąa)', + }, + 'es-LA': { + nativeName: 'EspaÃąol (LatinoamÊrica)', + }, + 'es-NI': { + nativeName: 'EspaÃąol (Nicaragua)', + }, + 'es-MX': { + nativeName: 'EspaÃąol (MÊxico)', + }, + 'es-US': { + nativeName: 'EspaÃąol (Estados Unidos)', + }, + 'es-VE': { + nativeName: 'EspaÃąol (Venezuela)', + }, + 'et': { + nativeName: 'eesti keel', + }, + 'et-EE': { + nativeName: 'Eesti (Estonia)', + }, + 'eu': { + nativeName: 'Euskara', + }, + 'eu-ES': { + nativeName: 'Euskara', + }, + 'fa': { + nativeName: 'ŲØ§ØąØŗی', + }, + 'fa-IR': { + nativeName: 'ŲØ§ØąØŗی', + }, + 'fb-LT': { + nativeName: 'Leet Speak', + }, + 'ff': { + nativeName: 'Fulah', + }, + 'fi': { + nativeName: 'Suomi', + }, + 'fi-FI': { + nativeName: 'Suomi', + }, + 'fo': { + nativeName: 'Føroyskt', + }, + 'fo-FO': { + nativeName: 'Føroyskt (FÃĻreyjar)', + }, + 'fr': { + nativeName: 'Français', + }, + 'fr-CA': { + nativeName: 'Français (Canada)', + }, + 'fr-FR': { + nativeName: 'Français (France)', + }, + 'fr-BE': { + nativeName: 'Français (Belgique)', + }, + 'fr-CH': { + nativeName: 'Français (Suisse)', + }, + 'fy-NL': { + nativeName: 'Frysk', + }, + 'ga': { + nativeName: 'Gaeilge', + }, + 'ga-IE': { + nativeName: 'Gaeilge', + }, + 'gd': { + nativeName: 'Gàidhlig', + }, + 'gl': { + nativeName: 'Galego', + }, + 'gl-ES': { + nativeName: 'Galego', + }, + 'gn-PY': { + nativeName: 'AvaÃąe\'áēŊ', + }, + 'gu-IN': { + nativeName: 'āĒ—āĢāĒœāĒ°āĒžāĒ¤āĢ€', + }, + 'gv': { + nativeName: 'Gaelg', + }, + 'gx-GR': { + nativeName: 'áŧ™ÎģÎģΡÎŊΚÎēÎŽ áŧ€ĪĪ‡ÎąÎ¯Îą', + }, + 'he': { + nativeName: '×ĸברי×Ē‏', + }, + 'he-IL': { + nativeName: '×ĸברי×Ē‏', + }, + 'hi': { + nativeName: 'ā¤šā¤ŋā¤¨āĨā¤ĻāĨ€', + }, + 'hi-IN': { + nativeName: 'ā¤šā¤ŋā¤¨āĨā¤ĻāĨ€', + }, + 'hr': { + nativeName: 'Hrvatski', + }, + 'hr-HR': { + nativeName: 'Hrvatski', + }, + 'hsb': { + nativeName: 'HornjoserbÅĄÄ‡ina', + }, + 'ht': { + nativeName: 'KreyÃ˛l', + }, + 'hu': { + nativeName: 'Magyar', + }, + 'hu-HU': { + nativeName: 'Magyar', + }, + 'hy': { + nativeName: 'Õ€ÕĄÕĩÕĨրÕĨÕļ', + }, + 'hy-AM': { + nativeName: 'Õ€ÕĄÕĩÕĨրÕĨÕļ (Õ€ÕĄÕĩÕĄÕŊÕŋÕĄÕļ)', + }, + 'id': { + nativeName: 'Bahasa Indonesia', + }, + 'id-ID': { + nativeName: 'Bahasa Indonesia', + }, + 'is': { + nativeName: 'Íslenska', + }, + 'is-IS': { + nativeName: 'Íslenska (Iceland)', + }, + 'it': { + nativeName: 'Italiano', + }, + 'it-IT': { + nativeName: 'Italiano', + }, + 'ja': { + nativeName: 'æ—ĨæœŦčĒž', + }, + 'ja-JP': { + nativeName: 'æ—ĨæœŦčĒž (æ—ĨæœŦ)', + }, + 'jv-ID': { + nativeName: 'Basa Jawa', + }, + 'ka-GE': { + nativeName: 'áƒĨართáƒŖლი', + }, + 'kk-KZ': { + nativeName: 'ŌšĐ°ĐˇĐ°Ō›ŅˆĐ°', + }, + 'km': { + nativeName: 'ភážļសážļខ្មែរ', + }, + 'kl': { + nativeName: 'kalaallisut', + }, + 'km-KH': { + nativeName: 'ភážļសážļខ្មែរ', + }, + 'kab': { + nativeName: 'Taqbaylit', + }, + 'kn': { + nativeName: 'ā˛•ā˛¨āŗā˛¨ā˛Ą', + }, + 'kn-IN': { + nativeName: 'ā˛•ā˛¨āŗā˛¨ā˛Ą (India)', + }, + 'ko': { + nativeName: '한ęĩ­ė–´', + }, + 'ko-KR': { + nativeName: '한ęĩ­ė–´ (한ęĩ­)', + }, + 'ku-TR': { + nativeName: 'KurdÃŽ', + }, + 'kw': { + nativeName: 'Kernewek', + }, + 'la': { + nativeName: 'Latin', + }, + 'la-VA': { + nativeName: 'Latin', + }, + 'lb': { + nativeName: 'LÃĢtzebuergesch', + }, + 'li-NL': { + nativeName: 'LèmbÃļrgs', + }, + 'lt': { + nativeName: 'LietuviÅŗ', + }, + 'lt-LT': { + nativeName: 'LietuviÅŗ', + }, + 'lv': { + nativeName: 'LatvieÅĄu', + }, + 'lv-LV': { + nativeName: 'LatvieÅĄu', + }, + 'mai': { + nativeName: 'ā¤ŽāĨˆā¤Ĩā¤ŋā¤˛āĨ€, āĻŽā§ˆāĻĨāĻŋāĻ˛ā§€', + }, + 'mg-MG': { + nativeName: 'Malagasy', + }, + 'mk': { + nativeName: 'МаĐēĐĩĐ´ĐžĐŊŅĐēи', + }, + 'mk-MK': { + nativeName: 'МаĐēĐĩĐ´ĐžĐŊŅĐēи (МаĐēĐĩĐ´ĐžĐŊŅĐēи)', + }, + 'ml': { + nativeName: 'ā´Žā´˛ā´¯ā´žā´ŗā´‚', + }, + 'ml-IN': { + nativeName: 'ā´Žā´˛ā´¯ā´žā´ŗā´‚', + }, + 'mn-MN': { + nativeName: 'МоĐŊĐŗĐžĐģ', + }, + 'mr': { + nativeName: 'ā¤Žā¤°ā¤žā¤ āĨ€', + }, + 'mr-IN': { + nativeName: 'ā¤Žā¤°ā¤žā¤ āĨ€', + }, + 'ms': { + nativeName: 'Bahasa Melayu', + }, + 'ms-MY': { + nativeName: 'Bahasa Melayu', + }, + 'mt': { + nativeName: 'Malti', + }, + 'mt-MT': { + nativeName: 'Malti', + }, + 'my': { + nativeName: 'ဗမá€Ŧစကá€Ŧ', + }, + 'no': { + nativeName: 'Norsk', + }, + 'nb': { + nativeName: 'Norsk (bokmÃĨl)', + }, + 'nb-NO': { + nativeName: 'Norsk (bokmÃĨl)', + }, + 'ne': { + nativeName: 'ā¤¨āĨ‡ā¤Ēā¤žā¤˛āĨ€', + }, + 'ne-NP': { + nativeName: 'ā¤¨āĨ‡ā¤Ēā¤žā¤˛āĨ€', + }, + 'nl': { + nativeName: 'Nederlands', + }, + 'nl-BE': { + nativeName: 'Nederlands (BelgiÃĢ)', + }, + 'nl-NL': { + nativeName: 'Nederlands (Nederland)', + }, + 'nn-NO': { + nativeName: 'Norsk (nynorsk)', + }, + 'oc': { + nativeName: 'Occitan', + }, + 'or-IN': { + nativeName: 'āŦ“āŦĄāŦŧāŦŋāŦ†', + }, + 'pa': { + nativeName: 'ā¨ĒāŠ°ā¨œā¨žā¨ŦāŠ€', + }, + 'pa-IN': { + nativeName: 'ā¨ĒāŠ°ā¨œā¨žā¨ŦāŠ€ (ā¨­ā¨žā¨°ā¨¤ ā¨¨āŠ‚āŠ°)', + }, + 'pl': { + nativeName: 'Polski', + }, + 'pl-PL': { + nativeName: 'Polski', + }, + 'ps-AF': { + nativeName: 'ŲžÚšØĒŲˆ', + }, + 'pt': { + nativeName: 'PortuguÃĒs', + }, + 'pt-BR': { + nativeName: 'PortuguÃĒs (Brasil)', + }, + 'pt-PT': { + nativeName: 'PortuguÃĒs (Portugal)', + }, + 'qu-PE': { + nativeName: 'Qhichwa', + }, + 'rm-CH': { + nativeName: 'Rumantsch', + }, + 'ro': { + nativeName: 'RomÃĸnă', + }, + 'ro-RO': { + nativeName: 'RomÃĸnă', + }, + 'ru': { + nativeName: 'Đ ŅƒŅŅĐēиК', + }, + 'ru-RU': { + nativeName: 'Đ ŅƒŅŅĐēиК', + }, + 'sa-IN': { + nativeName: 'ā¤¸ā¤‚ā¤¸āĨā¤•āĨƒā¤¤ā¤ŽāĨ', + }, + 'se-NO': { + nativeName: 'DavvisÃĄmegiella', + }, + 'sh': { + nativeName: 'ŅŅ€ĐŋŅĐēĐžŅ…Ņ€Đ˛Đ°Ņ‚ŅĐēи', + }, + 'si-LK': { + nativeName: 'āˇƒāˇ’āļ‚āˇ„āļŊ', + }, + 'sk': { + nativeName: 'Slovenčina', + }, + 'sk-SK': { + nativeName: 'Slovenčina (Slovakia)', + }, + 'sl': { + nativeName: 'SlovenÅĄÄina', + }, + 'sl-SI': { + nativeName: 'SlovenÅĄÄina', + }, + 'so-SO': { + nativeName: 'Soomaaliga', + }, + 'sq': { + nativeName: 'Shqip', + }, + 'sq-AL': { + nativeName: 'Shqip', + }, + 'sr': { + nativeName: 'ĐĄŅ€ĐŋŅĐēи', + }, + 'sr-RS': { + nativeName: 'ĐĄŅ€ĐŋŅĐēи (Serbia)', + }, + 'su': { + nativeName: 'Basa Sunda', + }, + 'sv': { + nativeName: 'Svenska', + }, + 'sv-SE': { + nativeName: 'Svenska', + }, + 'sw': { + nativeName: 'Kiswahili', + }, + 'sw-KE': { + nativeName: 'Kiswahili', + }, + 'ta': { + nativeName: 'āŽ¤āŽŽāŽŋāŽ´ā¯', + }, + 'ta-IN': { + nativeName: 'āŽ¤āŽŽāŽŋāŽ´ā¯', + }, + 'te': { + nativeName: 'ā°¤āą†ā°˛āąā°—āą', + }, + 'te-IN': { + nativeName: 'ā°¤āą†ā°˛āąā°—āą', + }, + 'tg': { + nativeName: 'СайОĖĐŊи Ņ‚ĐžŌˇĐ¸ĐēĶŖĖ', + }, + 'tg-TJ': { + nativeName: 'Ņ‚ĐžŌˇĐ¸ĐēĶŖ', + }, + 'th': { + nativeName: 'ā¸ ā¸˛ā¸Šā¸˛āš„ā¸—ā¸ĸ', + }, + 'th-TH': { + nativeName: 'ā¸ ā¸˛ā¸Šā¸˛āš„ā¸—ā¸ĸ (ā¸›ā¸Ŗā¸°āš€ā¸—ā¸¨āš„ā¸—ā¸ĸ)', + }, + 'fil': { + nativeName: 'Filipino', + }, + 'tlh': { + nativeName: 'tlhIngan-Hol', + }, + 'tr': { + nativeName: 'TÃŧrkçe', + }, + 'tr-TR': { + nativeName: 'TÃŧrkçe', + }, + 'tt-RU': { + nativeName: 'Ņ‚Đ°Ņ‚Đ°Ņ€Ņ‡Đ°', + }, + 'uk': { + nativeName: 'ĐŖĐēŅ€Đ°Ņ—ĐŊŅŅŒĐēĐ°', + }, + 'uk-UA': { + nativeName: 'ĐŖĐēŅ€Đ°Ņ—ĐŊŅŅŒĐēĐ°', + }, + 'ur': { + nativeName: 'Ø§ØąØ¯Ųˆ', + }, + 'ur-PK': { + nativeName: 'Ø§ØąØ¯Ųˆ', + }, + 'uz': { + nativeName: 'O\'zbek', + }, + 'uz-UZ': { + nativeName: 'O\'zbek', + }, + 'vi': { + nativeName: 'Tiáēŋng Viáģ‡t', + }, + 'vi-VN': { + nativeName: 'Tiáēŋng Viáģ‡t', + }, + 'xh-ZA': { + nativeName: 'isiXhosa', + }, + 'yi': { + nativeName: 'ייִדיש', + }, + 'yi-DE': { + nativeName: 'ייִדיש (German)', + }, + 'zh': { + nativeName: '中文', + }, + 'zh-Hans': { + nativeName: '中文įŽ€äŊ“', + }, + 'zh-Hant': { + nativeName: '中文įšéĢ”', + }, + 'zh-CN': { + nativeName: '中文īŧˆä¸­å›Ŋ大陆īŧ‰', + }, + 'zh-HK': { + nativeName: '中文īŧˆéĻ™æ¸¯īŧ‰', + }, + 'zh-SG': { + nativeName: '中文īŧˆæ–°åŠ åĄīŧ‰', + }, + 'zh-TW': { + nativeName: '中文īŧˆå°įŖīŧ‰', + }, + 'zu-ZA': { + nativeName: 'isiZulu', + }, +}; diff --git a/packages/backend/src/misc/populate-emojis.ts b/packages/backend/src/misc/populate-emojis.ts index 26c05e5fa..4953c6890 100644 --- a/packages/backend/src/misc/populate-emojis.ts +++ b/packages/backend/src/misc/populate-emojis.ts @@ -1,12 +1,12 @@ import { In } from 'typeorm'; -import { Emojis } from '@/models/index'; -import { Emoji } from '@/models/entities/emoji'; -import { Note } from '@/models/entities/note'; -import { Cache } from './cache'; -import { isSelfHost, toPunyNullable } from './convert-host'; -import { decodeReaction } from './reaction-lib'; -import config from '@/config/index'; -import { query } from '@/prelude/url'; +import { Emojis } from '@/models/index.js'; +import { Emoji } from '@/models/entities/emoji.js'; +import { Note } from '@/models/entities/note.js'; +import { Cache } from './cache.js'; +import { isSelfHost, toPunyNullable } from './convert-host.js'; +import { decodeReaction } from './reaction-lib.js'; +import config from '@/config/index.js'; +import { query } from '@/prelude/url.js'; const cache = new Cache(1000 * 60 * 60 * 12); diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts index 04b1e34eb..086944ccf 100644 --- a/packages/backend/src/misc/reaction-lib.ts +++ b/packages/backend/src/misc/reaction-lib.ts @@ -1,8 +1,8 @@ /* eslint-disable key-spacing */ -import { emojiRegex } from './emoji-regex'; -import { fetchMeta } from './fetch-meta'; -import { Emojis } from '@/models/index'; -import { toPunyNullable } from './convert-host'; +import { emojiRegex } from './emoji-regex.js'; +import { fetchMeta } from './fetch-meta.js'; +import { Emojis } from '@/models/index.js'; +import { toPunyNullable } from './convert-host.js'; const legacies: Record = { 'like': '👍', diff --git a/packages/backend/src/misc/schema.ts b/packages/backend/src/misc/schema.ts index 2dae954af..5b6981209 100644 --- a/packages/backend/src/misc/schema.ts +++ b/packages/backend/src/misc/schema.ts @@ -6,29 +6,29 @@ import { packedMeDetailedSchema, packedUserDetailedSchema, packedUserSchema, -} from '@/models/schema/user'; -import { packedNoteSchema } from '@/models/schema/note'; -import { packedUserListSchema } from '@/models/schema/user-list'; -import { packedAppSchema } from '@/models/schema/app'; -import { packedMessagingMessageSchema } from '@/models/schema/messaging-message'; -import { packedNotificationSchema } from '@/models/schema/notification'; -import { packedDriveFileSchema } from '@/models/schema/drive-file'; -import { packedDriveFolderSchema } from '@/models/schema/drive-folder'; -import { packedFollowingSchema } from '@/models/schema/following'; -import { packedMutingSchema } from '@/models/schema/muting'; -import { packedBlockingSchema } from '@/models/schema/blocking'; -import { packedNoteReactionSchema } from '@/models/schema/note-reaction'; -import { packedHashtagSchema } from '@/models/schema/hashtag'; -import { packedPageSchema } from '@/models/schema/page'; -import { packedUserGroupSchema } from '@/models/schema/user-group'; -import { packedNoteFavoriteSchema } from '@/models/schema/note-favorite'; -import { packedChannelSchema } from '@/models/schema/channel'; -import { packedAntennaSchema } from '@/models/schema/antenna'; -import { packedClipSchema } from '@/models/schema/clip'; -import { packedFederationInstanceSchema } from '@/models/schema/federation-instance'; -import { packedQueueCountSchema } from '@/models/schema/queue'; -import { packedGalleryPostSchema } from '@/models/schema/gallery-post'; -import { packedEmojiSchema } from '@/models/schema/emoji'; +} from '@/models/schema/user.js'; +import { packedNoteSchema } from '@/models/schema/note.js'; +import { packedUserListSchema } from '@/models/schema/user-list.js'; +import { packedAppSchema } from '@/models/schema/app.js'; +import { packedMessagingMessageSchema } from '@/models/schema/messaging-message.js'; +import { packedNotificationSchema } from '@/models/schema/notification.js'; +import { packedDriveFileSchema } from '@/models/schema/drive-file.js'; +import { packedDriveFolderSchema } from '@/models/schema/drive-folder.js'; +import { packedFollowingSchema } from '@/models/schema/following.js'; +import { packedMutingSchema } from '@/models/schema/muting.js'; +import { packedBlockingSchema } from '@/models/schema/blocking.js'; +import { packedNoteReactionSchema } from '@/models/schema/note-reaction.js'; +import { packedHashtagSchema } from '@/models/schema/hashtag.js'; +import { packedPageSchema } from '@/models/schema/page.js'; +import { packedUserGroupSchema } from '@/models/schema/user-group.js'; +import { packedNoteFavoriteSchema } from '@/models/schema/note-favorite.js'; +import { packedChannelSchema } from '@/models/schema/channel.js'; +import { packedAntennaSchema } from '@/models/schema/antenna.js'; +import { packedClipSchema } from '@/models/schema/clip.js'; +import { packedFederationInstanceSchema } from '@/models/schema/federation-instance.js'; +import { packedQueueCountSchema } from '@/models/schema/queue.js'; +import { packedGalleryPostSchema } from '@/models/schema/gallery-post.js'; +import { packedEmojiSchema } from '@/models/schema/emoji.js'; export const refs = { UserLite: packedUserLiteSchema, @@ -63,18 +63,13 @@ export const refs = { Emoji: packedEmojiSchema, }; -// Packed = SchemaTypeDef; ã¨ã™ã‚‹ã¨åą•é–‹ã•ã‚ŒãĻマã‚Ļ゚ホバãƒŧ時ãĢåž‹čĄ¨į¤ēがäŊŋいį‰ŠãĢãĒらãĒくãĒる -// ObjTypeを指厚するとīŧˆãĒぜかīŧ‰åą•é–‹ã•ã‚ŒãšãĢPacked<'Hoge'>ã¨čĄ¨į¤ēされる -type PackedDef; allOf?: ReadonlyArray }> = - r['allOf'] extends ReadonlyArray ? UnionToIntersection> : - r['oneOf'] extends ReadonlyArray ? UnionSchemaType : - r['properties'] extends Obj ? ObjType : - never; -export type Packed = PackedDef; +export type Packed = SchemaType; -type TypeStringef = 'boolean' | 'number' | 'string' | 'array' | 'object' | 'any'; +type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any'; type StringDefToType = + T extends 'null' ? null : T extends 'boolean' ? boolean : + T extends 'integer' ? number : T extends 'number' ? number : T extends 'string' ? string | Date : T extends 'array' ? ReadonlyArray : @@ -83,17 +78,18 @@ type StringDefToType = // https://swagger.io/specification/?sbsearch=optional#schema-object type OfSchema = { - readonly anyOf?: ReadonlyArray; - readonly oneOf?: ReadonlyArray; - readonly allOf?: ReadonlyArray; + readonly anyOf?: ReadonlyArray; + readonly oneOf?: ReadonlyArray; + readonly allOf?: ReadonlyArray; } -export interface MinimumSchema extends OfSchema { +export interface Schema extends OfSchema { readonly type?: TypeStringef; readonly nullable?: boolean; readonly optional?: boolean; - readonly items?: MinimumSchema; + readonly items?: Schema; readonly properties?: Obj; + readonly required?: ReadonlyArray>; readonly description?: string; readonly example?: any; readonly format?: string; @@ -104,26 +100,22 @@ export interface MinimumSchema extends OfSchema { readonly minLength?: number; } -export interface Schema extends MinimumSchema { - readonly nullable: boolean; - readonly optional: boolean; -} - -type NonUndefinedPropertyNames = { - [K in keyof T]: T[K]['optional'] extends true ? never : K -}[keyof T]; - -type UndefinedPropertyNames = { - [K in keyof T]: T[K]['optional'] extends true ? K : never -}[keyof T]; +type RequiredPropertyNames = { + [K in keyof s]: + // K is not optional + s[K]['optional'] extends false ? K : + // K has default value + s[K]['default'] extends null | string | number | boolean | Record ? K : never +}[keyof s]; export interface Obj { [key: string]: Schema; } -export type ObjType = - { -readonly [P in UndefinedPropertyNames]?: SchemaType } & - { -readonly [P in NonUndefinedPropertyNames]: SchemaType }; +export type ObjType = + { -readonly [P in keyof s]?: SchemaType } & + { -readonly [P in RequiredProps]: SchemaType } & + { -readonly [P in RequiredPropertyNames]: SchemaType }; -type NullOrUndefined

= +type NullOrUndefined

= p['nullable'] extends true ? p['optional'] extends true ? (T | null | undefined) @@ -132,15 +124,18 @@ type NullOrUndefined

= ? (T | undefined) : T; -// å…ąį”¨äŊ“åž‹ã‚’äē¤åˇŽåž‹ãĢする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection +// https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection +// Get intersection from union type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; // https://github.com/misskey-dev/misskey/pull/8144#discussion_r785287552 -// 単į´”ãĢSchemaTypeDefã§åˆ¤åŽšã™ã‚‹ã ã‘ã§ã¯ãƒ€ãƒĄ -type UnionSchemaType = X extends any ? SchemaType : never; +// To get union, we use `Foo extends any ? Hoge : never` +type UnionSchemaType = X extends any ? SchemaType : never; type ArrayUnion = T extends any ? Array : never; -export type SchemaTypeDef

= +export type SchemaTypeDef

= + p['type'] extends 'null' ? null : + p['type'] extends 'integer' ? number : p['type'] extends 'number' ? number : p['type'] extends 'string' ? ( p['enum'] extends readonly string[] ? @@ -151,22 +146,22 @@ export type SchemaTypeDef

= p['type'] extends 'boolean' ? boolean : p['type'] extends 'object' ? ( p['ref'] extends keyof typeof refs ? Packed : - p['properties'] extends NonNullable ? ObjType : - p['anyOf'] extends ReadonlyArray ? UnionSchemaType & Partial>> : - p['allOf'] extends ReadonlyArray ? UnionToIntersection> : + p['properties'] extends NonNullable ? ObjType[number]> : + p['anyOf'] extends ReadonlyArray ? UnionSchemaType & Partial>> : + p['allOf'] extends ReadonlyArray ? UnionToIntersection> : any ) : p['type'] extends 'array' ? ( p['items'] extends OfSchema ? ( - p['items']['anyOf'] extends ReadonlyArray ? UnionSchemaType>[] : - p['items']['oneOf'] extends ReadonlyArray ? ArrayUnion>> : - p['items']['allOf'] extends ReadonlyArray ? UnionToIntersection>>[] : + p['items']['anyOf'] extends ReadonlyArray ? UnionSchemaType>[] : + p['items']['oneOf'] extends ReadonlyArray ? ArrayUnion>> : + p['items']['allOf'] extends ReadonlyArray ? UnionToIntersection>>[] : never ) : - p['items'] extends NonNullable ? SchemaTypeDef[] : + p['items'] extends NonNullable ? SchemaTypeDef[] : any[] ) : - p['oneOf'] extends ReadonlyArray ? UnionSchemaType : + p['oneOf'] extends ReadonlyArray ? UnionSchemaType : any; -export type SchemaType

= NullOrUndefined>; +export type SchemaType

= NullOrUndefined>; diff --git a/packages/backend/src/misc/secure-rndstr.ts b/packages/backend/src/misc/secure-rndstr.ts index 76ee1225e..8d4fcb1ba 100644 --- a/packages/backend/src/misc/secure-rndstr.ts +++ b/packages/backend/src/misc/secure-rndstr.ts @@ -1,4 +1,4 @@ -import * as crypto from 'crypto'; +import * as crypto from 'node:crypto'; const L_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz'; const LU_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; diff --git a/packages/backend/src/misc/show-machine-info.ts b/packages/backend/src/misc/show-machine-info.ts index 58747c115..bc71cfbe9 100644 --- a/packages/backend/src/misc/show-machine-info.ts +++ b/packages/backend/src/misc/show-machine-info.ts @@ -1,6 +1,6 @@ -import * as os from 'os'; -import * as sysUtils from 'systeminformation'; -import Logger from '@/services/logger'; +import * as os from 'node:os'; +import sysUtils from 'systeminformation'; +import Logger from '@/services/logger.js'; export async function showMachineInfo(parentLogger: Logger) { const logger = parentLogger.createSubLogger('machine'); diff --git a/packages/backend/src/models/entities/abuse-user-report.ts b/packages/backend/src/models/entities/abuse-user-report.ts index 27c1e47fd..6ac563552 100644 --- a/packages/backend/src/models/entities/abuse-user-report.ts +++ b/packages/backend/src/models/entities/abuse-user-report.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class AbuseUserReport { diff --git a/packages/backend/src/models/entities/access-token.ts b/packages/backend/src/models/entities/access-token.ts index 33b60e44f..69cdc49ce 100644 --- a/packages/backend/src/models/entities/access-token.ts +++ b/packages/backend/src/models/entities/access-token.ts @@ -1,7 +1,7 @@ import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn } from 'typeorm'; -import { User } from './user'; -import { App } from './app'; -import { id } from '../id'; +import { User } from './user.js'; +import { App } from './app.js'; +import { id } from '../id.js'; @Entity() export class AccessToken { diff --git a/packages/backend/src/models/entities/ad.ts b/packages/backend/src/models/entities/ad.ts index 68be4ab1c..36b758f20 100644 --- a/packages/backend/src/models/entities/ad.ts +++ b/packages/backend/src/models/entities/ad.ts @@ -1,5 +1,5 @@ import { Entity, Index, Column, PrimaryColumn } from 'typeorm'; -import { id } from '../id'; +import { id } from '../id.js'; @Entity() export class Ad { diff --git a/packages/backend/src/models/entities/announcement-read.ts b/packages/backend/src/models/entities/announcement-read.ts index 88a1966e2..e4d256a86 100644 --- a/packages/backend/src/models/entities/announcement-read.ts +++ b/packages/backend/src/models/entities/announcement-read.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { Announcement } from './announcement'; -import { id } from '../id'; +import { User } from './user.js'; +import { Announcement } from './announcement.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'announcementId'], { unique: true }) diff --git a/packages/backend/src/models/entities/announcement.ts b/packages/backend/src/models/entities/announcement.ts index 3448bb686..beb2f8246 100644 --- a/packages/backend/src/models/entities/announcement.ts +++ b/packages/backend/src/models/entities/announcement.ts @@ -1,5 +1,5 @@ import { Entity, Index, Column, PrimaryColumn } from 'typeorm'; -import { id } from '../id'; +import { id } from '../id.js'; @Entity() export class Announcement { diff --git a/packages/backend/src/models/entities/antenna-note.ts b/packages/backend/src/models/entities/antenna-note.ts index a72da423d..fcca493fe 100644 --- a/packages/backend/src/models/entities/antenna-note.ts +++ b/packages/backend/src/models/entities/antenna-note.ts @@ -1,7 +1,7 @@ import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm'; -import { Note } from './note'; -import { Antenna } from './antenna'; -import { id } from '../id'; +import { Note } from './note.js'; +import { Antenna } from './antenna.js'; +import { id } from '../id.js'; @Entity() @Index(['noteId', 'antennaId'], { unique: true }) diff --git a/packages/backend/src/models/entities/antenna.ts b/packages/backend/src/models/entities/antenna.ts index ffe7cc7e3..6c8bb13e5 100644 --- a/packages/backend/src/models/entities/antenna.ts +++ b/packages/backend/src/models/entities/antenna.ts @@ -1,8 +1,8 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { UserList } from './user-list'; -import { UserGroupJoining } from './user-group-joining'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { UserList } from './user-list.js'; +import { UserGroupJoining } from './user-group-joining.js'; @Entity() export class Antenna { diff --git a/packages/backend/src/models/entities/app.ts b/packages/backend/src/models/entities/app.ts index c1efdc070..46c11548a 100644 --- a/packages/backend/src/models/entities/app.ts +++ b/packages/backend/src/models/entities/app.ts @@ -1,6 +1,6 @@ import { Entity, PrimaryColumn, Column, Index, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class App { diff --git a/packages/backend/src/models/entities/attestation-challenge.ts b/packages/backend/src/models/entities/attestation-challenge.ts index cf3527059..c40df2329 100644 --- a/packages/backend/src/models/entities/attestation-challenge.ts +++ b/packages/backend/src/models/entities/attestation-challenge.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, JoinColumn, Column, ManyToOne, Index } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class AttestationChallenge { diff --git a/packages/backend/src/models/entities/auth-session.ts b/packages/backend/src/models/entities/auth-session.ts index 199138552..b82585620 100644 --- a/packages/backend/src/models/entities/auth-session.ts +++ b/packages/backend/src/models/entities/auth-session.ts @@ -1,7 +1,7 @@ import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn } from 'typeorm'; -import { User } from './user'; -import { App } from './app'; -import { id } from '../id'; +import { User } from './user.js'; +import { App } from './app.js'; +import { id } from '../id.js'; @Entity() export class AuthSession { diff --git a/packages/backend/src/models/entities/blocking.ts b/packages/backend/src/models/entities/blocking.ts index aacbfef7f..4ac73a00b 100644 --- a/packages/backend/src/models/entities/blocking.ts +++ b/packages/backend/src/models/entities/blocking.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() @Index(['blockerId', 'blockeeId'], { unique: true }) diff --git a/packages/backend/src/models/entities/channel-following.ts b/packages/backend/src/models/entities/channel-following.ts index 3727283a2..029dd6cf1 100644 --- a/packages/backend/src/models/entities/channel-following.ts +++ b/packages/backend/src/models/entities/channel-following.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { Channel } from './channel'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { Channel } from './channel.js'; @Entity() @Index(['followerId', 'followeeId'], { unique: true }) diff --git a/packages/backend/src/models/entities/channel-note-pining.ts b/packages/backend/src/models/entities/channel-note-pining.ts index d6b677403..23be3b69d 100644 --- a/packages/backend/src/models/entities/channel-note-pining.ts +++ b/packages/backend/src/models/entities/channel-note-pining.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { Note } from './note'; -import { Channel } from './channel'; -import { id } from '../id'; +import { Note } from './note.js'; +import { Channel } from './channel.js'; +import { id } from '../id.js'; @Entity() @Index(['channelId', 'noteId'], { unique: true }) diff --git a/packages/backend/src/models/entities/channel.ts b/packages/backend/src/models/entities/channel.ts index a6767b038..abf6668bd 100644 --- a/packages/backend/src/models/entities/channel.ts +++ b/packages/backend/src/models/entities/channel.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { DriveFile } from './drive-file'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { DriveFile } from './drive-file.js'; @Entity() export class Channel { diff --git a/packages/backend/src/models/entities/clip-note.ts b/packages/backend/src/models/entities/clip-note.ts index 2bc435226..6f3688550 100644 --- a/packages/backend/src/models/entities/clip-note.ts +++ b/packages/backend/src/models/entities/clip-note.ts @@ -1,7 +1,7 @@ import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm'; -import { Note } from './note'; -import { Clip } from './clip'; -import { id } from '../id'; +import { Note } from './note.js'; +import { Clip } from './clip.js'; +import { id } from '../id.js'; @Entity() @Index(['noteId', 'clipId'], { unique: true }) diff --git a/packages/backend/src/models/entities/clip.ts b/packages/backend/src/models/entities/clip.ts index 84f5c4d21..da6b3c7a7 100644 --- a/packages/backend/src/models/entities/clip.ts +++ b/packages/backend/src/models/entities/clip.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class Clip { diff --git a/packages/backend/src/models/entities/drive-file.ts b/packages/backend/src/models/entities/drive-file.ts index cec86880f..3d375f0e3 100644 --- a/packages/backend/src/models/entities/drive-file.ts +++ b/packages/backend/src/models/entities/drive-file.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { DriveFolder } from './drive-folder'; -import { id } from '../id'; +import { User } from './user.js'; +import { DriveFolder } from './drive-folder.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'folderId', 'id']) diff --git a/packages/backend/src/models/entities/drive-folder.ts b/packages/backend/src/models/entities/drive-folder.ts index 09f5e6448..d4022c6eb 100644 --- a/packages/backend/src/models/entities/drive-folder.ts +++ b/packages/backend/src/models/entities/drive-folder.ts @@ -1,6 +1,6 @@ import { JoinColumn, ManyToOne, Entity, PrimaryColumn, Index, Column } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class DriveFolder { diff --git a/packages/backend/src/models/entities/emoji.ts b/packages/backend/src/models/entities/emoji.ts index 2e9c11d21..b72ca7233 100644 --- a/packages/backend/src/models/entities/emoji.ts +++ b/packages/backend/src/models/entities/emoji.ts @@ -1,5 +1,5 @@ import { PrimaryColumn, Entity, Index, Column } from 'typeorm'; -import { id } from '../id'; +import { id } from '../id.js'; @Entity() @Index(['name', 'host'], { unique: true }) diff --git a/packages/backend/src/models/entities/follow-request.ts b/packages/backend/src/models/entities/follow-request.ts index 6aa202299..89946f6d3 100644 --- a/packages/backend/src/models/entities/follow-request.ts +++ b/packages/backend/src/models/entities/follow-request.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() @Index(['followerId', 'followeeId'], { unique: true }) diff --git a/packages/backend/src/models/entities/following.ts b/packages/backend/src/models/entities/following.ts index c3631e850..b283ca7e8 100644 --- a/packages/backend/src/models/entities/following.ts +++ b/packages/backend/src/models/entities/following.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() @Index(['followerId', 'followeeId'], { unique: true }) @@ -41,6 +41,7 @@ export class Following { public follower: User | null; //#region Denormalized fields + @Index() @Column('varchar', { length: 128, nullable: true, comment: '[Denormalized]', @@ -59,6 +60,7 @@ export class Following { }) public followerSharedInbox: string | null; + @Index() @Column('varchar', { length: 128, nullable: true, comment: '[Denormalized]', diff --git a/packages/backend/src/models/entities/gallery-like.ts b/packages/backend/src/models/entities/gallery-like.ts index 41615dcea..4ce166d19 100644 --- a/packages/backend/src/models/entities/gallery-like.ts +++ b/packages/backend/src/models/entities/gallery-like.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { GalleryPost } from './gallery-post'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { GalleryPost } from './gallery-post.js'; @Entity() @Index(['userId', 'postId'], { unique: true }) diff --git a/packages/backend/src/models/entities/gallery-post.ts b/packages/backend/src/models/entities/gallery-post.ts index 393603e3d..774cb946e 100644 --- a/packages/backend/src/models/entities/gallery-post.ts +++ b/packages/backend/src/models/entities/gallery-post.ts @@ -1,7 +1,7 @@ import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { DriveFile } from './drive-file'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { DriveFile } from './drive-file.js'; @Entity() export class GalleryPost { diff --git a/packages/backend/src/models/entities/hashtag.ts b/packages/backend/src/models/entities/hashtag.ts index 761974590..6bd991f62 100644 --- a/packages/backend/src/models/entities/hashtag.ts +++ b/packages/backend/src/models/entities/hashtag.ts @@ -1,6 +1,6 @@ import { Entity, PrimaryColumn, Index, Column } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class Hashtag { diff --git a/packages/backend/src/models/entities/instance.ts b/packages/backend/src/models/entities/instance.ts index d1314be17..c15c80ff4 100644 --- a/packages/backend/src/models/entities/instance.ts +++ b/packages/backend/src/models/entities/instance.ts @@ -1,5 +1,5 @@ import { Entity, PrimaryColumn, Index, Column } from 'typeorm'; -import { id } from '../id'; +import { id } from '../id.js'; @Entity() export class Instance { diff --git a/packages/backend/src/models/entities/messaging-message.ts b/packages/backend/src/models/entities/messaging-message.ts index 06ae005de..099fb7aa0 100644 --- a/packages/backend/src/models/entities/messaging-message.ts +++ b/packages/backend/src/models/entities/messaging-message.ts @@ -1,8 +1,8 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { DriveFile } from './drive-file'; -import { id } from '../id'; -import { UserGroup } from './user-group'; +import { User } from './user.js'; +import { DriveFile } from './drive-file.js'; +import { id } from '../id.js'; +import { UserGroup } from './user-group.js'; @Entity() export class MessagingMessage { diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index c462d5ade..4d58b5f04 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -1,7 +1,7 @@ import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { Clip } from './clip'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { Clip } from './clip.js'; @Entity() export class Meta { @@ -88,6 +88,12 @@ export class Meta { }) public pinnedClipId: Clip['id'] | null; + @Column('varchar', { + length: 512, + nullable: true, + }) + public themeColor: string | null; + @Column('varchar', { length: 512, nullable: true, @@ -131,11 +137,6 @@ export class Meta { }) public cacheRemoteFiles: boolean; - @Column('boolean', { - default: false, - }) - public proxyRemoteFiles: boolean; - @Column({ ...id(), nullable: true, @@ -199,12 +200,6 @@ export class Meta { }) public remoteDriveCapacityMb: number; - @Column('integer', { - default: 500, - comment: 'Max allowed note text length in characters', - }) - public maxNoteTextLength: number; - @Column('varchar', { length: 128, nullable: true, @@ -349,6 +344,20 @@ export class Meta { }) public feedbackUrl: string | null; + @Column('varchar', { + length: 8192, + default: null, + nullable: true, + }) + public defaultLightTheme: string | null; + + @Column('varchar', { + length: 8192, + default: null, + nullable: true, + }) + public defaultDarkTheme: string | null; + @Column('boolean', { default: false, }) diff --git a/packages/backend/src/models/entities/moderation-log.ts b/packages/backend/src/models/entities/moderation-log.ts index fe000e14f..c99e55078 100644 --- a/packages/backend/src/models/entities/moderation-log.ts +++ b/packages/backend/src/models/entities/moderation-log.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class ModerationLog { diff --git a/packages/backend/src/models/entities/muted-note.ts b/packages/backend/src/models/entities/muted-note.ts index b01bb0551..96a4fa8e3 100644 --- a/packages/backend/src/models/entities/muted-note.ts +++ b/packages/backend/src/models/entities/muted-note.ts @@ -1,8 +1,8 @@ import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm'; -import { Note } from './note'; -import { User } from './user'; -import { id } from '../id'; -import { mutedNoteReasons } from '../../types'; +import { Note } from './note.js'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { mutedNoteReasons } from '../../types.js'; @Entity() @Index(['noteId', 'userId'], { unique: true }) diff --git a/packages/backend/src/models/entities/muting.ts b/packages/backend/src/models/entities/muting.ts index b9f18a585..8cdd2af9d 100644 --- a/packages/backend/src/models/entities/muting.ts +++ b/packages/backend/src/models/entities/muting.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() @Index(['muterId', 'muteeId'], { unique: true }) diff --git a/packages/backend/src/models/entities/note-favorite.ts b/packages/backend/src/models/entities/note-favorite.ts index 69d9b49d1..fe065b77a 100644 --- a/packages/backend/src/models/entities/note-favorite.ts +++ b/packages/backend/src/models/entities/note-favorite.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { Note } from './note'; -import { User } from './user'; -import { id } from '../id'; +import { Note } from './note.js'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'noteId'], { unique: true }) diff --git a/packages/backend/src/models/entities/note-reaction.ts b/packages/backend/src/models/entities/note-reaction.ts index 369505a6c..d7bc60989 100644 --- a/packages/backend/src/models/entities/note-reaction.ts +++ b/packages/backend/src/models/entities/note-reaction.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { Note } from './note'; -import { id } from '../id'; +import { User } from './user.js'; +import { Note } from './note.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'noteId'], { unique: true }) diff --git a/packages/backend/src/models/entities/note-thread-muting.ts b/packages/backend/src/models/entities/note-thread-muting.ts index f4a3a4887..8c5f7bbab 100644 --- a/packages/backend/src/models/entities/note-thread-muting.ts +++ b/packages/backend/src/models/entities/note-thread-muting.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { Note } from './note'; -import { id } from '../id'; +import { User } from './user.js'; +import { Note } from './note.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'threadId'], { unique: true }) diff --git a/packages/backend/src/models/entities/note-unread.ts b/packages/backend/src/models/entities/note-unread.ts index 952f71cda..a7acf254d 100644 --- a/packages/backend/src/models/entities/note-unread.ts +++ b/packages/backend/src/models/entities/note-unread.ts @@ -1,8 +1,8 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { Note } from './note'; -import { id } from '../id'; -import { Channel } from './channel'; +import { User } from './user.js'; +import { Note } from './note.js'; +import { id } from '../id.js'; +import { Channel } from './channel.js'; @Entity() @Index(['userId', 'noteId'], { unique: true }) diff --git a/packages/backend/src/models/entities/note-watching.ts b/packages/backend/src/models/entities/note-watching.ts index 2758efdc3..ed82e7dfe 100644 --- a/packages/backend/src/models/entities/note-watching.ts +++ b/packages/backend/src/models/entities/note-watching.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { Note } from './note'; -import { id } from '../id'; +import { User } from './user.js'; +import { Note } from './note.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'noteId'], { unique: true }) diff --git a/packages/backend/src/models/entities/note.ts b/packages/backend/src/models/entities/note.ts index e4a5ac871..da49d53b6 100644 --- a/packages/backend/src/models/entities/note.ts +++ b/packages/backend/src/models/entities/note.ts @@ -1,9 +1,9 @@ import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { DriveFile } from './drive-file'; -import { id } from '../id'; -import { noteVisibilities } from '../../types'; -import { Channel } from './channel'; +import { User } from './user.js'; +import { DriveFile } from './drive-file.js'; +import { id } from '../id.js'; +import { noteVisibilities } from '../../types.js'; +import { Channel } from './channel.js'; @Entity() @Index('IDX_NOTE_TAGS', { synchronize: false }) diff --git a/packages/backend/src/models/entities/notification.ts b/packages/backend/src/models/entities/notification.ts index 9c1d8242f..4a4739b8c 100644 --- a/packages/backend/src/models/entities/notification.ts +++ b/packages/backend/src/models/entities/notification.ts @@ -1,11 +1,11 @@ import { Entity, Index, JoinColumn, ManyToOne, Column, PrimaryColumn } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { Note } from './note'; -import { FollowRequest } from './follow-request'; -import { UserGroupInvitation } from './user-group-invitation'; -import { AccessToken } from './access-token'; -import { notificationTypes } from '@/types'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { Note } from './note.js'; +import { FollowRequest } from './follow-request.js'; +import { UserGroupInvitation } from './user-group-invitation.js'; +import { AccessToken } from './access-token.js'; +import { notificationTypes } from '@/types.js'; @Entity() export class Notification { diff --git a/packages/backend/src/models/entities/page-like.ts b/packages/backend/src/models/entities/page-like.ts index 16fb8f172..17f4ebf52 100644 --- a/packages/backend/src/models/entities/page-like.ts +++ b/packages/backend/src/models/entities/page-like.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { Page } from './page'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { Page } from './page.js'; @Entity() @Index(['userId', 'pageId'], { unique: true }) diff --git a/packages/backend/src/models/entities/page.ts b/packages/backend/src/models/entities/page.ts index 2b540e199..baad3a36f 100644 --- a/packages/backend/src/models/entities/page.ts +++ b/packages/backend/src/models/entities/page.ts @@ -1,7 +1,7 @@ import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; -import { DriveFile } from './drive-file'; +import { User } from './user.js'; +import { id } from '../id.js'; +import { DriveFile } from './drive-file.js'; @Entity() @Index(['userId', 'name'], { unique: true }) diff --git a/packages/backend/src/models/entities/password-reset-request.ts b/packages/backend/src/models/entities/password-reset-request.ts index a2db0f114..05e62cc5a 100644 --- a/packages/backend/src/models/entities/password-reset-request.ts +++ b/packages/backend/src/models/entities/password-reset-request.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, Column, ManyToOne, JoinColumn } from 'typeorm'; -import { id } from '../id'; -import { User } from './user'; +import { id } from '../id.js'; +import { User } from './user.js'; @Entity() export class PasswordResetRequest { diff --git a/packages/backend/src/models/entities/poll-vote.ts b/packages/backend/src/models/entities/poll-vote.ts index fb44a58e9..fca1cd009 100644 --- a/packages/backend/src/models/entities/poll-vote.ts +++ b/packages/backend/src/models/entities/poll-vote.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { Note } from './note'; -import { id } from '../id'; +import { User } from './user.js'; +import { Note } from './note.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'noteId', 'choice'], { unique: true }) diff --git a/packages/backend/src/models/entities/poll.ts b/packages/backend/src/models/entities/poll.ts index 9c8069349..83d0873cc 100644 --- a/packages/backend/src/models/entities/poll.ts +++ b/packages/backend/src/models/entities/poll.ts @@ -1,8 +1,8 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm'; -import { id } from '../id'; -import { Note } from './note'; -import { User } from './user'; -import { noteVisibilities } from '../../types'; +import { id } from '../id.js'; +import { Note } from './note.js'; +import { User } from './user.js'; +import { noteVisibilities } from '../../types.js'; @Entity() export class Poll { diff --git a/packages/backend/src/models/entities/promo-note.ts b/packages/backend/src/models/entities/promo-note.ts index e3fbab441..d110b81e9 100644 --- a/packages/backend/src/models/entities/promo-note.ts +++ b/packages/backend/src/models/entities/promo-note.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm'; -import { Note } from './note'; -import { User } from './user'; -import { id } from '../id'; +import { Note } from './note.js'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class PromoNote { diff --git a/packages/backend/src/models/entities/promo-read.ts b/packages/backend/src/models/entities/promo-read.ts index 777ed301b..a63b79cd1 100644 --- a/packages/backend/src/models/entities/promo-read.ts +++ b/packages/backend/src/models/entities/promo-read.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { Note } from './note'; -import { User } from './user'; -import { id } from '../id'; +import { Note } from './note.js'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'noteId'], { unique: true }) diff --git a/packages/backend/src/models/entities/registration-tickets.ts b/packages/backend/src/models/entities/registration-tickets.ts index d962f78a7..139e40f85 100644 --- a/packages/backend/src/models/entities/registration-tickets.ts +++ b/packages/backend/src/models/entities/registration-tickets.ts @@ -1,5 +1,5 @@ import { PrimaryColumn, Entity, Index, Column } from 'typeorm'; -import { id } from '../id'; +import { id } from '../id.js'; @Entity() export class RegistrationTicket { diff --git a/packages/backend/src/models/entities/registry-item.ts b/packages/backend/src/models/entities/registry-item.ts index 6d5f0185d..283796df9 100644 --- a/packages/backend/src/models/entities/registry-item.ts +++ b/packages/backend/src/models/entities/registry-item.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; // TODO: 同じdomain、同じscope、同じkeyぎãƒŦã‚ŗãƒŧドはäēŒã¤äģĨ上存在しãĒいようãĢåˆļį´„äģ˜ã‘たい @Entity() diff --git a/packages/backend/src/models/entities/relay.ts b/packages/backend/src/models/entities/relay.ts index 4c82ccb12..94d192957 100644 --- a/packages/backend/src/models/entities/relay.ts +++ b/packages/backend/src/models/entities/relay.ts @@ -1,5 +1,5 @@ import { PrimaryColumn, Entity, Index, Column } from 'typeorm'; -import { id } from '../id'; +import { id } from '../id.js'; @Entity() export class Relay { diff --git a/packages/backend/src/models/entities/signin.ts b/packages/backend/src/models/entities/signin.ts index 7f54f2ebf..ba81f45e4 100644 --- a/packages/backend/src/models/entities/signin.ts +++ b/packages/backend/src/models/entities/signin.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class Signin { diff --git a/packages/backend/src/models/entities/sw-subscription.ts b/packages/backend/src/models/entities/sw-subscription.ts index 2debcf744..59144d348 100644 --- a/packages/backend/src/models/entities/sw-subscription.ts +++ b/packages/backend/src/models/entities/sw-subscription.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class SwSubscription { diff --git a/packages/backend/src/models/entities/user-group-invitation.ts b/packages/backend/src/models/entities/user-group-invitation.ts index 479442a13..10f357049 100644 --- a/packages/backend/src/models/entities/user-group-invitation.ts +++ b/packages/backend/src/models/entities/user-group-invitation.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { UserGroup } from './user-group'; -import { id } from '../id'; +import { User } from './user.js'; +import { UserGroup } from './user-group.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'userGroupId'], { unique: true }) diff --git a/packages/backend/src/models/entities/user-group-joining.ts b/packages/backend/src/models/entities/user-group-joining.ts index 81f335858..62a814218 100644 --- a/packages/backend/src/models/entities/user-group-joining.ts +++ b/packages/backend/src/models/entities/user-group-joining.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { UserGroup } from './user-group'; -import { id } from '../id'; +import { User } from './user.js'; +import { UserGroup } from './user-group.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'userGroupId'], { unique: true }) diff --git a/packages/backend/src/models/entities/user-group.ts b/packages/backend/src/models/entities/user-group.ts index 1fdb60c40..8d5de1d92 100644 --- a/packages/backend/src/models/entities/user-group.ts +++ b/packages/backend/src/models/entities/user-group.ts @@ -1,6 +1,6 @@ import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class UserGroup { diff --git a/packages/backend/src/models/entities/user-keypair.ts b/packages/backend/src/models/entities/user-keypair.ts index 48bff0d10..85fa06297 100644 --- a/packages/backend/src/models/entities/user-keypair.ts +++ b/packages/backend/src/models/entities/user-keypair.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, JoinColumn, Column, OneToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class UserKeypair { diff --git a/packages/backend/src/models/entities/user-list-joining.ts b/packages/backend/src/models/entities/user-list-joining.ts index 2efa01752..12f28c414 100644 --- a/packages/backend/src/models/entities/user-list-joining.ts +++ b/packages/backend/src/models/entities/user-list-joining.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { UserList } from './user-list'; -import { id } from '../id'; +import { User } from './user.js'; +import { UserList } from './user-list.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'userListId'], { unique: true }) diff --git a/packages/backend/src/models/entities/user-list.ts b/packages/backend/src/models/entities/user-list.ts index c2896a1db..ca69394e9 100644 --- a/packages/backend/src/models/entities/user-list.ts +++ b/packages/backend/src/models/entities/user-list.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class UserList { diff --git a/packages/backend/src/models/entities/user-note-pining.ts b/packages/backend/src/models/entities/user-note-pining.ts index b91e02c5c..c91ab7fdd 100644 --- a/packages/backend/src/models/entities/user-note-pining.ts +++ b/packages/backend/src/models/entities/user-note-pining.ts @@ -1,7 +1,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { Note } from './note'; -import { User } from './user'; -import { id } from '../id'; +import { Note } from './note.js'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() @Index(['userId', 'noteId'], { unique: true }) diff --git a/packages/backend/src/models/entities/user-pending.ts b/packages/backend/src/models/entities/user-pending.ts index 40482af33..763794884 100644 --- a/packages/backend/src/models/entities/user-pending.ts +++ b/packages/backend/src/models/entities/user-pending.ts @@ -1,5 +1,5 @@ import { PrimaryColumn, Entity, Index, Column } from 'typeorm'; -import { id } from '../id'; +import { id } from '../id.js'; @Entity() export class UserPending { diff --git a/packages/backend/src/models/entities/user-profile.ts b/packages/backend/src/models/entities/user-profile.ts index d8317de8d..f95cb144c 100644 --- a/packages/backend/src/models/entities/user-profile.ts +++ b/packages/backend/src/models/entities/user-profile.ts @@ -1,8 +1,8 @@ import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; -import { id } from '../id'; -import { User } from './user'; -import { Page } from './page'; -import { ffVisibility, notificationTypes } from '@/types'; +import { id } from '../id.js'; +import { User } from './user.js'; +import { Page } from './page.js'; +import { ffVisibility, notificationTypes } from '@/types.js'; // TODO: こぎテãƒŧブãƒĢでįŽĄį†ã—ãĻã„ã‚‹æƒ…å ąã™ãšãĻãƒŦジ゚トãƒĒでįŽĄį†ã™ã‚‹ã‚ˆã†ãĢしãĻã‚‚č‰¯ã„ã‹ã‚‚ // ただ、「emailVerified が true ãĒãƒĻãƒŧã‚ļãƒŧを find する」ぎようãĒクエãƒĒは書けãĒくãĒるからã‚Ļãƒŧãƒŗ diff --git a/packages/backend/src/models/entities/user-publickey.ts b/packages/backend/src/models/entities/user-publickey.ts index 128e13510..31ed60de8 100644 --- a/packages/backend/src/models/entities/user-publickey.ts +++ b/packages/backend/src/models/entities/user-publickey.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class UserPublickey { diff --git a/packages/backend/src/models/entities/user-security-key.ts b/packages/backend/src/models/entities/user-security-key.ts index e7b63fb82..c4f2a852e 100644 --- a/packages/backend/src/models/entities/user-security-key.ts +++ b/packages/backend/src/models/entities/user-security-key.ts @@ -1,6 +1,6 @@ import { PrimaryColumn, Entity, JoinColumn, Column, ManyToOne, Index } from 'typeorm'; -import { User } from './user'; -import { id } from '../id'; +import { User } from './user.js'; +import { id } from '../id.js'; @Entity() export class UserSecurityKey { diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts index 0aa01ba00..9d5db10eb 100644 --- a/packages/backend/src/models/entities/user.ts +++ b/packages/backend/src/models/entities/user.ts @@ -1,6 +1,6 @@ import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; -import { DriveFile } from './drive-file'; -import { id } from '../id'; +import { DriveFile } from './drive-file.js'; +import { id } from '../id.js'; @Entity() @Index(['usernameLower', 'host'], { unique: true }) @@ -106,26 +106,6 @@ export class User { }) public tags: string[]; - @Column('varchar', { - length: 512, nullable: true, - }) - public avatarUrl: string | null; - - @Column('varchar', { - length: 512, nullable: true, - }) - public bannerUrl: string | null; - - @Column('varchar', { - length: 128, nullable: true, - }) - public avatarBlurhash: string | null; - - @Column('varchar', { - length: 128, nullable: true, - }) - public bannerBlurhash: string | null; - @Column('boolean', { default: false, comment: 'Whether the User is suspended.', @@ -225,6 +205,12 @@ export class User { }) public followersUri: string | null; + @Column('boolean', { + default: false, + comment: 'Whether to show users replying to other users in the timeline' + }) + public showTimelineReplies: boolean; + @Index({ unique: true }) @Column('char', { length: 16, nullable: true, unique: true, diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts index 67da34739..e7b685488 100644 --- a/packages/backend/src/models/index.ts +++ b/packages/backend/src/models/index.ts @@ -1,66 +1,67 @@ import { getRepository, getCustomRepository } from 'typeorm'; -import { Announcement } from './entities/announcement'; -import { AnnouncementRead } from './entities/announcement-read'; -import { Instance } from './entities/instance'; -import { Poll } from './entities/poll'; -import { PollVote } from './entities/poll-vote'; -import { Meta } from './entities/meta'; -import { SwSubscription } from './entities/sw-subscription'; -import { NoteWatching } from './entities/note-watching'; -import { NoteThreadMuting } from './entities/note-thread-muting'; -import { NoteUnread } from './entities/note-unread'; -import { RegistrationTicket } from './entities/registration-tickets'; -import { UserRepository } from './repositories/user'; -import { NoteRepository } from './repositories/note'; -import { DriveFileRepository } from './repositories/drive-file'; -import { DriveFolderRepository } from './repositories/drive-folder'; -import { AccessToken } from './entities/access-token'; -import { UserNotePining } from './entities/user-note-pining'; -import { SigninRepository } from './repositories/signin'; -import { MessagingMessageRepository } from './repositories/messaging-message'; -import { UserListRepository } from './repositories/user-list'; -import { UserListJoining } from './entities/user-list-joining'; -import { UserGroupRepository } from './repositories/user-group'; -import { UserGroupJoining } from './entities/user-group-joining'; -import { UserGroupInvitationRepository } from './repositories/user-group-invitation'; -import { FollowRequestRepository } from './repositories/follow-request'; -import { MutingRepository } from './repositories/muting'; -import { BlockingRepository } from './repositories/blocking'; -import { NoteReactionRepository } from './repositories/note-reaction'; -import { NotificationRepository } from './repositories/notification'; -import { NoteFavoriteRepository } from './repositories/note-favorite'; -import { UserPublickey } from './entities/user-publickey'; -import { UserKeypair } from './entities/user-keypair'; -import { AppRepository } from './repositories/app'; -import { FollowingRepository } from './repositories/following'; -import { AbuseUserReportRepository } from './repositories/abuse-user-report'; -import { AuthSessionRepository } from './repositories/auth-session'; -import { UserProfile } from './entities/user-profile'; -import { AttestationChallenge } from './entities/attestation-challenge'; -import { UserSecurityKey } from './entities/user-security-key'; -import { HashtagRepository } from './repositories/hashtag'; -import { PageRepository } from './repositories/page'; -import { PageLikeRepository } from './repositories/page-like'; -import { GalleryPostRepository } from './repositories/gallery-post'; -import { GalleryLikeRepository } from './repositories/gallery-like'; -import { ModerationLogRepository } from './repositories/moderation-logs'; -import { UsedUsername } from './entities/used-username'; -import { ClipRepository } from './repositories/clip'; -import { ClipNote } from './entities/clip-note'; -import { AntennaRepository } from './repositories/antenna'; -import { AntennaNote } from './entities/antenna-note'; -import { PromoNote } from './entities/promo-note'; -import { PromoRead } from './entities/promo-read'; -import { EmojiRepository } from './repositories/emoji'; -import { RelayRepository } from './repositories/relay'; -import { ChannelRepository } from './repositories/channel'; -import { MutedNote } from './entities/muted-note'; -import { ChannelFollowing } from './entities/channel-following'; -import { ChannelNotePining } from './entities/channel-note-pining'; -import { RegistryItem } from './entities/registry-item'; -import { Ad } from './entities/ad'; -import { PasswordResetRequest } from './entities/password-reset-request'; -import { UserPending } from './entities/user-pending'; +import { Announcement } from './entities/announcement.js'; +import { AnnouncementRead } from './entities/announcement-read.js'; +import { Instance } from './entities/instance.js'; +import { Poll } from './entities/poll.js'; +import { PollVote } from './entities/poll-vote.js'; +import { Meta } from './entities/meta.js'; +import { SwSubscription } from './entities/sw-subscription.js'; +import { NoteWatching } from './entities/note-watching.js'; +import { NoteThreadMuting } from './entities/note-thread-muting.js'; +import { NoteUnread } from './entities/note-unread.js'; +import { RegistrationTicket } from './entities/registration-tickets.js'; +import { UserRepository } from './repositories/user.js'; +import { NoteRepository } from './repositories/note.js'; +import { DriveFileRepository } from './repositories/drive-file.js'; +import { DriveFolderRepository } from './repositories/drive-folder.js'; +import { AccessToken } from './entities/access-token.js'; +import { UserNotePining } from './entities/user-note-pining.js'; +import { SigninRepository } from './repositories/signin.js'; +import { MessagingMessageRepository } from './repositories/messaging-message.js'; +import { UserListRepository } from './repositories/user-list.js'; +import { UserListJoining } from './entities/user-list-joining.js'; +import { UserGroupRepository } from './repositories/user-group.js'; +import { UserGroupJoining } from './entities/user-group-joining.js'; +import { UserGroupInvitationRepository } from './repositories/user-group-invitation.js'; +import { FollowRequestRepository } from './repositories/follow-request.js'; +import { MutingRepository } from './repositories/muting.js'; +import { BlockingRepository } from './repositories/blocking.js'; +import { NoteReactionRepository } from './repositories/note-reaction.js'; +import { NotificationRepository } from './repositories/notification.js'; +import { NoteFavoriteRepository } from './repositories/note-favorite.js'; +import { UserPublickey } from './entities/user-publickey.js'; +import { UserKeypair } from './entities/user-keypair.js'; +import { AppRepository } from './repositories/app.js'; +import { FollowingRepository } from './repositories/following.js'; +import { AbuseUserReportRepository } from './repositories/abuse-user-report.js'; +import { AuthSessionRepository } from './repositories/auth-session.js'; +import { UserProfile } from './entities/user-profile.js'; +import { AttestationChallenge } from './entities/attestation-challenge.js'; +import { UserSecurityKey } from './entities/user-security-key.js'; +import { HashtagRepository } from './repositories/hashtag.js'; +import { PageRepository } from './repositories/page.js'; +import { PageLikeRepository } from './repositories/page-like.js'; +import { GalleryPostRepository } from './repositories/gallery-post.js'; +import { GalleryLikeRepository } from './repositories/gallery-like.js'; +import { ModerationLogRepository } from './repositories/moderation-logs.js'; +import { UsedUsername } from './entities/used-username.js'; +import { ClipRepository } from './repositories/clip.js'; +import { ClipNote } from './entities/clip-note.js'; +import { AntennaRepository } from './repositories/antenna.js'; +import { AntennaNote } from './entities/antenna-note.js'; +import { PromoNote } from './entities/promo-note.js'; +import { PromoRead } from './entities/promo-read.js'; +import { EmojiRepository } from './repositories/emoji.js'; +import { RelayRepository } from './repositories/relay.js'; +import { ChannelRepository } from './repositories/channel.js'; +import { MutedNote } from './entities/muted-note.js'; +import { ChannelFollowing } from './entities/channel-following.js'; +import { ChannelNotePining } from './entities/channel-note-pining.js'; +import { RegistryItem } from './entities/registry-item.js'; +import { Ad } from './entities/ad.js'; +import { PasswordResetRequest } from './entities/password-reset-request.js'; +import { UserPending } from './entities/user-pending.js'; +import { InstanceRepository } from './repositories/instance.js'; export const Announcements = getRepository(Announcement); export const AnnouncementReads = getRepository(AnnouncementRead); @@ -89,7 +90,7 @@ export const UserNotePinings = getRepository(UserNotePining); export const UsedUsernames = getRepository(UsedUsername); export const Followings = getCustomRepository(FollowingRepository); export const FollowRequests = getCustomRepository(FollowRequestRepository); -export const Instances = getRepository(Instance); +export const Instances = getCustomRepository(InstanceRepository); export const Emojis = getCustomRepository(EmojiRepository); export const DriveFiles = getCustomRepository(DriveFileRepository); export const DriveFolders = getCustomRepository(DriveFolderRepository); diff --git a/packages/backend/src/models/repositories/abuse-user-report.ts b/packages/backend/src/models/repositories/abuse-user-report.ts index 943b65eb6..348f88b3a 100644 --- a/packages/backend/src/models/repositories/abuse-user-report.ts +++ b/packages/backend/src/models/repositories/abuse-user-report.ts @@ -1,7 +1,7 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Users } from '../index'; -import { AbuseUserReport } from '@/models/entities/abuse-user-report'; -import { awaitAll } from '@/prelude/await-all'; +import { Users } from '../index.js'; +import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; +import { awaitAll } from '@/prelude/await-all.js'; @EntityRepository(AbuseUserReport) export class AbuseUserReportRepository extends Repository { @@ -12,7 +12,7 @@ export class AbuseUserReportRepository extends Repository { return await awaitAll({ id: report.id, - createdAt: report.createdAt, + createdAt: report.createdAt.toISOString(), comment: report.comment, resolved: report.resolved, reporterId: report.reporterId, diff --git a/packages/backend/src/models/repositories/antenna.ts b/packages/backend/src/models/repositories/antenna.ts index 3bf0645a7..3440ca187 100644 --- a/packages/backend/src/models/repositories/antenna.ts +++ b/packages/backend/src/models/repositories/antenna.ts @@ -1,7 +1,7 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Antenna } from '@/models/entities/antenna'; -import { Packed } from '@/misc/schema'; -import { AntennaNotes, UserGroupJoinings } from '../index'; +import { Antenna } from '@/models/entities/antenna.js'; +import { Packed } from '@/misc/schema.js'; +import { AntennaNotes, UserGroupJoinings } from '../index.js'; @EntityRepository(Antenna) export class AntennaRepository extends Repository { diff --git a/packages/backend/src/models/repositories/app.ts b/packages/backend/src/models/repositories/app.ts index 6bac4d959..4c3c488da 100644 --- a/packages/backend/src/models/repositories/app.ts +++ b/packages/backend/src/models/repositories/app.ts @@ -1,8 +1,8 @@ import { EntityRepository, Repository } from 'typeorm'; -import { App } from '@/models/entities/app'; -import { AccessTokens } from '../index'; -import { Packed } from '@/misc/schema'; -import { User } from '../entities/user'; +import { App } from '@/models/entities/app.js'; +import { AccessTokens } from '../index.js'; +import { Packed } from '@/misc/schema.js'; +import { User } from '../entities/user.js'; @EntityRepository(App) export class AppRepository extends Repository { @@ -32,7 +32,7 @@ export class AppRepository extends Repository { ...(me ? { isAuthorized: await AccessTokens.count({ appId: app.id, - userId: me, + userId: me.id, }).then(count => count > 0), } : {}), }; diff --git a/packages/backend/src/models/repositories/auth-session.ts b/packages/backend/src/models/repositories/auth-session.ts index 6308909c4..7a7bd3a1e 100644 --- a/packages/backend/src/models/repositories/auth-session.ts +++ b/packages/backend/src/models/repositories/auth-session.ts @@ -1,8 +1,8 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Apps } from '../index'; -import { AuthSession } from '@/models/entities/auth-session'; -import { awaitAll } from '@/prelude/await-all'; -import { User } from '@/models/entities/user'; +import { Apps } from '../index.js'; +import { AuthSession } from '@/models/entities/auth-session.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(AuthSession) export class AuthSessionRepository extends Repository { diff --git a/packages/backend/src/models/repositories/blocking.ts b/packages/backend/src/models/repositories/blocking.ts index c20b02f50..b155bf944 100644 --- a/packages/backend/src/models/repositories/blocking.ts +++ b/packages/backend/src/models/repositories/blocking.ts @@ -1,9 +1,9 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Users } from '../index'; -import { Blocking } from '@/models/entities/blocking'; -import { awaitAll } from '@/prelude/await-all'; -import { Packed } from '@/misc/schema'; -import { User } from '@/models/entities/user'; +import { Users } from '../index.js'; +import { Blocking } from '@/models/entities/blocking.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { Packed } from '@/misc/schema.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(Blocking) export class BlockingRepository extends Repository { diff --git a/packages/backend/src/models/repositories/channel.ts b/packages/backend/src/models/repositories/channel.ts index b3afb823a..cc13d7c1e 100644 --- a/packages/backend/src/models/repositories/channel.ts +++ b/packages/backend/src/models/repositories/channel.ts @@ -1,8 +1,8 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Channel } from '@/models/entities/channel'; -import { Packed } from '@/misc/schema'; -import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index'; -import { User } from '@/models/entities/user'; +import { Channel } from '@/models/entities/channel.js'; +import { Packed } from '@/misc/schema.js'; +import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(Channel) export class ChannelRepository extends Repository { diff --git a/packages/backend/src/models/repositories/clip.ts b/packages/backend/src/models/repositories/clip.ts index 6f9ceeb50..9e1979729 100644 --- a/packages/backend/src/models/repositories/clip.ts +++ b/packages/backend/src/models/repositories/clip.ts @@ -1,8 +1,8 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Clip } from '@/models/entities/clip'; -import { Packed } from '@/misc/schema'; -import { Users } from '../index'; -import { awaitAll } from '@/prelude/await-all'; +import { Clip } from '@/models/entities/clip.js'; +import { Packed } from '@/misc/schema.js'; +import { Users } from '../index.js'; +import { awaitAll } from '@/prelude/await-all.js'; @EntityRepository(Clip) export class ClipRepository extends Repository { diff --git a/packages/backend/src/models/repositories/drive-file.ts b/packages/backend/src/models/repositories/drive-file.ts index 44db9a0a5..6452632db 100644 --- a/packages/backend/src/models/repositories/drive-file.ts +++ b/packages/backend/src/models/repositories/drive-file.ts @@ -1,14 +1,14 @@ import { EntityRepository, Repository } from 'typeorm'; -import { DriveFile } from '@/models/entities/drive-file'; -import { Users, DriveFolders } from '../index'; -import { User } from '@/models/entities/user'; -import { toPuny } from '@/misc/convert-host'; -import { awaitAll, Promiseable } from '@/prelude/await-all'; -import { Packed } from '@/misc/schema'; -import config from '@/config/index'; -import { query, appendQuery } from '@/prelude/url'; -import { Meta } from '@/models/entities/meta'; -import { fetchMeta } from '@/misc/fetch-meta'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { Users, DriveFolders } from '../index.js'; +import { User } from '@/models/entities/user.js'; +import { toPuny } from '@/misc/convert-host.js'; +import { awaitAll, Promiseable } from '@/prelude/await-all.js'; +import { Packed } from '@/misc/schema.js'; +import config from '@/config/index.js'; +import { query, appendQuery } from '@/prelude/url.js'; +import { Meta } from '@/models/entities/meta.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; type PackOptions = { detail?: boolean, @@ -41,7 +41,7 @@ export class DriveFileRepository extends Repository { return file.properties; } - public getPublicUrl(file: DriveFile, thumbnail = false, meta?: Meta): string | null { + public getPublicUrl(file: DriveFile, thumbnail = false): string | null { // ãƒĒãƒĸãƒŧãƒˆã‹ã¤ãƒĄãƒ‡ã‚Ŗã‚ĸãƒ—ãƒ­ã‚­ã‚ˇ if (file.uri != null && file.userHost != null && config.mediaProxy != null) { return appendQuery(config.mediaProxy, query({ @@ -51,7 +51,7 @@ export class DriveFileRepository extends Repository { } // ãƒĒãƒĸãƒŧトかつ期限切れはロãƒŧã‚ĢãƒĢãƒ—ãƒ­ã‚­ã‚ˇã‚’čŠĻãŋる - if (file.uri != null && file.isLink && meta && meta.proxyRemoteFiles) { + if (file.uri != null && file.isLink && config.proxyRemoteFiles) { const key = thumbnail ? file.thumbnailAccessKey : file.webpublicAccessKey; if (key && !key.match('/')) { // 古いもぎはここãĢã‚Ēブジェクト゚トãƒŦãƒŧジキãƒŧがå…ĨãŖãĻるぎで除外 @@ -136,8 +136,8 @@ export class DriveFileRepository extends Repository { isSensitive: file.isSensitive, blurhash: file.blurhash, properties: opts.self ? file.properties : this.getPublicProperties(file), - url: opts.self ? file.url : this.getPublicUrl(file, false, meta), - thumbnailUrl: this.getPublicUrl(file, true, meta), + url: opts.self ? file.url : this.getPublicUrl(file, false), + thumbnailUrl: this.getPublicUrl(file, true), comment: file.comment, folderId: file.folderId, folder: opts.detail && file.folderId ? DriveFolders.pack(file.folderId, { diff --git a/packages/backend/src/models/repositories/drive-folder.ts b/packages/backend/src/models/repositories/drive-folder.ts index b2e6cee9b..b0e09eedf 100644 --- a/packages/backend/src/models/repositories/drive-folder.ts +++ b/packages/backend/src/models/repositories/drive-folder.ts @@ -1,18 +1,11 @@ import { EntityRepository, Repository } from 'typeorm'; -import { DriveFolders, DriveFiles } from '../index'; -import { DriveFolder } from '@/models/entities/drive-folder'; -import { awaitAll } from '@/prelude/await-all'; -import { Packed } from '@/misc/schema'; +import { DriveFolders, DriveFiles } from '../index.js'; +import { DriveFolder } from '@/models/entities/drive-folder.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { Packed } from '@/misc/schema.js'; @EntityRepository(DriveFolder) export class DriveFolderRepository extends Repository { - public validateFolderName(name: string): boolean { - return ( - (name.trim().length > 0) && - (name.length <= 200) - ); - } - public async pack( src: DriveFolder['id'] | DriveFolder, options?: { diff --git a/packages/backend/src/models/repositories/emoji.ts b/packages/backend/src/models/repositories/emoji.ts index b9dc6ed0a..3b13832a3 100644 --- a/packages/backend/src/models/repositories/emoji.ts +++ b/packages/backend/src/models/repositories/emoji.ts @@ -1,6 +1,6 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Emoji } from '@/models/entities/emoji'; -import { Packed } from '@/misc/schema'; +import { Emoji } from '@/models/entities/emoji.js'; +import { Packed } from '@/misc/schema.js'; @EntityRepository(Emoji) export class EmojiRepository extends Repository { diff --git a/packages/backend/src/models/repositories/federation-instance.ts b/packages/backend/src/models/repositories/federation-instance.ts deleted file mode 100644 index 426fd5bfc..000000000 --- a/packages/backend/src/models/repositories/federation-instance.ts +++ /dev/null @@ -1,2 +0,0 @@ -import config from '@/config/index'; - diff --git a/packages/backend/src/models/repositories/follow-request.ts b/packages/backend/src/models/repositories/follow-request.ts index d6ee58e23..1da1f875e 100644 --- a/packages/backend/src/models/repositories/follow-request.ts +++ b/packages/backend/src/models/repositories/follow-request.ts @@ -1,7 +1,7 @@ import { EntityRepository, Repository } from 'typeorm'; -import { FollowRequest } from '@/models/entities/follow-request'; -import { Users } from '../index'; -import { User } from '@/models/entities/user'; +import { FollowRequest } from '@/models/entities/follow-request.js'; +import { Users } from '../index.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(FollowRequest) export class FollowRequestRepository extends Repository { diff --git a/packages/backend/src/models/repositories/following.ts b/packages/backend/src/models/repositories/following.ts index 9d20f442d..f25289d19 100644 --- a/packages/backend/src/models/repositories/following.ts +++ b/packages/backend/src/models/repositories/following.ts @@ -1,9 +1,9 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Users } from '../index'; -import { Following } from '@/models/entities/following'; -import { awaitAll } from '@/prelude/await-all'; -import { Packed } from '@/misc/schema'; -import { User } from '@/models/entities/user'; +import { Users } from '../index.js'; +import { Following } from '@/models/entities/following.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { Packed } from '@/misc/schema.js'; +import { User } from '@/models/entities/user.js'; type LocalFollowerFollowing = Following & { followerHost: null; diff --git a/packages/backend/src/models/repositories/gallery-like.ts b/packages/backend/src/models/repositories/gallery-like.ts index 79123e5ee..545186fa1 100644 --- a/packages/backend/src/models/repositories/gallery-like.ts +++ b/packages/backend/src/models/repositories/gallery-like.ts @@ -1,6 +1,6 @@ import { EntityRepository, Repository } from 'typeorm'; -import { GalleryLike } from '@/models/entities/gallery-like'; -import { GalleryPosts } from '../index'; +import { GalleryLike } from '@/models/entities/gallery-like.js'; +import { GalleryPosts } from '../index.js'; @EntityRepository(GalleryLike) export class GalleryLikeRepository extends Repository { diff --git a/packages/backend/src/models/repositories/gallery-post.ts b/packages/backend/src/models/repositories/gallery-post.ts index e9233bb91..bbb036dd0 100644 --- a/packages/backend/src/models/repositories/gallery-post.ts +++ b/packages/backend/src/models/repositories/gallery-post.ts @@ -1,9 +1,9 @@ import { EntityRepository, Repository } from 'typeorm'; -import { GalleryPost } from '@/models/entities/gallery-post'; -import { Packed } from '@/misc/schema'; -import { Users, DriveFiles, GalleryLikes } from '../index'; -import { awaitAll } from '@/prelude/await-all'; -import { User } from '@/models/entities/user'; +import { GalleryPost } from '@/models/entities/gallery-post.js'; +import { Packed } from '@/misc/schema.js'; +import { Users, DriveFiles, GalleryLikes } from '../index.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(GalleryPost) export class GalleryPostRepository extends Repository { diff --git a/packages/backend/src/models/repositories/hashtag.ts b/packages/backend/src/models/repositories/hashtag.ts index c4b8d50c4..0548e19ee 100644 --- a/packages/backend/src/models/repositories/hashtag.ts +++ b/packages/backend/src/models/repositories/hashtag.ts @@ -1,6 +1,6 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Hashtag } from '@/models/entities/hashtag'; -import { Packed } from '@/misc/schema'; +import { Hashtag } from '@/models/entities/hashtag.js'; +import { Packed } from '@/misc/schema.js'; @EntityRepository(Hashtag) export class HashtagRepository extends Repository { diff --git a/packages/backend/src/models/repositories/instance.ts b/packages/backend/src/models/repositories/instance.ts new file mode 100644 index 000000000..358e055aa --- /dev/null +++ b/packages/backend/src/models/repositories/instance.ts @@ -0,0 +1,39 @@ +import { EntityRepository, Repository } from 'typeorm'; +import { Instance } from '@/models/entities/instance.js'; +import { Packed } from '@/misc/schema.js'; + +@EntityRepository(Instance) +export class InstanceRepository extends Repository { + public async pack( + instance: Instance, + ): Promise> { + return { + id: instance.id, + caughtAt: instance.caughtAt.toISOString(), + host: instance.host, + usersCount: instance.usersCount, + notesCount: instance.notesCount, + followingCount: instance.followingCount, + followersCount: instance.followersCount, + latestRequestSentAt: instance.latestRequestSentAt ? instance.latestRequestSentAt.toISOString() : null, + lastCommunicatedAt: instance.lastCommunicatedAt.toISOString(), + isNotResponding: instance.isNotResponding, + isSuspended: instance.isSuspended, + softwareName: instance.softwareName, + softwareVersion: instance.softwareVersion, + openRegistrations: instance.openRegistrations, + name: instance.name, + description: instance.description, + maintainerName: instance.maintainerName, + maintainerEmail: instance.maintainerEmail, + iconUrl: instance.iconUrl, + infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null, + }; + } + + public packMany( + instances: Instance[], + ) { + return Promise.all(instances.map(x => this.pack(x))); + } +} diff --git a/packages/backend/src/models/repositories/messaging-message.ts b/packages/backend/src/models/repositories/messaging-message.ts index 0a342430b..3f5170700 100644 --- a/packages/backend/src/models/repositories/messaging-message.ts +++ b/packages/backend/src/models/repositories/messaging-message.ts @@ -1,15 +1,11 @@ import { EntityRepository, Repository } from 'typeorm'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { Users, DriveFiles, UserGroups } from '../index'; -import { Packed } from '@/misc/schema'; -import { User } from '@/models/entities/user'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import { Users, DriveFiles, UserGroups } from '../index.js'; +import { Packed } from '@/misc/schema.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(MessagingMessage) export class MessagingMessageRepository extends Repository { - public validateText(text: string): boolean { - return text.trim().length <= 1000 && text.trim() != ''; - } - public async pack( src: MessagingMessage['id'] | MessagingMessage, me?: { id: User['id'] } | null | undefined, diff --git a/packages/backend/src/models/repositories/moderation-logs.ts b/packages/backend/src/models/repositories/moderation-logs.ts index 1585d5bfc..ea7810496 100644 --- a/packages/backend/src/models/repositories/moderation-logs.ts +++ b/packages/backend/src/models/repositories/moderation-logs.ts @@ -1,7 +1,7 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Users } from '../index'; -import { ModerationLog } from '@/models/entities/moderation-log'; -import { awaitAll } from '@/prelude/await-all'; +import { Users } from '../index.js'; +import { ModerationLog } from '@/models/entities/moderation-log.js'; +import { awaitAll } from '@/prelude/await-all.js'; @EntityRepository(ModerationLog) export class ModerationLogRepository extends Repository { @@ -12,7 +12,7 @@ export class ModerationLogRepository extends Repository { return await awaitAll({ id: log.id, - createdAt: log.createdAt, + createdAt: log.createdAt.toISOString(), type: log.type, info: log.info, userId: log.userId, diff --git a/packages/backend/src/models/repositories/muting.ts b/packages/backend/src/models/repositories/muting.ts index bdbe9b47d..6ffecc302 100644 --- a/packages/backend/src/models/repositories/muting.ts +++ b/packages/backend/src/models/repositories/muting.ts @@ -1,9 +1,9 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Users } from '../index'; -import { Muting } from '@/models/entities/muting'; -import { awaitAll } from '@/prelude/await-all'; -import { Packed } from '@/misc/schema'; -import { User } from '@/models/entities/user'; +import { Users } from '../index.js'; +import { Muting } from '@/models/entities/muting.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { Packed } from '@/misc/schema.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(Muting) export class MutingRepository extends Repository { diff --git a/packages/backend/src/models/repositories/note-favorite.ts b/packages/backend/src/models/repositories/note-favorite.ts index c5de55c0c..d7a7925eb 100644 --- a/packages/backend/src/models/repositories/note-favorite.ts +++ b/packages/backend/src/models/repositories/note-favorite.ts @@ -1,7 +1,7 @@ import { EntityRepository, Repository } from 'typeorm'; -import { NoteFavorite } from '@/models/entities/note-favorite'; -import { Notes } from '../index'; -import { User } from '@/models/entities/user'; +import { NoteFavorite } from '@/models/entities/note-favorite.js'; +import { Notes } from '../index.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(NoteFavorite) export class NoteFavoriteRepository extends Repository { @@ -13,7 +13,7 @@ export class NoteFavoriteRepository extends Repository { return { id: favorite.id, - createdAt: favorite.createdAt, + createdAt: favorite.createdAt.toISOString(), noteId: favorite.noteId, note: await Notes.pack(favorite.note || favorite.noteId, me), }; diff --git a/packages/backend/src/models/repositories/note-reaction.ts b/packages/backend/src/models/repositories/note-reaction.ts index 097574eff..a212b0d3e 100644 --- a/packages/backend/src/models/repositories/note-reaction.ts +++ b/packages/backend/src/models/repositories/note-reaction.ts @@ -1,9 +1,9 @@ import { EntityRepository, Repository } from 'typeorm'; -import { NoteReaction } from '@/models/entities/note-reaction'; -import { Notes, Users } from '../index'; -import { Packed } from '@/misc/schema'; -import { convertLegacyReaction } from '@/misc/reaction-lib'; -import { User } from '@/models/entities/user'; +import { NoteReaction } from '@/models/entities/note-reaction.js'; +import { Notes, Users } from '../index.js'; +import { Packed } from '@/misc/schema.js'; +import { convertLegacyReaction } from '@/misc/reaction-lib.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(NoteReaction) export class NoteReactionRepository extends Repository { @@ -23,10 +23,10 @@ export class NoteReactionRepository extends Repository { return { id: reaction.id, createdAt: reaction.createdAt.toISOString(), - user: await Users.pack(reaction.userId, me), + user: await Users.pack(reaction.user ?? reaction.userId, me), type: convertLegacyReaction(reaction.reaction), ...(opts.withNote ? { - note: await Notes.pack(reaction.noteId, me), + note: await Notes.pack(reaction.note ?? reaction.noteId, me), } : {}), }; } diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index 9a7fef497..418d6e234 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -1,21 +1,17 @@ import { EntityRepository, Repository, In } from 'typeorm'; import * as mfm from 'mfm-js'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; -import { Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls, Channels } from '../index'; -import { Packed } from '@/misc/schema'; -import { nyaize } from '@/misc/nyaize'; -import { awaitAll } from '@/prelude/await-all'; -import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib'; -import { NoteReaction } from '@/models/entities/note-reaction'; -import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis'; +import { Note } from '@/models/entities/note.js'; +import { User } from '@/models/entities/user.js'; +import { Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls, Channels } from '../index.js'; +import { Packed } from '@/misc/schema.js'; +import { nyaize } from '@/misc/nyaize.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib.js'; +import { NoteReaction } from '@/models/entities/note-reaction.js'; +import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; @EntityRepository(Note) export class NoteRepository extends Repository { - public validateCw(x: string) { - return x.trim().length <= 100; - } - public async isVisibleForMe(note: Note, meId: User['id'] | null): Promise { // visibility が specified かつč‡Ē分が指厚されãĻいãĒかãŖãŸã‚‰éžčĄ¨į¤ē if (note.visibility === 'specified') { @@ -206,8 +202,8 @@ export class NoteRepository extends Repository { let text = note.text; - if (note.name && (note.url || note.uri)) { - text = `【${note.name}】\n${(note.text || '').trim()}\n\n${note.url || note.uri}`; + if (note.name && (note.url ?? note.uri)) { + text = `【${note.name}】\n${(note.text || '').trim()}\n\n${note.url ?? note.uri}`; } const channel = note.channelId @@ -222,7 +218,7 @@ export class NoteRepository extends Repository { id: note.id, createdAt: note.createdAt.toISOString(), userId: note.userId, - user: Users.pack(note.user || note.userId, me, { + user: Users.pack(note.user ?? note.userId, me, { detail: false, }), text: text, diff --git a/packages/backend/src/models/repositories/notification.ts b/packages/backend/src/models/repositories/notification.ts index 5e4279889..441bb7926 100644 --- a/packages/backend/src/models/repositories/notification.ts +++ b/packages/backend/src/models/repositories/notification.ts @@ -1,13 +1,13 @@ import { EntityRepository, In, Repository } from 'typeorm'; -import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '../index'; -import { Notification } from '@/models/entities/notification'; -import { awaitAll } from '@/prelude/await-all'; -import { Packed } from '@/misc/schema'; -import { Note } from '@/models/entities/note'; -import { NoteReaction } from '@/models/entities/note-reaction'; -import { User } from '@/models/entities/user'; -import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis'; -import { notificationTypes } from '@/types'; +import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '../index.js'; +import { Notification } from '@/models/entities/notification.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { Packed } from '@/misc/schema.js'; +import { Note } from '@/models/entities/note.js'; +import { NoteReaction } from '@/models/entities/note-reaction.js'; +import { User } from '@/models/entities/user.js'; +import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; +import { notificationTypes } from '@/types.js'; @EntityRepository(Notification) export class NotificationRepository extends Repository { diff --git a/packages/backend/src/models/repositories/page-like.ts b/packages/backend/src/models/repositories/page-like.ts index 28f34254d..66d780584 100644 --- a/packages/backend/src/models/repositories/page-like.ts +++ b/packages/backend/src/models/repositories/page-like.ts @@ -1,7 +1,7 @@ import { EntityRepository, Repository } from 'typeorm'; -import { PageLike } from '@/models/entities/page-like'; -import { Pages } from '../index'; -import { User } from '@/models/entities/user'; +import { PageLike } from '@/models/entities/page-like.js'; +import { Pages } from '../index.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(PageLike) export class PageLikeRepository extends Repository { diff --git a/packages/backend/src/models/repositories/page.ts b/packages/backend/src/models/repositories/page.ts index ec76c2e41..037c13c43 100644 --- a/packages/backend/src/models/repositories/page.ts +++ b/packages/backend/src/models/repositories/page.ts @@ -1,10 +1,10 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Page } from '@/models/entities/page'; -import { Packed } from '@/misc/schema'; -import { Users, DriveFiles, PageLikes } from '../index'; -import { awaitAll } from '@/prelude/await-all'; -import { DriveFile } from '@/models/entities/drive-file'; -import { User } from '@/models/entities/user'; +import { Page } from '@/models/entities/page.js'; +import { Packed } from '@/misc/schema.js'; +import { Users, DriveFiles, PageLikes } from '../index.js'; +import { awaitAll } from '@/prelude/await-all.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { User } from '@/models/entities/user.js'; @EntityRepository(Page) export class PageRepository extends Repository { diff --git a/packages/backend/src/models/repositories/relay.ts b/packages/backend/src/models/repositories/relay.ts index 72ead899f..160ca60f7 100644 --- a/packages/backend/src/models/repositories/relay.ts +++ b/packages/backend/src/models/repositories/relay.ts @@ -1,5 +1,5 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Relay } from '@/models/entities/relay'; +import { Relay } from '@/models/entities/relay.js'; @EntityRepository(Relay) export class RelayRepository extends Repository { diff --git a/packages/backend/src/models/repositories/signin.ts b/packages/backend/src/models/repositories/signin.ts index f375f9b5c..a0e2ce152 100644 --- a/packages/backend/src/models/repositories/signin.ts +++ b/packages/backend/src/models/repositories/signin.ts @@ -1,5 +1,5 @@ import { EntityRepository, Repository } from 'typeorm'; -import { Signin } from '@/models/entities/signin'; +import { Signin } from '@/models/entities/signin.js'; @EntityRepository(Signin) export class SigninRepository extends Repository { diff --git a/packages/backend/src/models/repositories/user-group-invitation.ts b/packages/backend/src/models/repositories/user-group-invitation.ts index 638603d6e..e338242c6 100644 --- a/packages/backend/src/models/repositories/user-group-invitation.ts +++ b/packages/backend/src/models/repositories/user-group-invitation.ts @@ -1,6 +1,6 @@ import { EntityRepository, Repository } from 'typeorm'; -import { UserGroupInvitation } from '@/models/entities/user-group-invitation'; -import { UserGroups } from '../index'; +import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js'; +import { UserGroups } from '../index.js'; @EntityRepository(UserGroupInvitation) export class UserGroupInvitationRepository extends Repository { diff --git a/packages/backend/src/models/repositories/user-group.ts b/packages/backend/src/models/repositories/user-group.ts index 3ed37ca0e..a9ffe7369 100644 --- a/packages/backend/src/models/repositories/user-group.ts +++ b/packages/backend/src/models/repositories/user-group.ts @@ -1,7 +1,7 @@ import { EntityRepository, Repository } from 'typeorm'; -import { UserGroup } from '@/models/entities/user-group'; -import { UserGroupJoinings } from '../index'; -import { Packed } from '@/misc/schema'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { UserGroupJoinings } from '../index.js'; +import { Packed } from '@/misc/schema.js'; @EntityRepository(UserGroup) export class UserGroupRepository extends Repository { diff --git a/packages/backend/src/models/repositories/user-list.ts b/packages/backend/src/models/repositories/user-list.ts index a2bffe835..0ea26427f 100644 --- a/packages/backend/src/models/repositories/user-list.ts +++ b/packages/backend/src/models/repositories/user-list.ts @@ -1,7 +1,7 @@ import { EntityRepository, Repository } from 'typeorm'; -import { UserList } from '@/models/entities/user-list'; -import { UserListJoinings } from '../index'; -import { Packed } from '@/misc/schema'; +import { UserList } from '@/models/entities/user-list.js'; +import { UserListJoinings } from '../index.js'; +import { Packed } from '@/misc/schema.js'; @EntityRepository(UserList) export class UserListRepository extends Repository { diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 2b8398832..a909ab3ba 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -1,13 +1,13 @@ -import $ from 'cafy'; import { EntityRepository, Repository, In, Not } from 'typeorm'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user'; -import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '../index'; -import config from '@/config/index'; -import { Packed } from '@/misc/schema'; -import { awaitAll, Promiseable } from '@/prelude/await-all'; -import { populateEmojis } from '@/misc/populate-emojis'; -import { getAntennas } from '@/misc/antenna-cache'; -import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const'; +import Ajv from 'ajv'; +import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; +import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js'; +import config from '@/config/index.js'; +import { Packed } from '@/misc/schema.js'; +import { awaitAll, Promiseable } from '@/prelude/await-all.js'; +import { populateEmojis } from '@/misc/populate-emojis.js'; +import { getAntennas } from '@/misc/antenna-cache.js'; +import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js'; type IsUserDetailed = Detailed extends true ? Packed<'UserDetailed'> : Packed<'UserLite'>; type IsMeAndIsUserDetailed = @@ -17,8 +17,26 @@ type IsMeAndIsUserDetailed : Packed<'UserLite'>; +const ajv = new Ajv(); + @EntityRepository(User) export class UserRepository extends Repository { + public localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; + public passwordSchema = { type: 'string', minLength: 1 } as const; + public nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; + public descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const; + public locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; + public birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const; + + //#region Validators + public validateLocalUsername = ajv.compile(this.localUsernameSchema); + public validatePassword = ajv.compile(this.passwordSchema); + public validateName = ajv.compile(this.nameSchema); + public validateDescription = ajv.compile(this.descriptionSchema); + public validateLocation = ajv.compile(this.locationSchema); + public validateBirthday = ajv.compile(this.birthdaySchema); + //#endregion + public async getRelation(me: User['id'], target: User['id']) { const [following1, following2, followReq1, followReq2, toBlocking, fromBlocked, mute] = await Promise.all([ Followings.findOne({ @@ -164,13 +182,18 @@ export class UserRepository extends Repository { } public getAvatarUrl(user: User): string { - if (user.avatarUrl) { - return user.avatarUrl; + // TODO: avatarIdがあるがavatarがãĒい(JOINされãĻãĒい)場合ぎハãƒŗドãƒĒãƒŗグ + if (user.avatar) { + return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); } else { - return `${config.url}/identicon/${user.id}`; + return this.getIdenticonUrl(user.id); } } + public getIdenticonUrl(userId: User['id']): string { + return `${config.url}/identicon/${userId}`; + } + public async pack( src: User['id'] | User, me?: { id: User['id'] } | null | undefined, @@ -184,7 +207,18 @@ export class UserRepository extends Repository { includeSecrets: false, }, options); - const user = typeof src === 'object' ? src : await this.findOneOrFail(src); + let user: User; + + if (typeof src === 'object') { + user = src; + if (src.avatar === undefined && src.avatarId) src.avatar = await DriveFiles.findOne(src.avatarId) ?? null; + if (src.banner === undefined && src.bannerId) src.banner = await DriveFiles.findOne(src.bannerId) ?? null; + } else { + user = await this.findOneOrFail(src, { + relations: ['avatar', 'banner'], + }); + } + const meId = me ? me.id : null; const isMe = meId === user.id; @@ -214,12 +248,13 @@ export class UserRepository extends Repository { username: user.username, host: user.host, avatarUrl: this.getAvatarUrl(user), - avatarBlurhash: user.avatarBlurhash, + avatarBlurhash: user.avatar?.blurhash || null, avatarColor: null, // 垌斚äē’換性ぎため isAdmin: user.isAdmin || falsy, isModerator: user.isModerator || falsy, isBot: user.isBot || falsy, isCat: user.isCat || falsy, + showTimelineReplies: user.showTimelineReplies || falsy, instance: user.host ? Instances.findOne({ host: user.host }).then(instance => instance ? { name: instance.name, softwareName: instance.softwareName, @@ -237,8 +272,8 @@ export class UserRepository extends Repository { createdAt: user.createdAt.toISOString(), updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null, - bannerUrl: user.bannerUrl, - bannerBlurhash: user.bannerBlurhash, + bannerUrl: user.banner ? DriveFiles.getPublicUrl(user.banner, false) : null, + bannerBlurhash: user.banner?.blurhash || null, bannerColor: null, // 垌斚äē’換性ぎため isLocked: user.isLocked, isSilenced: user.isSilenced || falsy, @@ -350,13 +385,4 @@ export class UserRepository extends Repository { public isRemoteUser(user: User | { host: User['host'] }): boolean { return !this.isLocalUser(user); } - - //#region Validators - public validateLocalUsername = $.str.match(/^\w{1,20}$/); - public validatePassword = $.str.min(1); - public validateName = $.str.min(1).max(50); - public validateDescription = $.str.min(1).max(500); - public validateLocation = $.str.min(1).max(50); - public validateBirthday = $.str.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/); - //#endregion } diff --git a/packages/backend/src/models/schema/federation-instance.ts b/packages/backend/src/models/schema/federation-instance.ts index eef2f9e24..c4e7b3f18 100644 --- a/packages/backend/src/models/schema/federation-instance.ts +++ b/packages/backend/src/models/schema/federation-instance.ts @@ -1,4 +1,4 @@ -import config from "@/config"; +import config from '@/config/index.js'; export const packedFederationInstanceSchema = { type: 'object', @@ -34,14 +34,6 @@ export const packedFederationInstanceSchema = { type: 'number', optional: false, nullable: false, }, - driveUsage: { - type: 'number', - optional: false, nullable: false, - }, - driveFiles: { - type: 'number', - optional: false, nullable: false, - }, latestRequestSentAt: { type: 'string', optional: false, nullable: true, diff --git a/packages/backend/src/models/schema/notification.ts b/packages/backend/src/models/schema/notification.ts index f3c293c48..d3f2405cd 100644 --- a/packages/backend/src/models/schema/notification.ts +++ b/packages/backend/src/models/schema/notification.ts @@ -1,4 +1,4 @@ -import { notificationTypes } from "@/types"; +import { notificationTypes } from '@/types.js'; export const packedNotificationSchema = { type: 'object', diff --git a/packages/backend/src/prelude/array.ts b/packages/backend/src/prelude/array.ts index 1e9e62b89..0b2830cb7 100644 --- a/packages/backend/src/prelude/array.ts +++ b/packages/backend/src/prelude/array.ts @@ -1,4 +1,4 @@ -import { EndoRelation, Predicate } from './relation'; +import { EndoRelation, Predicate } from './relation.js'; /** * Count the number of elements that satisfy the predicate diff --git a/packages/backend/src/queue/get-job-info.ts b/packages/backend/src/queue/get-job-info.ts index f601ae62d..d33e349c3 100644 --- a/packages/backend/src/queue/get-job-info.ts +++ b/packages/backend/src/queue/get-job-info.ts @@ -1,4 +1,4 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; export function getJobInfo(job: Bull.Job, increment = false) { const age = Date.now() - job.timestamp; diff --git a/packages/backend/src/queue/index.ts b/packages/backend/src/queue/index.ts index f9994c3b5..94055e9c5 100644 --- a/packages/backend/src/queue/index.ts +++ b/packages/backend/src/queue/index.ts @@ -1,18 +1,19 @@ -import * as httpSignature from 'http-signature'; +import httpSignature from 'http-signature'; -import config from '@/config/index'; -import { envOption } from '../env'; +import config from '@/config/index.js'; +import { envOption } from '../env.js'; -import processDeliver from './processors/deliver'; -import processInbox from './processors/inbox'; -import processDb from './processors/db/index'; -import procesObjectStorage from './processors/object-storage/index'; -import { queueLogger } from './logger'; -import { DriveFile } from '@/models/entities/drive-file'; -import { getJobInfo } from './get-job-info'; -import { systemQueue, dbQueue, deliverQueue, inboxQueue, objectStorageQueue } from './queues'; -import { ThinUser } from './types'; -import { IActivity } from '@/remote/activitypub/type'; +import processDeliver from './processors/deliver.js'; +import processInbox from './processors/inbox.js'; +import processDb from './processors/db/index.js'; +import processObjectStorage from './processors/object-storage/index.js'; +import processSystemQueue from './processors/system/index.js'; +import { queueLogger } from './logger.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { getJobInfo } from './get-job-info.js'; +import { systemQueue, dbQueue, deliverQueue, inboxQueue, objectStorageQueue } from './queues.js'; +import { ThinUser } from './types.js'; +import { IActivity } from '@/remote/activitypub/type.js'; function renderError(e: Error): any { return { @@ -255,12 +256,24 @@ export default function() { deliverQueue.process(config.deliverJobConcurrency || 128, processDeliver); inboxQueue.process(config.inboxJobConcurrency || 16, processInbox); processDb(dbQueue); - procesObjectStorage(objectStorageQueue); + processObjectStorage(objectStorageQueue); + + systemQueue.add('tickCharts', { + }, { + repeat: { cron: '55 * * * *' }, + }); systemQueue.add('resyncCharts', { }, { repeat: { cron: '0 0 * * *' }, }); + + systemQueue.add('cleanCharts', { + }, { + repeat: { cron: '0 0 * * *' }, + }); + + processSystemQueue(systemQueue); } export function destroy() { diff --git a/packages/backend/src/queue/initialize.ts b/packages/backend/src/queue/initialize.ts index af9acb3ce..1db118ca9 100644 --- a/packages/backend/src/queue/initialize.ts +++ b/packages/backend/src/queue/initialize.ts @@ -1,5 +1,5 @@ -import * as Bull from 'bull'; -import config from '@/config/index'; +import Bull from 'bull'; +import config from '@/config/index.js'; export function initialize(name: string, limitPerSec = -1) { return new Bull(name, { diff --git a/packages/backend/src/queue/logger.ts b/packages/backend/src/queue/logger.ts index f789b9d07..2843a3c26 100644 --- a/packages/backend/src/queue/logger.ts +++ b/packages/backend/src/queue/logger.ts @@ -1,3 +1,3 @@ -import Logger from '@/services/logger'; +import Logger from '@/services/logger.js'; export const queueLogger = new Logger('queue', 'orange'); diff --git a/packages/backend/src/queue/processors/db/delete-account.ts b/packages/backend/src/queue/processors/db/delete-account.ts index 4b620842a..dbc1f16a4 100644 --- a/packages/backend/src/queue/processors/db/delete-account.ts +++ b/packages/backend/src/queue/processors/db/delete-account.ts @@ -1,12 +1,12 @@ -import * as Bull from 'bull'; -import { queueLogger } from '../../logger'; -import { DriveFiles, Notes, UserProfiles, Users } from '@/models/index'; -import { DbUserDeleteJobData } from '@/queue/types'; -import { Note } from '@/models/entities/note'; -import { DriveFile } from '@/models/entities/drive-file'; +import Bull from 'bull'; +import { queueLogger } from '../../logger.js'; +import { DriveFiles, Notes, UserProfiles, Users } from '@/models/index.js'; +import { DbUserDeleteJobData } from '@/queue/types.js'; +import { Note } from '@/models/entities/note.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; import { MoreThan } from 'typeorm'; -import { deleteFileSync } from '@/services/drive/delete-file'; -import { sendEmail } from '@/services/send-email'; +import { deleteFileSync } from '@/services/drive/delete-file.js'; +import { sendEmail } from '@/services/send-email.js'; const logger = queueLogger.createSubLogger('delete-account'); @@ -31,7 +31,7 @@ export async function deleteAccount(job: Bull.Job): Promise order: { id: 1, }, - }); + }) as Note[]; if (notes.length === 0) { break; @@ -58,7 +58,7 @@ export async function deleteAccount(job: Bull.Job): Promise order: { id: 1, }, - }); + }) as DriveFile[]; if (files.length === 0) { break; diff --git a/packages/backend/src/queue/processors/db/delete-drive-files.ts b/packages/backend/src/queue/processors/db/delete-drive-files.ts index d26f5a47c..f6a869985 100644 --- a/packages/backend/src/queue/processors/db/delete-drive-files.ts +++ b/packages/backend/src/queue/processors/db/delete-drive-files.ts @@ -1,10 +1,10 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; -import { queueLogger } from '../../logger'; -import { deleteFileSync } from '@/services/drive/delete-file'; -import { Users, DriveFiles } from '@/models/index'; +import { queueLogger } from '../../logger.js'; +import { deleteFileSync } from '@/services/drive/delete-file.js'; +import { Users, DriveFiles } from '@/models/index.js'; import { MoreThan } from 'typeorm'; -import { DbUserJobData } from '@/queue/types'; +import { DbUserJobData } from '@/queue/types.js'; const logger = queueLogger.createSubLogger('delete-drive-files'); diff --git a/packages/backend/src/queue/processors/db/export-blocking.ts b/packages/backend/src/queue/processors/db/export-blocking.ts index 01edaaeb6..83f1ec8fd 100644 --- a/packages/backend/src/queue/processors/db/export-blocking.ts +++ b/packages/backend/src/queue/processors/db/export-blocking.ts @@ -1,14 +1,14 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; import * as tmp from 'tmp'; -import * as fs from 'fs'; +import * as fs from 'node:fs'; -import { queueLogger } from '../../logger'; -import { addFile } from '@/services/drive/add-file'; -import * as dateFormat from 'dateformat'; -import { getFullApAccount } from '@/misc/convert-host'; -import { Users, Blockings } from '@/models/index'; +import { queueLogger } from '../../logger.js'; +import { addFile } from '@/services/drive/add-file.js'; +import { format as dateFormat } from 'date-fns'; +import { getFullApAccount } from '@/misc/convert-host.js'; +import { Users, Blockings } from '@/models/index.js'; import { MoreThan } from 'typeorm'; -import { DbUserJobData } from '@/queue/types'; +import { DbUserJobData } from '@/queue/types.js'; const logger = queueLogger.createSubLogger('export-blocking'); @@ -85,7 +85,7 @@ export async function exportBlocking(job: Bull.Job, done: any): P stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'blocking-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.csv'; + const fileName = 'blocking-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.csv'; const driveFile = await addFile({ user, path, name: fileName, force: true }); logger.succ(`Exported to: ${driveFile.id}`); diff --git a/packages/backend/src/queue/processors/db/export-custom-emojis.ts b/packages/backend/src/queue/processors/db/export-custom-emojis.ts index 240a542fe..a65b46cc0 100644 --- a/packages/backend/src/queue/processors/db/export-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/export-custom-emojis.ts @@ -1,17 +1,17 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; import * as tmp from 'tmp'; -import * as fs from 'fs'; +import * as fs from 'node:fs'; import { ulid } from 'ulid'; -const mime = require('mime-types'); -const archiver = require('archiver'); -import { queueLogger } from '../../logger'; -import { addFile } from '@/services/drive/add-file'; -import * as dateFormat from 'dateformat'; -import { Users, Emojis } from '@/models/index'; -import { } from '@/queue/types'; -import { downloadUrl } from '@/misc/download-url'; -import config from '@/config/index'; +import mime from 'mime-types'; +import archiver from 'archiver'; +import { queueLogger } from '../../logger.js'; +import { addFile } from '@/services/drive/add-file.js'; +import { format as dateFormat } from 'date-fns'; +import { Users, Emojis } from '@/models/index.js'; +import { } from '@/queue/types.js'; +import { downloadUrl } from '@/misc/download-url.js'; +import config from '@/config/index.js'; const logger = queueLogger.createSubLogger('export-custom-emojis'); @@ -75,7 +75,7 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi await downloadUrl(emoji.originalUrl, emojiPath); downloaded = true; } catch (e) { // TODO: äŊ•åēĻか再čŠĻ行 - logger.error(e); + logger.error(e instanceof Error ? e : new Error(e as string)); } if (!downloaded) { @@ -110,7 +110,7 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi archiveStream.on('close', async () => { logger.succ(`Exported to: ${archivePath}`); - const fileName = 'custom-emojis-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.zip'; + const fileName = 'custom-emojis-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.zip'; const driveFile = await addFile({ user, path: archivePath, name: fileName, force: true }); logger.succ(`Exported to: ${driveFile.id}`); diff --git a/packages/backend/src/queue/processors/db/export-following.ts b/packages/backend/src/queue/processors/db/export-following.ts index 06572acec..162862180 100644 --- a/packages/backend/src/queue/processors/db/export-following.ts +++ b/packages/backend/src/queue/processors/db/export-following.ts @@ -1,15 +1,15 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; import * as tmp from 'tmp'; -import * as fs from 'fs'; +import * as fs from 'node:fs'; -import { queueLogger } from '../../logger'; -import { addFile } from '@/services/drive/add-file'; -import * as dateFormat from 'dateformat'; -import { getFullApAccount } from '@/misc/convert-host'; -import { Users, Followings, Mutings } from '@/models/index'; +import { queueLogger } from '../../logger.js'; +import { addFile } from '@/services/drive/add-file.js'; +import { format as dateFormat } from 'date-fns'; +import { getFullApAccount } from '@/misc/convert-host.js'; +import { Users, Followings, Mutings } from '@/models/index.js'; import { In, MoreThan, Not } from 'typeorm'; -import { DbUserJobData } from '@/queue/types'; -import { Following } from '@/models/entities/following'; +import { DbUserJobData } from '@/queue/types.js'; +import { Following } from '@/models/entities/following.js'; const logger = queueLogger.createSubLogger('export-following'); @@ -51,7 +51,7 @@ export async function exportFollowing(job: Bull.Job, done: () => order: { id: 1, }, - }); + }) as Following[]; if (followings.length === 0) { break; @@ -86,7 +86,7 @@ export async function exportFollowing(job: Bull.Job, done: () => stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'following-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.csv'; + const fileName = 'following-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.csv'; const driveFile = await addFile({ user, path, name: fileName, force: true }); logger.succ(`Exported to: ${driveFile.id}`); diff --git a/packages/backend/src/queue/processors/db/export-mute.ts b/packages/backend/src/queue/processors/db/export-mute.ts index 4a856f8ef..8602e00bf 100644 --- a/packages/backend/src/queue/processors/db/export-mute.ts +++ b/packages/backend/src/queue/processors/db/export-mute.ts @@ -1,14 +1,14 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; import * as tmp from 'tmp'; -import * as fs from 'fs'; +import * as fs from 'node:fs'; -import { queueLogger } from '../../logger'; -import { addFile } from '@/services/drive/add-file'; -import * as dateFormat from 'dateformat'; -import { getFullApAccount } from '@/misc/convert-host'; -import { Users, Mutings } from '@/models/index'; +import { queueLogger } from '../../logger.js'; +import { addFile } from '@/services/drive/add-file.js'; +import { format as dateFormat } from 'date-fns'; +import { getFullApAccount } from '@/misc/convert-host.js'; +import { Users, Mutings } from '@/models/index.js'; import { MoreThan } from 'typeorm'; -import { DbUserJobData } from '@/queue/types'; +import { DbUserJobData } from '@/queue/types.js'; const logger = queueLogger.createSubLogger('export-mute'); @@ -85,7 +85,7 @@ export async function exportMute(job: Bull.Job, done: any): Promi stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'mute-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.csv'; + const fileName = 'mute-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.csv'; const driveFile = await addFile({ user, path, name: fileName, force: true }); logger.succ(`Exported to: ${driveFile.id}`); diff --git a/packages/backend/src/queue/processors/db/export-notes.ts b/packages/backend/src/queue/processors/db/export-notes.ts index 305abf44c..c79679366 100644 --- a/packages/backend/src/queue/processors/db/export-notes.ts +++ b/packages/backend/src/queue/processors/db/export-notes.ts @@ -1,15 +1,15 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; import * as tmp from 'tmp'; -import * as fs from 'fs'; +import * as fs from 'node:fs'; -import { queueLogger } from '../../logger'; -import { addFile } from '@/services/drive/add-file'; -import * as dateFormat from 'dateformat'; -import { Users, Notes, Polls } from '@/models/index'; +import { queueLogger } from '../../logger.js'; +import { addFile } from '@/services/drive/add-file.js'; +import { format as dateFormat } from 'date-fns'; +import { Users, Notes, Polls } from '@/models/index.js'; import { MoreThan } from 'typeorm'; -import { Note } from '@/models/entities/note'; -import { Poll } from '@/models/entities/poll'; -import { DbUserJobData } from '@/queue/types'; +import { Note } from '@/models/entities/note.js'; +import { Poll } from '@/models/entities/poll.js'; +import { DbUserJobData } from '@/queue/types.js'; const logger = queueLogger.createSubLogger('export-notes'); @@ -62,7 +62,7 @@ export async function exportNotes(job: Bull.Job, done: any): Prom order: { id: 1, }, - }); + }) as Note[]; if (notes.length === 0) { job.progress(100); @@ -94,7 +94,7 @@ export async function exportNotes(job: Bull.Job, done: any): Prom stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'notes-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.json'; + const fileName = 'notes-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.json'; const driveFile = await addFile({ user, path, name: fileName, force: true }); logger.succ(`Exported to: ${driveFile.id}`); diff --git a/packages/backend/src/queue/processors/db/export-user-lists.ts b/packages/backend/src/queue/processors/db/export-user-lists.ts index f907cf952..1c04c3678 100644 --- a/packages/backend/src/queue/processors/db/export-user-lists.ts +++ b/packages/backend/src/queue/processors/db/export-user-lists.ts @@ -1,14 +1,14 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; import * as tmp from 'tmp'; -import * as fs from 'fs'; +import * as fs from 'node:fs'; -import { queueLogger } from '../../logger'; -import { addFile } from '@/services/drive/add-file'; -import * as dateFormat from 'dateformat'; -import { getFullApAccount } from '@/misc/convert-host'; -import { Users, UserLists, UserListJoinings } from '@/models/index'; +import { queueLogger } from '../../logger.js'; +import { addFile } from '@/services/drive/add-file.js'; +import { format as dateFormat } from 'date-fns'; +import { getFullApAccount } from '@/misc/convert-host.js'; +import { Users, UserLists, UserListJoinings } from '@/models/index.js'; import { In } from 'typeorm'; -import { DbUserJobData } from '@/queue/types'; +import { DbUserJobData } from '@/queue/types.js'; const logger = queueLogger.createSubLogger('export-user-lists'); @@ -62,7 +62,7 @@ export async function exportUserLists(job: Bull.Job, done: any): stream.end(); logger.succ(`Exported to: ${path}`); - const fileName = 'user-lists-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.csv'; + const fileName = 'user-lists-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.csv'; const driveFile = await addFile({ user, path, name: fileName, force: true }); logger.succ(`Exported to: ${driveFile.id}`); diff --git a/packages/backend/src/queue/processors/db/import-blocking.ts b/packages/backend/src/queue/processors/db/import-blocking.ts index 42c3cd0a4..857c2629e 100644 --- a/packages/backend/src/queue/processors/db/import-blocking.ts +++ b/packages/backend/src/queue/processors/db/import-blocking.ts @@ -1,13 +1,13 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; -import { queueLogger } from '../../logger'; -import * as Acct from 'misskey-js/built/acct'; -import { resolveUser } from '@/remote/resolve-user'; -import { downloadTextFile } from '@/misc/download-text-file'; -import { isSelfHost, toPuny } from '@/misc/convert-host'; -import { Users, DriveFiles, Blockings } from '@/models/index'; -import { DbUserImportJobData } from '@/queue/types'; -import block from '@/services/blocking/create'; +import { queueLogger } from '../../logger.js'; +import * as Acct from '@/misc/acct.js'; +import { resolveUser } from '@/remote/resolve-user.js'; +import { downloadTextFile } from '@/misc/download-text-file.js'; +import { isSelfHost, toPuny } from '@/misc/convert-host.js'; +import { Users, DriveFiles, Blockings } from '@/models/index.js'; +import { DbUserImportJobData } from '@/queue/types.js'; +import block from '@/services/blocking/create.js'; const logger = queueLogger.createSubLogger('import-blocking'); diff --git a/packages/backend/src/queue/processors/db/import-custom-emojis.ts b/packages/backend/src/queue/processors/db/import-custom-emojis.ts index 04e93671e..f862276b4 100644 --- a/packages/backend/src/queue/processors/db/import-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/import-custom-emojis.ts @@ -1,15 +1,15 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; import * as tmp from 'tmp'; -import * as fs from 'fs'; -const unzipper = require('unzipper'); +import * as fs from 'node:fs'; +import unzipper from 'unzipper'; import { getConnection } from 'typeorm'; -import { queueLogger } from '../../logger'; -import { downloadUrl } from '@/misc/download-url'; -import { DriveFiles, Emojis } from '@/models/index'; -import { DbUserImportJobData } from '@/queue/types'; -import { addFile } from '@/services/drive/add-file'; -import { genId } from '@/misc/gen-id'; +import { queueLogger } from '../../logger.js'; +import { downloadUrl } from '@/misc/download-url.js'; +import { DriveFiles, Emojis } from '@/models/index.js'; +import { DbUserImportJobData } from '@/queue/types.js'; +import { addFile } from '@/services/drive/add-file.js'; +import { genId } from '@/misc/gen-id.js'; const logger = queueLogger.createSubLogger('import-custom-emojis'); @@ -41,7 +41,9 @@ export async function importCustomEmojis(job: Bull.Job, don fs.writeFileSync(destPath, '', 'binary'); await downloadUrl(file.url, destPath); } catch (e) { // TODO: äŊ•åēĻか再čŠĻ行 - logger.error(e); + if (e instanceof Error || typeof e === 'string') { + logger.error(e); + } throw e; } diff --git a/packages/backend/src/queue/processors/db/import-following.ts b/packages/backend/src/queue/processors/db/import-following.ts index f19296832..235fc2839 100644 --- a/packages/backend/src/queue/processors/db/import-following.ts +++ b/packages/backend/src/queue/processors/db/import-following.ts @@ -1,13 +1,13 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; -import { queueLogger } from '../../logger'; -import follow from '@/services/following/create'; -import * as Acct from 'misskey-js/built/acct'; -import { resolveUser } from '@/remote/resolve-user'; -import { downloadTextFile } from '@/misc/download-text-file'; -import { isSelfHost, toPuny } from '@/misc/convert-host'; -import { Users, DriveFiles } from '@/models/index'; -import { DbUserImportJobData } from '@/queue/types'; +import { queueLogger } from '../../logger.js'; +import follow from '@/services/following/create.js'; +import * as Acct from '@/misc/acct.js'; +import { resolveUser } from '@/remote/resolve-user.js'; +import { downloadTextFile } from '@/misc/download-text-file.js'; +import { isSelfHost, toPuny } from '@/misc/convert-host.js'; +import { Users, DriveFiles } from '@/models/index.js'; +import { DbUserImportJobData } from '@/queue/types.js'; const logger = queueLogger.createSubLogger('import-following'); diff --git a/packages/backend/src/queue/processors/db/import-muting.ts b/packages/backend/src/queue/processors/db/import-muting.ts index 189740c29..32f5f6bbe 100644 --- a/packages/backend/src/queue/processors/db/import-muting.ts +++ b/packages/backend/src/queue/processors/db/import-muting.ts @@ -1,14 +1,14 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; -import { queueLogger } from '../../logger'; -import * as Acct from 'misskey-js/built/acct'; -import { resolveUser } from '@/remote/resolve-user'; -import { downloadTextFile } from '@/misc/download-text-file'; -import { isSelfHost, toPuny } from '@/misc/convert-host'; -import { Users, DriveFiles, Mutings } from '@/models/index'; -import { DbUserImportJobData } from '@/queue/types'; -import { User } from '@/models/entities/user'; -import { genId } from '@/misc/gen-id'; +import { queueLogger } from '../../logger.js'; +import * as Acct from '@/misc/acct.js'; +import { resolveUser } from '@/remote/resolve-user.js'; +import { downloadTextFile } from '@/misc/download-text-file.js'; +import { isSelfHost, toPuny } from '@/misc/convert-host.js'; +import { Users, DriveFiles, Mutings } from '@/models/index.js'; +import { DbUserImportJobData } from '@/queue/types.js'; +import { User } from '@/models/entities/user.js'; +import { genId } from '@/misc/gen-id.js'; const logger = queueLogger.createSubLogger('import-muting'); diff --git a/packages/backend/src/queue/processors/db/import-user-lists.ts b/packages/backend/src/queue/processors/db/import-user-lists.ts index e060e86dd..ae263e19b 100644 --- a/packages/backend/src/queue/processors/db/import-user-lists.ts +++ b/packages/backend/src/queue/processors/db/import-user-lists.ts @@ -1,14 +1,14 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; -import { queueLogger } from '../../logger'; -import * as Acct from 'misskey-js/built/acct'; -import { resolveUser } from '@/remote/resolve-user'; -import { pushUserToUserList } from '@/services/user-list/push'; -import { downloadTextFile } from '@/misc/download-text-file'; -import { isSelfHost, toPuny } from '@/misc/convert-host'; -import { DriveFiles, Users, UserLists, UserListJoinings } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { DbUserImportJobData } from '@/queue/types'; +import { queueLogger } from '../../logger.js'; +import * as Acct from '@/misc/acct.js'; +import { resolveUser } from '@/remote/resolve-user.js'; +import { pushUserToUserList } from '@/services/user-list/push.js'; +import { downloadTextFile } from '@/misc/download-text-file.js'; +import { isSelfHost, toPuny } from '@/misc/convert-host.js'; +import { DriveFiles, Users, UserLists, UserListJoinings } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { DbUserImportJobData } from '@/queue/types.js'; const logger = queueLogger.createSubLogger('import-user-lists'); @@ -51,7 +51,6 @@ export async function importUserLists(job: Bull.Job, done: createdAt: new Date(), userId: user.id, name: listName, - userIds: [], }).then(x => UserLists.findOneOrFail(x.identifiers[0])); } @@ -67,9 +66,9 @@ export async function importUserLists(job: Bull.Job, done: target = await resolveUser(username, host); } - if (await UserListJoinings.findOne({ userListId: list.id, userId: target.id }) != null) continue; + if (await UserListJoinings.findOne({ userListId: list!.id, userId: target.id }) != null) continue; - pushUserToUserList(target, list); + pushUserToUserList(target, list!); } catch (e) { logger.warn(`Error in line:${linenum} ${e}`); } diff --git a/packages/backend/src/queue/processors/db/index.ts b/packages/backend/src/queue/processors/db/index.ts index 5fffa378f..e91d56977 100644 --- a/packages/backend/src/queue/processors/db/index.ts +++ b/packages/backend/src/queue/processors/db/index.ts @@ -1,18 +1,18 @@ -import * as Bull from 'bull'; -import { DbJobData } from '@/queue/types'; -import { deleteDriveFiles } from './delete-drive-files'; -import { exportCustomEmojis } from './export-custom-emojis'; -import { exportNotes } from './export-notes'; -import { exportFollowing } from './export-following'; -import { exportMute } from './export-mute'; -import { exportBlocking } from './export-blocking'; -import { exportUserLists } from './export-user-lists'; -import { importFollowing } from './import-following'; -import { importUserLists } from './import-user-lists'; -import { deleteAccount } from './delete-account'; -import { importMuting } from './import-muting'; -import { importBlocking } from './import-blocking'; -import { importCustomEmojis } from './import-custom-emojis'; +import Bull from 'bull'; +import { DbJobData } from '@/queue/types.js'; +import { deleteDriveFiles } from './delete-drive-files.js'; +import { exportCustomEmojis } from './export-custom-emojis.js'; +import { exportNotes } from './export-notes.js'; +import { exportFollowing } from './export-following.js'; +import { exportMute } from './export-mute.js'; +import { exportBlocking } from './export-blocking.js'; +import { exportUserLists } from './export-user-lists.js'; +import { importFollowing } from './import-following.js'; +import { importUserLists } from './import-user-lists.js'; +import { deleteAccount } from './delete-account.js'; +import { importMuting } from './import-muting.js'; +import { importBlocking } from './import-blocking.js'; +import { importCustomEmojis } from './import-custom-emojis.js'; const jobs = { deleteDriveFiles, diff --git a/packages/backend/src/queue/processors/deliver.ts b/packages/backend/src/queue/processors/deliver.ts index 46aeb8cb7..291c05766 100644 --- a/packages/backend/src/queue/processors/deliver.ts +++ b/packages/backend/src/queue/processors/deliver.ts @@ -1,17 +1,17 @@ -import { URL } from 'url'; -import * as Bull from 'bull'; -import request from '@/remote/activitypub/request'; -import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc'; -import Logger from '@/services/logger'; -import { Instances } from '@/models/index'; -import { instanceChart } from '@/services/chart/index'; -import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { toPuny } from '@/misc/convert-host'; -import { Cache } from '@/misc/cache'; -import { Instance } from '@/models/entities/instance'; -import { DeliverJobData } from '../types'; -import { StatusError } from '@/misc/fetch'; +import { URL } from 'node:url'; +import Bull from 'bull'; +import request from '@/remote/activitypub/request.js'; +import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc.js'; +import Logger from '@/services/logger.js'; +import { Instances } from '@/models/index.js'; +import { apRequestChart, federationChart, instanceChart } from '@/services/chart/index.js'; +import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { toPuny } from '@/misc/convert-host.js'; +import { Cache } from '@/misc/cache.js'; +import { Instance } from '@/models/entities/instance.js'; +import { DeliverJobData } from '../types.js'; +import { StatusError } from '@/misc/fetch.js'; const logger = new Logger('deliver'); @@ -61,6 +61,8 @@ export default async (job: Bull.Job) => { fetchInstanceMetadata(i); instanceChart.requestSent(i.host, true); + apRequestChart.deliverSucc(); + federationChart.deliverd(i.host, true); }); return 'Success'; @@ -74,6 +76,8 @@ export default async (job: Bull.Job) => { }); instanceChart.requestSent(i.host, false); + apRequestChart.deliverFail(); + federationChart.deliverd(i.host, false); }); if (res instanceof StatusError) { diff --git a/packages/backend/src/queue/processors/inbox.ts b/packages/backend/src/queue/processors/inbox.ts index bfdebc007..1b3f94b70 100644 --- a/packages/backend/src/queue/processors/inbox.ts +++ b/packages/backend/src/queue/processors/inbox.ts @@ -1,20 +1,20 @@ -import { URL } from 'url'; -import * as Bull from 'bull'; -import * as httpSignature from 'http-signature'; -import perform from '@/remote/activitypub/perform'; -import Logger from '@/services/logger'; -import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc'; -import { Instances } from '@/models/index'; -import { instanceChart } from '@/services/chart/index'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { toPuny, extractDbHost } from '@/misc/convert-host'; -import { getApId } from '@/remote/activitypub/type'; -import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata'; -import { InboxJobData } from '../types'; -import DbResolver from '@/remote/activitypub/db-resolver'; -import { resolvePerson } from '@/remote/activitypub/models/person'; -import { LdSignature } from '@/remote/activitypub/misc/ld-signature'; -import { StatusError } from '@/misc/fetch'; +import { URL } from 'node:url'; +import Bull from 'bull'; +import httpSignature from 'http-signature'; +import perform from '@/remote/activitypub/perform.js'; +import Logger from '@/services/logger.js'; +import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc.js'; +import { Instances } from '@/models/index.js'; +import { apRequestChart, federationChart, instanceChart } from '@/services/chart/index.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { toPuny, extractDbHost } from '@/misc/convert-host.js'; +import { getApId } from '@/remote/activitypub/type.js'; +import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; +import { InboxJobData } from '../types.js'; +import DbResolver from '@/remote/activitypub/db-resolver.js'; +import { resolvePerson } from '@/remote/activitypub/models/person.js'; +import { LdSignature } from '@/remote/activitypub/misc/ld-signature.js'; +import { StatusError } from '@/misc/fetch.js'; const logger = new Logger('inbox'); @@ -54,10 +54,12 @@ export default async (job: Bull.Job): Promise => { authUser = await dbResolver.getAuthUserFromApId(getApId(activity.actor)); } catch (e) { // å¯žčąĄãŒ4xxãĒら゚キップ - if (e instanceof StatusError && e.isClientError) { - return `skip: Ignored deleted actors on both ends ${activity.actor} - ${e.statusCode}`; + if (e instanceof StatusError) { + if (e.isClientError) { + return `skip: Ignored deleted actors on both ends ${activity.actor} - ${e.statusCode}`; + } + throw `Error in actor ${activity.actor} - ${e.statusCode || e}`; } - throw `Error in actor ${activity.actor} - ${e.statusCode || e}`; } } @@ -141,6 +143,8 @@ export default async (job: Bull.Job): Promise => { fetchInstanceMetadata(i); instanceChart.requestReceived(i.host); + apRequestChart.inbox(); + federationChart.inbox(i.host); }); // ã‚ĸクテã‚Ŗビテã‚Ŗをå‡Ļį† diff --git a/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts b/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts index 788383a0a..7d71a20ad 100644 --- a/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts +++ b/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts @@ -1,8 +1,8 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; -import { queueLogger } from '../../logger'; -import { deleteFileSync } from '@/services/drive/delete-file'; -import { DriveFiles } from '@/models/index'; +import { queueLogger } from '../../logger.js'; +import { deleteFileSync } from '@/services/drive/delete-file.js'; +import { DriveFiles } from '@/models/index.js'; import { MoreThan, Not, IsNull } from 'typeorm'; const logger = queueLogger.createSubLogger('clean-remote-files'); diff --git a/packages/backend/src/queue/processors/object-storage/delete-file.ts b/packages/backend/src/queue/processors/object-storage/delete-file.ts index ed22968a2..c271e3ddd 100644 --- a/packages/backend/src/queue/processors/object-storage/delete-file.ts +++ b/packages/backend/src/queue/processors/object-storage/delete-file.ts @@ -1,6 +1,6 @@ -import { ObjectStorageFileJobData } from '@/queue/types'; -import * as Bull from 'bull'; -import { deleteObjectStorageFile } from '@/services/drive/delete-file'; +import { ObjectStorageFileJobData } from '@/queue/types.js'; +import Bull from 'bull'; +import { deleteObjectStorageFile } from '@/services/drive/delete-file.js'; export default async (job: Bull.Job) => { const key: string = job.data.key; diff --git a/packages/backend/src/queue/processors/object-storage/index.ts b/packages/backend/src/queue/processors/object-storage/index.ts index 0d9570e17..ae6c481fe 100644 --- a/packages/backend/src/queue/processors/object-storage/index.ts +++ b/packages/backend/src/queue/processors/object-storage/index.ts @@ -1,7 +1,7 @@ -import * as Bull from 'bull'; -import { ObjectStorageJobData } from '@/queue/types'; -import deleteFile from './delete-file'; -import cleanRemoteFiles from './clean-remote-files'; +import Bull from 'bull'; +import { ObjectStorageJobData } from '@/queue/types.js'; +import deleteFile from './delete-file.js'; +import cleanRemoteFiles from './clean-remote-files.js'; const jobs = { deleteFile, diff --git a/packages/backend/src/queue/processors/system/clean-charts.ts b/packages/backend/src/queue/processors/system/clean-charts.ts new file mode 100644 index 000000000..c9169d5ac --- /dev/null +++ b/packages/backend/src/queue/processors/system/clean-charts.ts @@ -0,0 +1,28 @@ +import Bull from 'bull'; + +import { queueLogger } from '../../logger.js'; +import { activeUsersChart, driveChart, federationChart, hashtagChart, instanceChart, notesChart, perUserDriveChart, perUserFollowingChart, perUserNotesChart, perUserReactionsChart, usersChart, apRequestChart } from '@/services/chart/index.js'; + +const logger = queueLogger.createSubLogger('clean-charts'); + +export async function cleanCharts(job: Bull.Job>, done: any): Promise { + logger.info(`Clean charts...`); + + await Promise.all([ + federationChart.clean(), + notesChart.clean(), + usersChart.clean(), + activeUsersChart.clean(), + instanceChart.clean(), + perUserNotesChart.clean(), + driveChart.clean(), + perUserReactionsChart.clean(), + hashtagChart.clean(), + perUserFollowingChart.clean(), + perUserDriveChart.clean(), + apRequestChart.clean(), + ]); + + logger.succ(`All charts successfully cleaned.`); + done(); +} diff --git a/packages/backend/src/queue/processors/system/index.ts b/packages/backend/src/queue/processors/system/index.ts index 8460ea0a9..dca3249e8 100644 --- a/packages/backend/src/queue/processors/system/index.ts +++ b/packages/backend/src/queue/processors/system/index.ts @@ -1,8 +1,12 @@ -import * as Bull from 'bull'; -import { resyncCharts } from './resync-charts'; +import Bull from 'bull'; +import { tickCharts } from './tick-charts.js'; +import { resyncCharts } from './resync-charts.js'; +import { cleanCharts } from './clean-charts.js'; const jobs = { + tickCharts, resyncCharts, + cleanCharts, } as Record> | Bull.ProcessPromiseFunction>>; export default function(dbQueue: Bull.Queue>) { diff --git a/packages/backend/src/queue/processors/system/resync-charts.ts b/packages/backend/src/queue/processors/system/resync-charts.ts index 78a70bb98..20012513a 100644 --- a/packages/backend/src/queue/processors/system/resync-charts.ts +++ b/packages/backend/src/queue/processors/system/resync-charts.ts @@ -1,7 +1,7 @@ -import * as Bull from 'bull'; +import Bull from 'bull'; -import { queueLogger } from '../../logger'; -import { driveChart, notesChart, usersChart } from '@/services/chart/index'; +import { queueLogger } from '../../logger.js'; +import { driveChart, notesChart, usersChart } from '@/services/chart/index.js'; const logger = queueLogger.createSubLogger('resync-charts'); diff --git a/packages/backend/src/queue/processors/system/tick-charts.ts b/packages/backend/src/queue/processors/system/tick-charts.ts new file mode 100644 index 000000000..13403f8f7 --- /dev/null +++ b/packages/backend/src/queue/processors/system/tick-charts.ts @@ -0,0 +1,28 @@ +import Bull from 'bull'; + +import { queueLogger } from '../../logger.js'; +import { activeUsersChart, driveChart, federationChart, hashtagChart, instanceChart, notesChart, perUserDriveChart, perUserFollowingChart, perUserNotesChart, perUserReactionsChart, usersChart, apRequestChart } from '@/services/chart/index.js'; + +const logger = queueLogger.createSubLogger('tick-charts'); + +export async function tickCharts(job: Bull.Job>, done: any): Promise { + logger.info(`Tick charts...`); + + await Promise.all([ + federationChart.tick(false), + notesChart.tick(false), + usersChart.tick(false), + activeUsersChart.tick(false), + instanceChart.tick(false), + perUserNotesChart.tick(false), + driveChart.tick(false), + perUserReactionsChart.tick(false), + hashtagChart.tick(false), + perUserFollowingChart.tick(false), + perUserDriveChart.tick(false), + apRequestChart.tick(false), + ]); + + logger.succ(`All charts successfully ticked.`); + done(); +} diff --git a/packages/backend/src/queue/queues.ts b/packages/backend/src/queue/queues.ts index b1d790fcb..6ac4ec69c 100644 --- a/packages/backend/src/queue/queues.ts +++ b/packages/backend/src/queue/queues.ts @@ -1,6 +1,6 @@ -import config from '@/config/index'; -import { initialize as initializeQueue } from './initialize'; -import { DeliverJobData, InboxJobData, DbJobData, ObjectStorageJobData } from './types'; +import config from '@/config/index.js'; +import { initialize as initializeQueue } from './initialize.js'; +import { DeliverJobData, InboxJobData, DbJobData, ObjectStorageJobData } from './types.js'; export const systemQueue = initializeQueue>('system'); export const deliverQueue = initializeQueue('deliver', config.deliverJobPerSec || 128); diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index 91036177d..de5f5d139 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -1,7 +1,7 @@ -import { DriveFile } from '@/models/entities/drive-file'; -import { User } from '@/models/entities/user'; -import { IActivity } from '@/remote/activitypub/type'; -import * as httpSignature from 'http-signature'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { User } from '@/models/entities/user.js'; +import { IActivity } from '@/remote/activitypub/type.js'; +import httpSignature from 'http-signature'; export type DeliverJobData = { /** Actor */ diff --git a/packages/backend/src/remote/activitypub/ap-request.ts b/packages/backend/src/remote/activitypub/ap-request.ts index c75f44f2e..96bfec3b1 100644 --- a/packages/backend/src/remote/activitypub/ap-request.ts +++ b/packages/backend/src/remote/activitypub/ap-request.ts @@ -1,5 +1,5 @@ -import * as crypto from 'crypto'; -import { URL } from 'url'; +import * as crypto from 'node:crypto'; +import { URL } from 'node:url'; type Request = { url: string; diff --git a/packages/backend/src/remote/activitypub/audience.ts b/packages/backend/src/remote/activitypub/audience.ts index e82ed94a6..ba69b11e8 100644 --- a/packages/backend/src/remote/activitypub/audience.ts +++ b/packages/backend/src/remote/activitypub/audience.ts @@ -1,9 +1,9 @@ -import { ApObject, getApIds } from './type'; -import Resolver from './resolver'; -import { resolvePerson } from './models/person'; -import { unique, concat } from '@/prelude/array'; -import * as promiseLimit from 'promise-limit'; -import { User, IRemoteUser } from '@/models/entities/user'; +import { ApObject, getApIds } from './type.js'; +import Resolver from './resolver.js'; +import { resolvePerson } from './models/person.js'; +import { unique, concat } from '@/prelude/array.js'; +import promiseLimit from 'promise-limit'; +import { User, IRemoteUser } from '@/models/entities/user.js'; type Visibility = 'public' | 'home' | 'followers' | 'specified'; diff --git a/packages/backend/src/remote/activitypub/db-resolver.ts b/packages/backend/src/remote/activitypub/db-resolver.ts index f2064cf26..9281e494d 100644 --- a/packages/backend/src/remote/activitypub/db-resolver.ts +++ b/packages/backend/src/remote/activitypub/db-resolver.ts @@ -1,12 +1,12 @@ -import config from '@/config/index'; -import { Note } from '@/models/entities/note'; -import { User, IRemoteUser } from '@/models/entities/user'; -import { UserPublickey } from '@/models/entities/user-publickey'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { Notes, Users, UserPublickeys, MessagingMessages } from '@/models/index'; -import { IObject, getApId } from './type'; -import { resolvePerson } from './models/person'; -import escapeRegexp = require('escape-regexp'); +import config from '@/config/index.js'; +import { Note } from '@/models/entities/note.js'; +import { User, IRemoteUser } from '@/models/entities/user.js'; +import { UserPublickey } from '@/models/entities/user-publickey.js'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import { Notes, Users, UserPublickeys, MessagingMessages } from '@/models/index.js'; +import { IObject, getApId } from './type.js'; +import { resolvePerson } from './models/person.js'; +import escapeRegexp from 'escape-regexp'; export default class DbResolver { constructor() { diff --git a/packages/backend/src/remote/activitypub/deliver-manager.ts b/packages/backend/src/remote/activitypub/deliver-manager.ts index b16f90769..9c4e3418f 100644 --- a/packages/backend/src/remote/activitypub/deliver-manager.ts +++ b/packages/backend/src/remote/activitypub/deliver-manager.ts @@ -1,6 +1,6 @@ -import { Users, Followings } from '@/models/index'; -import { ILocalUser, IRemoteUser, User } from '@/models/entities/user'; -import { deliver } from '@/queue/index'; +import { Users, Followings } from '@/models/index.js'; +import { ILocalUser, IRemoteUser, User } from '@/models/entities/user.js'; +import { deliver } from '@/queue/index.js'; //#region types interface IRecipe { diff --git a/packages/backend/src/remote/activitypub/kernel/accept/follow.ts b/packages/backend/src/remote/activitypub/kernel/accept/follow.ts index 1afb733ab..393516add 100644 --- a/packages/backend/src/remote/activitypub/kernel/accept/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/accept/follow.ts @@ -1,8 +1,8 @@ -import { IRemoteUser } from '@/models/entities/user'; -import accept from '@/services/following/requests/accept'; -import { IFollow } from '../../type'; -import DbResolver from '../../db-resolver'; -import { relayAccepted } from '@/services/relay'; +import { IRemoteUser } from '@/models/entities/user.js'; +import accept from '@/services/following/requests/accept.js'; +import { IFollow } from '../../type.js'; +import DbResolver from '../../db-resolver.js'; +import { relayAccepted } from '@/services/relay.js'; export default async (actor: IRemoteUser, activity: IFollow): Promise => { // â€ģ activityはこãŖãĄã‹ã‚‰æŠ•ã’ãŸãƒ•ã‚Šãƒ­ãƒŧãƒĒクエ゚トãĒぎで、activity.actorは存在するロãƒŧã‚ĢãƒĢãƒĻãƒŧã‚ļãƒŧであるåŋ…čĻãŒã‚ã‚‹ diff --git a/packages/backend/src/remote/activitypub/kernel/accept/index.ts b/packages/backend/src/remote/activitypub/kernel/accept/index.ts index 5c6f81b2e..354bd4f6e 100644 --- a/packages/backend/src/remote/activitypub/kernel/accept/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/accept/index.ts @@ -1,8 +1,8 @@ -import Resolver from '../../resolver'; -import { IRemoteUser } from '@/models/entities/user'; -import acceptFollow from './follow'; -import { IAccept, isFollow, getApType } from '../../type'; -import { apLogger } from '../../logger'; +import Resolver from '../../resolver.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import acceptFollow from './follow.js'; +import { IAccept, isFollow, getApType } from '../../type.js'; +import { apLogger } from '../../logger.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/kernel/add/index.ts b/packages/backend/src/remote/activitypub/kernel/add/index.ts index b33be0cc8..9a2fac1e7 100644 --- a/packages/backend/src/remote/activitypub/kernel/add/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/add/index.ts @@ -1,7 +1,7 @@ -import { IRemoteUser } from '@/models/entities/user'; -import { IAdd } from '../../type'; -import { resolveNote } from '../../models/note'; -import { addPinned } from '@/services/i/pin'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { IAdd } from '../../type.js'; +import { resolveNote } from '../../models/note.js'; +import { addPinned } from '@/services/i/pin.js'; export default async (actor: IRemoteUser, activity: IAdd): Promise => { if ('actor' in activity && actor.uri !== activity.actor) { diff --git a/packages/backend/src/remote/activitypub/kernel/announce/index.ts b/packages/backend/src/remote/activitypub/kernel/announce/index.ts index 581357e57..7e2e73bdd 100644 --- a/packages/backend/src/remote/activitypub/kernel/announce/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/announce/index.ts @@ -1,8 +1,8 @@ -import Resolver from '../../resolver'; -import { IRemoteUser } from '@/models/entities/user'; -import announceNote from './note'; -import { IAnnounce, getApId } from '../../type'; -import { apLogger } from '../../logger'; +import Resolver from '../../resolver.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import announceNote from './note.js'; +import { IAnnounce, getApId } from '../../type.js'; +import { apLogger } from '../../logger.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/kernel/announce/note.ts b/packages/backend/src/remote/activitypub/kernel/announce/note.ts index e9158f775..f6068fac7 100644 --- a/packages/backend/src/remote/activitypub/kernel/announce/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/announce/note.ts @@ -1,14 +1,14 @@ -import Resolver from '../../resolver'; -import post from '@/services/note/create'; -import { IRemoteUser } from '@/models/entities/user'; -import { IAnnounce, getApId } from '../../type'; -import { fetchNote, resolveNote } from '../../models/note'; -import { apLogger } from '../../logger'; -import { extractDbHost } from '@/misc/convert-host'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { getApLock } from '@/misc/app-lock'; -import { parseAudience } from '../../audience'; -import { StatusError } from '@/misc/fetch'; +import Resolver from '../../resolver.js'; +import post from '@/services/note/create.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { IAnnounce, getApId } from '../../type.js'; +import { fetchNote, resolveNote } from '../../models/note.js'; +import { apLogger } from '../../logger.js'; +import { extractDbHost } from '@/misc/convert-host.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { getApLock } from '@/misc/app-lock.js'; +import { parseAudience } from '../../audience.js'; +import { StatusError } from '@/misc/fetch.js'; const logger = apLogger; @@ -42,11 +42,14 @@ export default async function(resolver: Resolver, actor: IRemoteUser, activity: renote = await resolveNote(targetUri); } catch (e) { // å¯žčąĄãŒ4xxãĒら゚キップ - if (e instanceof StatusError && e.isClientError) { - logger.warn(`Ignored announce target ${targetUri} - ${e.statusCode}`); - return; + if (e instanceof StatusError) { + if (e.isClientError) { + logger.warn(`Ignored announce target ${targetUri} - ${e.statusCode}`); + return; + } + + logger.warn(`Error in announce target ${targetUri} - ${e.statusCode || e}`); } - logger.warn(`Error in announce target ${targetUri} - ${e.statusCode || e}`); throw e; } diff --git a/packages/backend/src/remote/activitypub/kernel/block/index.ts b/packages/backend/src/remote/activitypub/kernel/block/index.ts index 4fd1e07b9..9e4f1b316 100644 --- a/packages/backend/src/remote/activitypub/kernel/block/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/block/index.ts @@ -1,7 +1,7 @@ -import { IBlock } from '../../type'; -import block from '@/services/blocking/create'; -import { IRemoteUser } from '@/models/entities/user'; -import DbResolver from '../../db-resolver'; +import { IBlock } from '../../type.js'; +import block from '@/services/blocking/create.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import DbResolver from '../../db-resolver.js'; export default async (actor: IRemoteUser, activity: IBlock): Promise => { // â€ģ activity.objectãĢãƒ–ãƒ­ãƒƒã‚¯å¯žčąĄãŒã‚ã‚Šã€ãã‚Œã¯å­˜åœ¨ã™ã‚‹ãƒ­ãƒŧã‚ĢãƒĢãƒĻãƒŧã‚ļãƒŧぎはず diff --git a/packages/backend/src/remote/activitypub/kernel/create/index.ts b/packages/backend/src/remote/activitypub/kernel/create/index.ts index ce039a363..1187b95ac 100644 --- a/packages/backend/src/remote/activitypub/kernel/create/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/create/index.ts @@ -1,9 +1,9 @@ -import Resolver from '../../resolver'; -import { IRemoteUser } from '@/models/entities/user'; -import createNote from './note'; -import { ICreate, getApId, isPost, getApType } from '../../type'; -import { apLogger } from '../../logger'; -import { toArray, concat, unique } from '@/prelude/array'; +import Resolver from '../../resolver.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import createNote from './note.js'; +import { ICreate, getApId, isPost, getApType } from '../../type.js'; +import { apLogger } from '../../logger.js'; +import { toArray, concat, unique } from '@/prelude/array.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/kernel/create/note.ts b/packages/backend/src/remote/activitypub/kernel/create/note.ts index 14e311e4c..b5c47990a 100644 --- a/packages/backend/src/remote/activitypub/kernel/create/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/create/note.ts @@ -1,10 +1,10 @@ -import Resolver from '../../resolver'; -import { IRemoteUser } from '@/models/entities/user'; -import { createNote, fetchNote } from '../../models/note'; -import { getApId, IObject, ICreate } from '../../type'; -import { getApLock } from '@/misc/app-lock'; -import { extractDbHost } from '@/misc/convert-host'; -import { StatusError } from '@/misc/fetch'; +import Resolver from '../../resolver.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { createNote, fetchNote } from '../../models/note.js'; +import { getApId, IObject, ICreate } from '../../type.js'; +import { getApLock } from '@/misc/app-lock.js'; +import { extractDbHost } from '@/misc/convert-host.js'; +import { StatusError } from '@/misc/fetch.js'; /** * 投į¨ŋäŊœæˆã‚ĸクテã‚Ŗビテã‚Ŗを捌きぞす diff --git a/packages/backend/src/remote/activitypub/kernel/delete/actor.ts b/packages/backend/src/remote/activitypub/kernel/delete/actor.ts index 502f8d5ab..2f75841e5 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/actor.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/actor.ts @@ -1,7 +1,7 @@ -import { apLogger } from '../../logger'; -import { createDeleteAccountJob } from '@/queue'; -import { IRemoteUser } from '@/models/entities/user'; -import { Users } from '@/models/index'; +import { apLogger } from '../../logger.js'; +import { createDeleteAccountJob } from '@/queue/index.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/kernel/delete/index.ts b/packages/backend/src/remote/activitypub/kernel/delete/index.ts index 86a452de7..b6d5e96d0 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/index.ts @@ -1,8 +1,8 @@ -import deleteNote from './note'; -import { IRemoteUser } from '@/models/entities/user'; -import { IDelete, getApId, isTombstone, IObject, validPost, validActor } from '../../type'; -import { toSingle } from '@/prelude/array'; -import { deleteActor } from './actor'; +import deleteNote from './note.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { IDelete, getApId, isTombstone, IObject, validPost, validActor } from '../../type.js'; +import { toSingle } from '@/prelude/array.js'; +import { deleteActor } from './actor.js'; /** * 削除ã‚ĸクテã‚Ŗビテã‚Ŗを捌きぞす diff --git a/packages/backend/src/remote/activitypub/kernel/delete/note.ts b/packages/backend/src/remote/activitypub/kernel/delete/note.ts index 3875a33d1..ad5e1a2ed 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/note.ts @@ -1,9 +1,9 @@ -import { IRemoteUser } from '@/models/entities/user'; -import deleteNode from '@/services/note/delete'; -import { apLogger } from '../../logger'; -import DbResolver from '../../db-resolver'; -import { getApLock } from '@/misc/app-lock'; -import { deleteMessage } from '@/services/messages/delete'; +import { IRemoteUser } from '@/models/entities/user.js'; +import deleteNode from '@/services/note/delete.js'; +import { apLogger } from '../../logger.js'; +import DbResolver from '../../db-resolver.js'; +import { getApLock } from '@/misc/app-lock.js'; +import { deleteMessage } from '@/services/messages/delete.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/kernel/flag/index.ts b/packages/backend/src/remote/activitypub/kernel/flag/index.ts index aec6d2daa..e80e63278 100644 --- a/packages/backend/src/remote/activitypub/kernel/flag/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/flag/index.ts @@ -1,16 +1,16 @@ -import { IRemoteUser } from '@/models/entities/user'; -import config from '@/config/index'; -import { IFlag, getApIds } from '../../type'; -import { AbuseUserReports, Users } from '@/models/index'; +import { IRemoteUser } from '@/models/entities/user.js'; +import config from '@/config/index.js'; +import { IFlag, getApIds } from '../../type.js'; +import { AbuseUserReports, Users } from '@/models/index.js'; import { In } from 'typeorm'; -import { genId } from '@/misc/gen-id'; +import { genId } from '@/misc/gen-id.js'; export default async (actor: IRemoteUser, activity: IFlag): Promise => { // objectは `(User|Note) | (User|Note)[]` だけお、全パã‚ŋãƒŧãƒŗDBã‚šã‚­ãƒŧマと寞åŋœã•ã›ã‚‰ã‚ŒãĒいぎで // å¯žčąĄãƒĻãƒŧã‚ļãƒŧは一į•Ē最初ぎãƒĻãƒŧã‚ļãƒŧ としãĻ あとはã‚ŗãƒĄãƒŗトとしãĻæ ŧį´ã™ã‚‹ const uris = getApIds(activity.object); - const userIds = uris.filter(uri => uri.startsWith(config.url + '/users/')).map(uri => uri.split('/').pop()); + const userIds = uris.filter(uri => uri.startsWith(config.url + '/users/')).map(uri => uri.split('/').pop()!); const users = await Users.find({ id: In(userIds), }); diff --git a/packages/backend/src/remote/activitypub/kernel/follow.ts b/packages/backend/src/remote/activitypub/kernel/follow.ts index 3183207af..49c1a7ee0 100644 --- a/packages/backend/src/remote/activitypub/kernel/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/follow.ts @@ -1,7 +1,7 @@ -import { IRemoteUser } from '@/models/entities/user'; -import follow from '@/services/following/create'; -import { IFollow } from '../type'; -import DbResolver from '../db-resolver'; +import { IRemoteUser } from '@/models/entities/user.js'; +import follow from '@/services/following/create.js'; +import { IFollow } from '../type.js'; +import DbResolver from '../db-resolver.js'; export default async (actor: IRemoteUser, activity: IFollow): Promise => { const dbResolver = new DbResolver(); diff --git a/packages/backend/src/remote/activitypub/kernel/index.ts b/packages/backend/src/remote/activitypub/kernel/index.ts index 20df28eec..6aea8e57c 100644 --- a/packages/backend/src/remote/activitypub/kernel/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/index.ts @@ -1,22 +1,22 @@ -import { IObject, isCreate, isDelete, isUpdate, isRead, isFollow, isAccept, isReject, isAdd, isRemove, isAnnounce, isLike, isUndo, isBlock, isCollectionOrOrderedCollection, isCollection, isFlag } from '../type'; -import { IRemoteUser } from '@/models/entities/user'; -import create from './create/index'; -import performDeleteActivity from './delete/index'; -import performUpdateActivity from './update/index'; -import { performReadActivity } from './read'; -import follow from './follow'; -import undo from './undo/index'; -import like from './like'; -import announce from './announce/index'; -import accept from './accept/index'; -import reject from './reject/index'; -import add from './add/index'; -import remove from './remove/index'; -import block from './block/index'; -import flag from './flag/index'; -import { apLogger } from '../logger'; -import Resolver from '../resolver'; -import { toArray } from '@/prelude/array'; +import { IObject, isCreate, isDelete, isUpdate, isRead, isFollow, isAccept, isReject, isAdd, isRemove, isAnnounce, isLike, isUndo, isBlock, isCollectionOrOrderedCollection, isCollection, isFlag } from '../type.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import create from './create/index.js'; +import performDeleteActivity from './delete/index.js'; +import performUpdateActivity from './update/index.js'; +import { performReadActivity } from './read.js'; +import follow from './follow.js'; +import undo from './undo/index.js'; +import like from './like.js'; +import announce from './announce/index.js'; +import accept from './accept/index.js'; +import reject from './reject/index.js'; +import add from './add/index.js'; +import remove from './remove/index.js'; +import block from './block/index.js'; +import flag from './flag/index.js'; +import { apLogger } from '../logger.js'; +import Resolver from '../resolver.js'; +import { toArray } from '@/prelude/array.js'; export async function performActivity(actor: IRemoteUser, activity: IObject) { if (isCollectionOrOrderedCollection(activity)) { @@ -25,8 +25,10 @@ export async function performActivity(actor: IRemoteUser, activity: IObject) { const act = await resolver.resolve(item); try { await performOneActivity(actor, act); - } catch (e) { - apLogger.error(e); + } catch (err) { + if (err instanceof Error || typeof err === 'string') { + apLogger.error(err); + } } } } else { diff --git a/packages/backend/src/remote/activitypub/kernel/like.ts b/packages/backend/src/remote/activitypub/kernel/like.ts index 58d5aefef..715cc379b 100644 --- a/packages/backend/src/remote/activitypub/kernel/like.ts +++ b/packages/backend/src/remote/activitypub/kernel/like.ts @@ -1,7 +1,7 @@ -import { IRemoteUser } from '@/models/entities/user'; -import { ILike, getApId } from '../type'; -import create from '@/services/note/reaction/create'; -import { fetchNote, extractEmojis } from '../models/note'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { ILike, getApId } from '../type.js'; +import create from '@/services/note/reaction/create.js'; +import { fetchNote, extractEmojis } from '../models/note.js'; export default async (actor: IRemoteUser, activity: ILike) => { const targetUri = getApId(activity.object); diff --git a/packages/backend/src/remote/activitypub/kernel/read.ts b/packages/backend/src/remote/activitypub/kernel/read.ts index 11a173186..93cc36ec4 100644 --- a/packages/backend/src/remote/activitypub/kernel/read.ts +++ b/packages/backend/src/remote/activitypub/kernel/read.ts @@ -1,8 +1,8 @@ -import { IRemoteUser } from '@/models/entities/user'; -import { IRead, getApId } from '../type'; -import { isSelfHost, extractDbHost } from '@/misc/convert-host'; -import { MessagingMessages } from '@/models/index'; -import { readUserMessagingMessage } from '../../../server/api/common/read-messaging-message'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { IRead, getApId } from '../type.js'; +import { isSelfHost, extractDbHost } from '@/misc/convert-host.js'; +import { MessagingMessages } from '@/models/index.js'; +import { readUserMessagingMessage } from '../../../server/api/common/read-messaging-message.js'; export const performReadActivity = async (actor: IRemoteUser, activity: IRead): Promise => { const id = await getApId(activity.object); diff --git a/packages/backend/src/remote/activitypub/kernel/reject/follow.ts b/packages/backend/src/remote/activitypub/kernel/reject/follow.ts index 049437b18..72751e83c 100644 --- a/packages/backend/src/remote/activitypub/kernel/reject/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/reject/follow.ts @@ -1,9 +1,9 @@ -import { IRemoteUser } from '@/models/entities/user'; -import { remoteReject } from '@/services/following/reject'; -import { IFollow } from '../../type'; -import DbResolver from '../../db-resolver'; -import { relayRejected } from '@/services/relay'; -import { Users } from '@/models'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { remoteReject } from '@/services/following/reject.js'; +import { IFollow } from '../../type.js'; +import DbResolver from '../../db-resolver.js'; +import { relayRejected } from '@/services/relay.js'; +import { Users } from '@/models/index.js'; export default async (actor: IRemoteUser, activity: IFollow): Promise => { // â€ģ activityはこãŖãĄã‹ã‚‰æŠ•ã’ãŸãƒ•ã‚Šãƒ­ãƒŧãƒĒクエ゚トãĒぎで、activity.actorは存在するロãƒŧã‚ĢãƒĢãƒĻãƒŧã‚ļãƒŧであるåŋ…čĻãŒã‚ã‚‹ diff --git a/packages/backend/src/remote/activitypub/kernel/reject/index.ts b/packages/backend/src/remote/activitypub/kernel/reject/index.ts index d0de9c329..ed86a4aa2 100644 --- a/packages/backend/src/remote/activitypub/kernel/reject/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/reject/index.ts @@ -1,8 +1,8 @@ -import Resolver from '../../resolver'; -import { IRemoteUser } from '@/models/entities/user'; -import rejectFollow from './follow'; -import { IReject, isFollow, getApType } from '../../type'; -import { apLogger } from '../../logger'; +import Resolver from '../../resolver.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import rejectFollow from './follow.js'; +import { IReject, isFollow, getApType } from '../../type.js'; +import { apLogger } from '../../logger.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/kernel/remove/index.ts b/packages/backend/src/remote/activitypub/kernel/remove/index.ts index d59953e65..7d7b3386c 100644 --- a/packages/backend/src/remote/activitypub/kernel/remove/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/remove/index.ts @@ -1,7 +1,7 @@ -import { IRemoteUser } from '@/models/entities/user'; -import { IRemove } from '../../type'; -import { resolveNote } from '../../models/note'; -import { removePinned } from '@/services/i/pin'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { IRemove } from '../../type.js'; +import { resolveNote } from '../../models/note.js'; +import { removePinned } from '@/services/i/pin.js'; export default async (actor: IRemoteUser, activity: IRemove): Promise => { if ('actor' in activity && actor.uri !== activity.actor) { diff --git a/packages/backend/src/remote/activitypub/kernel/undo/accept.ts b/packages/backend/src/remote/activitypub/kernel/undo/accept.ts index 10c8a9c9d..2383eea5b 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/accept.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/accept.ts @@ -1,9 +1,9 @@ -import unfollow from '@/services/following/delete'; -import cancelRequest from '@/services/following/requests/cancel'; -import {IAccept} from '../../type'; -import { IRemoteUser } from '@/models/entities/user'; -import { Followings } from '@/models/index'; -import DbResolver from '../../db-resolver'; +import unfollow from '@/services/following/delete.js'; +import cancelRequest from '@/services/following/requests/cancel.js'; +import {IAccept} from '../../type.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { Followings } from '@/models/index.js'; +import DbResolver from '../../db-resolver.js'; export default async (actor: IRemoteUser, activity: IAccept): Promise => { const dbResolver = new DbResolver(); diff --git a/packages/backend/src/remote/activitypub/kernel/undo/announce.ts b/packages/backend/src/remote/activitypub/kernel/undo/announce.ts index 7f302a616..822c1e494 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/announce.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/announce.ts @@ -1,7 +1,7 @@ -import { Notes } from '@/models/index'; -import { IRemoteUser } from '@/models/entities/user'; -import { IAnnounce, getApId } from '../../type'; -import deleteNote from '@/services/note/delete'; +import { Notes } from '@/models/index.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { IAnnounce, getApId } from '../../type.js'; +import deleteNote from '@/services/note/delete.js'; export const undoAnnounce = async (actor: IRemoteUser, activity: IAnnounce): Promise => { const uri = getApId(activity); diff --git a/packages/backend/src/remote/activitypub/kernel/undo/block.ts b/packages/backend/src/remote/activitypub/kernel/undo/block.ts index 61940486b..844b067e2 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/block.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/block.ts @@ -1,7 +1,7 @@ -import { IBlock } from '../../type'; -import unblock from '@/services/blocking/delete'; -import { IRemoteUser } from '@/models/entities/user'; -import DbResolver from '../../db-resolver'; +import { IBlock } from '../../type.js'; +import unblock from '@/services/blocking/delete.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import DbResolver from '../../db-resolver.js'; export default async (actor: IRemoteUser, activity: IBlock): Promise => { const dbResolver = new DbResolver(); diff --git a/packages/backend/src/remote/activitypub/kernel/undo/follow.ts b/packages/backend/src/remote/activitypub/kernel/undo/follow.ts index 783e5acf1..6715adcf7 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/follow.ts @@ -1,9 +1,9 @@ -import unfollow from '@/services/following/delete'; -import cancelRequest from '@/services/following/requests/cancel'; -import { IFollow } from '../../type'; -import { IRemoteUser } from '@/models/entities/user'; -import { FollowRequests, Followings } from '@/models/index'; -import DbResolver from '../../db-resolver'; +import unfollow from '@/services/following/delete.js'; +import cancelRequest from '@/services/following/requests/cancel.js'; +import { IFollow } from '../../type.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { FollowRequests, Followings } from '@/models/index.js'; +import DbResolver from '../../db-resolver.js'; export default async (actor: IRemoteUser, activity: IFollow): Promise => { const dbResolver = new DbResolver(); diff --git a/packages/backend/src/remote/activitypub/kernel/undo/index.ts b/packages/backend/src/remote/activitypub/kernel/undo/index.ts index 8de78420e..05937c685 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/index.ts @@ -1,12 +1,12 @@ -import { IRemoteUser } from '@/models/entities/user'; -import {IUndo, isFollow, isBlock, isLike, isAnnounce, getApType, isAccept} from '../../type'; -import unfollow from './follow'; -import unblock from './block'; -import undoLike from './like'; -import undoAccept from './accept'; -import { undoAnnounce } from './announce'; -import Resolver from '../../resolver'; -import { apLogger } from '../../logger'; +import { IRemoteUser } from '@/models/entities/user.js'; +import {IUndo, isFollow, isBlock, isLike, isAnnounce, getApType, isAccept} from '../../type.js'; +import unfollow from './follow.js'; +import unblock from './block.js'; +import undoLike from './like.js'; +import undoAccept from './accept.js'; +import { undoAnnounce } from './announce.js'; +import Resolver from '../../resolver.js'; +import { apLogger } from '../../logger.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/kernel/undo/like.ts b/packages/backend/src/remote/activitypub/kernel/undo/like.ts index 107d3053e..08ac63035 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/like.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/like.ts @@ -1,7 +1,7 @@ -import { IRemoteUser } from '@/models/entities/user'; -import { ILike, getApId } from '../../type'; -import deleteReaction from '@/services/note/reaction/delete'; -import { fetchNote } from '../../models/note'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { ILike, getApId } from '../../type.js'; +import deleteReaction from '@/services/note/reaction/delete.js'; +import { fetchNote } from '../../models/note.js'; /** * Process Undo.Like activity diff --git a/packages/backend/src/remote/activitypub/kernel/update/index.ts b/packages/backend/src/remote/activitypub/kernel/update/index.ts index 52bfc5002..7888c698e 100644 --- a/packages/backend/src/remote/activitypub/kernel/update/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/update/index.ts @@ -1,9 +1,9 @@ -import { IRemoteUser } from '@/models/entities/user'; -import { getApType, IUpdate, isActor } from '../../type'; -import { apLogger } from '../../logger'; -import { updateQuestion } from '../../models/question'; -import Resolver from '../../resolver'; -import { updatePerson } from '../../models/person'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { getApType, IUpdate, isActor } from '../../type.js'; +import { apLogger } from '../../logger.js'; +import { updateQuestion } from '../../models/question.js'; +import Resolver from '../../resolver.js'; +import { updatePerson } from '../../models/person.js'; /** * Updateã‚ĸクテã‚Ŗビテã‚Ŗを捌きぞす diff --git a/packages/backend/src/remote/activitypub/logger.ts b/packages/backend/src/remote/activitypub/logger.ts index e13add01d..cab51b3bf 100644 --- a/packages/backend/src/remote/activitypub/logger.ts +++ b/packages/backend/src/remote/activitypub/logger.ts @@ -1,3 +1,3 @@ -import { remoteLogger } from '../logger'; +import { remoteLogger } from '../logger.js'; export const apLogger = remoteLogger.createSubLogger('ap', 'magenta'); diff --git a/packages/backend/src/remote/activitypub/misc/get-note-html.ts b/packages/backend/src/remote/activitypub/misc/get-note-html.ts index 043335a5b..3800b4060 100644 --- a/packages/backend/src/remote/activitypub/misc/get-note-html.ts +++ b/packages/backend/src/remote/activitypub/misc/get-note-html.ts @@ -1,6 +1,6 @@ import * as mfm from 'mfm-js'; -import { Note } from '@/models/entities/note'; -import { toHtml } from '../../../mfm/to-html'; +import { Note } from '@/models/entities/note.js'; +import { toHtml } from '../../../mfm/to-html.js'; export default function(note: Note) { let html = note.text ? toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers)) : null; diff --git a/packages/backend/src/remote/activitypub/misc/html-to-mfm.ts b/packages/backend/src/remote/activitypub/misc/html-to-mfm.ts index 5cca04df2..bb1ba7925 100644 --- a/packages/backend/src/remote/activitypub/misc/html-to-mfm.ts +++ b/packages/backend/src/remote/activitypub/misc/html-to-mfm.ts @@ -1,6 +1,6 @@ -import { IObject } from '../type'; -import { extractApHashtagObjects } from '../models/tag'; -import { fromHtml } from '../../../mfm/from-html'; +import { IObject } from '../type.js'; +import { extractApHashtagObjects } from '../models/tag.js'; +import { fromHtml } from '../../../mfm/from-html.js'; export function htmlToMfm(html: string, tag?: IObject | IObject[]) { const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null); diff --git a/packages/backend/src/remote/activitypub/misc/ld-signature.ts b/packages/backend/src/remote/activitypub/misc/ld-signature.ts index 946914bfa..34294c935 100644 --- a/packages/backend/src/remote/activitypub/misc/ld-signature.ts +++ b/packages/backend/src/remote/activitypub/misc/ld-signature.ts @@ -1,8 +1,8 @@ -import * as crypto from 'crypto'; +import * as crypto from 'node:crypto'; import * as jsonld from 'jsonld'; -import { CONTEXTS } from './contexts'; +import { CONTEXTS } from './contexts.js'; import fetch from 'node-fetch'; -import { httpAgent, httpsAgent } from '@/misc/fetch'; +import { httpAgent, httpsAgent } from '@/misc/fetch.js'; // RsaSignature2017 based from https://github.com/transmute-industries/RsaSignature2017 @@ -24,7 +24,7 @@ export class LdSignature { } as { type: string; creator: string; - domain: string; + domain?: string; nonce: string; created: string; }; @@ -114,7 +114,7 @@ export class LdSignature { Accept: 'application/ld+json, application/json', }, timeout: this.loderTimeout, - agent: u => u.protocol == 'http:' ? httpAgent : httpsAgent, + agent: u => u.protocol === 'http:' ? httpAgent : httpsAgent, }).then(res => { if (!res.ok) { throw `${res.status} ${res.statusText}`; diff --git a/packages/backend/src/remote/activitypub/models/image.ts b/packages/backend/src/remote/activitypub/models/image.ts index 6f60b7827..b5e9181d3 100644 --- a/packages/backend/src/remote/activitypub/models/image.ts +++ b/packages/backend/src/remote/activitypub/models/image.ts @@ -1,12 +1,12 @@ -import { uploadFromUrl } from '@/services/drive/upload-from-url'; -import { IRemoteUser } from '@/models/entities/user'; -import Resolver from '../resolver'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { apLogger } from '../logger'; -import { DriveFile } from '@/models/entities/drive-file'; -import { DriveFiles } from '@/models/index'; -import { truncate } from '@/misc/truncate'; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits'; +import { uploadFromUrl } from '@/services/drive/upload-from-url.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import Resolver from '../resolver.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { apLogger } from '../logger.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { DriveFiles } from '@/models/index.js'; +import { truncate } from '@/misc/truncate.js'; +import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/models/mention.ts b/packages/backend/src/remote/activitypub/models/mention.ts index ade9c9080..c5b0ea53c 100644 --- a/packages/backend/src/remote/activitypub/models/mention.ts +++ b/packages/backend/src/remote/activitypub/models/mention.ts @@ -1,9 +1,9 @@ -import { toArray, unique } from '@/prelude/array'; -import { IObject, isMention, IApMention } from '../type'; -import { resolvePerson } from './person'; -import * as promiseLimit from 'promise-limit'; -import Resolver from '../resolver'; -import { User } from '@/models/entities/user'; +import { toArray, unique } from '@/prelude/array.js'; +import { IObject, isMention, IApMention } from '../type.js'; +import { resolvePerson } from './person.js'; +import promiseLimit from 'promise-limit'; +import Resolver from '../resolver.js'; +import { User } from '@/models/entities/user.js'; export async function extractApMentions(tags: IObject | IObject[] | null | undefined) { const hrefs = unique(extractApMentionObjects(tags).map(x => x.href as string)); diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index 6847925a5..dca64d0a6 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -1,32 +1,32 @@ -import * as promiseLimit from 'promise-limit'; +import promiseLimit from 'promise-limit'; -import config from '@/config/index'; -import Resolver from '../resolver'; -import post from '@/services/note/create'; -import { resolvePerson, updatePerson } from './person'; -import { resolveImage } from './image'; -import { IRemoteUser } from '@/models/entities/user'; -import { htmlToMfm } from '../misc/html-to-mfm'; -import { extractApHashtags } from './tag'; -import { unique, toArray, toSingle } from '@/prelude/array'; -import { extractPollFromQuestion } from './question'; -import vote from '@/services/note/polls/vote'; -import { apLogger } from '../logger'; -import { DriveFile } from '@/models/entities/drive-file'; -import { deliverQuestionUpdate } from '@/services/note/polls/update'; -import { extractDbHost, toPuny } from '@/misc/convert-host'; -import { Emojis, Polls, MessagingMessages } from '@/models/index'; -import { Note } from '@/models/entities/note'; -import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type'; -import { Emoji } from '@/models/entities/emoji'; -import { genId } from '@/misc/gen-id'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { getApLock } from '@/misc/app-lock'; -import { createMessage } from '@/services/messages/create'; -import { parseAudience } from '../audience'; -import { extractApMentions } from './mention'; -import DbResolver from '../db-resolver'; -import { StatusError } from '@/misc/fetch'; +import config from '@/config/index.js'; +import Resolver from '../resolver.js'; +import post from '@/services/note/create.js'; +import { resolvePerson, updatePerson } from './person.js'; +import { resolveImage } from './image.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { htmlToMfm } from '../misc/html-to-mfm.js'; +import { extractApHashtags } from './tag.js'; +import { unique, toArray, toSingle } from '@/prelude/array.js'; +import { extractPollFromQuestion } from './question.js'; +import vote from '@/services/note/polls/vote.js'; +import { apLogger } from '../logger.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { deliverQuestionUpdate } from '@/services/note/polls/update.js'; +import { extractDbHost, toPuny } from '@/misc/convert-host.js'; +import { Emojis, Polls, MessagingMessages } from '@/models/index.js'; +import { Note } from '@/models/entities/note.js'; +import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type.js'; +import { Emoji } from '@/models/entities/emoji.js'; +import { genId } from '@/misc/gen-id.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { getApLock } from '@/misc/app-lock.js'; +import { createMessage } from '@/services/messages/create.js'; +import { parseAudience } from '../audience.js'; +import { extractApMentions } from './mention.js'; +import DbResolver from '../db-resolver.js'; +import { StatusError } from '@/misc/fetch.js'; const logger = apLogger; diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index 19a7a7090..659d3ac9a 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -1,35 +1,35 @@ -import { URL } from 'url'; -import * as promiseLimit from 'promise-limit'; +import { URL } from 'node:url'; +import promiseLimit from 'promise-limit'; import $, { Context } from 'cafy'; -import config from '@/config/index'; -import Resolver from '../resolver'; -import { resolveImage } from './image'; -import { isCollectionOrOrderedCollection, isCollection, IActor, getApId, getOneApHrefNullable, IObject, isPropertyValue, IApPropertyValue, getApType, isActor } from '../type'; -import { fromHtml } from '../../../mfm/from-html'; -import { htmlToMfm } from '../misc/html-to-mfm'; -import { resolveNote, extractEmojis } from './note'; -import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc'; -import { extractApHashtags } from './tag'; -import { apLogger } from '../logger'; -import { Note } from '@/models/entities/note'; -import { updateUsertags } from '@/services/update-hashtag'; -import { Users, Instances, DriveFiles, Followings, UserProfiles, UserPublickeys } from '@/models/index'; -import { User, IRemoteUser } from '@/models/entities/user'; -import { Emoji } from '@/models/entities/emoji'; -import { UserNotePining } from '@/models/entities/user-note-pining'; -import { genId } from '@/misc/gen-id'; -import { instanceChart, usersChart } from '@/services/chart/index'; -import { UserPublickey } from '@/models/entities/user-publickey'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error'; -import { toPuny } from '@/misc/convert-host'; -import { UserProfile } from '@/models/entities/user-profile'; +import config from '@/config/index.js'; +import Resolver from '../resolver.js'; +import { resolveImage } from './image.js'; +import { isCollectionOrOrderedCollection, isCollection, IActor, getApId, getOneApHrefNullable, IObject, isPropertyValue, IApPropertyValue, getApType, isActor } from '../type.js'; +import { fromHtml } from '../../../mfm/from-html.js'; +import { htmlToMfm } from '../misc/html-to-mfm.js'; +import { resolveNote, extractEmojis } from './note.js'; +import { registerOrFetchInstanceDoc } from '@/services/register-or-fetch-instance-doc.js'; +import { extractApHashtags } from './tag.js'; +import { apLogger } from '../logger.js'; +import { Note } from '@/models/entities/note.js'; +import { updateUsertags } from '@/services/update-hashtag.js'; +import { Users, Instances, DriveFiles, Followings, UserProfiles, UserPublickeys } from '@/models/index.js'; +import { User, IRemoteUser } from '@/models/entities/user.js'; +import { Emoji } from '@/models/entities/emoji.js'; +import { UserNotePining } from '@/models/entities/user-note-pining.js'; +import { genId } from '@/misc/gen-id.js'; +import { instanceChart, usersChart } from '@/services/chart/index.js'; +import { UserPublickey } from '@/models/entities/user-publickey.js'; +import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; +import { toPuny } from '@/misc/convert-host.js'; +import { UserProfile } from '@/models/entities/user-profile.js'; import { getConnection } from 'typeorm'; -import { toArray } from '@/prelude/array'; -import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; -import { truncate } from '@/misc/truncate'; -import { StatusError } from '@/misc/fetch'; +import { toArray } from '@/prelude/array.js'; +import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import { truncate } from '@/misc/truncate.js'; +import { StatusError } from '@/misc/fetch.js'; const logger = apLogger; @@ -57,15 +57,15 @@ function validateActor(x: IObject, uri: string): IActor { if (e) throw new Error(`invalid Actor: ${name} ${e.message}`); }; - validate('id', x.id, $.str.min(1)); - validate('inbox', x.inbox, $.str.min(1)); - validate('preferredUsername', x.preferredUsername, $.str.min(1).max(128).match(/^\w([\w-.]*\w)?$/)); + validate('id', x.id, $.default.str.min(1)); + validate('inbox', x.inbox, $.default.str.min(1)); + validate('preferredUsername', x.preferredUsername, $.default.str.min(1).max(128).match(/^\w([\w-.]*\w)?$/)); // These fields are only informational, and some AP software allows these // fields to be very long. If they are too long, we cut them off. This way // we can at least see these users and their activities. - validate('name', truncate(x.name, nameLength), $.optional.nullable.str); - validate('summary', truncate(x.summary, summaryLength), $.optional.nullable.str); + validate('name', truncate(x.name, nameLength), $.default.optional.nullable.str); + validate('summary', truncate(x.summary, summaryLength), $.default.optional.nullable.str); const idHost = toPuny(new URL(x.id!).hostname); if (idHost !== expectHost) { @@ -164,6 +164,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise { if (resolver == null) resolver = new Resolver(); diff --git a/packages/backend/src/remote/activitypub/models/tag.ts b/packages/backend/src/remote/activitypub/models/tag.ts index fbc6b9b42..964dabad0 100644 --- a/packages/backend/src/remote/activitypub/models/tag.ts +++ b/packages/backend/src/remote/activitypub/models/tag.ts @@ -1,5 +1,5 @@ -import { toArray } from '@/prelude/array'; -import { IObject, isHashtag, IApHashtag } from '../type'; +import { toArray } from '@/prelude/array.js'; +import { IObject, isHashtag, IApHashtag } from '../type.js'; export function extractApHashtags(tags: IObject | IObject[] | null | undefined) { if (tags == null) return []; diff --git a/packages/backend/src/remote/activitypub/perform.ts b/packages/backend/src/remote/activitypub/perform.ts index 01f0e3676..3e1881558 100644 --- a/packages/backend/src/remote/activitypub/perform.ts +++ b/packages/backend/src/remote/activitypub/perform.ts @@ -1,6 +1,6 @@ -import { IObject } from './type'; -import { IRemoteUser } from '@/models/entities/user'; -import { performActivity } from './kernel/index'; +import { IObject } from './type.js'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { performActivity } from './kernel/index.js'; export default async (actor: IRemoteUser, activity: IObject): Promise => { await performActivity(actor, activity); diff --git a/packages/backend/src/remote/activitypub/renderer/accept.ts b/packages/backend/src/remote/activitypub/renderer/accept.ts index 3bce2165c..cb01f6a91 100644 --- a/packages/backend/src/remote/activitypub/renderer/accept.ts +++ b/packages/backend/src/remote/activitypub/renderer/accept.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { User } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; export default (object: any, user: { id: User['id']; host: null }) => ({ type: 'Accept', diff --git a/packages/backend/src/remote/activitypub/renderer/add.ts b/packages/backend/src/remote/activitypub/renderer/add.ts index 960daf842..ec4788429 100644 --- a/packages/backend/src/remote/activitypub/renderer/add.ts +++ b/packages/backend/src/remote/activitypub/renderer/add.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { ILocalUser } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { ILocalUser } from '@/models/entities/user.js'; export default (user: ILocalUser, target: any, object: any) => ({ type: 'Add', diff --git a/packages/backend/src/remote/activitypub/renderer/announce.ts b/packages/backend/src/remote/activitypub/renderer/announce.ts index ab113b48e..2709fea51 100644 --- a/packages/backend/src/remote/activitypub/renderer/announce.ts +++ b/packages/backend/src/remote/activitypub/renderer/announce.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { Note } from '@/models/entities/note'; +import config from '@/config/index.js'; +import { Note } from '@/models/entities/note.js'; export default (object: any, note: Note) => { const attributedTo = `${config.url}/users/${note.userId}`; diff --git a/packages/backend/src/remote/activitypub/renderer/block.ts b/packages/backend/src/remote/activitypub/renderer/block.ts index bfb831daa..10a4fde51 100644 --- a/packages/backend/src/remote/activitypub/renderer/block.ts +++ b/packages/backend/src/remote/activitypub/renderer/block.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { ILocalUser, IRemoteUser } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { ILocalUser, IRemoteUser } from '@/models/entities/user.js'; export default (blocker: ILocalUser, blockee: IRemoteUser) => ({ type: 'Block', diff --git a/packages/backend/src/remote/activitypub/renderer/create.ts b/packages/backend/src/remote/activitypub/renderer/create.ts index ac9e69af2..281a3cb2a 100644 --- a/packages/backend/src/remote/activitypub/renderer/create.ts +++ b/packages/backend/src/remote/activitypub/renderer/create.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { Note } from '@/models/entities/note'; +import config from '@/config/index.js'; +import { Note } from '@/models/entities/note.js'; export default (object: any, note: Note) => { const activity = { diff --git a/packages/backend/src/remote/activitypub/renderer/delete.ts b/packages/backend/src/remote/activitypub/renderer/delete.ts index 176a6f7e2..4edd3a880 100644 --- a/packages/backend/src/remote/activitypub/renderer/delete.ts +++ b/packages/backend/src/remote/activitypub/renderer/delete.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { User } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; export default (object: any, user: { id: User['id']; host: null }) => ({ type: 'Delete', diff --git a/packages/backend/src/remote/activitypub/renderer/document.ts b/packages/backend/src/remote/activitypub/renderer/document.ts index a9d86dea1..c973de4c4 100644 --- a/packages/backend/src/remote/activitypub/renderer/document.ts +++ b/packages/backend/src/remote/activitypub/renderer/document.ts @@ -1,5 +1,5 @@ -import { DriveFile } from '@/models/entities/drive-file'; -import { DriveFiles } from '@/models/index'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { DriveFiles } from '@/models/index.js'; export default (file: DriveFile) => ({ type: 'Document', diff --git a/packages/backend/src/remote/activitypub/renderer/emoji.ts b/packages/backend/src/remote/activitypub/renderer/emoji.ts index e7ae7d959..0bf15eefd 100644 --- a/packages/backend/src/remote/activitypub/renderer/emoji.ts +++ b/packages/backend/src/remote/activitypub/renderer/emoji.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { Emoji } from '@/models/entities/emoji'; +import config from '@/config/index.js'; +import { Emoji } from '@/models/entities/emoji.js'; export default (emoji: Emoji) => ({ id: `${config.url}/emojis/${emoji.name}`, diff --git a/packages/backend/src/remote/activitypub/renderer/flag.ts b/packages/backend/src/remote/activitypub/renderer/flag.ts index 60ac49650..6fbc11580 100644 --- a/packages/backend/src/remote/activitypub/renderer/flag.ts +++ b/packages/backend/src/remote/activitypub/renderer/flag.ts @@ -1,7 +1,7 @@ -import config from '@/config/index'; -import { IObject, IActivity } from '@/remote/activitypub/type'; -import { ILocalUser, IRemoteUser } from '@/models/entities/user'; -import { getInstanceActor } from '@/services/instance-actor'; +import config from '@/config/index.js'; +import { IObject, IActivity } from '@/remote/activitypub/type.js'; +import { ILocalUser, IRemoteUser } from '@/models/entities/user.js'; +import { getInstanceActor } from '@/services/instance-actor.js'; // to anonymise reporters, the reporting actor must be a system user // object has to be a uri or array of uris diff --git a/packages/backend/src/remote/activitypub/renderer/follow-relay.ts b/packages/backend/src/remote/activitypub/renderer/follow-relay.ts index 38800267b..2c9678090 100644 --- a/packages/backend/src/remote/activitypub/renderer/follow-relay.ts +++ b/packages/backend/src/remote/activitypub/renderer/follow-relay.ts @@ -1,6 +1,6 @@ -import config from '@/config/index'; -import { Relay } from '@/models/entities/relay'; -import { ILocalUser } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { Relay } from '@/models/entities/relay.js'; +import { ILocalUser } from '@/models/entities/user.js'; export function renderFollowRelay(relay: Relay, relayActor: ILocalUser) { const follow = { diff --git a/packages/backend/src/remote/activitypub/renderer/follow-user.ts b/packages/backend/src/remote/activitypub/renderer/follow-user.ts index e3dde7f7f..ad1d63b93 100644 --- a/packages/backend/src/remote/activitypub/renderer/follow-user.ts +++ b/packages/backend/src/remote/activitypub/renderer/follow-user.ts @@ -1,6 +1,6 @@ -import config from '@/config/index'; -import { Users } from '@/models/index'; -import { User } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { Users } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; /** * Convert (local|remote)(Follower|Followee)ID to URL diff --git a/packages/backend/src/remote/activitypub/renderer/follow.ts b/packages/backend/src/remote/activitypub/renderer/follow.ts index 5258df7e9..9e9692b77 100644 --- a/packages/backend/src/remote/activitypub/renderer/follow.ts +++ b/packages/backend/src/remote/activitypub/renderer/follow.ts @@ -1,6 +1,6 @@ -import config from '@/config/index'; -import { User } from '@/models/entities/user'; -import { Users } from '@/models/index'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; export default (follower: { id: User['id']; host: User['host']; uri: User['host'] }, followee: { id: User['id']; host: User['host']; uri: User['host'] }, requestId?: string) => { const follow = { diff --git a/packages/backend/src/remote/activitypub/renderer/hashtag.ts b/packages/backend/src/remote/activitypub/renderer/hashtag.ts index d83a8e68b..a7b441e00 100644 --- a/packages/backend/src/remote/activitypub/renderer/hashtag.ts +++ b/packages/backend/src/remote/activitypub/renderer/hashtag.ts @@ -1,4 +1,4 @@ -import config from '@/config/index'; +import config from '@/config/index.js'; export default (tag: string) => ({ type: 'Hashtag', diff --git a/packages/backend/src/remote/activitypub/renderer/image.ts b/packages/backend/src/remote/activitypub/renderer/image.ts index ee3860be8..c7d5a31a2 100644 --- a/packages/backend/src/remote/activitypub/renderer/image.ts +++ b/packages/backend/src/remote/activitypub/renderer/image.ts @@ -1,5 +1,5 @@ -import { DriveFile } from '@/models/entities/drive-file'; -import { DriveFiles } from '@/models/index'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { DriveFiles } from '@/models/index.js'; export default (file: DriveFile) => ({ type: 'Image', diff --git a/packages/backend/src/remote/activitypub/renderer/index.ts b/packages/backend/src/remote/activitypub/renderer/index.ts index cffc9bfe0..5f6933226 100644 --- a/packages/backend/src/remote/activitypub/renderer/index.ts +++ b/packages/backend/src/remote/activitypub/renderer/index.ts @@ -1,9 +1,9 @@ -import config from '@/config/index'; +import config from '@/config/index.js'; import { v4 as uuid } from 'uuid'; -import { IActivity } from '../type'; -import { LdSignature } from '../misc/ld-signature'; -import { getUserKeypair } from '@/misc/keypair-store'; -import { User } from '@/models/entities/user'; +import { IActivity } from '../type.js'; +import { LdSignature } from '../misc/ld-signature.js'; +import { getUserKeypair } from '@/misc/keypair-store.js'; +import { User } from '@/models/entities/user.js'; export const renderActivity = (x: any): IActivity | null => { if (x == null) return null; diff --git a/packages/backend/src/remote/activitypub/renderer/key.ts b/packages/backend/src/remote/activitypub/renderer/key.ts index 51bc888dd..c4f3d464f 100644 --- a/packages/backend/src/remote/activitypub/renderer/key.ts +++ b/packages/backend/src/remote/activitypub/renderer/key.ts @@ -1,7 +1,7 @@ -import config from '@/config/index'; -import { ILocalUser } from '@/models/entities/user'; -import { UserKeypair } from '@/models/entities/user-keypair'; -import { createPublicKey } from 'crypto'; +import config from '@/config/index.js'; +import { ILocalUser } from '@/models/entities/user.js'; +import { UserKeypair } from '@/models/entities/user-keypair.js'; +import { createPublicKey } from 'node:crypto'; export default (user: ILocalUser, key: UserKeypair, postfix?: string) => ({ id: `${config.url}/users/${user.id}${postfix || '/publickey'}`, diff --git a/packages/backend/src/remote/activitypub/renderer/like.ts b/packages/backend/src/remote/activitypub/renderer/like.ts index 2e4da9d26..1bf36d470 100644 --- a/packages/backend/src/remote/activitypub/renderer/like.ts +++ b/packages/backend/src/remote/activitypub/renderer/like.ts @@ -1,8 +1,8 @@ -import config from '@/config/index'; -import { NoteReaction } from '@/models/entities/note-reaction'; -import { Note } from '@/models/entities/note'; -import { Emojis } from '@/models/index'; -import renderEmoji from './emoji'; +import config from '@/config/index.js'; +import { NoteReaction } from '@/models/entities/note-reaction.js'; +import { Note } from '@/models/entities/note.js'; +import { Emojis } from '@/models/index.js'; +import renderEmoji from './emoji.js'; export const renderLike = async (noteReaction: NoteReaction, note: Note) => { const reaction = noteReaction.reaction; diff --git a/packages/backend/src/remote/activitypub/renderer/mention.ts b/packages/backend/src/remote/activitypub/renderer/mention.ts index 06d2d33e5..c7e62e884 100644 --- a/packages/backend/src/remote/activitypub/renderer/mention.ts +++ b/packages/backend/src/remote/activitypub/renderer/mention.ts @@ -1,6 +1,6 @@ -import config from '@/config/index'; -import { User, ILocalUser } from '@/models/entities/user'; -import { Users } from '@/models/index'; +import config from '@/config/index.js'; +import { User, ILocalUser } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; export default (mention: User) => ({ type: 'Mention', diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts index 4f9a372b2..c3d9e120d 100644 --- a/packages/backend/src/remote/activitypub/renderer/note.ts +++ b/packages/backend/src/remote/activitypub/renderer/note.ts @@ -1,17 +1,17 @@ -import renderDocument from './document'; -import renderHashtag from './hashtag'; -import renderMention from './mention'; -import renderEmoji from './emoji'; -import config from '@/config/index'; -import toHtml from '../misc/get-note-html'; -import { Note, IMentionedRemoteUsers } from '@/models/entities/note'; -import { DriveFile } from '@/models/entities/drive-file'; -import { DriveFiles, Notes, Users, Emojis, Polls } from '@/models/index'; +import renderDocument from './document.js'; +import renderHashtag from './hashtag.js'; +import renderMention from './mention.js'; +import renderEmoji from './emoji.js'; +import config from '@/config/index.js'; +import toHtml from '../misc/get-note-html.js'; +import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { DriveFiles, Notes, Users, Emojis, Polls } from '@/models/index.js'; import { In } from 'typeorm'; -import { Emoji } from '@/models/entities/emoji'; -import { Poll } from '@/models/entities/poll'; +import { Emoji } from '@/models/entities/emoji.js'; +import { Poll } from '@/models/entities/poll.js'; -export default async function renderNote(note: Note, dive = true, isTalk = false): Promise { +export default async function renderNote(note: Note, dive = true, isTalk = false): Promise> { const getPromisedFiles = async (ids: string[]) => { if (!ids || ids.length === 0) return []; const items = await DriveFiles.find({ id: In(ids) }); diff --git a/packages/backend/src/remote/activitypub/renderer/ordered-collection.ts b/packages/backend/src/remote/activitypub/renderer/ordered-collection.ts index c4b4337af..ff9a77be3 100644 --- a/packages/backend/src/remote/activitypub/renderer/ordered-collection.ts +++ b/packages/backend/src/remote/activitypub/renderer/ordered-collection.ts @@ -6,7 +6,14 @@ * @param last URL of last page (optional) * @param orderedItems attached objects (optional) */ -export default function(id: string | null, totalItems: any, first?: string, last?: string, orderedItems?: Record) { +export default function(id: string | null, totalItems: any, first?: string, last?: string, orderedItems?: Record[]): { + id: string | null; + type: 'OrderedCollection'; + totalItems: any; + first?: string; + last?: string; + orderedItems?: Record[]; +} { const page: any = { id, type: 'OrderedCollection', diff --git a/packages/backend/src/remote/activitypub/renderer/person.ts b/packages/backend/src/remote/activitypub/renderer/person.ts index d1c4c0040..3d86e37cc 100644 --- a/packages/backend/src/remote/activitypub/renderer/person.ts +++ b/packages/backend/src/remote/activitypub/renderer/person.ts @@ -1,16 +1,16 @@ -import { URL } from 'url'; +import { URL } from 'node:url'; import * as mfm from 'mfm-js'; -import renderImage from './image'; -import renderKey from './key'; -import config from '@/config/index'; -import { ILocalUser } from '@/models/entities/user'; -import { toHtml } from '../../../mfm/to-html'; -import { getEmojis } from './note'; -import renderEmoji from './emoji'; -import { IIdentifier } from '../models/identifier'; -import renderHashtag from './hashtag'; -import { DriveFiles, UserProfiles } from '@/models/index'; -import { getUserKeypair } from '@/misc/keypair-store'; +import renderImage from './image.js'; +import renderKey from './key.js'; +import config from '@/config/index.js'; +import { ILocalUser } from '@/models/entities/user.js'; +import { toHtml } from '../../../mfm/to-html.js'; +import { getEmojis } from './note.js'; +import renderEmoji from './emoji.js'; +import { IIdentifier } from '../models/identifier.js'; +import renderHashtag from './hashtag.js'; +import { DriveFiles, UserProfiles } from '@/models/index.js'; +import { getUserKeypair } from '@/misc/keypair-store.js'; export async function renderPerson(user: ILocalUser) { const id = `${config.url}/users/${user.id}`; diff --git a/packages/backend/src/remote/activitypub/renderer/question.ts b/packages/backend/src/remote/activitypub/renderer/question.ts index 3cbff33ab..d4d1b590a 100644 --- a/packages/backend/src/remote/activitypub/renderer/question.ts +++ b/packages/backend/src/remote/activitypub/renderer/question.ts @@ -1,7 +1,7 @@ -import config from '@/config/index'; -import { User } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { Poll } from '@/models/entities/poll'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { Poll } from '@/models/entities/poll.js'; export default async function renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll) { const question = { diff --git a/packages/backend/src/remote/activitypub/renderer/read.ts b/packages/backend/src/remote/activitypub/renderer/read.ts index 2fe3b8e5e..a30e649f6 100644 --- a/packages/backend/src/remote/activitypub/renderer/read.ts +++ b/packages/backend/src/remote/activitypub/renderer/read.ts @@ -1,6 +1,6 @@ -import config from '@/config/index'; -import { User } from '@/models/entities/user'; -import { MessagingMessage } from '@/models/entities/messaging-message'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; export const renderReadActivity = (user: { id: User['id'] }, message: MessagingMessage) => ({ type: 'Read', diff --git a/packages/backend/src/remote/activitypub/renderer/reject.ts b/packages/backend/src/remote/activitypub/renderer/reject.ts index 575ef52ab..ab4cc1646 100644 --- a/packages/backend/src/remote/activitypub/renderer/reject.ts +++ b/packages/backend/src/remote/activitypub/renderer/reject.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { User } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; export default (object: any, user: { id: User['id'] }) => ({ type: 'Reject', diff --git a/packages/backend/src/remote/activitypub/renderer/remove.ts b/packages/backend/src/remote/activitypub/renderer/remove.ts index 8afaf199c..1be3edc5d 100644 --- a/packages/backend/src/remote/activitypub/renderer/remove.ts +++ b/packages/backend/src/remote/activitypub/renderer/remove.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { User } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; export default (user: { id: User['id'] }, target: any, object: any) => ({ type: 'Remove', diff --git a/packages/backend/src/remote/activitypub/renderer/undo.ts b/packages/backend/src/remote/activitypub/renderer/undo.ts index 14115b788..d28778e22 100644 --- a/packages/backend/src/remote/activitypub/renderer/undo.ts +++ b/packages/backend/src/remote/activitypub/renderer/undo.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { ILocalUser, User } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { ILocalUser, User } from '@/models/entities/user.js'; export default (object: any, user: { id: User['id'] }) => { if (object == null) return null; diff --git a/packages/backend/src/remote/activitypub/renderer/update.ts b/packages/backend/src/remote/activitypub/renderer/update.ts index 8bb415d11..cf880f03f 100644 --- a/packages/backend/src/remote/activitypub/renderer/update.ts +++ b/packages/backend/src/remote/activitypub/renderer/update.ts @@ -1,5 +1,5 @@ -import config from '@/config/index'; -import { User } from '@/models/entities/user'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; export default (object: any, user: { id: User['id'] }) => { const activity = { diff --git a/packages/backend/src/remote/activitypub/renderer/vote.ts b/packages/backend/src/remote/activitypub/renderer/vote.ts index fd7bc9dbe..b6eb8e095 100644 --- a/packages/backend/src/remote/activitypub/renderer/vote.ts +++ b/packages/backend/src/remote/activitypub/renderer/vote.ts @@ -1,8 +1,8 @@ -import config from '@/config/index'; -import { Note } from '@/models/entities/note'; -import { IRemoteUser, User } from '@/models/entities/user'; -import { PollVote } from '@/models/entities/poll-vote'; -import { Poll } from '@/models/entities/poll'; +import config from '@/config/index.js'; +import { Note } from '@/models/entities/note.js'; +import { IRemoteUser, User } from '@/models/entities/user.js'; +import { PollVote } from '@/models/entities/poll-vote.js'; +import { Poll } from '@/models/entities/poll.js'; export default async function renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser): Promise { return { diff --git a/packages/backend/src/remote/activitypub/request.ts b/packages/backend/src/remote/activitypub/request.ts index 715937e2a..5cbfd8c25 100644 --- a/packages/backend/src/remote/activitypub/request.ts +++ b/packages/backend/src/remote/activitypub/request.ts @@ -1,8 +1,8 @@ -import config from '@/config/index'; -import { getUserKeypair } from '@/misc/keypair-store'; -import { User } from '@/models/entities/user'; -import { getResponse } from '../../misc/fetch'; -import { createSignedPost, createSignedGet } from './ap-request'; +import config from '@/config/index.js'; +import { getUserKeypair } from '@/misc/keypair-store.js'; +import { User } from '@/models/entities/user.js'; +import { getResponse } from '../../misc/fetch.js'; +import { createSignedPost, createSignedGet } from './ap-request.js'; export default async (user: { id: User['id'] }, url: string, object: any) => { const body = JSON.stringify(object); diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts index f392a65e3..c1269c75c 100644 --- a/packages/backend/src/remote/activitypub/resolver.ts +++ b/packages/backend/src/remote/activitypub/resolver.ts @@ -1,11 +1,11 @@ -import config from '@/config/index'; -import { getJson } from '@/misc/fetch'; -import { ILocalUser } from '@/models/entities/user'; -import { getInstanceActor } from '@/services/instance-actor'; -import { signedGet } from './request'; -import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { extractDbHost } from '@/misc/convert-host'; +import config from '@/config/index.js'; +import { getJson } from '@/misc/fetch.js'; +import { ILocalUser } from '@/models/entities/user.js'; +import { getInstanceActor } from '@/services/instance-actor.js'; +import { signedGet } from './request.js'; +import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { extractDbHost } from '@/misc/convert-host.js'; export default class Resolver { private history: Set; diff --git a/packages/backend/src/remote/logger.ts b/packages/backend/src/remote/logger.ts index 9ffad4d71..4921f53bd 100644 --- a/packages/backend/src/remote/logger.ts +++ b/packages/backend/src/remote/logger.ts @@ -1,3 +1,3 @@ -import Logger from '@/services/logger'; +import Logger from '@/services/logger.js'; export const remoteLogger = new Logger('remote', 'cyan'); diff --git a/packages/backend/src/remote/resolve-user.ts b/packages/backend/src/remote/resolve-user.ts index 747735eca..aa37013c4 100644 --- a/packages/backend/src/remote/resolve-user.ts +++ b/packages/backend/src/remote/resolve-user.ts @@ -1,12 +1,12 @@ -import { URL } from 'url'; -import webFinger from './webfinger'; -import config from '@/config/index'; -import { createPerson, updatePerson } from './activitypub/models/person'; -import { remoteLogger } from './logger'; -import * as chalk from 'chalk'; -import { User, IRemoteUser } from '@/models/entities/user'; -import { Users } from '@/models/index'; -import { toPuny } from '@/misc/convert-host'; +import { URL } from 'node:url'; +import webFinger from './webfinger.js'; +import config from '@/config/index.js'; +import { createPerson, updatePerson } from './activitypub/models/person.js'; +import { remoteLogger } from './logger.js'; +import chalk from 'chalk'; +import { User, IRemoteUser } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; +import { toPuny } from '@/misc/convert-host.js'; const logger = remoteLogger.createSubLogger('resolve-user'); @@ -26,7 +26,7 @@ export async function resolveUser(username: string, host: string | null, option? host = toPuny(host); - if (config.host == host) { + if (config.host === host) { logger.info(`return local user: ${usernameLower}`); return await Users.findOne({ usernameLower, host: null }).then(u => { if (u == null) { diff --git a/packages/backend/src/remote/webfinger.ts b/packages/backend/src/remote/webfinger.ts index f63fd0362..9d3bfab24 100644 --- a/packages/backend/src/remote/webfinger.ts +++ b/packages/backend/src/remote/webfinger.ts @@ -1,6 +1,6 @@ -import { URL } from 'url'; -import { getJson } from '@/misc/fetch'; -import { query as urlQuery } from '@/prelude/url'; +import { URL } from 'node:url'; +import { getJson } from '@/misc/fetch.js'; +import { query as urlQuery } from '@/prelude/url.js'; type ILink = { href: string; diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index bbbc231b8..21be0a251 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -1,23 +1,23 @@ -import * as Router from '@koa/router'; -import * as json from 'koa-json-body'; -import * as httpSignature from 'http-signature'; +import Router from '@koa/router'; +import json from 'koa-json-body'; +import httpSignature from 'http-signature'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderNote from '@/remote/activitypub/renderer/note'; -import renderKey from '@/remote/activitypub/renderer/key'; -import { renderPerson } from '@/remote/activitypub/renderer/person'; -import renderEmoji from '@/remote/activitypub/renderer/emoji'; -import Outbox, { packActivity } from './activitypub/outbox'; -import Followers from './activitypub/followers'; -import Following from './activitypub/following'; -import Featured from './activitypub/featured'; -import { inbox as processInbox } from '@/queue/index'; -import { isSelfHost } from '@/misc/convert-host'; -import { Notes, Users, Emojis, NoteReactions } from '@/models/index'; -import { ILocalUser, User } from '@/models/entities/user'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderNote from '@/remote/activitypub/renderer/note.js'; +import renderKey from '@/remote/activitypub/renderer/key.js'; +import { renderPerson } from '@/remote/activitypub/renderer/person.js'; +import renderEmoji from '@/remote/activitypub/renderer/emoji.js'; +import Outbox, { packActivity } from './activitypub/outbox.js'; +import Followers from './activitypub/followers.js'; +import Following from './activitypub/following.js'; +import Featured from './activitypub/featured.js'; +import { inbox as processInbox } from '@/queue/index.js'; +import { isSelfHost } from '@/misc/convert-host.js'; +import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js'; +import { ILocalUser, User } from '@/models/entities/user.js'; import { In } from 'typeorm'; -import { renderLike } from '@/remote/activitypub/renderer/like'; -import { getUserKeypair } from '@/misc/keypair-store'; +import { renderLike } from '@/remote/activitypub/renderer/like.js'; +import { getUserKeypair } from '@/misc/keypair-store.js'; // Init router const router = new Router(); diff --git a/packages/backend/src/server/activitypub/featured.ts b/packages/backend/src/server/activitypub/featured.ts index 40b8d8cc8..129881a71 100644 --- a/packages/backend/src/server/activitypub/featured.ts +++ b/packages/backend/src/server/activitypub/featured.ts @@ -1,10 +1,10 @@ -import * as Router from '@koa/router'; -import config from '@/config/index'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection'; -import { setResponseType } from '../activitypub'; -import renderNote from '@/remote/activitypub/renderer/note'; -import { Users, Notes, UserNotePinings } from '@/models/index'; +import Router from '@koa/router'; +import config from '@/config/index.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; +import { setResponseType } from '../activitypub.js'; +import renderNote from '@/remote/activitypub/renderer/note.js'; +import { Users, Notes, UserNotePinings } from '@/models/index.js'; export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; @@ -32,7 +32,7 @@ export default async (ctx: Router.RouterContext) => { const rendered = renderOrderedCollection( `${config.url}/users/${userId}/collections/featured`, - renderedNotes.length, undefined, undefined, renderedNotes + renderedNotes.length, undefined, undefined, renderedNotes, ); ctx.body = renderActivity(rendered); diff --git a/packages/backend/src/server/activitypub/followers.ts b/packages/backend/src/server/activitypub/followers.ts index 927fb5d18..5d1d7c59e 100644 --- a/packages/backend/src/server/activitypub/followers.ts +++ b/packages/backend/src/server/activitypub/followers.ts @@ -1,24 +1,24 @@ -import * as Router from '@koa/router'; -import config from '@/config/index'; +import Router from '@koa/router'; +import config from '@/config/index.js'; import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import * as url from '@/prelude/url'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection'; -import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page'; -import renderFollowUser from '@/remote/activitypub/renderer/follow-user'; -import { setResponseType } from '../activitypub'; -import { Users, Followings, UserProfiles } from '@/models/index'; +import { ID } from '@/misc/cafy-id.js'; +import * as url from '@/prelude/url.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; +import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js'; +import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; +import { setResponseType } from '../activitypub.js'; +import { Users, Followings, UserProfiles } from '@/models/index.js'; import { LessThan } from 'typeorm'; export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; // Get 'cursor' parameter - const [cursor, cursorErr] = $.optional.type(ID).get(ctx.request.query.cursor); + const [cursor, cursorErr] = $.default.optional.type(ID).get(ctx.request.query.cursor); // Get 'page' parameter - const pageErr = !$.optional.str.or(['true', 'false']).ok(ctx.request.query.page); + const pageErr = !$.default.optional.str.or(['true', 'false']).ok(ctx.request.query.page); const page: boolean = ctx.request.query.page === 'true'; // Validate parameters diff --git a/packages/backend/src/server/activitypub/following.ts b/packages/backend/src/server/activitypub/following.ts index a3237582a..23110ce87 100644 --- a/packages/backend/src/server/activitypub/following.ts +++ b/packages/backend/src/server/activitypub/following.ts @@ -1,25 +1,25 @@ -import * as Router from '@koa/router'; -import config from '@/config/index'; +import Router from '@koa/router'; +import config from '@/config/index.js'; import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import * as url from '@/prelude/url'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection'; -import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page'; -import renderFollowUser from '@/remote/activitypub/renderer/follow-user'; -import { setResponseType } from '../activitypub'; -import { Users, Followings, UserProfiles } from '@/models/index'; +import { ID } from '@/misc/cafy-id.js'; +import * as url from '@/prelude/url.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; +import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js'; +import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; +import { setResponseType } from '../activitypub.js'; +import { Users, Followings, UserProfiles } from '@/models/index.js'; import { LessThan, FindConditions } from 'typeorm'; -import { Following } from '@/models/entities/following'; +import { Following } from '@/models/entities/following.js'; export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; // Get 'cursor' parameter - const [cursor, cursorErr] = $.optional.type(ID).get(ctx.request.query.cursor); + const [cursor, cursorErr] = $.default.optional.type(ID).get(ctx.request.query.cursor); // Get 'page' parameter - const pageErr = !$.optional.str.or(['true', 'false']).ok(ctx.request.query.page); + const pageErr = !$.default.optional.str.or(['true', 'false']).ok(ctx.request.query.page); const page: boolean = ctx.request.query.page === 'true'; // Validate parameters diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index ba6b46a0c..57c126752 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -1,32 +1,32 @@ -import * as Router from '@koa/router'; -import config from '@/config/index'; +import Router from '@koa/router'; +import config from '@/config/index.js'; import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection'; -import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page'; -import { setResponseType } from '../activitypub'; -import renderNote from '@/remote/activitypub/renderer/note'; -import renderCreate from '@/remote/activitypub/renderer/create'; -import renderAnnounce from '@/remote/activitypub/renderer/announce'; -import { countIf } from '@/prelude/array'; -import * as url from '@/prelude/url'; -import { Users, Notes } from '@/models/index'; -import { makePaginationQuery } from '../api/common/make-pagination-query'; +import { ID } from '@/misc/cafy-id.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; +import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js'; +import { setResponseType } from '../activitypub.js'; +import renderNote from '@/remote/activitypub/renderer/note.js'; +import renderCreate from '@/remote/activitypub/renderer/create.js'; +import renderAnnounce from '@/remote/activitypub/renderer/announce.js'; +import { countIf } from '@/prelude/array.js'; +import * as url from '@/prelude/url.js'; +import { Users, Notes } from '@/models/index.js'; +import { makePaginationQuery } from '../api/common/make-pagination-query.js'; import { Brackets } from 'typeorm'; -import { Note } from '@/models/entities/note'; +import { Note } from '@/models/entities/note.js'; export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; // Get 'sinceId' parameter - const [sinceId, sinceIdErr] = $.optional.type(ID).get(ctx.request.query.since_id); + const [sinceId, sinceIdErr] = $.default.optional.type(ID).get(ctx.request.query.since_id); // Get 'untilId' parameter - const [untilId, untilIdErr] = $.optional.type(ID).get(ctx.request.query.until_id); + const [untilId, untilIdErr] = $.default.optional.type(ID).get(ctx.request.query.until_id); // Get 'page' parameter - const pageErr = !$.optional.str.or(['true', 'false']).ok(ctx.request.query.page); + const pageErr = !$.default.optional.str.or(['true', 'false']).ok(ctx.request.query.page); const page: boolean = ctx.request.query.page === 'true'; // Validate parameters diff --git a/packages/backend/src/server/api/2fa.ts b/packages/backend/src/server/api/2fa.ts index 2a69e49c8..e1c226979 100644 --- a/packages/backend/src/server/api/2fa.ts +++ b/packages/backend/src/server/api/2fa.ts @@ -1,5 +1,5 @@ -import * as crypto from 'crypto'; -import config from '@/config/index'; +import * as crypto from 'node:crypto'; +import config from '@/config/index.js'; import * as jsrsasign from 'jsrsasign'; const ECC_PRELUDE = Buffer.from([0x04]); diff --git a/packages/backend/src/server/api/api-handler.ts b/packages/backend/src/server/api/api-handler.ts index faa35d12d..f97c3dd39 100644 --- a/packages/backend/src/server/api/api-handler.ts +++ b/packages/backend/src/server/api/api-handler.ts @@ -1,11 +1,11 @@ -import * as Koa from 'koa'; +import Koa from 'koa'; -import { IEndpoint } from './endpoints'; -import authenticate, { AuthenticationError } from './authenticate'; -import call from './call'; -import { ApiError } from './error'; +import { IEndpoint } from './endpoints.js'; +import authenticate, { AuthenticationError } from './authenticate.js'; +import call from './call.js'; +import { ApiError } from './error.js'; -export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => { +export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => { const body = ctx.request.body; const reply = (x?: any, y?: ApiError) => { @@ -32,7 +32,7 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => { // Authentication authenticate(body['i']).then(([user, app]) => { // API invoking - call(endpoint.name, user, app, body, (ctx as any).file).then((res: any) => { + call(endpoint.name, user, app, body, ctx).then((res: any) => { reply(res); }).catch((e: ApiError) => { reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e); diff --git a/packages/backend/src/server/api/authenticate.ts b/packages/backend/src/server/api/authenticate.ts index 9e2f3eb74..7fdf14666 100644 --- a/packages/backend/src/server/api/authenticate.ts +++ b/packages/backend/src/server/api/authenticate.ts @@ -1,7 +1,7 @@ -import isNativeToken from './common/is-native-token'; -import { User } from '@/models/entities/user'; -import { Users, AccessTokens, Apps } from '@/models/index'; -import { AccessToken } from '@/models/entities/access-token'; +import isNativeToken from './common/is-native-token.js'; +import { User } from '@/models/entities/user.js'; +import { Users, AccessTokens, Apps } from '@/models/index.js'; +import { AccessToken } from '@/models/entities/access-token.js'; export class AuthenticationError extends Error { constructor(message: string) { diff --git a/packages/backend/src/server/api/call.ts b/packages/backend/src/server/api/call.ts index 399ee65bd..5c5ef6601 100644 --- a/packages/backend/src/server/api/call.ts +++ b/packages/backend/src/server/api/call.ts @@ -1,10 +1,11 @@ +import Koa from 'koa'; import { performance } from 'perf_hooks'; -import { limiter } from './limiter'; -import { User } from '@/models/entities/user'; -import endpoints from './endpoints'; -import { ApiError } from './error'; -import { apiLogger } from './logger'; -import { AccessToken } from '@/models/entities/access-token'; +import { limiter } from './limiter.js'; +import { User } from '@/models/entities/user.js'; +import endpoints, { IEndpoint } from './endpoints.js'; +import { ApiError } from './error.js'; +import { apiLogger } from './logger.js'; +import { AccessToken } from '@/models/entities/access-token.js'; const accessDenied = { message: 'Access denied.', @@ -12,7 +13,7 @@ const accessDenied = { id: '56f35758-7dd5-468b-8439-5d6fb8ec9b8e', }; -export default async (endpoint: string, user: User | null | undefined, token: AccessToken | null | undefined, data: any, file?: any) => { +export default async (endpoint: string, user: User | null | undefined, token: AccessToken | null | undefined, data: any, ctx?: Koa.Context) => { const isSecure = user != null && token == null; const ep = endpoints.find(e => e.name === endpoint); @@ -66,7 +67,7 @@ export default async (endpoint: string, user: User | null | undefined, token: Ac if (ep.meta.requireCredential && ep.meta.limit && !user!.isAdmin && !user!.isModerator) { // Rate limit - await limiter(ep, user!).catch(e => { + await limiter(ep as IEndpoint & { meta: { limit: NonNullable } }, user!).catch(e => { throw new ApiError({ message: 'Rate limit exceeded. Please try again later.', code: 'RATE_LIMIT_EXCEEDED', @@ -76,9 +77,30 @@ export default async (endpoint: string, user: User | null | undefined, token: Ac }); } + // Cast non JSON input + if (ep.meta.requireFile && ep.params.properties) { + for (const k of Object.keys(ep.params.properties)) { + const param = ep.params.properties![k]; + if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') { + try { + data[k] = JSON.parse(data[k]); + } catch (e) { + throw new ApiError({ + message: 'Invalid param.', + code: 'INVALID_PARAM', + id: '0b5f1631-7c1a-41a6-b399-cce335f34d85', + }, { + param: k, + reason: `cannot cast to ${param.type}`, + }); + } + } + } + } + // API invoking const before = performance.now(); - return await ep.exec(data, user, token, file).catch((e: Error) => { + return await ep.exec(data, user, token, ctx?.file).catch((e: Error) => { if (e instanceof ApiError) { throw e; } else { diff --git a/packages/backend/src/server/api/common/generate-block-query.ts b/packages/backend/src/server/api/common/generate-block-query.ts index 4fd618473..60db1e731 100644 --- a/packages/backend/src/server/api/common/generate-block-query.ts +++ b/packages/backend/src/server/api/common/generate-block-query.ts @@ -1,5 +1,5 @@ -import { User } from '@/models/entities/user'; -import { Blockings } from '@/models/index'; +import { User } from '@/models/entities/user.js'; +import { Blockings } from '@/models/index.js'; import { Brackets, SelectQueryBuilder } from 'typeorm'; // ここでいうBlockedはčĸĢBlockedぎ意 diff --git a/packages/backend/src/server/api/common/generate-channel-query.ts b/packages/backend/src/server/api/common/generate-channel-query.ts index 80a0acf7f..333bb73b8 100644 --- a/packages/backend/src/server/api/common/generate-channel-query.ts +++ b/packages/backend/src/server/api/common/generate-channel-query.ts @@ -1,5 +1,5 @@ -import { User } from '@/models/entities/user'; -import { ChannelFollowings } from '@/models/index'; +import { User } from '@/models/entities/user.js'; +import { ChannelFollowings } from '@/models/index.js'; import { Brackets, SelectQueryBuilder } from 'typeorm'; export function generateChannelQuery(q: SelectQueryBuilder, me?: { id: User['id'] } | null) { diff --git a/packages/backend/src/server/api/common/generate-muted-instance-query.ts b/packages/backend/src/server/api/common/generate-muted-instance-query.ts index dbc9fc98f..72a6fec68 100644 --- a/packages/backend/src/server/api/common/generate-muted-instance-query.ts +++ b/packages/backend/src/server/api/common/generate-muted-instance-query.ts @@ -1,6 +1,6 @@ -import { User } from '@/models/entities/user'; -import { id } from '@/models/id'; -import { UserProfiles } from '@/models/index'; +import { User } from '@/models/entities/user.js'; +import { id } from '@/models/id.js'; +import { UserProfiles } from '@/models/index.js'; import { SelectQueryBuilder, Brackets } from 'typeorm'; function createMutesQuery(id: string) { diff --git a/packages/backend/src/server/api/common/generate-muted-note-query.ts b/packages/backend/src/server/api/common/generate-muted-note-query.ts index 073784261..f544e334d 100644 --- a/packages/backend/src/server/api/common/generate-muted-note-query.ts +++ b/packages/backend/src/server/api/common/generate-muted-note-query.ts @@ -1,5 +1,5 @@ -import { User } from '@/models/entities/user'; -import { MutedNotes } from '@/models/index'; +import { User } from '@/models/entities/user.js'; +import { MutedNotes } from '@/models/index.js'; import { SelectQueryBuilder } from 'typeorm'; export function generateMutedNoteQuery(q: SelectQueryBuilder, me: { id: User['id'] }) { diff --git a/packages/backend/src/server/api/common/generate-muted-note-thread-query.ts b/packages/backend/src/server/api/common/generate-muted-note-thread-query.ts index 7e2cbd498..7263ea2e6 100644 --- a/packages/backend/src/server/api/common/generate-muted-note-thread-query.ts +++ b/packages/backend/src/server/api/common/generate-muted-note-thread-query.ts @@ -1,5 +1,5 @@ -import { User } from '@/models/entities/user'; -import { NoteThreadMutings } from '@/models/index'; +import { User } from '@/models/entities/user.js'; +import { NoteThreadMutings } from '@/models/index.js'; import { Brackets, SelectQueryBuilder } from 'typeorm'; export function generateMutedNoteThreadQuery(q: SelectQueryBuilder, me: { id: User['id'] }) { diff --git a/packages/backend/src/server/api/common/generate-muted-user-query.ts b/packages/backend/src/server/api/common/generate-muted-user-query.ts index 7e200b87e..79cb3ff89 100644 --- a/packages/backend/src/server/api/common/generate-muted-user-query.ts +++ b/packages/backend/src/server/api/common/generate-muted-user-query.ts @@ -1,5 +1,5 @@ -import { User } from '@/models/entities/user'; -import { Mutings } from '@/models/index'; +import { User } from '@/models/entities/user.js'; +import { Mutings } from '@/models/index.js'; import { SelectQueryBuilder, Brackets } from 'typeorm'; export function generateMutedUserQuery(q: SelectQueryBuilder, me: { id: User['id'] }, exclude?: User) { diff --git a/packages/backend/src/server/api/common/generate-native-user-token.ts b/packages/backend/src/server/api/common/generate-native-user-token.ts index 1f791c57c..5d8a4c537 100644 --- a/packages/backend/src/server/api/common/generate-native-user-token.ts +++ b/packages/backend/src/server/api/common/generate-native-user-token.ts @@ -1,3 +1,3 @@ -import { secureRndstr } from '@/misc/secure-rndstr'; +import { secureRndstr } from '@/misc/secure-rndstr.js'; export default () => secureRndstr(16, true); diff --git a/packages/backend/src/server/api/common/generate-replies-query.ts b/packages/backend/src/server/api/common/generate-replies-query.ts index fbc41b2c2..301782eab 100644 --- a/packages/backend/src/server/api/common/generate-replies-query.ts +++ b/packages/backend/src/server/api/common/generate-replies-query.ts @@ -1,7 +1,7 @@ -import { User } from '@/models/entities/user'; +import { User } from '@/models/entities/user.js'; import { Brackets, SelectQueryBuilder } from 'typeorm'; -export function generateRepliesQuery(q: SelectQueryBuilder, me?: { id: User['id'] } | null) { +export function generateRepliesQuery(q: SelectQueryBuilder, me?: Pick | null) { if (me == null) { q.andWhere(new Brackets(qb => { qb .where(`note.replyId IS NULL`) // čŋ”äŋĄã§ã¯ãĒい @@ -10,7 +10,7 @@ export function generateRepliesQuery(q: SelectQueryBuilder, me?: { id: User .andWhere('note.replyUserId = note.userId'); })); })); - } else { + } else if (!me.showTimelineReplies) { q.andWhere(new Brackets(qb => { qb .where(`note.replyId IS NULL`) // čŋ”äŋĄã§ã¯ãĒい .orWhere('note.replyUserId = :meId', { meId: me.id }) // čŋ”äŋĄã ã‘おč‡Ē分ぎノãƒŧトへぎčŋ”äŋĄ diff --git a/packages/backend/src/server/api/common/generate-visibility-query.ts b/packages/backend/src/server/api/common/generate-visibility-query.ts index 813e8b6c0..715982934 100644 --- a/packages/backend/src/server/api/common/generate-visibility-query.ts +++ b/packages/backend/src/server/api/common/generate-visibility-query.ts @@ -1,5 +1,5 @@ -import { User } from '@/models/entities/user'; -import { Followings } from '@/models/index'; +import { User } from '@/models/entities/user.js'; +import { Followings } from '@/models/index.js'; import { Brackets, SelectQueryBuilder } from 'typeorm'; export function generateVisibilityQuery(q: SelectQueryBuilder, me?: { id: User['id'] } | null) { diff --git a/packages/backend/src/server/api/common/getters.ts b/packages/backend/src/server/api/common/getters.ts index 4b2ee8f1d..c5a47876d 100644 --- a/packages/backend/src/server/api/common/getters.ts +++ b/packages/backend/src/server/api/common/getters.ts @@ -1,7 +1,7 @@ -import { IdentifiableError } from '@/misc/identifiable-error'; -import { User } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { Notes, Users } from '@/models/index'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { User } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { Notes, Users } from '@/models/index.js'; /** * Get note for API processing diff --git a/packages/backend/src/server/api/common/inject-featured.ts b/packages/backend/src/server/api/common/inject-featured.ts index 1dc13c83e..b7dd8028b 100644 --- a/packages/backend/src/server/api/common/inject-featured.ts +++ b/packages/backend/src/server/api/common/inject-featured.ts @@ -1,9 +1,9 @@ import rndstr from 'rndstr'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; -import { Notes, UserProfiles, NoteReactions } from '@/models/index'; -import { generateMutedUserQuery } from './generate-muted-user-query'; -import { generateBlockedUserQuery } from './generate-block-query'; +import { Note } from '@/models/entities/note.js'; +import { User } from '@/models/entities/user.js'; +import { Notes, UserProfiles, NoteReactions } from '@/models/index.js'; +import { generateMutedUserQuery } from './generate-muted-user-query.js'; +import { generateBlockedUserQuery } from './generate-block-query.js'; // TODO: ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗ、Renote、čŋ”äŋĄãĒおをしたノãƒŧトは除外する diff --git a/packages/backend/src/server/api/common/inject-promo.ts b/packages/backend/src/server/api/common/inject-promo.ts index 06a384199..b467b7b70 100644 --- a/packages/backend/src/server/api/common/inject-promo.ts +++ b/packages/backend/src/server/api/common/inject-promo.ts @@ -1,7 +1,7 @@ import rndstr from 'rndstr'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; -import { PromoReads, PromoNotes, Notes, Users } from '@/models/index'; +import { Note } from '@/models/entities/note.js'; +import { User } from '@/models/entities/user.js'; +import { PromoReads, PromoNotes, Notes, Users } from '@/models/index.js'; export async function injectPromo(timeline: Note[], user?: User | null) { if (timeline.length < 5) return; diff --git a/packages/backend/src/server/api/common/read-messaging-message.ts b/packages/backend/src/server/api/common/read-messaging-message.ts index 928333e59..b0ce54d37 100644 --- a/packages/backend/src/server/api/common/read-messaging-message.ts +++ b/packages/backend/src/server/api/common/read-messaging-message.ts @@ -1,17 +1,17 @@ -import { publishMainStream, publishGroupMessagingStream } from '@/services/stream'; -import { publishMessagingStream } from '@/services/stream'; -import { publishMessagingIndexStream } from '@/services/stream'; -import { User, IRemoteUser } from '@/models/entities/user'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { MessagingMessages, UserGroupJoinings, Users } from '@/models/index'; +import { publishMainStream, publishGroupMessagingStream } from '@/services/stream.js'; +import { publishMessagingStream } from '@/services/stream.js'; +import { publishMessagingIndexStream } from '@/services/stream.js'; +import { User, IRemoteUser } from '@/models/entities/user.js'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import { MessagingMessages, UserGroupJoinings, Users } from '@/models/index.js'; import { In } from 'typeorm'; -import { IdentifiableError } from '@/misc/identifiable-error'; -import { UserGroup } from '@/models/entities/user-group'; -import { toArray } from '@/prelude/array'; -import { renderReadActivity } from '@/remote/activitypub/renderer/read'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { deliver } from '@/queue/index'; -import orderedCollection from '@/remote/activitypub/renderer/ordered-collection'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { toArray } from '@/prelude/array.js'; +import { renderReadActivity } from '@/remote/activitypub/renderer/read.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { deliver } from '@/queue/index.js'; +import orderedCollection from '@/remote/activitypub/renderer/ordered-collection.js'; /** * Mark messages as read diff --git a/packages/backend/src/server/api/common/read-notification.ts b/packages/backend/src/server/api/common/read-notification.ts index 049a7feed..1f575042a 100644 --- a/packages/backend/src/server/api/common/read-notification.ts +++ b/packages/backend/src/server/api/common/read-notification.ts @@ -1,7 +1,7 @@ -import { publishMainStream } from '@/services/stream'; -import { User } from '@/models/entities/user'; -import { Notification } from '@/models/entities/notification'; -import { Notifications, Users } from '@/models/index'; +import { publishMainStream } from '@/services/stream.js'; +import { User } from '@/models/entities/user.js'; +import { Notification } from '@/models/entities/notification.js'; +import { Notifications, Users } from '@/models/index.js'; import { In } from 'typeorm'; export async function readNotification( diff --git a/packages/backend/src/server/api/common/signin.ts b/packages/backend/src/server/api/common/signin.ts index df986fc45..163f132a4 100644 --- a/packages/backend/src/server/api/common/signin.ts +++ b/packages/backend/src/server/api/common/signin.ts @@ -1,10 +1,10 @@ -import * as Koa from 'koa'; +import Koa from 'koa'; -import config from '@/config/index'; -import { ILocalUser } from '@/models/entities/user'; -import { Signins } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { publishMainStream } from '@/services/stream'; +import config from '@/config/index.js'; +import { ILocalUser } from '@/models/entities/user.js'; +import { Signins } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { publishMainStream } from '@/services/stream.js'; export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) { if (redirect) { diff --git a/packages/backend/src/server/api/common/signup.ts b/packages/backend/src/server/api/common/signup.ts index f8db7e374..7689e8233 100644 --- a/packages/backend/src/server/api/common/signup.ts +++ b/packages/backend/src/server/api/common/signup.ts @@ -1,15 +1,15 @@ -import * as bcrypt from 'bcryptjs'; -import { generateKeyPair } from 'crypto'; -import generateUserToken from './generate-native-user-token'; -import { User } from '@/models/entities/user'; -import { Users, UsedUsernames } from '@/models/index'; -import { UserProfile } from '@/models/entities/user-profile'; +import bcrypt from 'bcryptjs'; +import { generateKeyPair } from 'node:crypto'; +import generateUserToken from './generate-native-user-token.js'; +import { User } from '@/models/entities/user.js'; +import { Users, UsedUsernames } from '@/models/index.js'; +import { UserProfile } from '@/models/entities/user-profile.js'; import { getConnection } from 'typeorm'; -import { genId } from '@/misc/gen-id'; -import { toPunyNullable } from '@/misc/convert-host'; -import { UserKeypair } from '@/models/entities/user-keypair'; -import { usersChart } from '@/services/chart/index'; -import { UsedUsername } from '@/models/entities/used-username'; +import { genId } from '@/misc/gen-id.js'; +import { toPunyNullable } from '@/misc/convert-host.js'; +import { UserKeypair } from '@/models/entities/user-keypair.js'; +import { usersChart } from '@/services/chart/index.js'; +import { UsedUsername } from '@/models/entities/used-username.js'; export async function signup(opts: { username: User['username']; @@ -21,13 +21,13 @@ export async function signup(opts: { let hash = passwordHash; // Validate username - if (!Users.validateLocalUsername.ok(username)) { + if (!Users.validateLocalUsername(username)) { throw new Error('INVALID_USERNAME'); } if (password != null && passwordHash == null) { // Validate password - if (!Users.validatePassword.ok(password)) { + if (!Users.validatePassword(password)) { throw new Error('INVALID_PASSWORD'); } diff --git a/packages/backend/src/server/api/define.ts b/packages/backend/src/server/api/define.ts index 71e5fadde..9094fcffc 100644 --- a/packages/backend/src/server/api/define.ts +++ b/packages/backend/src/server/api/define.ts @@ -1,14 +1,14 @@ -import * as fs from 'fs'; -import { ILocalUser } from '@/models/entities/user'; -import { IEndpointMeta } from './endpoints'; -import { ApiError } from './error'; -import { SchemaType } from '@/misc/schema'; -import { AccessToken } from '@/models/entities/access-token'; - -type NonOptional = T extends undefined ? never : T; +import * as fs from 'node:fs'; +import Ajv from 'ajv'; +import { ILocalUser } from '@/models/entities/user.js'; +import { IEndpointMeta } from './endpoints.js'; +import { ApiError } from './error.js'; +import { Schema, SchemaType } from '@/misc/schema.js'; +import { AccessToken } from '@/models/entities/access-token.js'; type SimpleUserInfo = { id: ILocalUser['id']; + createdAt: ILocalUser['createdAt']; host: ILocalUser['host']; username: ILocalUser['username']; uri: ILocalUser['uri']; @@ -17,24 +17,27 @@ type SimpleUserInfo = { isAdmin: ILocalUser['isAdmin']; isModerator: ILocalUser['isModerator']; isSilenced: ILocalUser['isSilenced']; -}; - -type Params = { - [P in keyof T['params']]: NonNullable[P]['transform'] extends () => any - ? ReturnType[P]['transform']> - : NonNullable[P]['default'] extends null | number | string - ? NonOptional[P]['validator']['get']>[0]> - : ReturnType[P]['validator']['get']>[0]; + showTimelineReplies: ILocalUser['showTimelineReplies']; }; export type Response = Record | void; -type executor = - (params: Params, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any, cleanup?: () => any) => +// TODO: paramsぎ型をT['params']ぎ゚キãƒŧマ厚įžŠã‹ã‚‰æŽ¨čĢ–する +type executor = + (params: SchemaType, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any, cleanup?: () => any) => Promise>>; -export default function (meta: T, cb: executor) +const ajv = new Ajv({ + useDefaults: true, +}); + +ajv.addFormat('misskey:id', /^[a-z0-9]+$/); + +export default function (meta: T, paramDef: Ps, cb: executor) : (params: any, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any) => Promise { + + const validate = ajv.compile(paramDef); + return (params: any, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any) => { function cleanup() { fs.unlink(file.path, () => {}); @@ -46,42 +49,22 @@ export default function (meta: T, cb: executor) id: '4267801e-70d1-416a-b011-4ee502885d8b', })); - const [ps, pserr] = getParams(meta, params); - if (pserr) { + const valid = validate(params); + if (!valid) { if (file) cleanup(); - return Promise.reject(pserr); - } - return cb(ps, user, token, file, cleanup); - }; -} - -function getParams(defs: T, params: any): [Params, ApiError | null] { - if (defs.params == null) return [params, null]; - - const x: any = {}; - let err: ApiError | null = null; - Object.entries(defs.params).some(([k, def]) => { - const [v, e] = def.validator.get(params[k]); - if (e) { - err = new ApiError({ + const errors = validate.errors!; + const err = new ApiError({ message: 'Invalid param.', code: 'INVALID_PARAM', id: '3d81ceae-475f-4600-b2a8-2bc116157532', }, { - param: k, - reason: e.message, + param: errors[0].schemaPath, + reason: errors[0].message, }); - return true; - } else { - if (v === undefined && Object.prototype.hasOwnProperty.call(def, 'default')) { - x[k] = def.default; - } else { - x[k] = v; - } - if (def.transform) x[k] = def.transform(x[k]); - return false; + return Promise.reject(err); } - }); - return [x, err]; + + return cb(params as SchemaType, user, token, file, cleanup); + }; } diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index bb4e972b8..6b4eff078 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -1,31 +1,618 @@ -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; -import { Context } from 'cafy'; -import * as path from 'path'; -import * as glob from 'glob'; -import { Schema } from '@/misc/schema'; +import { Schema } from '@/misc/schema.js'; -//const _filename = fileURLToPath(import.meta.url); -const _filename = __filename; -const _dirname = dirname(_filename); +import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js'; +import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js'; +import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js'; +import * as ep___admin_ad_create from './endpoints/admin/ad/create.js'; +import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js'; +import * as ep___admin_ad_list from './endpoints/admin/ad/list.js'; +import * as ep___admin_ad_update from './endpoints/admin/ad/update.js'; +import * as ep___admin_announcements_create from './endpoints/admin/announcements/create.js'; +import * as ep___admin_announcements_delete from './endpoints/admin/announcements/delete.js'; +import * as ep___admin_announcements_list from './endpoints/admin/announcements/list.js'; +import * as ep___admin_announcements_update from './endpoints/admin/announcements/update.js'; +import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js'; +import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js'; +import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js'; +import * as ep___admin_drive_files from './endpoints/admin/drive/files.js'; +import * as ep___admin_drive_showFile from './endpoints/admin/drive/show-file.js'; +import * as ep___admin_emoji_addAliasesBulk from './endpoints/admin/emoji/add-aliases-bulk.js'; +import * as ep___admin_emoji_add from './endpoints/admin/emoji/add.js'; +import * as ep___admin_emoji_copy from './endpoints/admin/emoji/copy.js'; +import * as ep___admin_emoji_deleteBulk from './endpoints/admin/emoji/delete-bulk.js'; +import * as ep___admin_emoji_delete from './endpoints/admin/emoji/delete.js'; +import * as ep___admin_emoji_importZip from './endpoints/admin/emoji/import-zip.js'; +import * as ep___admin_emoji_listRemote from './endpoints/admin/emoji/list-remote.js'; +import * as ep___admin_emoji_list from './endpoints/admin/emoji/list.js'; +import * as ep___admin_emoji_removeAliasesBulk from './endpoints/admin/emoji/remove-aliases-bulk.js'; +import * as ep___admin_emoji_setAliasesBulk from './endpoints/admin/emoji/set-aliases-bulk.js'; +import * as ep___admin_emoji_setCategoryBulk from './endpoints/admin/emoji/set-category-bulk.js'; +import * as ep___admin_emoji_update from './endpoints/admin/emoji/update.js'; +import * as ep___admin_federation_deleteAllFiles from './endpoints/admin/federation/delete-all-files.js'; +import * as ep___admin_federation_refreshRemoteInstanceMetadata from './endpoints/admin/federation/refresh-remote-instance-metadata.js'; +import * as ep___admin_federation_removeAllFollowing from './endpoints/admin/federation/remove-all-following.js'; +import * as ep___admin_federation_updateInstance from './endpoints/admin/federation/update-instance.js'; +import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js'; +import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js'; +import * as ep___admin_invite from './endpoints/admin/invite.js'; +import * as ep___admin_moderators_add from './endpoints/admin/moderators/add.js'; +import * as ep___admin_moderators_remove from './endpoints/admin/moderators/remove.js'; +import * as ep___admin_promo_create from './endpoints/admin/promo/create.js'; +import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js'; +import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js'; +import * as ep___admin_queue_inboxDelayed from './endpoints/admin/queue/inbox-delayed.js'; +import * as ep___admin_queue_stats from './endpoints/admin/queue/stats.js'; +import * as ep___admin_relays_add from './endpoints/admin/relays/add.js'; +import * as ep___admin_relays_list from './endpoints/admin/relays/list.js'; +import * as ep___admin_relays_remove from './endpoints/admin/relays/remove.js'; +import * as ep___admin_resetPassword from './endpoints/admin/reset-password.js'; +import * as ep___admin_resolveAbuseUserReport from './endpoints/admin/resolve-abuse-user-report.js'; +import * as ep___admin_sendEmail from './endpoints/admin/send-email.js'; +import * as ep___admin_serverInfo from './endpoints/admin/server-info.js'; +import * as ep___admin_showModerationLogs from './endpoints/admin/show-moderation-logs.js'; +import * as ep___admin_showUser from './endpoints/admin/show-user.js'; +import * as ep___admin_showUsers from './endpoints/admin/show-users.js'; +import * as ep___admin_silenceUser from './endpoints/admin/silence-user.js'; +import * as ep___admin_suspendUser from './endpoints/admin/suspend-user.js'; +import * as ep___admin_unsilenceUser from './endpoints/admin/unsilence-user.js'; +import * as ep___admin_unsuspendUser from './endpoints/admin/unsuspend-user.js'; +import * as ep___admin_updateMeta from './endpoints/admin/update-meta.js'; +import * as ep___admin_vacuum from './endpoints/admin/vacuum.js'; +import * as ep___announcements from './endpoints/announcements.js'; +import * as ep___antennas_create from './endpoints/antennas/create.js'; +import * as ep___antennas_delete from './endpoints/antennas/delete.js'; +import * as ep___antennas_list from './endpoints/antennas/list.js'; +import * as ep___antennas_notes from './endpoints/antennas/notes.js'; +import * as ep___antennas_show from './endpoints/antennas/show.js'; +import * as ep___antennas_update from './endpoints/antennas/update.js'; +import * as ep___ap_get from './endpoints/ap/get.js'; +import * as ep___ap_show from './endpoints/ap/show.js'; +import * as ep___app_create from './endpoints/app/create.js'; +import * as ep___app_show from './endpoints/app/show.js'; +import * as ep___auth_accept from './endpoints/auth/accept.js'; +import * as ep___auth_session_generate from './endpoints/auth/session/generate.js'; +import * as ep___auth_session_show from './endpoints/auth/session/show.js'; +import * as ep___auth_session_userkey from './endpoints/auth/session/userkey.js'; +import * as ep___blocking_create from './endpoints/blocking/create.js'; +import * as ep___blocking_delete from './endpoints/blocking/delete.js'; +import * as ep___blocking_list from './endpoints/blocking/list.js'; +import * as ep___channels_create from './endpoints/channels/create.js'; +import * as ep___channels_featured from './endpoints/channels/featured.js'; +import * as ep___channels_follow from './endpoints/channels/follow.js'; +import * as ep___channels_followed from './endpoints/channels/followed.js'; +import * as ep___channels_owned from './endpoints/channels/owned.js'; +import * as ep___channels_show from './endpoints/channels/show.js'; +import * as ep___channels_timeline from './endpoints/channels/timeline.js'; +import * as ep___channels_unfollow from './endpoints/channels/unfollow.js'; +import * as ep___channels_update from './endpoints/channels/update.js'; +import * as ep___charts_activeUsers from './endpoints/charts/active-users.js'; +import * as ep___charts_apRequest from './endpoints/charts/ap-request.js'; +import * as ep___charts_drive from './endpoints/charts/drive.js'; +import * as ep___charts_federation from './endpoints/charts/federation.js'; +import * as ep___charts_hashtag from './endpoints/charts/hashtag.js'; +import * as ep___charts_instance from './endpoints/charts/instance.js'; +import * as ep___charts_notes from './endpoints/charts/notes.js'; +import * as ep___charts_user_drive from './endpoints/charts/user/drive.js'; +import * as ep___charts_user_following from './endpoints/charts/user/following.js'; +import * as ep___charts_user_notes from './endpoints/charts/user/notes.js'; +import * as ep___charts_user_reactions from './endpoints/charts/user/reactions.js'; +import * as ep___charts_users from './endpoints/charts/users.js'; +import * as ep___clips_addNote from './endpoints/clips/add-note.js'; +import * as ep___clips_create from './endpoints/clips/create.js'; +import * as ep___clips_delete from './endpoints/clips/delete.js'; +import * as ep___clips_list from './endpoints/clips/list.js'; +import * as ep___clips_notes from './endpoints/clips/notes.js'; +import * as ep___clips_show from './endpoints/clips/show.js'; +import * as ep___clips_update from './endpoints/clips/update.js'; +import * as ep___drive from './endpoints/drive.js'; +import * as ep___drive_files from './endpoints/drive/files.js'; +import * as ep___drive_files_attachedNotes from './endpoints/drive/files/attached-notes.js'; +import * as ep___drive_files_checkExistence from './endpoints/drive/files/check-existence.js'; +import * as ep___drive_files_create from './endpoints/drive/files/create.js'; +import * as ep___drive_files_delete from './endpoints/drive/files/delete.js'; +import * as ep___drive_files_findByHash from './endpoints/drive/files/find-by-hash.js'; +import * as ep___drive_files_find from './endpoints/drive/files/find.js'; +import * as ep___drive_files_show from './endpoints/drive/files/show.js'; +import * as ep___drive_files_update from './endpoints/drive/files/update.js'; +import * as ep___drive_files_uploadFromUrl from './endpoints/drive/files/upload-from-url.js'; +import * as ep___drive_folders from './endpoints/drive/folders.js'; +import * as ep___drive_folders_create from './endpoints/drive/folders/create.js'; +import * as ep___drive_folders_delete from './endpoints/drive/folders/delete.js'; +import * as ep___drive_folders_find from './endpoints/drive/folders/find.js'; +import * as ep___drive_folders_show from './endpoints/drive/folders/show.js'; +import * as ep___drive_folders_update from './endpoints/drive/folders/update.js'; +import * as ep___drive_stream from './endpoints/drive/stream.js'; +import * as ep___emailAddress_available from './endpoints/email-address/available.js'; +import * as ep___endpoint from './endpoints/endpoint.js'; +import * as ep___endpoints from './endpoints/endpoints.js'; +import * as ep___exportCustomEmojis from './endpoints/export-custom-emojis.js'; +import * as ep___federation_followers from './endpoints/federation/followers.js'; +import * as ep___federation_following from './endpoints/federation/following.js'; +import * as ep___federation_instances from './endpoints/federation/instances.js'; +import * as ep___federation_showInstance from './endpoints/federation/show-instance.js'; +import * as ep___federation_updateRemoteUser from './endpoints/federation/update-remote-user.js'; +import * as ep___federation_users from './endpoints/federation/users.js'; +import * as ep___following_create from './endpoints/following/create.js'; +import * as ep___following_delete from './endpoints/following/delete.js'; +import * as ep___following_invalidate from './endpoints/following/invalidate.js'; +import * as ep___following_requests_accept from './endpoints/following/requests/accept.js'; +import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js'; +import * as ep___following_requests_list from './endpoints/following/requests/list.js'; +import * as ep___following_requests_reject from './endpoints/following/requests/reject.js'; +import * as ep___gallery_featured from './endpoints/gallery/featured.js'; +import * as ep___gallery_popular from './endpoints/gallery/popular.js'; +import * as ep___gallery_posts from './endpoints/gallery/posts.js'; +import * as ep___gallery_posts_create from './endpoints/gallery/posts/create.js'; +import * as ep___gallery_posts_delete from './endpoints/gallery/posts/delete.js'; +import * as ep___gallery_posts_like from './endpoints/gallery/posts/like.js'; +import * as ep___gallery_posts_show from './endpoints/gallery/posts/show.js'; +import * as ep___gallery_posts_unlike from './endpoints/gallery/posts/unlike.js'; +import * as ep___gallery_posts_update from './endpoints/gallery/posts/update.js'; +import * as ep___getOnlineUsersCount from './endpoints/get-online-users-count.js'; +import * as ep___hashtags_list from './endpoints/hashtags/list.js'; +import * as ep___hashtags_search from './endpoints/hashtags/search.js'; +import * as ep___hashtags_show from './endpoints/hashtags/show.js'; +import * as ep___hashtags_trend from './endpoints/hashtags/trend.js'; +import * as ep___hashtags_users from './endpoints/hashtags/users.js'; +import * as ep___i from './endpoints/i.js'; +import * as ep___i_2fa_done from './endpoints/i/2fa/done.js'; +import * as ep___i_2fa_keyDone from './endpoints/i/2fa/key-done.js'; +import * as ep___i_2fa_passwordLess from './endpoints/i/2fa/password-less.js'; +import * as ep___i_2fa_registerKey from './endpoints/i/2fa/register-key.js'; +import * as ep___i_2fa_register from './endpoints/i/2fa/register.js'; +import * as ep___i_2fa_removeKey from './endpoints/i/2fa/remove-key.js'; +import * as ep___i_2fa_unregister from './endpoints/i/2fa/unregister.js'; +import * as ep___i_apps from './endpoints/i/apps.js'; +import * as ep___i_authorizedApps from './endpoints/i/authorized-apps.js'; +import * as ep___i_changePassword from './endpoints/i/change-password.js'; +import * as ep___i_deleteAccount from './endpoints/i/delete-account.js'; +import * as ep___i_exportBlocking from './endpoints/i/export-blocking.js'; +import * as ep___i_exportFollowing from './endpoints/i/export-following.js'; +import * as ep___i_exportMute from './endpoints/i/export-mute.js'; +import * as ep___i_exportNotes from './endpoints/i/export-notes.js'; +import * as ep___i_exportUserLists from './endpoints/i/export-user-lists.js'; +import * as ep___i_favorites from './endpoints/i/favorites.js'; +import * as ep___i_gallery_likes from './endpoints/i/gallery/likes.js'; +import * as ep___i_gallery_posts from './endpoints/i/gallery/posts.js'; +import * as ep___i_getWordMutedNotesCount from './endpoints/i/get-word-muted-notes-count.js'; +import * as ep___i_importBlocking from './endpoints/i/import-blocking.js'; +import * as ep___i_importFollowing from './endpoints/i/import-following.js'; +import * as ep___i_importMuting from './endpoints/i/import-muting.js'; +import * as ep___i_importUserLists from './endpoints/i/import-user-lists.js'; +import * as ep___i_notifications from './endpoints/i/notifications.js'; +import * as ep___i_pageLikes from './endpoints/i/page-likes.js'; +import * as ep___i_pages from './endpoints/i/pages.js'; +import * as ep___i_pin from './endpoints/i/pin.js'; +import * as ep___i_readAllMessagingMessages from './endpoints/i/read-all-messaging-messages.js'; +import * as ep___i_readAllUnreadNotes from './endpoints/i/read-all-unread-notes.js'; +import * as ep___i_readAnnouncement from './endpoints/i/read-announcement.js'; +import * as ep___i_regenerateToken from './endpoints/i/regenerate-token.js'; +import * as ep___i_registry_getAll from './endpoints/i/registry/get-all.js'; +import * as ep___i_registry_getDetail from './endpoints/i/registry/get-detail.js'; +import * as ep___i_registry_get from './endpoints/i/registry/get.js'; +import * as ep___i_registry_keysWithType from './endpoints/i/registry/keys-with-type.js'; +import * as ep___i_registry_keys from './endpoints/i/registry/keys.js'; +import * as ep___i_registry_remove from './endpoints/i/registry/remove.js'; +import * as ep___i_registry_scopes from './endpoints/i/registry/scopes.js'; +import * as ep___i_registry_set from './endpoints/i/registry/set.js'; +import * as ep___i_revokeToken from './endpoints/i/revoke-token.js'; +import * as ep___i_signinHistory from './endpoints/i/signin-history.js'; +import * as ep___i_unpin from './endpoints/i/unpin.js'; +import * as ep___i_updateEmail from './endpoints/i/update-email.js'; +import * as ep___i_update from './endpoints/i/update.js'; +import * as ep___i_userGroupInvites from './endpoints/i/user-group-invites.js'; +import * as ep___messaging_history from './endpoints/messaging/history.js'; +import * as ep___messaging_messages from './endpoints/messaging/messages.js'; +import * as ep___messaging_messages_create from './endpoints/messaging/messages/create.js'; +import * as ep___messaging_messages_delete from './endpoints/messaging/messages/delete.js'; +import * as ep___messaging_messages_read from './endpoints/messaging/messages/read.js'; +import * as ep___meta from './endpoints/meta.js'; +import * as ep___miauth_genToken from './endpoints/miauth/gen-token.js'; +import * as ep___mute_create from './endpoints/mute/create.js'; +import * as ep___mute_delete from './endpoints/mute/delete.js'; +import * as ep___mute_list from './endpoints/mute/list.js'; +import * as ep___my_apps from './endpoints/my/apps.js'; +import * as ep___notes from './endpoints/notes.js'; +import * as ep___notes_children from './endpoints/notes/children.js'; +import * as ep___notes_clips from './endpoints/notes/clips.js'; +import * as ep___notes_conversation from './endpoints/notes/conversation.js'; +import * as ep___notes_create from './endpoints/notes/create.js'; +import * as ep___notes_delete from './endpoints/notes/delete.js'; +import * as ep___notes_favorites_create from './endpoints/notes/favorites/create.js'; +import * as ep___notes_favorites_delete from './endpoints/notes/favorites/delete.js'; +import * as ep___notes_featured from './endpoints/notes/featured.js'; +import * as ep___notes_globalTimeline from './endpoints/notes/global-timeline.js'; +import * as ep___notes_hybridTimeline from './endpoints/notes/hybrid-timeline.js'; +import * as ep___notes_localTimeline from './endpoints/notes/local-timeline.js'; +import * as ep___notes_mentions from './endpoints/notes/mentions.js'; +import * as ep___notes_polls_recommendation from './endpoints/notes/polls/recommendation.js'; +import * as ep___notes_polls_vote from './endpoints/notes/polls/vote.js'; +import * as ep___notes_reactions from './endpoints/notes/reactions.js'; +import * as ep___notes_reactions_create from './endpoints/notes/reactions/create.js'; +import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js'; +import * as ep___notes_renotes from './endpoints/notes/renotes.js'; +import * as ep___notes_replies from './endpoints/notes/replies.js'; +import * as ep___notes_searchByTag from './endpoints/notes/search-by-tag.js'; +import * as ep___notes_search from './endpoints/notes/search.js'; +import * as ep___notes_show from './endpoints/notes/show.js'; +import * as ep___notes_state from './endpoints/notes/state.js'; +import * as ep___notes_threadMuting_create from './endpoints/notes/thread-muting/create.js'; +import * as ep___notes_threadMuting_delete from './endpoints/notes/thread-muting/delete.js'; +import * as ep___notes_timeline from './endpoints/notes/timeline.js'; +import * as ep___notes_translate from './endpoints/notes/translate.js'; +import * as ep___notes_unrenote from './endpoints/notes/unrenote.js'; +import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js'; +import * as ep___notes_watching_create from './endpoints/notes/watching/create.js'; +import * as ep___notes_watching_delete from './endpoints/notes/watching/delete.js'; +import * as ep___notifications_create from './endpoints/notifications/create.js'; +import * as ep___notifications_markAllAsRead from './endpoints/notifications/mark-all-as-read.js'; +import * as ep___notifications_read from './endpoints/notifications/read.js'; +import * as ep___pagePush from './endpoints/page-push.js'; +import * as ep___pages_create from './endpoints/pages/create.js'; +import * as ep___pages_delete from './endpoints/pages/delete.js'; +import * as ep___pages_featured from './endpoints/pages/featured.js'; +import * as ep___pages_like from './endpoints/pages/like.js'; +import * as ep___pages_show from './endpoints/pages/show.js'; +import * as ep___pages_unlike from './endpoints/pages/unlike.js'; +import * as ep___pages_update from './endpoints/pages/update.js'; +import * as ep___ping from './endpoints/ping.js'; +import * as ep___pinnedUsers from './endpoints/pinned-users.js'; +import * as ep___promo_read from './endpoints/promo/read.js'; +import * as ep___requestResetPassword from './endpoints/request-reset-password.js'; +import * as ep___resetDb from './endpoints/reset-db.js'; +import * as ep___resetPassword from './endpoints/reset-password.js'; +import * as ep___serverInfo from './endpoints/server-info.js'; +import * as ep___stats from './endpoints/stats.js'; +import * as ep___sw_register from './endpoints/sw/register.js'; +import * as ep___sw_unregister from './endpoints/sw/unregister.js'; +import * as ep___test from './endpoints/test.js'; +import * as ep___username_available from './endpoints/username/available.js'; +import * as ep___users from './endpoints/users.js'; +import * as ep___users_clips from './endpoints/users/clips.js'; +import * as ep___users_followers from './endpoints/users/followers.js'; +import * as ep___users_following from './endpoints/users/following.js'; +import * as ep___users_gallery_posts from './endpoints/users/gallery/posts.js'; +import * as ep___users_getFrequentlyRepliedUsers from './endpoints/users/get-frequently-replied-users.js'; +import * as ep___users_groups_create from './endpoints/users/groups/create.js'; +import * as ep___users_groups_delete from './endpoints/users/groups/delete.js'; +import * as ep___users_groups_invitations_accept from './endpoints/users/groups/invitations/accept.js'; +import * as ep___users_groups_invitations_reject from './endpoints/users/groups/invitations/reject.js'; +import * as ep___users_groups_invite from './endpoints/users/groups/invite.js'; +import * as ep___users_groups_joined from './endpoints/users/groups/joined.js'; +import * as ep___users_groups_leave from './endpoints/users/groups/leave.js'; +import * as ep___users_groups_owned from './endpoints/users/groups/owned.js'; +import * as ep___users_groups_pull from './endpoints/users/groups/pull.js'; +import * as ep___users_groups_show from './endpoints/users/groups/show.js'; +import * as ep___users_groups_transfer from './endpoints/users/groups/transfer.js'; +import * as ep___users_groups_update from './endpoints/users/groups/update.js'; +import * as ep___users_lists_create from './endpoints/users/lists/create.js'; +import * as ep___users_lists_delete from './endpoints/users/lists/delete.js'; +import * as ep___users_lists_list from './endpoints/users/lists/list.js'; +import * as ep___users_lists_pull from './endpoints/users/lists/pull.js'; +import * as ep___users_lists_push from './endpoints/users/lists/push.js'; +import * as ep___users_lists_show from './endpoints/users/lists/show.js'; +import * as ep___users_lists_update from './endpoints/users/lists/update.js'; +import * as ep___users_notes from './endpoints/users/notes.js'; +import * as ep___users_pages from './endpoints/users/pages.js'; +import * as ep___users_reactions from './endpoints/users/reactions.js'; +import * as ep___users_recommendation from './endpoints/users/recommendation.js'; +import * as ep___users_relation from './endpoints/users/relation.js'; +import * as ep___users_reportAbuse from './endpoints/users/report-abuse.js'; +import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js'; +import * as ep___users_search from './endpoints/users/search.js'; +import * as ep___users_show from './endpoints/users/show.js'; +import * as ep___users_stats from './endpoints/users/stats.js'; -export type Param = { - validator: Context; - transform?: any; - default?: any; - deprecated?: boolean; - ref?: string; -}; +const eps = [ + ['admin/abuse-user-reports', ep___admin_abuseUserReports], + ['admin/accounts/create', ep___admin_accounts_create], + ['admin/accounts/delete', ep___admin_accounts_delete], + ['admin/ad/create', ep___admin_ad_create], + ['admin/ad/delete', ep___admin_ad_delete], + ['admin/ad/list', ep___admin_ad_list], + ['admin/ad/update', ep___admin_ad_update], + ['admin/announcements/create', ep___admin_announcements_create], + ['admin/announcements/delete', ep___admin_announcements_delete], + ['admin/announcements/list', ep___admin_announcements_list], + ['admin/announcements/update', ep___admin_announcements_update], + ['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser], + ['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles], + ['admin/drive/cleanup', ep___admin_drive_cleanup], + ['admin/drive/files', ep___admin_drive_files], + ['admin/drive/show-file', ep___admin_drive_showFile], + ['admin/emoji/add-aliases-bulk', ep___admin_emoji_addAliasesBulk], + ['admin/emoji/add', ep___admin_emoji_add], + ['admin/emoji/copy', ep___admin_emoji_copy], + ['admin/emoji/delete-bulk', ep___admin_emoji_deleteBulk], + ['admin/emoji/delete', ep___admin_emoji_delete], + ['admin/emoji/import-zip', ep___admin_emoji_importZip], + ['admin/emoji/list-remote', ep___admin_emoji_listRemote], + ['admin/emoji/list', ep___admin_emoji_list], + ['admin/emoji/remove-aliases-bulk', ep___admin_emoji_removeAliasesBulk], + ['admin/emoji/set-aliases-bulk', ep___admin_emoji_setAliasesBulk], + ['admin/emoji/set-category-bulk', ep___admin_emoji_setCategoryBulk], + ['admin/emoji/update', ep___admin_emoji_update], + ['admin/federation/delete-all-files', ep___admin_federation_deleteAllFiles], + ['admin/federation/refresh-remote-instance-metadata', ep___admin_federation_refreshRemoteInstanceMetadata], + ['admin/federation/remove-all-following', ep___admin_federation_removeAllFollowing], + ['admin/federation/update-instance', ep___admin_federation_updateInstance], + ['admin/get-index-stats', ep___admin_getIndexStats], + ['admin/get-table-stats', ep___admin_getTableStats], + ['admin/invite', ep___admin_invite], + ['admin/moderators/add', ep___admin_moderators_add], + ['admin/moderators/remove', ep___admin_moderators_remove], + ['admin/promo/create', ep___admin_promo_create], + ['admin/queue/clear', ep___admin_queue_clear], + ['admin/queue/deliver-delayed', ep___admin_queue_deliverDelayed], + ['admin/queue/inbox-delayed', ep___admin_queue_inboxDelayed], + ['admin/queue/stats', ep___admin_queue_stats], + ['admin/relays/add', ep___admin_relays_add], + ['admin/relays/list', ep___admin_relays_list], + ['admin/relays/remove', ep___admin_relays_remove], + ['admin/reset-password', ep___admin_resetPassword], + ['admin/resolve-abuse-user-report', ep___admin_resolveAbuseUserReport], + ['admin/send-email', ep___admin_sendEmail], + ['admin/server-info', ep___admin_serverInfo], + ['admin/show-moderation-logs', ep___admin_showModerationLogs], + ['admin/show-user', ep___admin_showUser], + ['admin/show-users', ep___admin_showUsers], + ['admin/silence-user', ep___admin_silenceUser], + ['admin/suspend-user', ep___admin_suspendUser], + ['admin/unsilence-user', ep___admin_unsilenceUser], + ['admin/unsuspend-user', ep___admin_unsuspendUser], + ['admin/update-meta', ep___admin_updateMeta], + ['admin/vacuum', ep___admin_vacuum], + ['announcements', ep___announcements], + ['antennas/create', ep___antennas_create], + ['antennas/delete', ep___antennas_delete], + ['antennas/list', ep___antennas_list], + ['antennas/notes', ep___antennas_notes], + ['antennas/show', ep___antennas_show], + ['antennas/update', ep___antennas_update], + ['ap/get', ep___ap_get], + ['ap/show', ep___ap_show], + ['app/create', ep___app_create], + ['app/show', ep___app_show], + ['auth/accept', ep___auth_accept], + ['auth/session/generate', ep___auth_session_generate], + ['auth/session/show', ep___auth_session_show], + ['auth/session/userkey', ep___auth_session_userkey], + ['blocking/create', ep___blocking_create], + ['blocking/delete', ep___blocking_delete], + ['blocking/list', ep___blocking_list], + ['channels/create', ep___channels_create], + ['channels/featured', ep___channels_featured], + ['channels/follow', ep___channels_follow], + ['channels/followed', ep___channels_followed], + ['channels/owned', ep___channels_owned], + ['channels/show', ep___channels_show], + ['channels/timeline', ep___channels_timeline], + ['channels/unfollow', ep___channels_unfollow], + ['channels/update', ep___channels_update], + ['charts/active-users', ep___charts_activeUsers], + ['charts/ap-request', ep___charts_apRequest], + ['charts/drive', ep___charts_drive], + ['charts/federation', ep___charts_federation], + ['charts/hashtag', ep___charts_hashtag], + ['charts/instance', ep___charts_instance], + ['charts/notes', ep___charts_notes], + ['charts/user/drive', ep___charts_user_drive], + ['charts/user/following', ep___charts_user_following], + ['charts/user/notes', ep___charts_user_notes], + ['charts/user/reactions', ep___charts_user_reactions], + ['charts/users', ep___charts_users], + ['clips/add-note', ep___clips_addNote], + ['clips/create', ep___clips_create], + ['clips/delete', ep___clips_delete], + ['clips/list', ep___clips_list], + ['clips/notes', ep___clips_notes], + ['clips/show', ep___clips_show], + ['clips/update', ep___clips_update], + ['drive', ep___drive], + ['drive/files', ep___drive_files], + ['drive/files/attached-notes', ep___drive_files_attachedNotes], + ['drive/files/check-existence', ep___drive_files_checkExistence], + ['drive/files/create', ep___drive_files_create], + ['drive/files/delete', ep___drive_files_delete], + ['drive/files/find-by-hash', ep___drive_files_findByHash], + ['drive/files/find', ep___drive_files_find], + ['drive/files/show', ep___drive_files_show], + ['drive/files/update', ep___drive_files_update], + ['drive/files/upload-from-url', ep___drive_files_uploadFromUrl], + ['drive/folders', ep___drive_folders], + ['drive/folders/create', ep___drive_folders_create], + ['drive/folders/delete', ep___drive_folders_delete], + ['drive/folders/find', ep___drive_folders_find], + ['drive/folders/show', ep___drive_folders_show], + ['drive/folders/update', ep___drive_folders_update], + ['drive/stream', ep___drive_stream], + ['email-address/available', ep___emailAddress_available], + ['endpoint', ep___endpoint], + ['endpoints', ep___endpoints], + ['export-custom-emojis', ep___exportCustomEmojis], + ['federation/followers', ep___federation_followers], + ['federation/following', ep___federation_following], + ['federation/instances', ep___federation_instances], + ['federation/show-instance', ep___federation_showInstance], + ['federation/update-remote-user', ep___federation_updateRemoteUser], + ['federation/users', ep___federation_users], + ['following/create', ep___following_create], + ['following/delete', ep___following_delete], + ['following/invalidate', ep___following_invalidate], + ['following/requests/accept', ep___following_requests_accept], + ['following/requests/cancel', ep___following_requests_cancel], + ['following/requests/list', ep___following_requests_list], + ['following/requests/reject', ep___following_requests_reject], + ['gallery/featured', ep___gallery_featured], + ['gallery/popular', ep___gallery_popular], + ['gallery/posts', ep___gallery_posts], + ['gallery/posts/create', ep___gallery_posts_create], + ['gallery/posts/delete', ep___gallery_posts_delete], + ['gallery/posts/like', ep___gallery_posts_like], + ['gallery/posts/show', ep___gallery_posts_show], + ['gallery/posts/unlike', ep___gallery_posts_unlike], + ['gallery/posts/update', ep___gallery_posts_update], + ['get-online-users-count', ep___getOnlineUsersCount], + ['hashtags/list', ep___hashtags_list], + ['hashtags/search', ep___hashtags_search], + ['hashtags/show', ep___hashtags_show], + ['hashtags/trend', ep___hashtags_trend], + ['hashtags/users', ep___hashtags_users], + ['i', ep___i], + ['i/2fa/done', ep___i_2fa_done], + ['i/2fa/key-done', ep___i_2fa_keyDone], + ['i/2fa/password-less', ep___i_2fa_passwordLess], + ['i/2fa/register-key', ep___i_2fa_registerKey], + ['i/2fa/register', ep___i_2fa_register], + ['i/2fa/remove-key', ep___i_2fa_removeKey], + ['i/2fa/unregister', ep___i_2fa_unregister], + ['i/apps', ep___i_apps], + ['i/authorized-apps', ep___i_authorizedApps], + ['i/change-password', ep___i_changePassword], + ['i/delete-account', ep___i_deleteAccount], + ['i/export-blocking', ep___i_exportBlocking], + ['i/export-following', ep___i_exportFollowing], + ['i/export-mute', ep___i_exportMute], + ['i/export-notes', ep___i_exportNotes], + ['i/export-user-lists', ep___i_exportUserLists], + ['i/favorites', ep___i_favorites], + ['i/gallery/likes', ep___i_gallery_likes], + ['i/gallery/posts', ep___i_gallery_posts], + ['i/get-word-muted-notes-count', ep___i_getWordMutedNotesCount], + ['i/import-blocking', ep___i_importBlocking], + ['i/import-following', ep___i_importFollowing], + ['i/import-muting', ep___i_importMuting], + ['i/import-user-lists', ep___i_importUserLists], + ['i/notifications', ep___i_notifications], + ['i/page-likes', ep___i_pageLikes], + ['i/pages', ep___i_pages], + ['i/pin', ep___i_pin], + ['i/read-all-messaging-messages', ep___i_readAllMessagingMessages], + ['i/read-all-unread-notes', ep___i_readAllUnreadNotes], + ['i/read-announcement', ep___i_readAnnouncement], + ['i/regenerate-token', ep___i_regenerateToken], + ['i/registry/get-all', ep___i_registry_getAll], + ['i/registry/get-detail', ep___i_registry_getDetail], + ['i/registry/get', ep___i_registry_get], + ['i/registry/keys-with-type', ep___i_registry_keysWithType], + ['i/registry/keys', ep___i_registry_keys], + ['i/registry/remove', ep___i_registry_remove], + ['i/registry/scopes', ep___i_registry_scopes], + ['i/registry/set', ep___i_registry_set], + ['i/revoke-token', ep___i_revokeToken], + ['i/signin-history', ep___i_signinHistory], + ['i/unpin', ep___i_unpin], + ['i/update-email', ep___i_updateEmail], + ['i/update', ep___i_update], + ['i/user-group-invites', ep___i_userGroupInvites], + ['messaging/history', ep___messaging_history], + ['messaging/messages', ep___messaging_messages], + ['messaging/messages/create', ep___messaging_messages_create], + ['messaging/messages/delete', ep___messaging_messages_delete], + ['messaging/messages/read', ep___messaging_messages_read], + ['meta', ep___meta], + ['miauth/gen-token', ep___miauth_genToken], + ['mute/create', ep___mute_create], + ['mute/delete', ep___mute_delete], + ['mute/list', ep___mute_list], + ['my/apps', ep___my_apps], + ['notes', ep___notes], + ['notes/children', ep___notes_children], + ['notes/clips', ep___notes_clips], + ['notes/conversation', ep___notes_conversation], + ['notes/create', ep___notes_create], + ['notes/delete', ep___notes_delete], + ['notes/favorites/create', ep___notes_favorites_create], + ['notes/favorites/delete', ep___notes_favorites_delete], + ['notes/featured', ep___notes_featured], + ['notes/global-timeline', ep___notes_globalTimeline], + ['notes/hybrid-timeline', ep___notes_hybridTimeline], + ['notes/local-timeline', ep___notes_localTimeline], + ['notes/mentions', ep___notes_mentions], + ['notes/polls/recommendation', ep___notes_polls_recommendation], + ['notes/polls/vote', ep___notes_polls_vote], + ['notes/reactions', ep___notes_reactions], + ['notes/reactions/create', ep___notes_reactions_create], + ['notes/reactions/delete', ep___notes_reactions_delete], + ['notes/renotes', ep___notes_renotes], + ['notes/replies', ep___notes_replies], + ['notes/search-by-tag', ep___notes_searchByTag], + ['notes/search', ep___notes_search], + ['notes/show', ep___notes_show], + ['notes/state', ep___notes_state], + ['notes/thread-muting/create', ep___notes_threadMuting_create], + ['notes/thread-muting/delete', ep___notes_threadMuting_delete], + ['notes/timeline', ep___notes_timeline], + ['notes/translate', ep___notes_translate], + ['notes/unrenote', ep___notes_unrenote], + ['notes/user-list-timeline', ep___notes_userListTimeline], + ['notes/watching/create', ep___notes_watching_create], + ['notes/watching/delete', ep___notes_watching_delete], + ['notifications/create', ep___notifications_create], + ['notifications/mark-all-as-read', ep___notifications_markAllAsRead], + ['notifications/read', ep___notifications_read], + ['page-push', ep___pagePush], + ['pages/create', ep___pages_create], + ['pages/delete', ep___pages_delete], + ['pages/featured', ep___pages_featured], + ['pages/like', ep___pages_like], + ['pages/show', ep___pages_show], + ['pages/unlike', ep___pages_unlike], + ['pages/update', ep___pages_update], + ['ping', ep___ping], + ['pinned-users', ep___pinnedUsers], + ['promo/read', ep___promo_read], + ['request-reset-password', ep___requestResetPassword], + ['reset-db', ep___resetDb], + ['reset-password', ep___resetPassword], + ['server-info', ep___serverInfo], + ['stats', ep___stats], + ['sw/register', ep___sw_register], + ['sw/unregister', ep___sw_unregister], + ['test', ep___test], + ['username/available', ep___username_available], + ['users', ep___users], + ['users/clips', ep___users_clips], + ['users/followers', ep___users_followers], + ['users/following', ep___users_following], + ['users/gallery/posts', ep___users_gallery_posts], + ['users/get-frequently-replied-users', ep___users_getFrequentlyRepliedUsers], + ['users/groups/create', ep___users_groups_create], + ['users/groups/delete', ep___users_groups_delete], + ['users/groups/invitations/accept', ep___users_groups_invitations_accept], + ['users/groups/invitations/reject', ep___users_groups_invitations_reject], + ['users/groups/invite', ep___users_groups_invite], + ['users/groups/joined', ep___users_groups_joined], + ['users/groups/leave', ep___users_groups_leave], + ['users/groups/owned', ep___users_groups_owned], + ['users/groups/pull', ep___users_groups_pull], + ['users/groups/show', ep___users_groups_show], + ['users/groups/transfer', ep___users_groups_transfer], + ['users/groups/update', ep___users_groups_update], + ['users/lists/create', ep___users_lists_create], + ['users/lists/delete', ep___users_lists_delete], + ['users/lists/list', ep___users_lists_list], + ['users/lists/pull', ep___users_lists_pull], + ['users/lists/push', ep___users_lists_push], + ['users/lists/show', ep___users_lists_show], + ['users/lists/update', ep___users_lists_update], + ['users/notes', ep___users_notes], + ['users/pages', ep___users_pages], + ['users/reactions', ep___users_reactions], + ['users/recommendation', ep___users_recommendation], + ['users/relation', ep___users_relation], + ['users/report-abuse', ep___users_reportAbuse], + ['users/search-by-username-and-host', ep___users_searchByUsernameAndHost], + ['users/search', ep___users_search], + ['users/show', ep___users_show], + ['users/stats', ep___users_stats], +]; export interface IEndpointMeta { readonly stability?: 'deprecated' | 'experimental' | 'stable'; readonly tags?: ReadonlyArray; - readonly params?: { - readonly [key: string]: Param; - }; - readonly errors?: { readonly [key: string]: { readonly message: string; @@ -99,25 +686,23 @@ export interface IEndpointMeta { * パãƒŧãƒŸãƒƒã‚ˇãƒ§ãƒŗぎ原įžãĢ刊į”¨ã•ã‚Œãžã™ã€‚ */ readonly kind?: string; + + readonly description?: string; } export interface IEndpoint { name: string; exec: any; meta: IEndpointMeta; + params: Schema; } -const files = glob.sync('**/*.js', { - cwd: path.resolve(_dirname + '/endpoints/'), -}); - -const endpoints: IEndpoint[] = files.map(f => { - const ep = require(`./endpoints/${f}`); - +const endpoints: IEndpoint[] = eps.map(([name, ep]) => { return { - name: f.replace('.js', ''), + name: name, exec: ep.default, meta: ep.meta || {}, + params: ep.paramDef, }; }); diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts index ed7b146d0..333746f42 100644 --- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts +++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { AbuseUserReports } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { AbuseUserReports } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['admin'], @@ -10,49 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - state: { - validator: $.optional.nullable.str, - default: null, - }, - - reporterOrigin: { - validator: $.optional.str.or([ - 'combined', - 'local', - 'remote', - ]), - default: 'combined', - }, - - targetUserOrigin: { - validator: $.optional.str.or([ - 'combined', - 'local', - 'remote', - ]), - default: 'combined', - }, - - forwarded: { - validator: $.optional.bool, - default: false, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -115,8 +70,22 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + state: { type: 'string', nullable: true, default: null }, + reporterOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "combined" }, + targetUserOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "combined" }, + forwarded: { type: 'boolean', default: false }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const query = makePaginationQuery(AbuseUserReports.createQueryBuilder('report'), ps.sinceId, ps.untilId); switch (ps.state) { @@ -134,7 +103,7 @@ export default define(meta, async (ps) => { case 'remote': query.andWhere('report.targetUserHost IS NOT NULL'); break; } - const reports = await query.take(ps.limit!).getMany(); + const reports = await query.take(ps.limit).getMany(); return await AbuseUserReports.packMany(reports); }); diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts index 20f123295..2820c7993 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts @@ -1,20 +1,10 @@ -import define from '../../../define'; -import { Users } from '@/models/index'; -import { signup } from '../../../common/signup'; +import define from '../../../define.js'; +import { Users } from '@/models/index.js'; +import { signup } from '../../../common/signup.js'; export const meta = { tags: ['admin'], - params: { - username: { - validator: Users.validateLocalUsername, - }, - - password: { - validator: Users.validatePassword, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -28,8 +18,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + username: Users.localUsernameSchema, + password: Users.passwordSchema, + }, + required: ['username', 'password'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, _me) => { +export default define(meta, paramDef, async (ps, _me) => { const me = _me ? await Users.findOneOrFail(_me.id) : null; const noUsers = (await Users.count({ host: null, diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts index 1701c1e3a..01754ec8f 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts @@ -1,26 +1,26 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Users } from '@/models/index'; -import { doPostSuspend } from '@/services/suspend-user'; -import { publishUserEvent } from '@/services/stream'; -import { createDeleteAccountJob } from '@/queue'; -import { ID } from '@/misc/cafy-id'; +import define from '../../../define.js'; +import { Users } from '@/models/index.js'; +import { doPostSuspend } from '@/services/suspend-user.js'; +import { publishUserEvent } from '@/services/stream.js'; +import { createDeleteAccountJob } from '@/queue/index.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts index 00ad2012f..ab2c50b50 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts @@ -1,41 +1,30 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Ads } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../../define.js'; +import { Ads } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - url: { - validator: $.str.min(1), - }, - memo: { - validator: $.str, - }, - place: { - validator: $.str, - }, - priority: { - validator: $.str, - }, - ratio: { - validator: $.num.int().min(0), - }, - expiresAt: { - validator: $.num.int(), - }, - imageUrl: { - validator: $.str.min(1), - }, +export const paramDef = { + type: 'object', + properties: { + url: { type: 'string', minLength: 1 }, + memo: { type: 'string' }, + place: { type: 'string' }, + priority: { type: 'string' }, + ratio: { type: 'integer' }, + expiresAt: { type: 'integer' }, + imageUrl: { type: 'string', minLength: 1 }, }, + required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'imageUrl'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { await Ads.insert({ id: genId(), createdAt: new Date(), diff --git a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts index c0124e248..3663d974c 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Ads } from '@/models/index'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import { Ads } from '@/models/index.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], @@ -10,12 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - id: { - validator: $.type(ID), - }, - }, - errors: { noSuchAd: { message: 'No such ad.', @@ -25,8 +17,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + id: { type: 'string', format: 'misskey:id' }, + }, + required: ['id'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const ad = await Ads.findOne(ps.id); if (ad == null) throw new ApiError(meta.errors.noSuchAd); diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index 7a83637f3..74f154f27 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -1,37 +1,30 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { Ads } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; +import define from '../../../define.js'; +import { Ads } from '@/models/index.js'; +import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const query = makePaginationQuery(Ads.createQueryBuilder('ad'), ps.sinceId, ps.untilId) .andWhere('ad.expiresAt > :now', { now: new Date() }); - const ads = await query.take(ps.limit!).getMany(); + const ads = await query.take(ps.limit).getMany(); return ads; }); diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts index c2b09ab9c..89c421db6 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Ads } from '@/models/index'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import { Ads } from '@/models/index.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], @@ -10,33 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - id: { - validator: $.type(ID), - }, - memo: { - validator: $.str, - }, - url: { - validator: $.str.min(1), - }, - imageUrl: { - validator: $.str.min(1), - }, - place: { - validator: $.str, - }, - priority: { - validator: $.str, - }, - ratio: { - validator: $.num.int().min(0), - }, - expiresAt: { - validator: $.num.int(), - }, - }, - errors: { noSuchAd: { message: 'No such ad.', @@ -46,8 +17,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + id: { type: 'string', format: 'misskey:id' }, + memo: { type: 'string' }, + url: { type: 'string', minLength: 1 }, + imageUrl: { type: 'string', minLength: 1 }, + place: { type: 'string' }, + priority: { type: 'string' }, + ratio: { type: 'integer' }, + expiresAt: { type: 'integer' }, + }, + required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const ad = await Ads.findOne(ps.id); if (ad == null) throw new ApiError(meta.errors.noSuchAd); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 24c4caa37..41570078d 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -1,7 +1,6 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Announcements } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../../define.js'; +import { Announcements } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['admin'], @@ -9,18 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - title: { - validator: $.str.min(1), - }, - text: { - validator: $.str.min(1), - }, - imageUrl: { - validator: $.nullable.str.min(1), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -57,8 +44,18 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + title: { type: 'string', minLength: 1 }, + text: { type: 'string', minLength: 1 }, + imageUrl: { type: 'string', nullable: true, minLength: 1 }, + }, + required: ['title', 'text', 'imageUrl'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const announcement = await Announcements.insert({ id: genId(), createdAt: new Date(), @@ -68,5 +65,5 @@ export default define(meta, async (ps) => { imageUrl: ps.imageUrl, }).then(x => Announcements.findOneOrFail(x.identifiers[0])); - return announcement; + return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts index 5548f9900..4871dc4e1 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Announcements } from '@/models/index'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import { Announcements } from '@/models/index.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], @@ -10,12 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - id: { - validator: $.type(ID), - }, - }, - errors: { noSuchAnnouncement: { message: 'No such announcement.', @@ -25,8 +17,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + id: { type: 'string', format: 'misskey:id' }, + }, + required: ['id'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const announcement = await Announcements.findOne(ps.id); if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index e5cc53ccd..0ba0a8ee0 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { Announcements, AnnouncementReads } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; +import define from '../../../define.js'; +import { Announcements, AnnouncementReads } from '@/models/index.js'; +import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { tags: ['admin'], @@ -10,21 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -69,11 +52,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId); - const announcements = await query.take(ps.limit!).getMany(); + const announcements = await query.take(ps.limit).getMany(); for (const announcement of announcements) { (announcement as any).reads = await AnnouncementReads.count({ diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index f66293bb1..138337ef5 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Announcements } from '@/models/index'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import { Announcements } from '@/models/index.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], @@ -10,21 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - id: { - validator: $.type(ID), - }, - title: { - validator: $.str.min(1), - }, - text: { - validator: $.str.min(1), - }, - imageUrl: { - validator: $.nullable.str.min(1), - }, - }, - errors: { noSuchAnnouncement: { message: 'No such announcement.', @@ -34,8 +17,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + id: { type: 'string', format: 'misskey:id' }, + title: { type: 'string', minLength: 1 }, + text: { type: 'string', minLength: 1 }, + imageUrl: { type: 'string', nullable: true, minLength: 1 }, + }, + required: ['id', 'title', 'text', 'imageUrl'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const announcement = await Announcements.findOne(ps.id); if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement); diff --git a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts index 249e63a0f..90e65ec4c 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts @@ -1,24 +1,24 @@ -import $ from 'cafy'; -import define from '../../define'; -import { deleteFile } from '@/services/drive/delete-file'; -import { DriveFiles } from '@/models/index'; -import { ID } from '@/misc/cafy-id'; +import define from '../../define.js'; +import { deleteFile } from '@/services/drive/delete-file.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const files = await DriveFiles.find({ userId: ps.userId, }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts index acabbfef5..bab149532 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts @@ -1,5 +1,5 @@ -import define from '../../../define'; -import { createCleanRemoteFilesJob } from '@/queue/index'; +import define from '../../../define.js'; +import { createCleanRemoteFilesJob } from '@/queue/index.js'; export const meta = { tags: ['admin'], @@ -8,7 +8,13 @@ export const meta = { requireModerator: true, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { createCleanRemoteFilesJob(); }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts index 452e7069a..3e7d43fb0 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts @@ -1,7 +1,7 @@ import { IsNull } from 'typeorm'; -import define from '../../../define'; -import { deleteFile } from '@/services/drive/delete-file'; -import { DriveFiles } from '@/models/index'; +import define from '../../../define.js'; +import { deleteFile } from '@/services/drive/delete-file.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['admin'], @@ -10,8 +10,14 @@ export const meta = { requireModerator: true, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const files = await DriveFiles.find({ userId: IsNull(), }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/files.ts b/packages/backend/src/server/api/endpoints/admin/drive/files.ts index 264f54986..646d85a1e 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/files.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { DriveFiles } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; -import { ID } from '@/misc/cafy-id'; +import define from '../../../define.js'; +import { DriveFiles } from '@/models/index.js'; +import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { tags: ['admin'], @@ -10,39 +8,6 @@ export const meta = { requireCredential: false, requireModerator: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - type: { - validator: $.optional.nullable.str.match(/^[a-zA-Z0-9\/\-*]+$/), - }, - - origin: { - validator: $.optional.str.or([ - 'combined', - 'local', - 'remote', - ]), - default: 'local', - }, - - hostname: { - validator: $.optional.nullable.str, - default: null, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -54,8 +19,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + type: { type: 'string', nullable: true, pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1) }, + origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "local" }, + hostname: { type: 'string', nullable: true, default: null }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId); if (ps.origin === 'local') { @@ -76,7 +54,7 @@ export default define(meta, async (ps, me) => { } } - const files = await query.take(ps.limit!).getMany(); + const files = await query.take(ps.limit).getMany(); return await DriveFiles.packMany(files, { detail: true, withUser: true, self: true }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts index 5d9a1f270..e82116009 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { DriveFiles } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['admin'], @@ -10,16 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - fileId: { - validator: $.optional.type(ID), - }, - - url: { - validator: $.optional.str, - }, - }, - errors: { noSuchFile: { message: 'No such file.', @@ -161,8 +149,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + url: { type: 'string' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const file = ps.fileId ? await DriveFiles.findOne(ps.fileId) : await DriveFiles.findOne({ where: [{ url: ps.url, diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts index f0fd73c27..77a4adea6 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts @@ -1,29 +1,30 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Emojis } from '@/models/index'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; import { getConnection, In } from 'typeorm'; -import { ApiError } from '../../../error'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - ids: { - validator: $.arr($.type(ID)), - }, - - aliases: { - validator: $.arr($.str), - }, +export const paramDef = { + type: 'object', + properties: { + ids: { type: 'array', items: { + type: 'string', format: 'misskey:id', + } }, + aliases: { type: 'array', items: { + type: 'string', + } }, }, + required: ['ids', 'aliases'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const emojis = await Emojis.find({ id: In(ps.ids), }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index 1dfeae262..c5787d59d 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -1,13 +1,11 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Emojis, DriveFiles } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../../define.js'; +import { Emojis, DriveFiles } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; import { getConnection } from 'typeorm'; -import { insertModerationLog } from '@/services/insert-moderation-log'; -import { ApiError } from '../../../error'; -import { ID } from '@/misc/cafy-id'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { ApiError } from '../../../error.js'; import rndstr from 'rndstr'; -import { publishBroadcastStream } from '@/services/stream'; +import { publishBroadcastStream } from '@/services/stream.js'; export const meta = { tags: ['admin'], @@ -15,12 +13,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - fileId: { - validator: $.type(ID), - }, - }, - errors: { noSuchFile: { message: 'No such file.', @@ -30,8 +22,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const file = await DriveFiles.findOne(ps.fileId); if (file == null) throw new ApiError(meta.errors.noSuchFile); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts index 17cbf208a..a0eaa6125 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts @@ -1,13 +1,11 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Emojis } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; import { getConnection } from 'typeorm'; -import { ApiError } from '../../../error'; -import { DriveFile } from '@/models/entities/drive-file'; -import { ID } from '@/misc/cafy-id'; -import { uploadFromUrl } from '@/services/drive/upload-from-url'; -import { publishBroadcastStream } from '@/services/stream'; +import { ApiError } from '../../../error.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { uploadFromUrl } from '@/services/drive/upload-from-url.js'; +import { publishBroadcastStream } from '@/services/stream.js'; export const meta = { tags: ['admin'], @@ -15,12 +13,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - emojiId: { - validator: $.type(ID), - }, - }, - errors: { noSuchEmoji: { message: 'No such emoji.', @@ -42,8 +34,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + emojiId: { type: 'string', format: 'misskey:id' }, + }, + required: ['emojiId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const emoji = await Emojis.findOne(ps.emojiId); if (emoji == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts index 797a5de67..38a2d65cf 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts @@ -1,26 +1,28 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Emojis } from '@/models/index'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; import { getConnection, In } from 'typeorm'; -import { insertModerationLog } from '@/services/insert-moderation-log'; -import { ApiError } from '../../../error'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - ids: { - validator: $.arr($.type(ID)), - }, +export const paramDef = { + type: 'object', + properties: { + ids: { type: 'array', items: { + type: 'string', format: 'misskey:id', + } }, }, + required: ['ids'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const emojis = await Emojis.find({ id: In(ps.ids), }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index 158043902..a0cffb47f 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Emojis } from '@/models/index'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; import { getConnection } from 'typeorm'; -import { insertModerationLog } from '@/services/insert-moderation-log'; -import { ApiError } from '../../../error'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], @@ -12,12 +10,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - id: { - validator: $.type(ID), - }, - }, - errors: { noSuchEmoji: { message: 'No such emoji.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + id: { type: 'string', format: 'misskey:id' }, + }, + required: ['id'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const emoji = await Emojis.findOne(ps.id); if (emoji == null) throw new ApiError(meta.errors.noSuchEmoji); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts index 8856a38f2..3f03dc2da 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts @@ -1,21 +1,22 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { createImportCustomEmojisJob } from '@/queue/index'; +import define from '../../../define.js'; +import { createImportCustomEmojisJob } from '@/queue/index.js'; import ms from 'ms'; -import { ID } from '@/misc/cafy-id'; export const meta = { secure: true, requireCredential: true, requireModerator: true, - params: { - fileId: { - validator: $.type(ID), - }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, }, + required: ['fileId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { createImportCustomEmojisJob(user, ps.fileId); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index 6e502547f..f19c3ddbd 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Emojis } from '@/models/index'; -import { toPuny } from '@/misc/convert-host'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; -import { ID } from '@/misc/cafy-id'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; +import { toPuny } from '@/misc/convert-host.js'; +import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { tags: ['admin'], @@ -11,31 +9,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - query: { - validator: $.optional.nullable.str, - default: null, - }, - - host: { - validator: $.optional.nullable.str, - default: null, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -77,8 +50,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + query: { type: 'string', nullable: true, default: null }, + host: { type: 'string', nullable: true, default: null }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const q = makePaginationQuery(Emojis.createQueryBuilder('emoji'), ps.sinceId, ps.untilId); if (ps.host == null) { @@ -93,7 +78,7 @@ export default define(meta, async (ps) => { const emojis = await q .orderBy('emoji.id', 'DESC') - .take(ps.limit!) + .take(ps.limit) .getMany(); return Emojis.packMany(emojis); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts index 76ef190f9..f488a71a0 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Emojis } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; -import { ID } from '@/misc/cafy-id'; -import { Emoji } from '@/models/entities/emoji'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; +import { makePaginationQuery } from '../../../common/make-pagination-query.js'; +import { Emoji } from '@/models/entities/emoji.js'; export const meta = { tags: ['admin'], @@ -11,26 +9,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - query: { - validator: $.optional.nullable.str, - default: null, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -72,8 +50,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + query: { type: 'string', nullable: true, default: null }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const q = makePaginationQuery(Emojis.createQueryBuilder('emoji'), ps.sinceId, ps.untilId) .andWhere(`emoji.host IS NULL`); @@ -81,7 +70,7 @@ export default define(meta, async (ps) => { if (ps.query) { //q.andWhere('emoji.name ILIKE :q', { q: `%${ps.query}%` }); - //const emojis = await q.take(ps.limit!).getMany(); + //const emojis = await q.take(ps.limit).getMany(); emojis = await q.getMany(); @@ -90,9 +79,9 @@ export default define(meta, async (ps) => { emoji.aliases.some(a => a.includes(ps.query!)) || emoji.category?.includes(ps.query!)); - emojis.splice(ps.limit! + 1); + emojis.splice(ps.limit + 1); } else { - emojis = await q.take(ps.limit!).getMany(); + emojis = await q.take(ps.limit).getMany(); } return Emojis.packMany(emojis); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts index c49f84b7f..dbad93d33 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts @@ -1,29 +1,30 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Emojis } from '@/models/index'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; import { getConnection, In } from 'typeorm'; -import { ApiError } from '../../../error'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - ids: { - validator: $.arr($.type(ID)), - }, - - aliases: { - validator: $.arr($.str), - }, +export const paramDef = { + type: 'object', + properties: { + ids: { type: 'array', items: { + type: 'string', format: 'misskey:id', + } }, + aliases: { type: 'array', items: { + type: 'string', + } }, }, + required: ['ids', 'aliases'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const emojis = await Emojis.find({ id: In(ps.ids), }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts index 06197820f..470b9bef0 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts @@ -1,29 +1,30 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Emojis } from '@/models/index'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; import { getConnection, In } from 'typeorm'; -import { ApiError } from '../../../error'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - ids: { - validator: $.arr($.type(ID)), - }, - - aliases: { - validator: $.arr($.str), - }, +export const paramDef = { + type: 'object', + properties: { + ids: { type: 'array', items: { + type: 'string', format: 'misskey:id', + } }, + aliases: { type: 'array', items: { + type: 'string', + } }, }, + required: ['ids', 'aliases'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { await Emojis.update({ id: In(ps.ids), }, { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts index f0645f111..40e4c0199 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts @@ -1,29 +1,28 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Emojis } from '@/models/index'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; import { getConnection, In } from 'typeorm'; -import { ApiError } from '../../../error'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - ids: { - validator: $.arr($.type(ID)), - }, - - category: { - validator: $.optional.nullable.str, - }, +export const paramDef = { + type: 'object', + properties: { + ids: { type: 'array', items: { + type: 'string', format: 'misskey:id', + } }, + category: { type: 'string', nullable: true }, }, + required: ['ids'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { await Emojis.update({ id: In(ps.ids), }, { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index 54a2cf951..c6d07e16f 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { Emojis } from '@/models/index'; +import define from '../../../define.js'; +import { Emojis } from '@/models/index.js'; import { getConnection } from 'typeorm'; -import { ApiError } from '../../../error'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], @@ -11,24 +9,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - id: { - validator: $.type(ID), - }, - - name: { - validator: $.str, - }, - - category: { - validator: $.optional.nullable.str, - }, - - aliases: { - validator: $.arr($.str), - }, - }, - errors: { noSuchEmoji: { message: 'No such emoji.', @@ -38,8 +18,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + id: { type: 'string', format: 'misskey:id' }, + name: { type: 'string' }, + category: { type: 'string', nullable: true }, + aliases: { type: 'array', items: { + type: 'string', + } }, + }, + required: ['id', 'name', 'aliases'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const emoji = await Emojis.findOne(ps.id); if (emoji == null) throw new ApiError(meta.errors.noSuchEmoji); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts index db023c6f0..d4251f2fe 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts @@ -1,23 +1,24 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { deleteFile } from '@/services/drive/delete-file'; -import { DriveFiles } from '@/models/index'; +import define from '../../../define.js'; +import { deleteFile } from '@/services/drive/delete-file.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - host: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string' }, }, + required: ['host'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const files = await DriveFiles.find({ userHost: ps.host, }); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index b68252ef2..86978cc30 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -1,24 +1,25 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Instances } from '@/models/index'; -import { toPuny } from '@/misc/convert-host'; -import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata'; +import define from '../../../define.js'; +import { Instances } from '@/models/index.js'; +import { toPuny } from '@/misc/convert-host.js'; +import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - host: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string' }, }, + required: ['host'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const instance = await Instances.findOne({ host: toPuny(ps.host) }); if (instance == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts index 4de8ad133..ccd07489c 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts @@ -1,23 +1,24 @@ -import $ from 'cafy'; -import define from '../../../define'; -import deleteFollowing from '@/services/following/delete'; -import { Followings, Users } from '@/models/index'; +import define from '../../../define.js'; +import deleteFollowing from '@/services/following/delete.js'; +import { Followings, Users } from '@/models/index.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - host: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string' }, }, + required: ['host'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const followings = await Followings.find({ followerHost: ps.host, }); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index 6ac2f1f46..198108242 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -1,27 +1,25 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Instances } from '@/models/index'; -import { toPuny } from '@/misc/convert-host'; +import define from '../../../define.js'; +import { Instances } from '@/models/index.js'; +import { toPuny } from '@/misc/convert-host.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - host: { - validator: $.str, - }, - - isSuspended: { - validator: $.bool, - }, +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string' }, + isSuspended: { type: 'boolean' }, }, + required: ['host', 'isSuspended'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const instance = await Instances.findOne({ host: toPuny(ps.host) }); if (instance == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts index 9a2bccec7..37878c414 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts @@ -1,4 +1,4 @@ -import define from '../../define'; +import define from '../../define.js'; import { getConnection } from 'typeorm'; export const meta = { @@ -6,13 +6,16 @@ export const meta = { requireModerator: true, tags: ['admin'], +} as const; - params: { - }, +export const paramDef = { + type: 'object', + properties: {}, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { const stats = await getConnection().query(`SELECT * FROM pg_indexes;`) .then(recs => { diff --git a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts index 1c5f25067..7cf2d5ffd 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts @@ -1,4 +1,4 @@ -import define from '../../define'; +import define from '../../define.js'; import { getConnection } from 'typeorm'; export const meta = { @@ -7,9 +7,6 @@ export const meta = { tags: ['admin'], - params: { - }, - res: { type: 'object', optional: false, nullable: false, @@ -22,8 +19,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { const sizes = await getConnection().query(` SELECT relname AS "table", reltuples as "count", pg_total_relation_size(C.oid) AS "size" diff --git a/packages/backend/src/server/api/endpoints/admin/invite.ts b/packages/backend/src/server/api/endpoints/admin/invite.ts index 3428709c0..7e950cf87 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite.ts @@ -1,7 +1,7 @@ import rndstr from 'rndstr'; -import define from '../../define'; -import { RegistrationTickets } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../define.js'; +import { RegistrationTickets } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['admin'], @@ -9,8 +9,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: {}, - res: { type: 'object', optional: false, nullable: false, @@ -26,8 +24,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { const code = rndstr({ length: 8, chars: '2-9A-HJ-NP-Z', // [0-9A-Z] w/o [01IO] (32 patterns) diff --git a/packages/backend/src/server/api/endpoints/admin/moderators/add.ts b/packages/backend/src/server/api/endpoints/admin/moderators/add.ts index 0308cf276..4206e3a3c 100644 --- a/packages/backend/src/server/api/endpoints/admin/moderators/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/moderators/add.ts @@ -1,23 +1,23 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { Users } from '@/models/index'; +import define from '../../../define.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['admin'], requireCredential: true, requireAdmin: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const user = await Users.findOne(ps.userId as string); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts b/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts index bdb976e9e..143119bfe 100644 --- a/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts @@ -1,23 +1,23 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { Users } from '@/models/index'; +import define from '../../../define.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['admin'], requireCredential: true, requireAdmin: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const user = await Users.findOne(ps.userId as string); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts index f2735ac9f..2eec5bf0d 100644 --- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getNote } from '../../../common/getters'; -import { PromoNotes } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getNote } from '../../../common/getters.js'; +import { PromoNotes } from '@/models/index.js'; export const meta = { tags: ['admin'], @@ -11,16 +9,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - noteId: { - validator: $.type(ID), - }, - - expiresAt: { - validator: $.num.int(), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -36,8 +24,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + expiresAt: { type: 'integer' }, + }, + required: ['noteId', 'expiresAt'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; @@ -51,7 +48,6 @@ export default define(meta, async (ps, user) => { await PromoNotes.insert({ noteId: note.id, - createdAt: new Date(), expiresAt: new Date(ps.expiresAt), userId: note.userId, }); diff --git a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts index 3c8e7a27a..8f015c280 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts @@ -1,18 +1,22 @@ -import define from '../../../define'; -import { destroy } from '@/queue/index'; -import { insertModerationLog } from '@/services/insert-moderation-log'; +import define from '../../../define.js'; +import { destroy } from '@/queue/index.js'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: {}, +export const paramDef = { + type: 'object', + properties: {}, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { destroy(); insertModerationLog(me, 'clearQueue'); diff --git a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts index 4760e2c31..70f7d77de 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts @@ -1,6 +1,6 @@ -import { deliverQueue } from '@/queue/queues'; -import { URL } from 'url'; -import define from '../../../define'; +import { deliverQueue } from '@/queue/queues.js'; +import { URL } from 'node:url'; +import define from '../../../define.js'; export const meta = { tags: ['admin'], @@ -8,9 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - }, - res: { type: 'array', optional: false, nullable: false, @@ -35,8 +32,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const jobs = await deliverQueue.getJobs(['delayed']); const res = [] as [string, number][]; diff --git a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts index a95aabc50..2235ce8f9 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts @@ -1,6 +1,6 @@ -import { URL } from 'url'; -import define from '../../../define'; -import { inboxQueue } from '@/queue/queues'; +import { URL } from 'node:url'; +import define from '../../../define.js'; +import { inboxQueue } from '@/queue/queues.js'; export const meta = { tags: ['admin'], @@ -8,9 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - }, - res: { type: 'array', optional: false, nullable: false, @@ -35,8 +32,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const jobs = await inboxQueue.getJobs(['delayed']); const res = [] as [string, number][]; diff --git a/packages/backend/src/server/api/endpoints/admin/queue/jobs.ts b/packages/backend/src/server/api/endpoints/admin/queue/jobs.ts deleted file mode 100644 index df0b4a8f1..000000000 --- a/packages/backend/src/server/api/endpoints/admin/queue/jobs.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { deliverQueue, inboxQueue, dbQueue, objectStorageQueue } from '@/queue/queues'; -import $ from 'cafy'; -import define from '../../../define'; - -export const meta = { - tags: ['admin'], - - requireCredential: true, - requireModerator: true, - - params: { - domain: { - validator: $.str.or(['deliver', 'inbox', 'db', 'objectStorage']), - }, - - state: { - validator: $.str.or(['active', 'waiting', 'delayed']), - }, - - limit: { - validator: $.optional.num, - default: 50, - }, - }, - - res: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - properties: { - id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - }, - data: { - type: 'object', - optional: false, nullable: false, - }, - attempts: { - type: 'number', - optional: false, nullable: false, - }, - maxAttempts: { - type: 'number', - optional: false, nullable: false, - }, - timestamp: { - type: 'number', - optional: false, nullable: false, - }, - }, - }, - }, -} as const; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - const queue = - ps.domain === 'deliver' ? deliverQueue : - ps.domain === 'inbox' ? inboxQueue : - ps.domain === 'db' ? dbQueue : - ps.domain === 'objectStorage' ? objectStorageQueue : - null as never; - - const jobs = await queue.getJobs([ps.state], 0, ps.limit!); - - return jobs.map(job => { - const data = job.data; - delete data.content; - delete data.user; - return { - id: job.id, - data, - attempts: job.attemptsMade, - maxAttempts: job.opts ? job.opts.attempts : 0, - timestamp: job.timestamp, - }; - }); -}); diff --git a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts index dab0be5db..988b5a5e3 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts @@ -1,5 +1,5 @@ -import { deliverQueue, inboxQueue, dbQueue, objectStorageQueue } from '@/queue/queues'; -import define from '../../../define'; +import { deliverQueue, inboxQueue, dbQueue, objectStorageQueue } from '@/queue/queues.js'; +import define from '../../../define.js'; export const meta = { tags: ['admin'], @@ -7,8 +7,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: {}, - res: { type: 'object', optional: false, nullable: false, @@ -33,8 +31,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const deliverJobCounts = await deliverQueue.getJobCounts(); const inboxJobCounts = await inboxQueue.getJobCounts(); const dbJobCounts = await dbQueue.getJobCounts(); diff --git a/packages/backend/src/server/api/endpoints/admin/relays/add.ts b/packages/backend/src/server/api/endpoints/admin/relays/add.ts index 65890a00f..348e9baca 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/add.ts @@ -1,8 +1,7 @@ -import { URL } from 'url'; -import $ from 'cafy'; -import define from '../../../define'; -import { addRelay } from '@/services/relay'; -import { ApiError } from '../../../error'; +import { URL } from 'node:url'; +import define from '../../../define.js'; +import { addRelay } from '@/services/relay.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], @@ -10,12 +9,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - inbox: { - validator: $.str, - }, - }, - errors: { invalidUrl: { message: 'Invalid URL', @@ -52,8 +45,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + inbox: { type: 'string' }, + }, + required: ['inbox'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { try { if (new URL(ps.inbox).protocol !== 'https:') throw 'https only'; } catch { diff --git a/packages/backend/src/server/api/endpoints/admin/relays/list.ts b/packages/backend/src/server/api/endpoints/admin/relays/list.ts index bdddf1337..89ec651e6 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/list.ts @@ -1,5 +1,5 @@ -import define from '../../../define'; -import { listRelay } from '@/services/relay'; +import define from '../../../define.js'; +import { listRelay } from '@/services/relay.js'; export const meta = { tags: ['admin'], @@ -7,9 +7,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - }, - res: { type: 'array', optional: false, nullable: false, @@ -42,7 +39,13 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { return await listRelay(); }); diff --git a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts index 4b04e620c..b59cf72c5 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts @@ -1,21 +1,22 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { removeRelay } from '@/services/relay'; +import define from '../../../define.js'; +import { removeRelay } from '@/services/relay.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - inbox: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + inbox: { type: 'string' }, }, + required: ['inbox'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { return await removeRelay(ps.inbox); }); diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index b6cf1ee2d..1fd5c8d5a 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import * as bcrypt from 'bcryptjs'; +import define from '../../define.js'; +import bcrypt from 'bcryptjs'; import rndstr from 'rndstr'; -import { Users, UserProfiles } from '@/models/index'; +import { Users, UserProfiles } from '@/models/index.js'; export const meta = { tags: ['admin'], @@ -11,12 +9,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - userId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -31,8 +23,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const user = await Users.findOne(ps.userId as string); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts index b00457f09..a9e565841 100644 --- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts +++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts @@ -1,33 +1,28 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { AbuseUserReports, Users } from '@/models/index'; -import { getInstanceActor } from '@/services/instance-actor'; -import { deliver } from '@/queue/index'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { renderFlag } from '@/remote/activitypub/renderer/flag'; +import define from '../../define.js'; +import { AbuseUserReports, Users } from '@/models/index.js'; +import { getInstanceActor } from '@/services/instance-actor.js'; +import { deliver } from '@/queue/index.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { renderFlag } from '@/remote/activitypub/renderer/flag.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - reportId: { - validator: $.type(ID), - }, - - forward: { - validator: $.optional.boolean, - required: false, - default: false, - }, +export const paramDef = { + type: 'object', + properties: { + reportId: { type: 'string', format: 'misskey:id' }, + forward: { type: 'boolean', default: false }, }, + required: ['reportId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const report = await AbuseUserReports.findOne(ps.reportId); if (report == null) { @@ -36,9 +31,9 @@ export default define(meta, async (ps, me) => { if (ps.forward && report.targetUserHost != null) { const actor = await getInstanceActor(); - const targetUser = await Users.findOne(report.targetUserId); + const targetUser = await Users.findOneOrFail(report.targetUserId); - deliver(actor, renderActivity(renderFlag(actor, [targetUser.uri], report.comment)), targetUser.inbox); + deliver(actor, renderActivity(renderFlag(actor, [targetUser.uri!], report.comment)), targetUser.inbox); } await AbuseUserReports.update(report.id, { diff --git a/packages/backend/src/server/api/endpoints/admin/resync-chart.ts b/packages/backend/src/server/api/endpoints/admin/resync-chart.ts deleted file mode 100644 index d80d2b042..000000000 --- a/packages/backend/src/server/api/endpoints/admin/resync-chart.ts +++ /dev/null @@ -1,22 +0,0 @@ -import define from '../../define'; -import { driveChart, notesChart, usersChart } from '@/services/chart/index'; -import { insertModerationLog } from '@/services/insert-moderation-log'; - -export const meta = { - tags: ['admin'], - - requireCredential: true, - requireModerator: true, -} as const; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { - insertModerationLog(me, 'chartResync'); - - driveChart.resync(); - notesChart.resync(); - usersChart.resync(); - - // TODO: ãƒĻãƒŧã‚ļãƒŧごとぎチãƒŖãƒŧトもキãƒĨãƒŧãĢå…ĨれãĻ更新する - // TODO: イãƒŗã‚šã‚ŋãƒŗ゚ごとぎチãƒŖãƒŧトもキãƒĨãƒŧãĢå…ĨれãĻ更新する -}); diff --git a/packages/backend/src/server/api/endpoints/admin/send-email.ts b/packages/backend/src/server/api/endpoints/admin/send-email.ts index c2972c35f..bbdd66e4c 100644 --- a/packages/backend/src/server/api/endpoints/admin/send-email.ts +++ b/packages/backend/src/server/api/endpoints/admin/send-email.ts @@ -1,27 +1,24 @@ -import $ from 'cafy'; -import define from '../../define'; -import { sendEmail } from '@/services/send-email'; +import define from '../../define.js'; +import { sendEmail } from '@/services/send-email.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - to: { - validator: $.str, - }, - subject: { - validator: $.str, - }, - text: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + to: { type: 'string' }, + subject: { type: 'string' }, + text: { type: 'string' }, }, + required: ['to', 'subject', 'text'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { await sendEmail(ps.to, ps.subject, ps.text, ps.text); }); diff --git a/packages/backend/src/server/api/endpoints/admin/server-info.ts b/packages/backend/src/server/api/endpoints/admin/server-info.ts index cd282e364..8bf1c4341 100644 --- a/packages/backend/src/server/api/endpoints/admin/server-info.ts +++ b/packages/backend/src/server/api/endpoints/admin/server-info.ts @@ -1,8 +1,8 @@ -import * as os from 'os'; -import * as si from 'systeminformation'; +import * as os from 'node:os'; +import si from 'systeminformation'; import { getConnection } from 'typeorm'; -import define from '../../define'; -import { redisClient } from '../../../../db/redis'; +import define from '../../define.js'; +import { redisClient } from '../../../../db/redis.js'; export const meta = { requireCredential: true, @@ -10,9 +10,6 @@ export const meta = { tags: ['admin', 'meta'], - params: { - }, - res: { type: 'object', optional: false, nullable: false, @@ -90,8 +87,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { const memStats = await si.mem(); const fsStats = await si.fsSize(); const netInterface = await si.networkInterfaceDefault(); diff --git a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts index 84e2b84bb..3545536aa 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ModerationLogs } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { ModerationLogs } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['admin'], @@ -10,21 +8,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -65,11 +48,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const query = makePaginationQuery(ModerationLogs.createQueryBuilder('report'), ps.sinceId, ps.untilId); - const reports = await query.take(ps.limit!).getMany(); + const reports = await query.take(ps.limit).getMany(); return await ModerationLogs.packMany(reports); }); diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index c2a6a294b..a435dcc28 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -1,7 +1,5 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Users } from '@/models/index'; +import define from '../../define.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['admin'], @@ -9,158 +7,22 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - userId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', nullable: false, optional: false, - properties: { - id: { - type: 'string', - nullable: false, optional: false, - format: 'id', - }, - createdAt: { - type: 'string', - nullable: false, optional: false, - format: 'date-time', - }, - updatedAt: { - type: 'string', - nullable: true, optional: false, - format: 'date-time', - }, - lastFetchedAt: { - type: 'string', - nullable: true, optional: false, - }, - username: { - type: 'string', - nullable: false, optional: false, - }, - name: { - type: 'string', - nullable: true, optional: false, - }, - folowersCount: { - type: 'number', - nullable: false, optional: true, - }, - followingCount: { - type: 'number', - nullable: false, optional: false, - }, - notesCount: { - type: 'number', - nullable: false, optional: false, - }, - avatarId: { - type: 'string', - nullable: true, optional: false, - }, - bannerId: { - type: 'string', - nullable: true, optional: false, - }, - tags: { - type: 'array', - nullable: false, optional: false, - items: { - type: 'string', - nullable: false, optional: false, - }, - }, - avatarUrl: { - type: 'string', - nullable: true, optional: false, - format: 'url', - }, - bannerUrl: { - type: 'string', - nullable: true, optional: false, - format: 'url', - }, - avatarBlurhash: { - type: 'any', - nullable: true, optional: false, - default: null, - }, - bannerBlurhash: { - type: 'any', - nullable: true, optional: false, - default: null, - }, - isSuspended: { - type: 'boolean', - nullable: false, optional: false, - }, - isSilenced: { - type: 'boolean', - nullable: false, optional: false, - }, - isLocked: { - type: 'boolean', - nullable: false, optional: false, - }, - isBot: { - type: 'boolean', - nullable: false, optional: false, - }, - isCat: { - type: 'boolean', - nullable: false, optional: false, - }, - isAdmin: { - type: 'boolean', - nullable: false, optional: false, - }, - isModerator: { - type: 'boolean', - nullable: false, optional: false, - }, - emojis: { - type: 'array', - nullable: false, optional: false, - items: { - type: 'string', - nullable: false, optional: false, - }, - }, - host: { - type: 'string', - nullable: true, optional: false, - }, - inbox: { - type: 'string', - nullable: true, optional: false, - }, - sharedInbox: { - type: 'string', - nullable: true, optional: false, - }, - featured: { - type: 'string', - nullable: true, optional: false, - }, - uri: { - type: 'string', - nullable: true, optional: false, - }, - token: { - type: 'string', - nullable: true, optional: false, - default: '', - }, - }, }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index d3dde99b7..1ec86fef2 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -1,6 +1,5 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Users } from '@/models/index'; +import define from '../../define.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['admin'], @@ -8,61 +7,6 @@ export const meta = { requireCredential: true, requireModerator: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - - sort: { - validator: $.optional.str.or([ - '+follower', - '-follower', - '+createdAt', - '-createdAt', - '+updatedAt', - '-updatedAt', - ]), - }, - - state: { - validator: $.optional.str.or([ - 'all', - 'available', - 'admin', - 'moderator', - 'adminOrModerator', - 'silenced', - 'suspended', - ]), - default: 'all', - }, - - origin: { - validator: $.optional.str.or([ - 'combined', - 'local', - 'remote', - ]), - default: 'local', - }, - - username: { - validator: $.optional.str, - default: null, - }, - - hostname: { - validator: $.optional.str, - default: null, - }, - }, - res: { type: 'array', nullable: false, optional: false, @@ -74,8 +18,22 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt'] }, + state: { type: 'string', enum: ['all', 'available', 'admin', 'moderator', 'adminOrModerator', 'silenced', 'suspended'], default: "all" }, + origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "local" }, + username: { type: 'string', default: null }, + hostname: { type: 'string', default: null }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = Users.createQueryBuilder('user'); switch (ps.state) { @@ -111,7 +69,7 @@ export default define(meta, async (ps, me) => { default: query.orderBy('user.id', 'ASC'); break; } - query.take(ps.limit!); + query.take(ps.limit); query.skip(ps.offset); const users = await query.getMany(); diff --git a/packages/backend/src/server/api/endpoints/admin/silence-user.ts b/packages/backend/src/server/api/endpoints/admin/silence-user.ts index 872bd2a6a..4a74c3fb0 100644 --- a/packages/backend/src/server/api/endpoints/admin/silence-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/silence-user.ts @@ -1,24 +1,24 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Users } from '@/models/index'; -import { insertModerationLog } from '@/services/insert-moderation-log'; +import define from '../../define.js'; +import { Users } from '@/models/index.js'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts index 2bb1875fc..adaa7b86c 100644 --- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts @@ -1,28 +1,28 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import deleteFollowing from '@/services/following/delete'; -import { Users, Followings, Notifications } from '@/models/index'; -import { User } from '@/models/entities/user'; -import { insertModerationLog } from '@/services/insert-moderation-log'; -import { doPostSuspend } from '@/services/suspend-user'; -import { publishUserEvent } from '@/services/stream'; +import define from '../../define.js'; +import deleteFollowing from '@/services/following/delete.js'; +import { Users, Followings, Notifications } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { doPostSuspend } from '@/services/suspend-user.js'; +import { publishUserEvent } from '@/services/stream.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts b/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts index a4c6ff2ad..4e6366aa1 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts @@ -1,24 +1,24 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Users } from '@/models/index'; -import { insertModerationLog } from '@/services/insert-moderation-log'; +import define from '../../define.js'; +import { Users } from '@/models/index.js'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts index 5ab56d51c..3b9e0a94e 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts @@ -1,25 +1,25 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Users } from '@/models/index'; -import { insertModerationLog } from '@/services/insert-moderation-log'; -import { doPostUnsuspend } from '@/services/unsuspend-user'; +import define from '../../define.js'; +import { Users } from '@/models/index.js'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { doPostUnsuspend } from '@/services/unsuspend-user.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index aa2d1222f..66b634c87 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -1,306 +1,107 @@ -import $ from 'cafy'; -import define from '../../define'; +import define from '../../define.js'; import { getConnection } from 'typeorm'; -import { Meta } from '@/models/entities/meta'; -import { insertModerationLog } from '@/services/insert-moderation-log'; -import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits'; -import { ID } from '@/misc/cafy-id'; +import { Meta } from '@/models/entities/meta.js'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits.js'; export const meta = { tags: ['admin'], requireCredential: true, requireAdmin: true, - - params: { - disableRegistration: { - validator: $.optional.nullable.bool, - }, - - disableLocalTimeline: { - validator: $.optional.nullable.bool, - }, - - disableGlobalTimeline: { - validator: $.optional.nullable.bool, - }, - - useStarForReactionFallback: { - validator: $.optional.nullable.bool, - }, - - pinnedUsers: { - validator: $.optional.nullable.arr($.str), - }, - - hiddenTags: { - validator: $.optional.nullable.arr($.str), - }, - - blockedHosts: { - validator: $.optional.nullable.arr($.str), - }, - - mascotImageUrl: { - validator: $.optional.nullable.str, - }, - - bannerUrl: { - validator: $.optional.nullable.str, - }, - - errorImageUrl: { - validator: $.optional.nullable.str, - }, - - iconUrl: { - validator: $.optional.nullable.str, - }, - - backgroundImageUrl: { - validator: $.optional.nullable.str, - }, - - logoImageUrl: { - validator: $.optional.nullable.str, - }, - - name: { - validator: $.optional.nullable.str, - }, - - description: { - validator: $.optional.nullable.str, - }, - - maxNoteTextLength: { - validator: $.optional.num.min(0).max(DB_MAX_NOTE_TEXT_LENGTH), - }, - - localDriveCapacityMb: { - validator: $.optional.num.min(0), - }, - - remoteDriveCapacityMb: { - validator: $.optional.num.min(0), - }, - - cacheRemoteFiles: { - validator: $.optional.bool, - }, - - proxyRemoteFiles: { - validator: $.optional.bool, - }, - - emailRequiredForSignup: { - validator: $.optional.bool, - }, - - enableHcaptcha: { - validator: $.optional.bool, - }, - - hcaptchaSiteKey: { - validator: $.optional.nullable.str, - }, - - hcaptchaSecretKey: { - validator: $.optional.nullable.str, - }, - - enableRecaptcha: { - validator: $.optional.bool, - }, - - recaptchaSiteKey: { - validator: $.optional.nullable.str, - }, - - recaptchaSecretKey: { - validator: $.optional.nullable.str, - }, - - proxyAccountId: { - validator: $.optional.nullable.type(ID), - }, - - maintainerName: { - validator: $.optional.nullable.str, - }, - - maintainerEmail: { - validator: $.optional.nullable.str, - }, - - pinnedPages: { - validator: $.optional.arr($.str), - }, - - pinnedClipId: { - validator: $.optional.nullable.type(ID), - }, - - langs: { - validator: $.optional.arr($.str), - }, - - summalyProxy: { - validator: $.optional.nullable.str, - }, - - deeplAuthKey: { - validator: $.optional.nullable.str, - }, - - deeplIsPro: { - validator: $.optional.bool, - }, - - enableTwitterIntegration: { - validator: $.optional.bool, - }, - - twitterConsumerKey: { - validator: $.optional.nullable.str, - }, - - twitterConsumerSecret: { - validator: $.optional.nullable.str, - }, - - enableGithubIntegration: { - validator: $.optional.bool, - }, - - githubClientId: { - validator: $.optional.nullable.str, - }, - - githubClientSecret: { - validator: $.optional.nullable.str, - }, - - enableDiscordIntegration: { - validator: $.optional.bool, - }, - - discordClientId: { - validator: $.optional.nullable.str, - }, - - discordClientSecret: { - validator: $.optional.nullable.str, - }, - - enableEmail: { - validator: $.optional.bool, - }, - - email: { - validator: $.optional.nullable.str, - }, - - smtpSecure: { - validator: $.optional.bool, - }, - - smtpHost: { - validator: $.optional.nullable.str, - }, - - smtpPort: { - validator: $.optional.nullable.num, - }, - - smtpUser: { - validator: $.optional.nullable.str, - }, - - smtpPass: { - validator: $.optional.nullable.str, - }, - - enableServiceWorker: { - validator: $.optional.bool, - }, - - swPublicKey: { - validator: $.optional.nullable.str, - }, - - swPrivateKey: { - validator: $.optional.nullable.str, - }, - - tosUrl: { - validator: $.optional.nullable.str, - }, - - repositoryUrl: { - validator: $.optional.str, - }, - - feedbackUrl: { - validator: $.optional.str, - }, - - useObjectStorage: { - validator: $.optional.bool, - }, - - objectStorageBaseUrl: { - validator: $.optional.nullable.str, - }, - - objectStorageBucket: { - validator: $.optional.nullable.str, - }, - - objectStoragePrefix: { - validator: $.optional.nullable.str, - }, - - objectStorageEndpoint: { - validator: $.optional.nullable.str, - }, - - objectStorageRegion: { - validator: $.optional.nullable.str, - }, - - objectStoragePort: { - validator: $.optional.nullable.num, - }, - - objectStorageAccessKey: { - validator: $.optional.nullable.str, - }, - - objectStorageSecretKey: { - validator: $.optional.nullable.str, - }, - - objectStorageUseSSL: { - validator: $.optional.bool, - }, - - objectStorageUseProxy: { - validator: $.optional.bool, - }, - - objectStorageSetPublicRead: { - validator: $.optional.bool, - }, - - objectStorageS3ForcePathStyle: { - validator: $.optional.bool, - }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + disableRegistration: { type: 'boolean', nullable: true }, + disableLocalTimeline: { type: 'boolean', nullable: true }, + disableGlobalTimeline: { type: 'boolean', nullable: true }, + useStarForReactionFallback: { type: 'boolean', nullable: true }, + pinnedUsers: { type: 'array', nullable: true, items: { + type: 'string', + } }, + hiddenTags: { type: 'array', nullable: true, items: { + type: 'string', + } }, + blockedHosts: { type: 'array', nullable: true, items: { + type: 'string', + } }, + themeColor: { type: 'string', nullable: true }, + mascotImageUrl: { type: 'string', nullable: true }, + bannerUrl: { type: 'string', nullable: true }, + errorImageUrl: { type: 'string', nullable: true }, + iconUrl: { type: 'string', nullable: true }, + backgroundImageUrl: { type: 'string', nullable: true }, + logoImageUrl: { type: 'string', nullable: true }, + name: { type: 'string', nullable: true }, + description: { type: 'string', nullable: true }, + defaultLightTheme: { type: 'string', nullable: true }, + defaultDarkTheme: { type: 'string', nullable: true }, + localDriveCapacityMb: { type: 'integer' }, + remoteDriveCapacityMb: { type: 'integer' }, + cacheRemoteFiles: { type: 'boolean' }, + emailRequiredForSignup: { type: 'boolean' }, + enableHcaptcha: { type: 'boolean' }, + hcaptchaSiteKey: { type: 'string', nullable: true }, + hcaptchaSecretKey: { type: 'string', nullable: true }, + enableRecaptcha: { type: 'boolean' }, + recaptchaSiteKey: { type: 'string', nullable: true }, + recaptchaSecretKey: { type: 'string', nullable: true }, + proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true }, + maintainerName: { type: 'string', nullable: true }, + maintainerEmail: { type: 'string', nullable: true }, + pinnedPages: { type: 'array', items: { + type: 'string', + } }, + pinnedClipId: { type: 'string', format: 'misskey:id', nullable: true }, + langs: { type: 'array', items: { + type: 'string', + } }, + summalyProxy: { type: 'string', nullable: true }, + deeplAuthKey: { type: 'string', nullable: true }, + deeplIsPro: { type: 'boolean' }, + enableTwitterIntegration: { type: 'boolean' }, + twitterConsumerKey: { type: 'string', nullable: true }, + twitterConsumerSecret: { type: 'string', nullable: true }, + enableGithubIntegration: { type: 'boolean' }, + githubClientId: { type: 'string', nullable: true }, + githubClientSecret: { type: 'string', nullable: true }, + enableDiscordIntegration: { type: 'boolean' }, + discordClientId: { type: 'string', nullable: true }, + discordClientSecret: { type: 'string', nullable: true }, + enableEmail: { type: 'boolean' }, + email: { type: 'string', nullable: true }, + smtpSecure: { type: 'boolean' }, + smtpHost: { type: 'string', nullable: true }, + smtpPort: { type: 'integer', nullable: true }, + smtpUser: { type: 'string', nullable: true }, + smtpPass: { type: 'string', nullable: true }, + enableServiceWorker: { type: 'boolean' }, + swPublicKey: { type: 'string', nullable: true }, + swPrivateKey: { type: 'string', nullable: true }, + tosUrl: { type: 'string', nullable: true }, + repositoryUrl: { type: 'string' }, + feedbackUrl: { type: 'string' }, + useObjectStorage: { type: 'boolean' }, + objectStorageBaseUrl: { type: 'string', nullable: true }, + objectStorageBucket: { type: 'string', nullable: true }, + objectStoragePrefix: { type: 'string', nullable: true }, + objectStorageEndpoint: { type: 'string', nullable: true }, + objectStorageRegion: { type: 'string', nullable: true }, + objectStoragePort: { type: 'integer', nullable: true }, + objectStorageAccessKey: { type: 'string', nullable: true }, + objectStorageSecretKey: { type: 'string', nullable: true }, + objectStorageUseSSL: { type: 'boolean' }, + objectStorageUseProxy: { type: 'boolean' }, + objectStorageSetPublicRead: { type: 'boolean' }, + objectStorageS3ForcePathStyle: { type: 'boolean' }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const set = {} as Partial; if (typeof ps.disableRegistration === 'boolean') { @@ -331,6 +132,10 @@ export default define(meta, async (ps, me) => { set.blockedHosts = ps.blockedHosts.filter(Boolean); } + if (ps.themeColor !== undefined) { + set.themeColor = ps.themeColor; + } + if (ps.mascotImageUrl !== undefined) { set.mascotImageUrl = ps.mascotImageUrl; } @@ -359,8 +164,12 @@ export default define(meta, async (ps, me) => { set.description = ps.description; } - if (ps.maxNoteTextLength) { - set.maxNoteTextLength = ps.maxNoteTextLength; + if (ps.defaultLightTheme !== undefined) { + set.defaultLightTheme = ps.defaultLightTheme; + } + + if (ps.defaultDarkTheme !== undefined) { + set.defaultDarkTheme = ps.defaultDarkTheme; } if (ps.localDriveCapacityMb !== undefined) { @@ -375,10 +184,6 @@ export default define(meta, async (ps, me) => { set.cacheRemoteFiles = ps.cacheRemoteFiles; } - if (ps.proxyRemoteFiles !== undefined) { - set.proxyRemoteFiles = ps.proxyRemoteFiles; - } - if (ps.emailRequiredForSignup !== undefined) { set.emailRequiredForSignup = ps.emailRequiredForSignup; } diff --git a/packages/backend/src/server/api/endpoints/admin/vacuum.ts b/packages/backend/src/server/api/endpoints/admin/vacuum.ts index 4229ef0d2..4c04e019d 100644 --- a/packages/backend/src/server/api/endpoints/admin/vacuum.ts +++ b/packages/backend/src/server/api/endpoints/admin/vacuum.ts @@ -1,26 +1,25 @@ -import $ from 'cafy'; -import define from '../../define'; +import define from '../../define.js'; import { getConnection } from 'typeorm'; -import { insertModerationLog } from '@/services/insert-moderation-log'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; export const meta = { tags: ['admin'], requireCredential: true, requireModerator: true, +} as const; - params: { - full: { - validator: $.bool, - }, - analyze: { - validator: $.bool, - }, +export const paramDef = { + type: 'object', + properties: { + full: { type: 'boolean' }, + analyze: { type: 'boolean' }, }, + required: ['full', 'analyze'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const params: string[] = []; if (ps.full) { diff --git a/packages/backend/src/server/api/endpoints/announcements.ts b/packages/backend/src/server/api/endpoints/announcements.ts index 0bd29607d..bba66e98c 100644 --- a/packages/backend/src/server/api/endpoints/announcements.ts +++ b/packages/backend/src/server/api/endpoints/announcements.ts @@ -1,34 +1,12 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../define'; -import { Announcements, AnnouncementReads } from '@/models/index'; -import { makePaginationQuery } from '../common/make-pagination-query'; +import define from '../define.js'; +import { Announcements, AnnouncementReads } from '@/models/index.js'; +import { makePaginationQuery } from '../common/make-pagination-query.js'; export const meta = { tags: ['meta'], requireCredential: false, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - withUnreads: { - validator: $.optional.boolean, - default: false, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -73,11 +51,22 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + withUnreads: { type: 'boolean', default: false }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId); - const announcements = await query.take(ps.limit!).getMany(); + const announcements = await query.take(ps.limit).getMany(); if (user) { const reads = (await AnnouncementReads.find({ @@ -89,5 +78,9 @@ export default define(meta, async (ps, user) => { } } - return ps.withUnreads ? announcements.filter((a: any) => !a.isRead) : announcements; + return (ps.withUnreads ? announcements.filter((a: any) => !a.isRead) : announcements).map((a) => ({ + ...a, + createdAt: a.createdAt.toISOString(), + updatedAt: a.updatedAt?.toISOString() ?? null, + })); }); diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts index 2092d177b..92cbba817 100644 --- a/packages/backend/src/server/api/endpoints/antennas/create.ts +++ b/packages/backend/src/server/api/endpoints/antennas/create.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import define from '../../define'; -import { genId } from '@/misc/gen-id'; -import { Antennas, UserLists, UserGroupJoinings } from '@/models/index'; -import { ID } from '@/misc/cafy-id'; -import { ApiError } from '../../error'; -import { publishInternalEvent } from '@/services/stream'; +import define from '../../define.js'; +import { genId } from '@/misc/gen-id.js'; +import { Antennas, UserLists, UserGroupJoinings } from '@/models/index.js'; +import { ApiError } from '../../error.js'; +import { publishInternalEvent } from '@/services/stream.js'; export const meta = { tags: ['antennas'], @@ -13,52 +11,6 @@ export const meta = { kind: 'write:account', - params: { - name: { - validator: $.str.range(1, 100), - }, - - src: { - validator: $.str.or(['home', 'all', 'users', 'list', 'group']), - }, - - userListId: { - validator: $.nullable.optional.type(ID), - }, - - userGroupId: { - validator: $.nullable.optional.type(ID), - }, - - keywords: { - validator: $.arr($.arr($.str)), - }, - - excludeKeywords: { - validator: $.arr($.arr($.str)), - }, - - users: { - validator: $.arr($.str), - }, - - caseSensitive: { - validator: $.bool, - }, - - withReplies: { - validator: $.bool, - }, - - withFile: { - validator: $.bool, - }, - - notify: { - validator: $.bool, - }, - }, - errors: { noSuchUserList: { message: 'No such user list.', @@ -80,8 +32,36 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string', minLength: 1, maxLength: 100 }, + src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'group'] }, + userListId: { type: 'string', format: 'misskey:id', nullable: true }, + userGroupId: { type: 'string', format: 'misskey:id', nullable: true }, + keywords: { type: 'array', items: { + type: 'array', items: { + type: 'string', + }, + } }, + excludeKeywords: { type: 'array', items: { + type: 'array', items: { + type: 'string', + }, + } }, + users: { type: 'array', items: { + type: 'string', + } }, + caseSensitive: { type: 'boolean' }, + withReplies: { type: 'boolean' }, + withFile: { type: 'boolean' }, + notify: { type: 'boolean' }, + }, + required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { let userList; let userGroupJoining; diff --git a/packages/backend/src/server/api/endpoints/antennas/delete.ts b/packages/backend/src/server/api/endpoints/antennas/delete.ts index b2793fc70..4e6b8b3d2 100644 --- a/packages/backend/src/server/api/endpoints/antennas/delete.ts +++ b/packages/backend/src/server/api/endpoints/antennas/delete.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Antennas } from '@/models/index'; -import { publishInternalEvent } from '@/services/stream'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Antennas } from '@/models/index.js'; +import { publishInternalEvent } from '@/services/stream.js'; export const meta = { tags: ['antennas'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - antennaId: { - validator: $.type(ID), - }, - }, - errors: { noSuchAntenna: { message: 'No such antenna.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + antennaId: { type: 'string', format: 'misskey:id' }, + }, + required: ['antennaId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const antenna = await Antennas.findOne({ id: ps.antennaId, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/antennas/list.ts b/packages/backend/src/server/api/endpoints/antennas/list.ts index bb5891261..accca5de7 100644 --- a/packages/backend/src/server/api/endpoints/antennas/list.ts +++ b/packages/backend/src/server/api/endpoints/antennas/list.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { Antennas } from '@/models/index'; +import define from '../../define.js'; +import { Antennas } from '@/models/index.js'; export const meta = { tags: ['antennas', 'account'], @@ -19,8 +19,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const antennas = await Antennas.find({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index eb7de901c..f0cb2ba3c 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -1,13 +1,11 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import readNote from '@/services/note/read'; -import { Antennas, Notes, AntennaNotes } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { ApiError } from '../../error'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import define from '../../define.js'; +import readNote from '@/services/note/read.js'; +import { Antennas, Notes, AntennaNotes } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { ApiError } from '../../error.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['antennas', 'account', 'notes'], @@ -16,33 +14,6 @@ export const meta = { kind: 'read:account', - params: { - antennaId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - }, - errors: { noSuchAntenna: { message: 'No such antenna.', @@ -62,8 +33,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + antennaId: { type: 'string', format: 'misskey:id' }, + 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: ['antennaId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const antenna = await Antennas.findOne({ id: ps.antennaId, userId: user.id, @@ -81,10 +65,16 @@ export default define(meta, async (ps, user) => { ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere(`note.id IN (${ antennaQuery.getQuery() })`) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .setParameters(antennaQuery.getParameters()); generateVisibilityQuery(query, user); @@ -92,7 +82,7 @@ export default define(meta, async (ps, user) => { generateBlockedUserQuery(query, user); const notes = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); if (notes.length > 0) { diff --git a/packages/backend/src/server/api/endpoints/antennas/show.ts b/packages/backend/src/server/api/endpoints/antennas/show.ts index a37d37d31..36c4da81b 100644 --- a/packages/backend/src/server/api/endpoints/antennas/show.ts +++ b/packages/backend/src/server/api/endpoints/antennas/show.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Antennas } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Antennas } from '@/models/index.js'; export const meta = { tags: ['antennas', 'account'], @@ -11,12 +9,6 @@ export const meta = { kind: 'read:account', - params: { - antennaId: { - validator: $.type(ID), - }, - }, - errors: { noSuchAntenna: { message: 'No such antenna.', @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + antennaId: { type: 'string', format: 'misskey:id' }, + }, + required: ['antennaId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the antenna const antenna = await Antennas.findOne({ id: ps.antennaId, diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts index 900f72550..a99964555 100644 --- a/packages/backend/src/server/api/endpoints/antennas/update.ts +++ b/packages/backend/src/server/api/endpoints/antennas/update.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Antennas, UserLists, UserGroupJoinings } from '@/models/index'; -import { publishInternalEvent } from '@/services/stream'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Antennas, UserLists, UserGroupJoinings } from '@/models/index.js'; +import { publishInternalEvent } from '@/services/stream.js'; export const meta = { tags: ['antennas'], @@ -12,56 +10,6 @@ export const meta = { kind: 'write:account', - params: { - antennaId: { - validator: $.type(ID), - }, - - name: { - validator: $.str.range(1, 100), - }, - - src: { - validator: $.str.or(['home', 'all', 'users', 'list', 'group']), - }, - - userListId: { - validator: $.nullable.optional.type(ID), - }, - - userGroupId: { - validator: $.nullable.optional.type(ID), - }, - - keywords: { - validator: $.arr($.arr($.str)), - }, - - excludeKeywords: { - validator: $.arr($.arr($.str)), - }, - - users: { - validator: $.arr($.str), - }, - - caseSensitive: { - validator: $.bool, - }, - - withReplies: { - validator: $.bool, - }, - - withFile: { - validator: $.bool, - }, - - notify: { - validator: $.bool, - }, - }, - errors: { noSuchAntenna: { message: 'No such antenna.', @@ -89,8 +37,37 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + antennaId: { type: 'string', format: 'misskey:id' }, + name: { type: 'string', minLength: 1, maxLength: 100 }, + src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'group'] }, + userListId: { type: 'string', format: 'misskey:id', nullable: true }, + userGroupId: { type: 'string', format: 'misskey:id', nullable: true }, + keywords: { type: 'array', items: { + type: 'array', items: { + type: 'string', + }, + } }, + excludeKeywords: { type: 'array', items: { + type: 'array', items: { + type: 'string', + }, + } }, + users: { type: 'array', items: { + type: 'string', + } }, + caseSensitive: { type: 'boolean' }, + withReplies: { type: 'boolean' }, + withFile: { type: 'boolean' }, + notify: { type: 'boolean' }, + }, + required: ['antennaId', 'name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch the antenna const antenna = await Antennas.findOne({ id: ps.antennaId, diff --git a/packages/backend/src/server/api/endpoints/ap/get.ts b/packages/backend/src/server/api/endpoints/ap/get.ts index ff8c677b9..0cbe7ebc6 100644 --- a/packages/backend/src/server/api/endpoints/ap/get.ts +++ b/packages/backend/src/server/api/endpoints/ap/get.ts @@ -1,7 +1,6 @@ -import $ from 'cafy'; -import define from '../../define'; -import Resolver from '@/remote/activitypub/resolver'; -import { ApiError } from '../../error'; +import define from '../../define.js'; +import Resolver from '@/remote/activitypub/resolver.js'; +import { ApiError } from '../../error.js'; import ms from 'ms'; export const meta = { @@ -14,12 +13,6 @@ export const meta = { max: 30, }, - params: { - uri: { - validator: $.str, - }, - }, - errors: { }, @@ -29,8 +22,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + uri: { type: 'string' }, + }, + required: ['uri'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const resolver = new Resolver(); const object = await resolver.resolve(ps.uri); return object; diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 7d17d8edc..7595c38e8 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -1,18 +1,17 @@ -import $ from 'cafy'; -import define from '../../define'; -import config from '@/config/index'; -import { createPerson } from '@/remote/activitypub/models/person'; -import { createNote } from '@/remote/activitypub/models/note'; -import Resolver from '@/remote/activitypub/resolver'; -import { ApiError } from '../../error'; -import { extractDbHost } from '@/misc/convert-host'; -import { Users, Notes } from '@/models/index'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { isActor, isPost, getApId } from '@/remote/activitypub/type'; +import define from '../../define.js'; +import config from '@/config/index.js'; +import { createPerson } from '@/remote/activitypub/models/person.js'; +import { createNote } from '@/remote/activitypub/models/note.js'; +import Resolver from '@/remote/activitypub/resolver.js'; +import { ApiError } from '../../error.js'; +import { extractDbHost } from '@/misc/convert-host.js'; +import { Users, Notes } from '@/models/index.js'; +import { Note } from '@/models/entities/note.js'; +import { User } from '@/models/entities/user.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { isActor, isPost, getApId } from '@/remote/activitypub/type.js'; import ms from 'ms'; -import { SchemaType } from '@/misc/schema'; +import { SchemaType } from '@/misc/schema.js'; export const meta = { tags: ['federation'], @@ -24,12 +23,6 @@ export const meta = { max: 30, }, - params: { - uri: { - validator: $.str, - }, - }, - errors: { noSuchObject: { message: 'No such object.', @@ -75,8 +68,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + uri: { type: 'string' }, + }, + required: ['uri'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const object = await fetchAny(ps.uri); if (object) { return object; diff --git a/packages/backend/src/server/api/endpoints/app/create.ts b/packages/backend/src/server/api/endpoints/app/create.ts index fbe6690f1..e0cf8632f 100644 --- a/packages/backend/src/server/api/endpoints/app/create.ts +++ b/packages/backend/src/server/api/endpoints/app/create.ts @@ -1,35 +1,14 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Apps } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { unique } from '@/prelude/array'; -import { secureRndstr } from '@/misc/secure-rndstr'; +import define from '../../define.js'; +import { Apps } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { unique } from '@/prelude/array.js'; +import { secureRndstr } from '@/misc/secure-rndstr.js'; export const meta = { tags: ['app'], requireCredential: false, - params: { - name: { - validator: $.str, - }, - - description: { - validator: $.str, - }, - - permission: { - validator: $.arr($.str).unique(), - }, - - // TODO: Check it is valid url - callbackUrl: { - validator: $.optional.nullable.str, - default: null, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -37,8 +16,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string' }, + description: { type: 'string' }, + permission: { type: 'array', uniqueItems: true, items: { + type: 'string', + } }, + callbackUrl: { type: 'string', nullable: true }, + }, + required: ['name', 'description', 'permission'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Generate secret const secret = secureRndstr(32, true); diff --git a/packages/backend/src/server/api/endpoints/app/show.ts b/packages/backend/src/server/api/endpoints/app/show.ts index 9f4777b38..54e714e19 100644 --- a/packages/backend/src/server/api/endpoints/app/show.ts +++ b/packages/backend/src/server/api/endpoints/app/show.ts @@ -1,18 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Apps } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Apps } from '@/models/index.js'; export const meta = { tags: ['app'], - params: { - appId: { - validator: $.type(ID), - }, - }, - errors: { noSuchApp: { message: 'No such app.', @@ -28,8 +20,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + appId: { type: 'string', format: 'misskey:id' }, + }, + required: ['appId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user, token) => { +export default define(meta, paramDef, async (ps, user, token) => { const isSecure = user != null && token == null; // Lookup app diff --git a/packages/backend/src/server/api/endpoints/auth/accept.ts b/packages/backend/src/server/api/endpoints/auth/accept.ts index f028135ca..0760eef52 100644 --- a/packages/backend/src/server/api/endpoints/auth/accept.ts +++ b/packages/backend/src/server/api/endpoints/auth/accept.ts @@ -1,10 +1,9 @@ -import * as crypto from 'crypto'; -import $ from 'cafy'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { AuthSessions, AccessTokens, Apps } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { secureRndstr } from '@/misc/secure-rndstr'; +import * as crypto from 'node:crypto'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { AuthSessions, AccessTokens, Apps } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { secureRndstr } from '@/misc/secure-rndstr.js'; export const meta = { tags: ['auth'], @@ -13,12 +12,6 @@ export const meta = { secure: true, - params: { - token: { - validator: $.str, - }, - }, - errors: { noSuchSession: { message: 'No such session.', @@ -28,8 +21,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + token: { type: 'string' }, + }, + required: ['token'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch token const session = await AuthSessions .findOne({ token: ps.token }); diff --git a/packages/backend/src/server/api/endpoints/auth/session/generate.ts b/packages/backend/src/server/api/endpoints/auth/session/generate.ts index 98987eba5..bd571327d 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/generate.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/generate.ts @@ -1,22 +1,15 @@ import { v4 as uuid } from 'uuid'; -import $ from 'cafy'; -import config from '@/config/index'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { Apps, AuthSessions } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import config from '@/config/index.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { Apps, AuthSessions } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['auth'], requireCredential: false, - params: { - appSecret: { - validator: $.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -42,8 +35,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + appSecret: { type: 'string' }, + }, + required: ['appSecret'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { // Lookup app const app = await Apps.findOne({ secret: ps.appSecret, diff --git a/packages/backend/src/server/api/endpoints/auth/session/show.ts b/packages/backend/src/server/api/endpoints/auth/session/show.ts index ae0d016ce..d40c9363c 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/show.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/show.ts @@ -1,19 +1,12 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { AuthSessions } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { AuthSessions } from '@/models/index.js'; export const meta = { tags: ['auth'], requireCredential: false, - params: { - token: { - validator: $.str, - }, - }, - errors: { noSuchSession: { message: 'No such session.', @@ -44,8 +37,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + token: { type: 'string' }, + }, + required: ['token'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Lookup session const session = await AuthSessions.findOne({ token: ps.token, diff --git a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts index fe0211ebe..b699c6fa2 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts @@ -1,23 +1,12 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { Apps, AuthSessions, AccessTokens, Users } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { Apps, AuthSessions, AccessTokens, Users } from '@/models/index.js'; export const meta = { tags: ['auth'], requireCredential: false, - params: { - appSecret: { - validator: $.str, - }, - - token: { - validator: $.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -56,8 +45,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + appSecret: { type: 'string' }, + token: { type: 'string' }, + }, + required: ['appSecret', 'token'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { // Lookup app const app = await Apps.findOne({ secret: ps.appSecret, diff --git a/packages/backend/src/server/api/endpoints/blocking/create.ts b/packages/backend/src/server/api/endpoints/blocking/create.ts index 6d555ff56..c5e73c013 100644 --- a/packages/backend/src/server/api/endpoints/blocking/create.ts +++ b/packages/backend/src/server/api/endpoints/blocking/create.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; import ms from 'ms'; -import create from '@/services/blocking/create'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { Blockings, NoteWatchings, Users } from '@/models/index'; +import create from '@/services/blocking/create.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { Blockings, NoteWatchings, Users } from '@/models/index.js'; export const meta = { tags: ['account'], @@ -19,12 +17,6 @@ export const meta = { kind: 'write:blocks', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -52,8 +44,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const blocker = await Users.findOneOrFail(user.id); // č‡Ē分č‡ĒčēĢ diff --git a/packages/backend/src/server/api/endpoints/blocking/delete.ts b/packages/backend/src/server/api/endpoints/blocking/delete.ts index 942cddaed..a45547290 100644 --- a/packages/backend/src/server/api/endpoints/blocking/delete.ts +++ b/packages/backend/src/server/api/endpoints/blocking/delete.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; import ms from 'ms'; -import deleteBlocking from '@/services/blocking/delete'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { Blockings, Users } from '@/models/index'; +import deleteBlocking from '@/services/blocking/delete.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { Blockings, Users } from '@/models/index.js'; export const meta = { tags: ['account'], @@ -19,12 +17,6 @@ export const meta = { kind: 'write:blocks', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -52,8 +44,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const blocker = await Users.findOneOrFail(user.id); // Check if the blockee is yourself diff --git a/packages/backend/src/server/api/endpoints/blocking/list.ts b/packages/backend/src/server/api/endpoints/blocking/list.ts index 9a4f66214..29095ebe2 100644 --- a/packages/backend/src/server/api/endpoints/blocking/list.ts +++ b/packages/backend/src/server/api/endpoints/blocking/list.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Blockings } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Blockings } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['account'], @@ -11,21 +9,6 @@ export const meta = { kind: 'read:blocks', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 30, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -37,13 +20,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(Blockings.createQueryBuilder('blocking'), ps.sinceId, ps.untilId) .andWhere(`blocking.blockerId = :meId`, { meId: me.id }); const blockings = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Blockings.packMany(blockings, me); diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts index 68cdf1143..16456b9c0 100644 --- a/packages/backend/src/server/api/endpoints/channels/create.ts +++ b/packages/backend/src/server/api/endpoints/channels/create.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Channels, DriveFiles } from '@/models/index'; -import { Channel } from '@/models/entities/channel'; -import { genId } from '@/misc/gen-id'; -import { ID } from '@/misc/cafy-id'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Channels, DriveFiles } from '@/models/index.js'; +import { Channel } from '@/models/entities/channel.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['channels'], @@ -13,20 +11,6 @@ export const meta = { kind: 'write:channels', - params: { - name: { - validator: $.str.range(1, 128), - }, - - description: { - validator: $.nullable.optional.str.range(1, 2048), - }, - - bannerId: { - validator: $.nullable.optional.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -42,8 +26,18 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string', minLength: 1, maxLength: 128 }, + description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, + bannerId: { type: 'string', format: 'misskey:id', nullable: true }, + }, + required: ['name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { let banner = null; if (ps.bannerId != null) { banner = await DriveFiles.findOne({ diff --git a/packages/backend/src/server/api/endpoints/channels/featured.ts b/packages/backend/src/server/api/endpoints/channels/featured.ts index ceadde907..73980c0fa 100644 --- a/packages/backend/src/server/api/endpoints/channels/featured.ts +++ b/packages/backend/src/server/api/endpoints/channels/featured.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { Channels } from '@/models/index'; +import define from '../../define.js'; +import { Channels } from '@/models/index.js'; export const meta = { tags: ['channels'], @@ -17,8 +17,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = Channels.createQueryBuilder('channel') .where('channel.lastNotedAt IS NOT NULL') .orderBy('channel.lastNotedAt', 'DESC'); diff --git a/packages/backend/src/server/api/endpoints/channels/follow.ts b/packages/backend/src/server/api/endpoints/channels/follow.ts index bf580eea6..4372c283c 100644 --- a/packages/backend/src/server/api/endpoints/channels/follow.ts +++ b/packages/backend/src/server/api/endpoints/channels/follow.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Channels, ChannelFollowings } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { publishUserEvent } from '@/services/stream'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Channels, ChannelFollowings } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { publishUserEvent } from '@/services/stream.js'; export const meta = { tags: ['channels'], @@ -13,12 +11,6 @@ export const meta = { kind: 'write:channels', - params: { - channelId: { - validator: $.type(ID), - }, - }, - errors: { noSuchChannel: { message: 'No such channel.', @@ -28,8 +20,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + channelId: { type: 'string', format: 'misskey:id' }, + }, + required: ['channelId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const channel = await Channels.findOne({ id: ps.channelId, }); diff --git a/packages/backend/src/server/api/endpoints/channels/followed.ts b/packages/backend/src/server/api/endpoints/channels/followed.ts index 9e4c942af..e4aa4d161 100644 --- a/packages/backend/src/server/api/endpoints/channels/followed.ts +++ b/packages/backend/src/server/api/endpoints/channels/followed.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Channels, ChannelFollowings } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Channels, ChannelFollowings } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['channels', 'account'], @@ -11,21 +9,6 @@ export const meta = { kind: 'read:channels', - params: { - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 5, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -37,13 +20,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(ChannelFollowings.createQueryBuilder(), ps.sinceId, ps.untilId) .andWhere({ followerId: me.id }); const followings = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Promise.all(followings.map(x => Channels.pack(x.followeeId, me))); diff --git a/packages/backend/src/server/api/endpoints/channels/owned.ts b/packages/backend/src/server/api/endpoints/channels/owned.ts index 5473636a8..ed7e41cac 100644 --- a/packages/backend/src/server/api/endpoints/channels/owned.ts +++ b/packages/backend/src/server/api/endpoints/channels/owned.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Channels } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Channels } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['channels', 'account'], @@ -11,21 +9,6 @@ export const meta = { kind: 'read:channels', - params: { - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 5, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -37,13 +20,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(Channels.createQueryBuilder(), ps.sinceId, ps.untilId) .andWhere({ userId: me.id }); const channels = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Promise.all(channels.map(x => Channels.pack(x, me))); diff --git a/packages/backend/src/server/api/endpoints/channels/show.ts b/packages/backend/src/server/api/endpoints/channels/show.ts index 598a87ec4..ea4e01307 100644 --- a/packages/backend/src/server/api/endpoints/channels/show.ts +++ b/packages/backend/src/server/api/endpoints/channels/show.ts @@ -1,20 +1,12 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Channels } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Channels } from '@/models/index.js'; export const meta = { tags: ['channels'], requireCredential: false, - params: { - channelId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -30,8 +22,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + channelId: { type: 'string', format: 'misskey:id' }, + }, + required: ['channelId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const channel = await Channels.findOne({ id: ps.channelId, }); diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index 927ce7c74..57a9fa44b 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -1,43 +1,14 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Notes, Channels } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { activeUsersChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Notes, Channels } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; export const meta = { tags: ['notes', 'channels'], requireCredential: false, - params: { - channelId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -57,8 +28,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + channelId: { type: 'string', format: 'misskey:id' }, + 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: ['channelId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const channel = await Channels.findOne({ id: ps.channelId, }); @@ -71,16 +55,22 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.channelId = :channelId', { channelId: channel.id }) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .leftJoinAndSelect('note.channel', 'channel'); //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); - if (user) activeUsersChart.update(user); + if (user) activeUsersChart.read(user); return await Notes.packMany(timeline, user); }); diff --git a/packages/backend/src/server/api/endpoints/channels/unfollow.ts b/packages/backend/src/server/api/endpoints/channels/unfollow.ts index ada0cb29f..32beb24d6 100644 --- a/packages/backend/src/server/api/endpoints/channels/unfollow.ts +++ b/packages/backend/src/server/api/endpoints/channels/unfollow.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Channels, ChannelFollowings } from '@/models/index'; -import { publishUserEvent } from '@/services/stream'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Channels, ChannelFollowings } from '@/models/index.js'; +import { publishUserEvent } from '@/services/stream.js'; export const meta = { tags: ['channels'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:channels', - params: { - channelId: { - validator: $.type(ID), - }, - }, - errors: { noSuchChannel: { message: 'No such channel.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + channelId: { type: 'string', format: 'misskey:id' }, + }, + required: ['channelId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const channel = await Channels.findOne({ id: ps.channelId, }); diff --git a/packages/backend/src/server/api/endpoints/channels/update.ts b/packages/backend/src/server/api/endpoints/channels/update.ts index 1f7108a1c..2f2b4aeeb 100644 --- a/packages/backend/src/server/api/endpoints/channels/update.ts +++ b/packages/backend/src/server/api/endpoints/channels/update.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Channels, DriveFiles } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Channels, DriveFiles } from '@/models/index.js'; export const meta = { tags: ['channels'], @@ -11,24 +9,6 @@ export const meta = { kind: 'write:channels', - params: { - channelId: { - validator: $.type(ID), - }, - - name: { - validator: $.optional.str.range(1, 128), - }, - - description: { - validator: $.nullable.optional.str.range(1, 2048), - }, - - bannerId: { - validator: $.nullable.optional.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -56,8 +36,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + channelId: { type: 'string', format: 'misskey:id' }, + name: { type: 'string', minLength: 1, maxLength: 128 }, + description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, + bannerId: { type: 'string', format: 'misskey:id', nullable: true }, + }, + required: ['channelId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const channel = await Channels.findOne({ id: ps.channelId, }); diff --git a/packages/backend/src/server/api/endpoints/charts/active-users.ts b/packages/backend/src/server/api/endpoints/charts/active-users.ts index f7eadc708..97f7885db 100644 --- a/packages/backend/src/server/api/endpoints/charts/active-users.ts +++ b/packages/backend/src/server/api/endpoints/charts/active-users.ts @@ -1,31 +1,24 @@ -import $ from 'cafy'; -import define from '../../define'; -import { convertLog } from '@/services/chart/core'; -import { activeUsersChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { activeUsersChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'users'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(activeUsersChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, }, - - res: convertLog(activeUsersChart.schema), + required: ['span'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await activeUsersChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); +export default define(meta, paramDef, async (ps) => { + return await activeUsersChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); }); diff --git a/packages/backend/src/server/api/endpoints/charts/ap-request.ts b/packages/backend/src/server/api/endpoints/charts/ap-request.ts new file mode 100644 index 000000000..4477bfc98 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/charts/ap-request.ts @@ -0,0 +1,24 @@ +import define from '../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { apRequestChart } from '@/services/chart/index.js'; + +export const meta = { + tags: ['charts'], + + res: getJsonSchema(apRequestChart.schema), +} as const; + +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, + }, + required: ['span'], +} as const; + +// eslint-disable-next-line import/no-default-export +export default define(meta, paramDef, async (ps) => { + return await apRequestChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); +}); diff --git a/packages/backend/src/server/api/endpoints/charts/drive.ts b/packages/backend/src/server/api/endpoints/charts/drive.ts index 364279da9..fd6033392 100644 --- a/packages/backend/src/server/api/endpoints/charts/drive.ts +++ b/packages/backend/src/server/api/endpoints/charts/drive.ts @@ -1,31 +1,24 @@ -import $ from 'cafy'; -import define from '../../define'; -import { convertLog } from '@/services/chart/core'; -import { driveChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { driveChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'drive'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(driveChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, }, - - res: convertLog(driveChart.schema), + required: ['span'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await driveChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); +export default define(meta, paramDef, async (ps) => { + return await driveChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); }); diff --git a/packages/backend/src/server/api/endpoints/charts/federation.ts b/packages/backend/src/server/api/endpoints/charts/federation.ts index 6feb82b6d..f842f574e 100644 --- a/packages/backend/src/server/api/endpoints/charts/federation.ts +++ b/packages/backend/src/server/api/endpoints/charts/federation.ts @@ -1,31 +1,24 @@ -import $ from 'cafy'; -import define from '../../define'; -import { convertLog } from '@/services/chart/core'; -import { federationChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { federationChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(federationChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, }, - - res: convertLog(federationChart.schema), + required: ['span'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await federationChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); +export default define(meta, paramDef, async (ps) => { + return await federationChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); }); diff --git a/packages/backend/src/server/api/endpoints/charts/hashtag.ts b/packages/backend/src/server/api/endpoints/charts/hashtag.ts index 99dc77998..01407defd 100644 --- a/packages/backend/src/server/api/endpoints/charts/hashtag.ts +++ b/packages/backend/src/server/api/endpoints/charts/hashtag.ts @@ -1,35 +1,25 @@ -import $ from 'cafy'; -import define from '../../define'; -import { convertLog } from '@/services/chart/core'; -import { hashtagChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { hashtagChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'hashtags'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(hashtagChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, - - tag: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, + tag: { type: 'string' }, }, - - res: convertLog(hashtagChart.schema), + required: ['span', 'tag'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await hashtagChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.tag); +export default define(meta, paramDef, async (ps) => { + return await hashtagChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.tag); }); diff --git a/packages/backend/src/server/api/endpoints/charts/instance.ts b/packages/backend/src/server/api/endpoints/charts/instance.ts index 23e6fbf2b..2d12951c6 100644 --- a/packages/backend/src/server/api/endpoints/charts/instance.ts +++ b/packages/backend/src/server/api/endpoints/charts/instance.ts @@ -1,35 +1,25 @@ -import $ from 'cafy'; -import define from '../../define'; -import { convertLog } from '@/services/chart/core'; -import { instanceChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { instanceChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(instanceChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, - - host: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, + host: { type: 'string' }, }, - - res: convertLog(instanceChart.schema), + required: ['span', 'host'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await instanceChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.host); +export default define(meta, paramDef, async (ps) => { + return await instanceChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.host); }); diff --git a/packages/backend/src/server/api/endpoints/charts/network.ts b/packages/backend/src/server/api/endpoints/charts/network.ts deleted file mode 100644 index c5a39bbd7..000000000 --- a/packages/backend/src/server/api/endpoints/charts/network.ts +++ /dev/null @@ -1,31 +0,0 @@ -import $ from 'cafy'; -import define from '../../define'; -import { convertLog } from '@/services/chart/core'; -import { networkChart } from '@/services/chart/index'; - -export const meta = { - tags: ['charts'], - - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, - - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, - }, - - res: convertLog(networkChart.schema), -} as const; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await networkChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); -}); diff --git a/packages/backend/src/server/api/endpoints/charts/notes.ts b/packages/backend/src/server/api/endpoints/charts/notes.ts index dcbd80c3e..b6089f67e 100644 --- a/packages/backend/src/server/api/endpoints/charts/notes.ts +++ b/packages/backend/src/server/api/endpoints/charts/notes.ts @@ -1,31 +1,24 @@ -import $ from 'cafy'; -import define from '../../define'; -import { convertLog } from '@/services/chart/core'; -import { notesChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { notesChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'notes'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(notesChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, }, - - res: convertLog(notesChart.schema), + required: ['span'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await notesChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); +export default define(meta, paramDef, async (ps) => { + return await notesChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); }); diff --git a/packages/backend/src/server/api/endpoints/charts/user/drive.ts b/packages/backend/src/server/api/endpoints/charts/user/drive.ts index 94787b4a5..e5db7131a 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/drive.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/drive.ts @@ -1,36 +1,25 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { convertLog } from '@/services/chart/core'; -import { perUserDriveChart } from '@/services/chart/index'; +import define from '../../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { perUserDriveChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'drive', 'users'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(perUserDriveChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, - - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, + userId: { type: 'string', format: 'misskey:id' }, }, - - res: convertLog(perUserDriveChart.schema), + required: ['span', 'userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await perUserDriveChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.userId); +export default define(meta, paramDef, async (ps) => { + return await perUserDriveChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.userId); }); diff --git a/packages/backend/src/server/api/endpoints/charts/user/following.ts b/packages/backend/src/server/api/endpoints/charts/user/following.ts index effe0c54b..9b72de745 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/following.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/following.ts @@ -1,36 +1,25 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { convertLog } from '@/services/chart/core'; -import { perUserFollowingChart } from '@/services/chart/index'; +import define from '../../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { perUserFollowingChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'users', 'following'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(perUserFollowingChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, - - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, + userId: { type: 'string', format: 'misskey:id' }, }, - - res: convertLog(perUserFollowingChart.schema), + required: ['span', 'userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await perUserFollowingChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.userId); +export default define(meta, paramDef, async (ps) => { + return await perUserFollowingChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.userId); }); diff --git a/packages/backend/src/server/api/endpoints/charts/user/notes.ts b/packages/backend/src/server/api/endpoints/charts/user/notes.ts index df68a5fe5..7cc6cbf31 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/notes.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/notes.ts @@ -1,36 +1,25 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { convertLog } from '@/services/chart/core'; -import { perUserNotesChart } from '@/services/chart/index'; +import define from '../../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { perUserNotesChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'users', 'notes'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(perUserNotesChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, - - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, + userId: { type: 'string', format: 'misskey:id' }, }, - - res: convertLog(perUserNotesChart.schema), + required: ['span', 'userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await perUserNotesChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.userId); +export default define(meta, paramDef, async (ps) => { + return await perUserNotesChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.userId); }); diff --git a/packages/backend/src/server/api/endpoints/charts/user/reactions.ts b/packages/backend/src/server/api/endpoints/charts/user/reactions.ts index dcd067305..5c58a7f15 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/reactions.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/reactions.ts @@ -1,36 +1,25 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ID } from '@/misc/cafy-id'; -import { convertLog } from '@/services/chart/core'; -import { perUserReactionsChart } from '@/services/chart/index'; +import define from '../../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { perUserReactionsChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'users', 'reactions'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(perUserReactionsChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, - - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, + userId: { type: 'string', format: 'misskey:id' }, }, - - res: convertLog(perUserReactionsChart.schema), + required: ['span', 'userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await perUserReactionsChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.userId); +export default define(meta, paramDef, async (ps) => { + return await perUserReactionsChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null, ps.userId); }); diff --git a/packages/backend/src/server/api/endpoints/charts/users.ts b/packages/backend/src/server/api/endpoints/charts/users.ts index d32e14ad6..49c762b2e 100644 --- a/packages/backend/src/server/api/endpoints/charts/users.ts +++ b/packages/backend/src/server/api/endpoints/charts/users.ts @@ -1,31 +1,24 @@ -import $ from 'cafy'; -import define from '../../define'; -import { convertLog } from '@/services/chart/core'; -import { usersChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { getJsonSchema } from '@/services/chart/core.js'; +import { usersChart } from '@/services/chart/index.js'; export const meta = { tags: ['charts', 'users'], - params: { - span: { - validator: $.str.or(['day', 'hour']), - }, + res: getJsonSchema(usersChart.schema), +} as const; - limit: { - validator: $.optional.num.range(1, 500), - default: 30, - }, - - offset: { - validator: $.optional.nullable.num, - default: null, - }, +export const paramDef = { + type: 'object', + properties: { + span: { type: 'string', enum: ['day', 'hour'] }, + limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 }, + offset: { type: 'integer', nullable: true, default: null }, }, - - res: convertLog(usersChart.schema), + required: ['span'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { - return await usersChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); +export default define(meta, paramDef, async (ps) => { + return await usersChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null); }); diff --git a/packages/backend/src/server/api/endpoints/clips/add-note.ts b/packages/backend/src/server/api/endpoints/clips/add-note.ts index 4a740b6cf..c630302b9 100644 --- a/packages/backend/src/server/api/endpoints/clips/add-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/add-note.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ClipNotes, Clips } from '@/models/index'; -import { ApiError } from '../../error'; -import { genId } from '@/misc/gen-id'; -import { getNote } from '../../common/getters'; +import define from '../../define.js'; +import { ClipNotes, Clips } from '@/models/index.js'; +import { ApiError } from '../../error.js'; +import { genId } from '@/misc/gen-id.js'; +import { getNote } from '../../common/getters.js'; export const meta = { tags: ['account', 'notes', 'clips'], @@ -13,16 +11,6 @@ export const meta = { kind: 'write:account', - params: { - clipId: { - validator: $.type(ID), - }, - - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchClip: { message: 'No such clip.', @@ -44,8 +32,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + clipId: { type: 'string', format: 'misskey:id' }, + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['clipId', 'noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const clip = await Clips.findOne({ id: ps.clipId, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/clips/create.ts b/packages/backend/src/server/api/endpoints/clips/create.ts index 852e66c9e..531847d15 100644 --- a/packages/backend/src/server/api/endpoints/clips/create.ts +++ b/packages/backend/src/server/api/endpoints/clips/create.ts @@ -1,7 +1,6 @@ -import $ from 'cafy'; -import define from '../../define'; -import { genId } from '@/misc/gen-id'; -import { Clips } from '@/models/index'; +import define from '../../define.js'; +import { genId } from '@/misc/gen-id.js'; +import { Clips } from '@/models/index.js'; export const meta = { tags: ['clips'], @@ -10,20 +9,6 @@ export const meta = { kind: 'write:account', - params: { - name: { - validator: $.str.range(1, 100), - }, - - isPublic: { - validator: $.optional.bool, - }, - - description: { - validator: $.optional.nullable.str.range(1, 2048), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -31,8 +16,18 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string', minLength: 1, maxLength: 100 }, + isPublic: { type: 'boolean' }, + description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, + }, + required: ['name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const clip = await Clips.insert({ id: genId(), createdAt: new Date(), diff --git a/packages/backend/src/server/api/endpoints/clips/delete.ts b/packages/backend/src/server/api/endpoints/clips/delete.ts index 85c64a115..675db1d57 100644 --- a/packages/backend/src/server/api/endpoints/clips/delete.ts +++ b/packages/backend/src/server/api/endpoints/clips/delete.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Clips } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Clips } from '@/models/index.js'; export const meta = { tags: ['clips'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:account', - params: { - clipId: { - validator: $.type(ID), - }, - }, - errors: { noSuchClip: { message: 'No such clip.', @@ -26,8 +18,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + clipId: { type: 'string', format: 'misskey:id' }, + }, + required: ['clipId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const clip = await Clips.findOne({ id: ps.clipId, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/clips/list.ts b/packages/backend/src/server/api/endpoints/clips/list.ts index d88897d16..1c955d64f 100644 --- a/packages/backend/src/server/api/endpoints/clips/list.ts +++ b/packages/backend/src/server/api/endpoints/clips/list.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { Clips } from '@/models/index'; +import define from '../../define.js'; +import { Clips } from '@/models/index.js'; export const meta = { tags: ['clips', 'account'], @@ -19,8 +19,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const clips = await Clips.find({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts index eeb20631c..2627884ee 100644 --- a/packages/backend/src/server/api/endpoints/clips/notes.ts +++ b/packages/backend/src/server/api/endpoints/clips/notes.ts @@ -1,12 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ClipNotes, Clips, Notes } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { ApiError } from '../../error'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import define from '../../define.js'; +import { ClipNotes, Clips, Notes } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { ApiError } from '../../error.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['account', 'notes', 'clips'], @@ -15,25 +13,6 @@ export const meta = { kind: 'read:account', - params: { - clipId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - errors: { noSuchClip: { message: 'No such clip.', @@ -53,8 +32,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + clipId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: ['clipId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const clip = await Clips.findOne({ id: ps.clipId, }); @@ -74,10 +64,16 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.id IN (${ clipQuery.getQuery() })`) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .setParameters(clipQuery.getParameters()); if (user) { @@ -87,7 +83,7 @@ export default define(meta, async (ps, user) => { } const notes = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Notes.packMany(notes, user); diff --git a/packages/backend/src/server/api/endpoints/clips/show.ts b/packages/backend/src/server/api/endpoints/clips/show.ts index 0a4567201..0a3b25c94 100644 --- a/packages/backend/src/server/api/endpoints/clips/show.ts +++ b/packages/backend/src/server/api/endpoints/clips/show.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Clips } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Clips } from '@/models/index.js'; export const meta = { tags: ['clips', 'account'], @@ -11,12 +9,6 @@ export const meta = { kind: 'read:account', - params: { - clipId: { - validator: $.type(ID), - }, - }, - errors: { noSuchClip: { message: 'No such clip.', @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + clipId: { type: 'string', format: 'misskey:id' }, + }, + required: ['clipId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the clip const clip = await Clips.findOne({ id: ps.clipId, diff --git a/packages/backend/src/server/api/endpoints/clips/update.ts b/packages/backend/src/server/api/endpoints/clips/update.ts index 795483d5b..0ac5ccd04 100644 --- a/packages/backend/src/server/api/endpoints/clips/update.ts +++ b/packages/backend/src/server/api/endpoints/clips/update.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Clips } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Clips } from '@/models/index.js'; export const meta = { tags: ['clips'], @@ -11,24 +9,6 @@ export const meta = { kind: 'write:account', - params: { - clipId: { - validator: $.type(ID), - }, - - name: { - validator: $.str.range(1, 100), - }, - - isPublic: { - validator: $.optional.bool, - }, - - description: { - validator: $.optional.nullable.str.range(1, 2048), - }, - }, - errors: { noSuchClip: { message: 'No such clip.', @@ -44,8 +24,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + clipId: { type: 'string', format: 'misskey:id' }, + name: { type: 'string', minLength: 1, maxLength: 100 }, + isPublic: { type: 'boolean' }, + description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, + }, + required: ['clipId', 'name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch the clip const clip = await Clips.findOne({ id: ps.clipId, diff --git a/packages/backend/src/server/api/endpoints/drive.ts b/packages/backend/src/server/api/endpoints/drive.ts index d9ab9883c..c599d96ca 100644 --- a/packages/backend/src/server/api/endpoints/drive.ts +++ b/packages/backend/src/server/api/endpoints/drive.ts @@ -1,6 +1,6 @@ -import define from '../define'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { DriveFiles } from '@/models/index'; +import define from '../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['drive', 'account'], @@ -25,8 +25,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const instance = await fetchMeta(true); // Calculate drive usage diff --git a/packages/backend/src/server/api/endpoints/drive/files.ts b/packages/backend/src/server/api/endpoints/drive/files.ts index a5c0a626a..40e6c16c9 100644 --- a/packages/backend/src/server/api/endpoints/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/drive/files.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { DriveFiles } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { DriveFiles } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['drive'], @@ -11,30 +9,6 @@ export const meta = { kind: 'read:drive', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - folderId: { - validator: $.optional.nullable.type(ID), - default: null, - }, - - type: { - validator: $.optional.nullable.str.match(/^[a-zA-Z\/\-*]+$/), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -46,8 +20,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + type: { type: 'string', nullable: true, pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId) .andWhere('file.userId = :userId', { userId: user.id }); @@ -65,7 +51,7 @@ export default define(meta, async (ps, user) => { } } - const files = await query.take(ps.limit!).getMany(); + const files = await query.take(ps.limit).getMany(); return await DriveFiles.packMany(files, { detail: false, self: true }); }); diff --git a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts index 835dde805..3c68beee1 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { DriveFiles, Notes } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { DriveFiles, Notes } from '@/models/index.js'; export const meta = { tags: ['drive', 'notes'], @@ -11,12 +9,6 @@ export const meta = { kind: 'read:drive', - params: { - fileId: { - validator: $.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -36,8 +28,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch file const file = await DriveFiles.findOne({ id: ps.fileId, diff --git a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts index a45d357ee..7e5cb2498 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts @@ -1,6 +1,5 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { DriveFiles } from '@/models/index'; +import define from '../../../define.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -9,20 +8,22 @@ export const meta = { kind: 'read:drive', - params: { - md5: { - validator: $.str, - }, - }, - res: { type: 'boolean', optional: false, nullable: false, }, } as const; +export const paramDef = { + type: 'object', + properties: { + md5: { type: 'string' }, + }, + required: ['md5'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOne({ md5: ps.md5, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/drive/files/create.ts b/packages/backend/src/server/api/endpoints/drive/files/create.ts index dd65ab061..b6a2cf720 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/create.ts @@ -1,12 +1,10 @@ import ms from 'ms'; -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { addFile } from '@/services/drive/add-file'; -import define from '../../../define'; -import { apiLogger } from '../../../logger'; -import { ApiError } from '../../../error'; -import { DriveFiles } from '@/models/index'; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits'; +import { addFile } from '@/services/drive/add-file.js'; +import define from '../../../define.js'; +import { apiLogger } from '../../../logger.js'; +import { ApiError } from '../../../error.js'; +import { DriveFiles } from '@/models/index.js'; +import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; export const meta = { tags: ['drive'], @@ -22,35 +20,6 @@ export const meta = { kind: 'write:drive', - params: { - folderId: { - validator: $.optional.nullable.type(ID), - default: null, - }, - - name: { - validator: $.optional.nullable.str, - default: null, - }, - - comment: { - validator: $.optional.nullable.str.max(DB_MAX_IMAGE_COMMENT_LENGTH), - default: null, - }, - - isSensitive: { - validator: $.optional.either($.bool, $.str), - default: false, - transform: (v: any): boolean => v === true || v === 'true', - }, - - force: { - validator: $.optional.either($.bool, $.str), - default: false, - transform: (v: any): boolean => v === true || v === 'true', - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -66,8 +35,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + name: { type: 'string', nullable: true, default: null }, + comment: { type: 'string', nullable: true, maxLength: DB_MAX_IMAGE_COMMENT_LENGTH, default: null }, + isSensitive: { type: 'boolean', default: false }, + force: { type: 'boolean', default: false }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user, _, file, cleanup) => { +// @ts-ignore +export default define(meta, paramDef, async (ps, user, _, file, cleanup) => { // Get 'name' parameter let name = ps.name || file.originalname; if (name !== undefined && name !== null) { @@ -88,7 +70,9 @@ export default define(meta, async (ps, user, _, file, cleanup) => { const driveFile = await addFile({ user, path: file.path, name, comment: ps.comment, folderId: ps.folderId, force: ps.force, sensitive: ps.isSensitive }); return await DriveFiles.pack(driveFile, { self: true }); } catch (e) { - apiLogger.error(e); + if (e instanceof Error || typeof e === 'string') { + apiLogger.error(e); + } throw new ApiError(); } finally { cleanup!(); diff --git a/packages/backend/src/server/api/endpoints/drive/files/delete.ts b/packages/backend/src/server/api/endpoints/drive/files/delete.ts index 308beb58a..5f565a63f 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/delete.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { deleteFile } from '@/services/drive/delete-file'; -import { publishDriveStream } from '@/services/stream'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { DriveFiles } from '@/models/index'; +import { deleteFile } from '@/services/drive/delete-file.js'; +import { publishDriveStream } from '@/services/stream.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -13,12 +11,6 @@ export const meta = { kind: 'write:drive', - params: { - fileId: { - validator: $.type(ID), - }, - }, - errors: { noSuchFile: { message: 'No such file.', @@ -34,8 +26,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOne(ps.fileId); if (file == null) { diff --git a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts index dc74dcb7e..e45ec633d 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts @@ -1,6 +1,5 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { DriveFiles } from '@/models/index'; +import define from '../../../define.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -9,12 +8,6 @@ export const meta = { kind: 'read:drive', - params: { - md5: { - validator: $.str, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -26,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + md5: { type: 'string' }, + }, + required: ['md5'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const files = await DriveFiles.find({ md5: ps.md5, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/drive/files/find.ts b/packages/backend/src/server/api/endpoints/drive/files/find.ts index 2244df13c..974fc9fba 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find.ts @@ -1,7 +1,5 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { DriveFiles } from '@/models/index'; +import define from '../../../define.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { requireCredential: true, @@ -10,17 +8,6 @@ export const meta = { kind: 'read:drive', - params: { - name: { - validator: $.str, - }, - - folderId: { - validator: $.optional.nullable.type(ID), - default: null, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -32,8 +19,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + }, + required: ['name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const files = await DriveFiles.find({ name: ps.name, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/drive/files/show.ts b/packages/backend/src/server/api/endpoints/drive/files/show.ts index 18b17c465..181365c7e 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/show.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { DriveFile } from '@/models/entities/drive-file'; -import { DriveFiles } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -12,16 +10,6 @@ export const meta = { kind: 'read:drive', - params: { - fileId: { - validator: $.optional.type(ID), - }, - - url: { - validator: $.optional.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -49,8 +37,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + url: { type: 'string' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { let file: DriveFile | undefined; if (ps.fileId) { diff --git a/packages/backend/src/server/api/endpoints/drive/files/update.ts b/packages/backend/src/server/api/endpoints/drive/files/update.ts index b7ca80e83..ab8e4aeeb 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/update.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { publishDriveStream } from '@/services/stream'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { DriveFiles, DriveFolders } from '@/models/index'; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits'; +import { publishDriveStream } from '@/services/stream.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { DriveFiles, DriveFolders } from '@/models/index.js'; +import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; export const meta = { tags: ['drive'], @@ -13,33 +11,13 @@ export const meta = { kind: 'write:drive', - params: { - fileId: { - validator: $.type(ID), - }, - - folderId: { - validator: $.optional.nullable.type(ID), - default: undefined as any, - }, - - name: { - validator: $.optional.str.pipe(DriveFiles.validateFileName), - default: undefined as any, - }, - - isSensitive: { - validator: $.optional.bool, - default: undefined as any, - }, - - comment: { - validator: $.optional.nullable.str.max(DB_MAX_IMAGE_COMMENT_LENGTH), - default: undefined as any, - }, - }, - errors: { + invalidFileName: { + message: 'Invalid file name.', + code: 'INVALID_FILE_NAME', + id: '395e7156-f9f0-475e-af89-53c3c23080c2', + }, + noSuchFile: { message: 'No such file.', code: 'NO_SUCH_FILE', @@ -66,8 +44,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true }, + name: { type: 'string' }, + isSensitive: { type: 'boolean' }, + comment: { type: 'string', nullable: true, maxLength: 512 }, + }, + required: ['fileId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOne(ps.fileId); if (file == null) { @@ -79,6 +69,9 @@ export default define(meta, async (ps, user) => { } if (ps.name) file.name = ps.name; + if (!DriveFiles.validateFileName(file.name)) { + throw new ApiError(meta.errors.invalidFileName); + } if (ps.comment !== undefined) file.comment = ps.comment; diff --git a/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts b/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts index 40da1a4fb..3bfecac80 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; import ms from 'ms'; -import { uploadFromUrl } from '@/services/drive/upload-from-url'; -import define from '../../../define'; -import { DriveFiles } from '@/models/index'; -import { publishMainStream } from '@/services/stream'; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits'; +import { uploadFromUrl } from '@/services/drive/upload-from-url.js'; +import define from '../../../define.js'; +import { DriveFiles } from '@/models/index.js'; +import { publishMainStream } from '@/services/stream.js'; +import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; export const meta = { tags: ['drive'], @@ -18,42 +16,23 @@ export const meta = { requireCredential: true, kind: 'write:drive', +} as const; - params: { - url: { - // TODO: Validate this url - validator: $.str, - }, - - folderId: { - validator: $.optional.nullable.type(ID), - default: null, - }, - - isSensitive: { - validator: $.optional.bool, - default: false, - }, - - comment: { - validator: $.optional.nullable.str.max(DB_MAX_IMAGE_COMMENT_LENGTH), - default: null, - }, - - marker: { - validator: $.optional.nullable.str, - default: null, - }, - - force: { - validator: $.optional.bool, - default: false, - }, +export const paramDef = { + type: 'object', + properties: { + url: { type: 'string' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + isSensitive: { type: 'boolean', default: false }, + comment: { type: 'string', nullable: true, maxLength: 512, default: null }, + marker: { type: 'string', nullable: true, default: null }, + force: { type: 'boolean', default: false }, }, + required: ['url'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { uploadFromUrl({ url: ps.url, user, folderId: ps.folderId, sensitive: ps.isSensitive, force: ps.force, comment: ps.comment }).then(file => { DriveFiles.pack(file, { self: true }).then(packedFile => { publishMainStream(user.id, 'urlUploadFinished', { diff --git a/packages/backend/src/server/api/endpoints/drive/folders.ts b/packages/backend/src/server/api/endpoints/drive/folders.ts index 8f8d1d2c0..d4d530ba9 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { DriveFolders } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { DriveFolders } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['drive'], @@ -11,26 +9,6 @@ export const meta = { kind: 'read:drive', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - folderId: { - validator: $.optional.nullable.type(ID), - default: null, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -42,8 +20,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(DriveFolders.createQueryBuilder('folder'), ps.sinceId, ps.untilId) .andWhere('folder.userId = :userId', { userId: user.id }); @@ -53,7 +42,7 @@ export default define(meta, async (ps, user) => { query.andWhere('folder.parentId IS NULL'); } - const folders = await query.take(ps.limit!).getMany(); + const folders = await query.take(ps.limit).getMany(); return await Promise.all(folders.map(folder => DriveFolders.pack(folder))); }); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/create.ts b/packages/backend/src/server/api/endpoints/drive/folders/create.ts index 38ed17e0e..4ae10f062 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/create.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { publishDriveStream } from '@/services/stream'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { DriveFolders } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import { publishDriveStream } from '@/services/stream.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { DriveFolders } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['drive'], @@ -13,17 +11,6 @@ export const meta = { kind: 'write:drive', - params: { - name: { - validator: $.optional.str.pipe(DriveFolders.validateFolderName), - default: 'Untitled', - }, - - parentId: { - validator: $.optional.nullable.type(ID), - }, - }, - errors: { noSuchFolder: { message: 'No such folder.', @@ -39,8 +26,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string', default: "Untitled", maxLength: 200 }, + parentId: { type: 'string', format: 'misskey:id', nullable: true }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // If the parent folder is specified let parent = null; if (ps.parentId) { diff --git a/packages/backend/src/server/api/endpoints/drive/folders/delete.ts b/packages/backend/src/server/api/endpoints/drive/folders/delete.ts index 13716fcce..4994615cc 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/delete.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { publishDriveStream } from '@/services/stream'; -import { ApiError } from '../../../error'; -import { DriveFolders, DriveFiles } from '@/models/index'; +import define from '../../../define.js'; +import { publishDriveStream } from '@/services/stream.js'; +import { ApiError } from '../../../error.js'; +import { DriveFolders, DriveFiles } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:drive', - params: { - folderId: { - validator: $.type(ID), - }, - }, - errors: { noSuchFolder: { message: 'No such folder.', @@ -33,8 +25,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + folderId: { type: 'string', format: 'misskey:id' }, + }, + required: ['folderId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Get folder const folder = await DriveFolders.findOne({ id: ps.folderId, diff --git a/packages/backend/src/server/api/endpoints/drive/folders/find.ts b/packages/backend/src/server/api/endpoints/drive/folders/find.ts index 911f51d78..9bf0e3d61 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/find.ts @@ -1,7 +1,5 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { DriveFolders } from '@/models/index'; +import define from '../../../define.js'; +import { DriveFolders } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -10,17 +8,6 @@ export const meta = { kind: 'read:drive', - params: { - name: { - validator: $.str, - }, - - parentId: { - validator: $.optional.nullable.type(ID), - default: null, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -32,8 +19,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string' }, + parentId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + }, + required: ['name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const folders = await DriveFolders.find({ name: ps.name, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/drive/folders/show.ts b/packages/backend/src/server/api/endpoints/drive/folders/show.ts index 58a6dd3c0..f09816d57 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/show.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { DriveFolders } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { DriveFolders } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -11,12 +9,6 @@ export const meta = { kind: 'read:drive', - params: { - folderId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + folderId: { type: 'string', format: 'misskey:id' }, + }, + required: ['folderId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Get folder const folder = await DriveFolders.findOne({ id: ps.folderId, diff --git a/packages/backend/src/server/api/endpoints/drive/folders/update.ts b/packages/backend/src/server/api/endpoints/drive/folders/update.ts index 5b0cccd1c..c020b243e 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/update.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { publishDriveStream } from '@/services/stream'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { DriveFolders } from '@/models/index'; +import { publishDriveStream } from '@/services/stream.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { DriveFolders } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -12,20 +10,6 @@ export const meta = { kind: 'write:drive', - params: { - folderId: { - validator: $.type(ID), - }, - - name: { - validator: $.optional.str.pipe(DriveFolders.validateFolderName), - }, - - parentId: { - validator: $.optional.nullable.type(ID), - }, - }, - errors: { noSuchFolder: { message: 'No such folder.', @@ -53,8 +37,18 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + folderId: { type: 'string', format: 'misskey:id' }, + name: { type: 'string', maxLength: 200 }, + parentId: { type: 'string', format: 'misskey:id', nullable: true }, + }, + required: ['folderId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch folder const folder = await DriveFolders.findOne({ id: ps.folderId, diff --git a/packages/backend/src/server/api/endpoints/drive/stream.ts b/packages/backend/src/server/api/endpoints/drive/stream.ts index 9ba780494..99e8d024f 100644 --- a/packages/backend/src/server/api/endpoints/drive/stream.ts +++ b/packages/backend/src/server/api/endpoints/drive/stream.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { DriveFiles } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { DriveFiles } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['drive'], @@ -11,25 +9,6 @@ export const meta = { kind: 'read:drive', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - type: { - validator: $.optional.str.match(/^[a-zA-Z\/\-*]+$/), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -41,8 +20,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + type: { type: 'string', pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId) .andWhere('file.userId = :userId', { userId: user.id }); @@ -54,7 +44,7 @@ export default define(meta, async (ps, user) => { } } - const files = await query.take(ps.limit!).getMany(); + const files = await query.take(ps.limit).getMany(); return await DriveFiles.packMany(files, { detail: false, self: true }); }); diff --git a/packages/backend/src/server/api/endpoints/email-address/available.ts b/packages/backend/src/server/api/endpoints/email-address/available.ts index 19f9b7ccd..07064ce9f 100644 --- a/packages/backend/src/server/api/endpoints/email-address/available.ts +++ b/packages/backend/src/server/api/endpoints/email-address/available.ts @@ -1,18 +1,11 @@ -import $ from 'cafy'; -import define from '../../define'; -import { validateEmailForAccount } from '@/services/validate-email-for-account'; +import define from '../../define.js'; +import { validateEmailForAccount } from '@/services/validate-email-for-account.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - emailAddress: { - validator: $.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -29,7 +22,15 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + emailAddress: { type: 'string' }, + }, + required: ['emailAddress'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { return await validateEmailForAccount(ps.emailAddress); }); diff --git a/packages/backend/src/server/api/endpoints/endpoint.ts b/packages/backend/src/server/api/endpoints/endpoint.ts index 42fd46883..9db140183 100644 --- a/packages/backend/src/server/api/endpoints/endpoint.ts +++ b/packages/backend/src/server/api/endpoints/endpoint.ts @@ -1,21 +1,22 @@ -import $ from 'cafy'; -import define from '../define'; -import endpoints from '../endpoints'; +import define from '../define.js'; +import endpoints from '../endpoints.js'; export const meta = { requireCredential: false, tags: ['meta'], +} as const; - params: { - endpoint: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + endpoint: { type: 'string' }, }, + required: ['endpoint'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const ep = endpoints.find(x => x.name === ps.endpoint); if (ep == null) return null; return { diff --git a/packages/backend/src/server/api/endpoints/endpoints.ts b/packages/backend/src/server/api/endpoints/endpoints.ts index ebb78de33..b20da96eb 100644 --- a/packages/backend/src/server/api/endpoints/endpoints.ts +++ b/packages/backend/src/server/api/endpoints/endpoints.ts @@ -1,14 +1,11 @@ -import define from '../define'; -import endpoints from '../endpoints'; +import define from '../define.js'; +import endpoints from '../endpoints.js'; export const meta = { requireCredential: false, tags: ['meta'], - params: { - }, - res: { type: 'array', optional: false, nullable: false, @@ -25,7 +22,13 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { return endpoints.map(x => x.name); }); diff --git a/packages/backend/src/server/api/endpoints/export-custom-emojis.ts b/packages/backend/src/server/api/endpoints/export-custom-emojis.ts index 24c9f56aa..bc8d2e2ac 100644 --- a/packages/backend/src/server/api/endpoints/export-custom-emojis.ts +++ b/packages/backend/src/server/api/endpoints/export-custom-emojis.ts @@ -1,6 +1,5 @@ -import $ from 'cafy'; -import define from '../define'; -import { createExportCustomEmojisJob } from '@/queue/index'; +import define from '../define.js'; +import { createExportCustomEmojisJob } from '@/queue/index.js'; import ms from 'ms'; export const meta = { @@ -12,7 +11,13 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { createExportCustomEmojisJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/federation/followers.ts b/packages/backend/src/server/api/endpoints/federation/followers.ts index c0a85f166..7b1197d1e 100644 --- a/packages/backend/src/server/api/endpoints/federation/followers.ts +++ b/packages/backend/src/server/api/endpoints/federation/followers.ts @@ -1,33 +1,12 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Followings } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Followings } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['federation'], requireCredential: false, - params: { - host: { - validator: $.str, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -39,13 +18,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['host'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) .andWhere(`following.followeeHost = :host`, { host: ps.host }); const followings = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Followings.packMany(followings, me, { populateFollowee: true }); diff --git a/packages/backend/src/server/api/endpoints/federation/following.ts b/packages/backend/src/server/api/endpoints/federation/following.ts index 147f0aedb..ed1f142d8 100644 --- a/packages/backend/src/server/api/endpoints/federation/following.ts +++ b/packages/backend/src/server/api/endpoints/federation/following.ts @@ -1,33 +1,12 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Followings } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Followings } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['federation'], requireCredential: false, - params: { - host: { - validator: $.str, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -39,13 +18,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['host'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) .andWhere(`following.followerHost = :host`, { host: ps.host }); const followings = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Followings.packMany(followings, me, { populateFollowee: true }); diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 11df7ed6b..70fef051b 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -1,58 +1,13 @@ -import $ from 'cafy'; -import config from '@/config/index'; -import define from '../../define'; -import { Instances } from '@/models/index'; -import { fetchMeta } from '@/misc/fetch-meta'; +import config from '@/config/index.js'; +import define from '../../define.js'; +import { Instances } from '@/models/index.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; export const meta = { tags: ['federation'], requireCredential: false, - params: { - host: { - validator: $.optional.nullable.str, - }, - - blocked: { - validator: $.optional.nullable.bool, - }, - - notResponding: { - validator: $.optional.nullable.bool, - }, - - suspended: { - validator: $.optional.nullable.bool, - }, - - federating: { - validator: $.optional.nullable.bool, - }, - - subscribing: { - validator: $.optional.nullable.bool, - }, - - publishing: { - validator: $.optional.nullable.bool, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 30, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - - sort: { - validator: $.optional.str, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -64,8 +19,25 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string', nullable: true }, + blocked: { type: 'boolean', nullable: true }, + notResponding: { type: 'boolean', nullable: true }, + suspended: { type: 'boolean', nullable: true }, + federating: { type: 'boolean', nullable: true }, + subscribing: { type: 'boolean', nullable: true }, + publishing: { type: 'boolean', nullable: true }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, + offset: { type: 'integer', default: 0 }, + sort: { type: 'string' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = Instances.createQueryBuilder('instance'); switch (ps.sort) { @@ -144,7 +116,7 @@ export default define(meta, async (ps, me) => { query.andWhere('instance.host like :host', { host: '%' + ps.host.toLowerCase() + '%' }); } - const instances = await query.take(ps.limit!).skip(ps.offset).getMany(); + const instances = await query.take(ps.limit).skip(ps.offset).getMany(); - return instances; + return await Instances.packMany(instances); }); diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index 6f13b28ca..5bfe43fc9 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -1,30 +1,34 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Instances } from '@/models/index'; -import { toPuny } from '@/misc/convert-host'; +import define from '../../define.js'; +import { Instances } from '@/models/index.js'; +import { toPuny } from '@/misc/convert-host.js'; export const meta = { tags: ['federation'], requireCredential: false, - params: { - host: { - validator: $.str, - }, - }, - res: { - type: 'object', - optional: true, nullable: false, - ref: 'FederationInstance', + oneOf: [{ + type: 'object', + ref: 'FederationInstance', + }, { + type: 'null', + }], }, } as const; +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string' }, + }, + required: ['host'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const instance = await Instances .findOne({ host: toPuny(ps.host) }); - return instance; + return instance ? await Instances.pack(instance) : null; }); diff --git a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts index 092f805bc..409cc7695 100644 --- a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts +++ b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts @@ -1,23 +1,23 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { getRemoteUser } from '../../common/getters'; -import { updatePerson } from '@/remote/activitypub/models/person'; +import define from '../../define.js'; +import { getRemoteUser } from '../../common/getters.js'; +import { updatePerson } from '@/remote/activitypub/models/person.js'; export const meta = { tags: ['federation'], requireCredential: true, +} as const; - params: { - userId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const user = await getRemoteUser(ps.userId); await updatePerson(user.uri!); }); diff --git a/packages/backend/src/server/api/endpoints/federation/users.ts b/packages/backend/src/server/api/endpoints/federation/users.ts index 9a8f74993..65ad9f88d 100644 --- a/packages/backend/src/server/api/endpoints/federation/users.ts +++ b/packages/backend/src/server/api/endpoints/federation/users.ts @@ -1,33 +1,12 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Users } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Users } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['federation'], requireCredential: false, - params: { - host: { - validator: $.str, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -39,13 +18,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + host: { type: 'string' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['host'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(Users.createQueryBuilder('user'), ps.sinceId, ps.untilId) .andWhere(`user.host = :host`, { host: ps.host }); const users = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Users.packMany(users, me, { detail: true }); diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index 96aede455..8758a64a3 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -1,11 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; import ms from 'ms'; -import create from '@/services/following/create'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { Followings, Users } from '@/models/index'; +import create from '@/services/following/create.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { Followings, Users } from '@/models/index.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; export const meta = { tags: ['following', 'users'], @@ -19,12 +18,6 @@ export const meta = { kind: 'write:following', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -64,8 +57,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const follower = user; // č‡Ē分č‡ĒčēĢ @@ -92,8 +93,10 @@ export default define(meta, async (ps, user) => { try { await create(follower, followee); } catch (e) { - if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking); - if (e.id === '3338392a-f764-498d-8855-db939dcf8c48') throw new ApiError(meta.errors.blocked); + if (e instanceof IdentifiableError) { + if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking); + if (e.id === '3338392a-f764-498d-8855-db939dcf8c48') throw new ApiError(meta.errors.blocked); + } throw e; } diff --git a/packages/backend/src/server/api/endpoints/following/delete.ts b/packages/backend/src/server/api/endpoints/following/delete.ts index 4cd0c4945..47efc59b8 100644 --- a/packages/backend/src/server/api/endpoints/following/delete.ts +++ b/packages/backend/src/server/api/endpoints/following/delete.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; import ms from 'ms'; -import deleteFollowing from '@/services/following/delete'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { Followings, Users } from '@/models/index'; +import deleteFollowing from '@/services/following/delete.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { Followings, Users } from '@/models/index.js'; export const meta = { tags: ['following', 'users'], @@ -19,12 +17,6 @@ export const meta = { kind: 'write:following', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -52,8 +44,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const follower = user; // Check if the followee is yourself diff --git a/packages/backend/src/server/api/endpoints/following/invalidate.ts b/packages/backend/src/server/api/endpoints/following/invalidate.ts index 92e887e00..24d8256ca 100644 --- a/packages/backend/src/server/api/endpoints/following/invalidate.ts +++ b/packages/backend/src/server/api/endpoints/following/invalidate.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import * as ms from 'ms'; -import deleteFollowing from '@/services/following/delete'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { Followings, Users } from '@/models/index'; +import ms from 'ms'; +import deleteFollowing from '@/services/following/delete.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { Followings, Users } from '@/models/index.js'; export const meta = { tags: ['following', 'users'], @@ -19,12 +17,6 @@ export const meta = { kind: 'write:following', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -52,8 +44,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const followee = user; // Check if the follower is yourself diff --git a/packages/backend/src/server/api/endpoints/following/requests/accept.ts b/packages/backend/src/server/api/endpoints/following/requests/accept.ts index 7e7c056f5..e5df55375 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/accept.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/accept.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import acceptFollowRequest from '@/services/following/requests/accept'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; +import acceptFollowRequest from '@/services/following/requests/accept.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; export const meta = { tags: ['following', 'account'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:following', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch follower const follower = await getUser(ps.userId).catch(e => { if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); diff --git a/packages/backend/src/server/api/endpoints/following/requests/cancel.ts b/packages/backend/src/server/api/endpoints/following/requests/cancel.ts index 19ed02c15..80d37fb07 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/cancel.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/cancel.ts @@ -1,10 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import cancelFollowRequest from '@/services/following/requests/cancel'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { Users } from '@/models/index'; +import cancelFollowRequest from '@/services/following/requests/cancel.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; +import { Users } from '@/models/index.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; export const meta = { tags: ['following', 'account'], @@ -13,12 +12,6 @@ export const meta = { kind: 'write:following', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -40,8 +33,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch followee const followee = await getUser(ps.userId).catch(e => { if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); @@ -51,7 +52,9 @@ export default define(meta, async (ps, user) => { try { await cancelFollowRequest(followee, user); } catch (e) { - if (e.id === '17447091-ce07-46dd-b331-c1fd4f15b1e7') throw new ApiError(meta.errors.followRequestNotFound); + if (e instanceof IdentifiableError) { + if (e.id === '17447091-ce07-46dd-b331-c1fd4f15b1e7') throw new ApiError(meta.errors.followRequestNotFound); + } throw e; } diff --git a/packages/backend/src/server/api/endpoints/following/requests/list.ts b/packages/backend/src/server/api/endpoints/following/requests/list.ts index ec0c76502..3b60b89b3 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/list.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/list.ts @@ -1,5 +1,5 @@ -import define from '../../../define'; -import { FollowRequests } from '@/models/index'; +import define from '../../../define.js'; +import { FollowRequests } from '@/models/index.js'; export const meta = { tags: ['following', 'account'], @@ -35,8 +35,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const reqs = await FollowRequests.find({ followeeId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/following/requests/reject.ts b/packages/backend/src/server/api/endpoints/following/requests/reject.ts index a5ce1e7c7..cebe60428 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/reject.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/reject.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { rejectFollowRequest } from '@/services/following/reject'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; +import { rejectFollowRequest } from '@/services/following/reject.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; export const meta = { tags: ['following', 'account'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:following', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch follower const follower = await getUser(ps.userId).catch(e => { if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); diff --git a/packages/backend/src/server/api/endpoints/gallery/featured.ts b/packages/backend/src/server/api/endpoints/gallery/featured.ts index ff7c16889..e6acd3691 100644 --- a/packages/backend/src/server/api/endpoints/gallery/featured.ts +++ b/packages/backend/src/server/api/endpoints/gallery/featured.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { GalleryPosts } from '@/models/index'; +import define from '../../define.js'; +import { GalleryPosts } from '@/models/index.js'; export const meta = { tags: ['gallery'], @@ -17,8 +17,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = GalleryPosts.createQueryBuilder('post') .andWhere('post.createdAt > :date', { date: new Date(Date.now() - (1000 * 60 * 60 * 24 * 3)) }) .andWhere('post.likedCount > 0') diff --git a/packages/backend/src/server/api/endpoints/gallery/popular.ts b/packages/backend/src/server/api/endpoints/gallery/popular.ts index 2c3368a19..c4c8982fc 100644 --- a/packages/backend/src/server/api/endpoints/gallery/popular.ts +++ b/packages/backend/src/server/api/endpoints/gallery/popular.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { GalleryPosts } from '@/models/index'; +import define from '../../define.js'; +import { GalleryPosts } from '@/models/index.js'; export const meta = { tags: ['gallery'], @@ -17,8 +17,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = GalleryPosts.createQueryBuilder('post') .andWhere('post.likedCount > 0') .orderBy('post.likedCount', 'DESC'); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts.ts b/packages/backend/src/server/api/endpoints/gallery/posts.ts index 9d2601c7e..428ba9cc7 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts.ts @@ -1,27 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { GalleryPosts } from '@/models/index'; +import define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { GalleryPosts } from '@/models/index.js'; export const meta = { tags: ['gallery'], - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -33,12 +16,22 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId) .innerJoinAndSelect('post.user', 'user'); - const posts = await query.take(ps.limit!).getMany(); + const posts = await query.take(ps.limit).getMany(); return await GalleryPosts.packMany(posts, me); }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts index e9d5df1ab..eb6c0f3eb 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts @@ -1,12 +1,10 @@ -import $ from 'cafy'; import ms from 'ms'; -import define from '../../../define'; -import { ID } from '../../../../../misc/cafy-id'; -import { DriveFiles, GalleryPosts } from '@/models/index'; -import { genId } from '../../../../../misc/gen-id'; -import { GalleryPost } from '@/models/entities/gallery-post'; -import { ApiError } from '../../../error'; -import { DriveFile } from '@/models/entities/drive-file'; +import define from '../../../define.js'; +import { DriveFiles, GalleryPosts } from '@/models/index.js'; +import { genId } from '../../../../../misc/gen-id.js'; +import { GalleryPost } from '@/models/entities/gallery-post.js'; +import { ApiError } from '../../../error.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; export const meta = { tags: ['gallery'], @@ -20,25 +18,6 @@ export const meta = { max: 300, }, - params: { - title: { - validator: $.str.min(1), - }, - - description: { - validator: $.optional.nullable.str, - }, - - fileIds: { - validator: $.arr($.type(ID)).unique().range(1, 32), - }, - - isSensitive: { - validator: $.optional.bool, - default: false, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -50,8 +29,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + title: { type: 'string', minLength: 1 }, + description: { type: 'string', nullable: true }, + fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 32, items: { + type: 'string', format: 'misskey:id', + } }, + isSensitive: { type: 'boolean', default: false }, + }, + required: ['title', 'fileIds'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const files = (await Promise.all(ps.fileIds.map(fileId => DriveFiles.findOne({ id: fileId, diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts index 2a13b9ed5..f8bf785ee 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { GalleryPosts } from '@/models/index'; -import { ID } from '@/misc/cafy-id'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { GalleryPosts } from '@/models/index.js'; export const meta = { tags: ['gallery'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:gallery', - params: { - postId: { - validator: $.type(ID), - }, - }, - errors: { noSuchPost: { message: 'No such post.', @@ -26,8 +18,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + postId: { type: 'string', format: 'misskey:id' }, + }, + required: ['postId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const post = await GalleryPosts.findOne({ id: ps.postId, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts index 0fb408fa5..d154bfc3c 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { GalleryPosts, GalleryLikes } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { GalleryPosts, GalleryLikes } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['gallery'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:gallery-likes', - params: { - postId: { - validator: $.type(ID), - }, - }, - errors: { noSuchPost: { message: 'No such post.', @@ -39,8 +31,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + postId: { type: 'string', format: 'misskey:id' }, + }, + required: ['postId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const post = await GalleryPosts.findOne(ps.postId); if (post == null) { throw new ApiError(meta.errors.noSuchPost); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts index 4325d2ad3..5b4594070 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts @@ -1,20 +1,12 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { GalleryPosts } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { GalleryPosts } from '@/models/index.js'; export const meta = { tags: ['gallery'], requireCredential: false, - params: { - postId: { - validator: $.type(ID), - }, - }, - errors: { noSuchPost: { message: 'No such post.', @@ -30,8 +22,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + postId: { type: 'string', format: 'misskey:id' }, + }, + required: ['postId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const post = await GalleryPosts.findOne({ id: ps.postId, }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts index 9cca09bdd..b00008a86 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { GalleryPosts, GalleryLikes } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { GalleryPosts, GalleryLikes } from '@/models/index.js'; export const meta = { tags: ['gallery'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:gallery-likes', - params: { - postId: { - validator: $.type(ID), - }, - }, - errors: { noSuchPost: { message: 'No such post.', @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + postId: { type: 'string', format: 'misskey:id' }, + }, + required: ['postId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const post = await GalleryPosts.findOne(ps.postId); if (post == null) { throw new ApiError(meta.errors.noSuchPost); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts index c35e1bbf5..123794d08 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; import ms from 'ms'; -import define from '../../../define'; -import { ID } from '../../../../../misc/cafy-id'; -import { DriveFiles, GalleryPosts } from '@/models/index'; -import { GalleryPost } from '@/models/entities/gallery-post'; -import { ApiError } from '../../../error'; -import { DriveFile } from '@/models/entities/drive-file'; +import define from '../../../define.js'; +import { DriveFiles, GalleryPosts } from '@/models/index.js'; +import { GalleryPost } from '@/models/entities/gallery-post.js'; +import { ApiError } from '../../../error.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; export const meta = { tags: ['gallery'], @@ -19,29 +17,6 @@ export const meta = { max: 300, }, - params: { - postId: { - validator: $.type(ID), - }, - - title: { - validator: $.str.min(1), - }, - - description: { - validator: $.optional.nullable.str, - }, - - fileIds: { - validator: $.arr($.type(ID)).unique().range(1, 32), - }, - - isSensitive: { - validator: $.optional.bool, - default: false, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -53,8 +28,22 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + postId: { type: 'string', format: 'misskey:id' }, + title: { type: 'string', minLength: 1 }, + description: { type: 'string', nullable: true }, + fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 32, items: { + type: 'string', format: 'misskey:id', + } }, + isSensitive: { type: 'boolean', default: false }, + }, + required: ['postId', 'title', 'fileIds'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const files = (await Promise.all(ps.fileIds.map(fileId => DriveFiles.findOne({ id: fileId, diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts index 5b13d5a3b..80a2334cf 100644 --- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts +++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts @@ -1,19 +1,22 @@ -import { USER_ONLINE_THRESHOLD } from '@/const'; -import { Users } from '@/models/index'; +import { USER_ONLINE_THRESHOLD } from '@/const.js'; +import { Users } from '@/models/index.js'; import { MoreThan } from 'typeorm'; -import define from '../define'; +import define from '../define.js'; export const meta = { tags: ['meta'], requireCredential: false, +} as const; - params: { - }, +export const paramDef = { + type: 'object', + properties: {}, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { const count = await Users.count({ lastActiveDate: MoreThan(new Date(Date.now() - USER_ONLINE_THRESHOLD)), }); diff --git a/packages/backend/src/server/api/endpoints/hashtags/list.ts b/packages/backend/src/server/api/endpoints/hashtags/list.ts index 9fa9b3edc..50e36386c 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/list.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/list.ts @@ -1,51 +1,11 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Hashtags } from '@/models/index'; +import define from '../../define.js'; +import { Hashtags } from '@/models/index.js'; export const meta = { tags: ['hashtags'], requireCredential: false, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - attachedToUserOnly: { - validator: $.optional.bool, - default: false, - }, - - attachedToLocalUserOnly: { - validator: $.optional.bool, - default: false, - }, - - attachedToRemoteUserOnly: { - validator: $.optional.bool, - default: false, - }, - - sort: { - validator: $.str.or([ - '+mentionedUsers', - '-mentionedUsers', - '+mentionedLocalUsers', - '-mentionedLocalUsers', - '+mentionedRemoteUsers', - '-mentionedRemoteUsers', - '+attachedUsers', - '-attachedUsers', - '+attachedLocalUsers', - '-attachedLocalUsers', - '+attachedRemoteUsers', - '-attachedRemoteUsers', - ]), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -57,8 +17,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + attachedToUserOnly: { type: 'boolean', default: false }, + attachedToLocalUserOnly: { type: 'boolean', default: false }, + attachedToRemoteUserOnly: { type: 'boolean', default: false }, + sort: { type: 'string', enum: ['+mentionedUsers', '-mentionedUsers', '+mentionedLocalUsers', '-mentionedLocalUsers', '+mentionedRemoteUsers', '-mentionedRemoteUsers', '+attachedUsers', '-attachedUsers', '+attachedLocalUsers', '-attachedLocalUsers', '+attachedRemoteUsers', '-attachedRemoteUsers'] }, + }, + required: ['sort'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = Hashtags.createQueryBuilder('tag'); if (ps.attachedToUserOnly) query.andWhere('tag.attachedUsersCount != 0'); @@ -90,7 +62,7 @@ export default define(meta, async (ps, me) => { 'tag.attachedRemoteUsersCount', ]); - const tags = await query.take(ps.limit!).getMany(); + const tags = await query.take(ps.limit).getMany(); return Hashtags.packMany(tags); }); diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts index 0d646c64f..c28984477 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/search.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts @@ -1,28 +1,11 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Hashtags } from '@/models/index'; +import define from '../../define.js'; +import { Hashtags } from '@/models/index.js'; export const meta = { tags: ['hashtags'], requireCredential: false, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - query: { - validator: $.str, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -33,13 +16,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + query: { type: 'string' }, + offset: { type: 'integer', default: 0 }, + }, + required: ['query'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const hashtags = await Hashtags.createQueryBuilder('tag') .where('tag.name like :q', { q: ps.query.toLowerCase() + '%' }) .orderBy('tag.count', 'DESC') .groupBy('tag.id') - .take(ps.limit!) + .take(ps.limit) .skip(ps.offset) .getMany(); diff --git a/packages/backend/src/server/api/endpoints/hashtags/show.ts b/packages/backend/src/server/api/endpoints/hashtags/show.ts index 242cef99d..6e6afa4f1 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/show.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/show.ts @@ -1,20 +1,13 @@ -import $ from 'cafy'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Hashtags } from '@/models/index'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Hashtags } from '@/models/index.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; export const meta = { tags: ['hashtags'], requireCredential: false, - params: { - tag: { - validator: $.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -30,8 +23,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + tag: { type: 'string' }, + }, + required: ['tag'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const hashtag = await Hashtags.findOne({ name: normalizeForSearch(ps.tag) }); if (hashtag == null) { throw new ApiError(meta.errors.noSuchHashtag); diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index be964ad63..9cdbc8941 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -1,10 +1,10 @@ import { Brackets } from 'typeorm'; -import define from '../../define'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Notes } from '@/models/index'; -import { Note } from '@/models/entities/note'; -import { safeForSql } from '@/misc/safe-for-sql'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; +import define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Notes } from '@/models/index.js'; +import { Note } from '@/models/entities/note.js'; +import { safeForSql } from '@/misc/safe-for-sql.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; /* トãƒŦãƒŗドãĢčŧ‰ã‚‹ãŸã‚ãĢは「『į›´čŋ‘a分間ぎãƒĻニãƒŧク投į¨ŋ数がäģŠã‹ã‚‰a分前īŊžäģŠã‹ã‚‰b分前ぎ間ぎãƒĻニãƒŧク投į¨ŋ数ぎn倍äģĨä¸Šã€ãŽãƒãƒƒã‚ˇãƒĨã‚ŋグぎ上äŊ5äŊäģĨ内ãĢå…Ĩる」ことがåŋ…čĻ @@ -53,8 +53,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { const instance = await fetchMeta(true); const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t)); diff --git a/packages/backend/src/server/api/endpoints/hashtags/users.ts b/packages/backend/src/server/api/endpoints/hashtags/users.ts index 2158dc434..a5df21a7e 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/users.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/users.ts @@ -1,52 +1,12 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Users } from '@/models/index'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; +import define from '../../define.js'; +import { Users } from '@/models/index.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; export const meta = { requireCredential: false, tags: ['hashtags', 'users'], - params: { - tag: { - validator: $.str, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sort: { - validator: $.str.or([ - '+follower', - '-follower', - '+createdAt', - '-createdAt', - '+updatedAt', - '-updatedAt', - ]), - }, - - state: { - validator: $.optional.str.or([ - 'all', - 'alive', - ]), - default: 'all', - }, - - origin: { - validator: $.optional.str.or([ - 'combined', - 'local', - 'remote', - ]), - default: 'local', - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -58,8 +18,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + tag: { type: 'string' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt'] }, + state: { type: 'string', enum: ['all', 'alive'], default: "all" }, + origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "local" }, + }, + required: ['tag', 'sort'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = Users.createQueryBuilder('user') .where(':tag = ANY(user.tags)', { tag: normalizeForSearch(ps.tag) }); @@ -84,7 +56,7 @@ export default define(meta, async (ps, me) => { case '-updatedAt': query.orderBy('user.updatedAt', 'ASC'); break; } - const users = await query.take(ps.limit!).getMany(); + const users = await query.take(ps.limit).getMany(); return await Users.packMany(users, me, { detail: true }); }); diff --git a/packages/backend/src/server/api/endpoints/i.ts b/packages/backend/src/server/api/endpoints/i.ts index d69c118cf..5b1ad2b09 100644 --- a/packages/backend/src/server/api/endpoints/i.ts +++ b/packages/backend/src/server/api/endpoints/i.ts @@ -1,13 +1,11 @@ -import define from '../define'; -import { Users } from '@/models/index'; +import define from '../define.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['account'], requireCredential: true, - params: {}, - res: { type: 'object', optional: false, nullable: false, @@ -15,8 +13,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user, token) => { +export default define(meta, paramDef, async (ps, user, token) => { const isSecure = token == null; // ã“ã“ã§æ¸ĄãŖãĻきãĻいる user はキãƒŖãƒƒã‚ˇãƒĨされãĻいãĻ古い可čƒŊ性もあるぎで id ã ã‘æ¸Ąã™ diff --git a/packages/backend/src/server/api/endpoints/i/2fa/done.ts b/packages/backend/src/server/api/endpoints/i/2fa/done.ts index 485390869..70478430d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/done.ts @@ -1,22 +1,23 @@ -import $ from 'cafy'; import * as speakeasy from 'speakeasy'; -import define from '../../../define'; -import { UserProfiles } from '@/models/index'; +import define from '../../../define.js'; +import { UserProfiles } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - token: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + token: { type: 'string' }, }, + required: ['token'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const token = ps.token.replace(/\s/g, ''); const profile = await UserProfiles.findOneOrFail(user.id); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index 26e9a6088..f33237c8b 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -1,48 +1,40 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; -import { promisify } from 'util'; +import bcrypt from 'bcryptjs'; +import { promisify } from 'node:util'; import * as cbor from 'cbor'; -import define from '../../../define'; +import define from '../../../define.js'; import { UserProfiles, UserSecurityKeys, AttestationChallenges, Users, -} from '@/models/index'; -import config from '@/config/index'; -import { procedures, hash } from '../../../2fa'; -import { publishMainStream } from '@/services/stream'; +} from '@/models/index.js'; +import config from '@/config/index.js'; +import { procedures, hash } from '../../../2fa.js'; +import { publishMainStream } from '@/services/stream.js'; const cborDecodeFirst = promisify(cbor.decodeFirst) as any; +const rpIdHashReal = hash(Buffer.from(config.hostname, 'utf-8')); export const meta = { requireCredential: true, secure: true, - - params: { - clientDataJSON: { - validator: $.str, - }, - attestationObject: { - validator: $.str, - }, - password: { - validator: $.str, - }, - challengeId: { - validator: $.str, - }, - name: { - validator: $.str, - }, - }, } as const; -const rpIdHashReal = hash(Buffer.from(config.hostname, 'utf-8')); +export const paramDef = { + type: 'object', + properties: { + clientDataJSON: { type: 'string' }, + attestationObject: { type: 'string' }, + password: { type: 'string' }, + challengeId: { type: 'string' }, + name: { type: 'string' }, + }, + required: ['clientDataJSON', 'attestationObject', 'password', 'challengeId', 'name'], +} as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts b/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts index 854848a43..4bfa24f97 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts @@ -1,21 +1,22 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { UserProfiles } from '@/models/index'; +import define from '../../../define.js'; +import { UserProfiles } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - value: { - validator: $.boolean, - }, +export const paramDef = { + type: 'object', + properties: { + value: { type: 'boolean' }, }, + required: ['value'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { await UserProfiles.update(user.id, { usePasswordLessLogin: ps.value, }); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index 057e54c69..0c4c99271 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -1,11 +1,10 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; -import define from '../../../define'; -import { UserProfiles, AttestationChallenges } from '@/models/index'; -import { promisify } from 'util'; -import * as crypto from 'crypto'; -import { genId } from '@/misc/gen-id'; -import { hash } from '../../../2fa'; +import bcrypt from 'bcryptjs'; +import define from '../../../define.js'; +import { UserProfiles, AttestationChallenges } from '@/models/index.js'; +import { promisify } from 'node:util'; +import * as crypto from 'node:crypto'; +import { genId } from '@/misc/gen-id.js'; +import { hash } from '../../../2fa.js'; const randomBytes = promisify(crypto.randomBytes); @@ -13,16 +12,18 @@ export const meta = { requireCredential: true, secure: true, +} as const; - params: { - password: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + password: { type: 'string' }, }, + required: ['password'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts index c5cfb9dfa..7951e393b 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts @@ -1,25 +1,26 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; +import bcrypt from 'bcryptjs'; import * as speakeasy from 'speakeasy'; import * as QRCode from 'qrcode'; -import config from '@/config/index'; -import define from '../../../define'; -import { UserProfiles } from '@/models/index'; +import config from '@/config/index.js'; +import define from '../../../define.js'; +import { UserProfiles } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - password: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + password: { type: 'string' }, }, + required: ['password'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts index 03e1d0434..2b69b1f8c 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts @@ -1,26 +1,25 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; -import define from '../../../define'; -import { UserProfiles, UserSecurityKeys, Users } from '@/models/index'; -import { publishMainStream } from '@/services/stream'; +import bcrypt from 'bcryptjs'; +import define from '../../../define.js'; +import { UserProfiles, UserSecurityKeys, Users } from '@/models/index.js'; +import { publishMainStream } from '@/services/stream.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - password: { - validator: $.str, - }, - credentialId: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + password: { type: 'string' }, + credentialId: { type: 'string' }, }, + required: ['password', 'credentialId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts index a19ad6810..c5633f68b 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts @@ -1,22 +1,23 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; -import define from '../../../define'; -import { UserProfiles } from '@/models/index'; +import bcrypt from 'bcryptjs'; +import define from '../../../define.js'; +import { UserProfiles } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - password: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + password: { type: 'string' }, }, + required: ['password'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/packages/backend/src/server/api/endpoints/i/apps.ts b/packages/backend/src/server/api/endpoints/i/apps.ts index 63999b098..eca955884 100644 --- a/packages/backend/src/server/api/endpoints/i/apps.ts +++ b/packages/backend/src/server/api/endpoints/i/apps.ts @@ -1,26 +1,22 @@ -import $ from 'cafy'; -import define from '../../define'; -import { AccessTokens } from '@/models/index'; +import define from '../../define.js'; +import { AccessTokens } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - sort: { - validator: $.optional.str.or([ - '+createdAt', - '-createdAt', - '+lastUsedAt', - '-lastUsedAt', - ]), - }, +export const paramDef = { + type: 'object', + properties: { + sort: { type: 'string', enum: ['+createdAt', '-createdAt', '+lastUsedAt', '-lastUsedAt'] }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = AccessTokens.createQueryBuilder('token') .where('token.userId = :userId', { userId: user.id }); diff --git a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts index 52122b851..3301808e7 100644 --- a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts +++ b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts @@ -1,38 +1,30 @@ -import $ from 'cafy'; -import define from '../../define'; -import { AccessTokens, Apps } from '@/models/index'; +import define from '../../define.js'; +import { AccessTokens, Apps } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - - sort: { - validator: $.optional.str.or('desc|asc'), - default: 'desc', - }, +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + sort: { type: 'string', enum: ['desc', 'asc'], default: "desc" }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Get tokens const tokens = await AccessTokens.find({ where: { userId: user.id, }, - take: ps.limit!, + take: ps.limit, skip: ps.offset, order: { id: ps.sort == 'asc' ? 1 : -1, diff --git a/packages/backend/src/server/api/endpoints/i/change-password.ts b/packages/backend/src/server/api/endpoints/i/change-password.ts index 7b6c13773..16509d2dc 100644 --- a/packages/backend/src/server/api/endpoints/i/change-password.ts +++ b/packages/backend/src/server/api/endpoints/i/change-password.ts @@ -1,26 +1,24 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; -import define from '../../define'; -import { UserProfiles } from '@/models/index'; +import bcrypt from 'bcryptjs'; +import define from '../../define.js'; +import { UserProfiles } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - currentPassword: { - validator: $.str, - }, - - newPassword: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + currentPassword: { type: 'string' }, + newPassword: { type: 'string', minLength: 1 }, }, + required: ['currentPassword', 'newPassword'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/packages/backend/src/server/api/endpoints/i/delete-account.ts b/packages/backend/src/server/api/endpoints/i/delete-account.ts index e1eee949f..8cb6b6a63 100644 --- a/packages/backend/src/server/api/endpoints/i/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/i/delete-account.ts @@ -1,25 +1,26 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; -import define from '../../define'; -import { UserProfiles, Users } from '@/models/index'; -import { doPostSuspend } from '@/services/suspend-user'; -import { publishUserEvent } from '@/services/stream'; -import { createDeleteAccountJob } from '@/queue'; +import bcrypt from 'bcryptjs'; +import define from '../../define.js'; +import { UserProfiles, Users } from '@/models/index.js'; +import { doPostSuspend } from '@/services/suspend-user.js'; +import { publishUserEvent } from '@/services/stream.js'; +import { createDeleteAccountJob } from '@/queue/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - password: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + password: { type: 'string' }, }, + required: ['password'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); const userDetailed = await Users.findOneOrFail(user.id); if (userDetailed.isDeleted) { diff --git a/packages/backend/src/server/api/endpoints/i/export-blocking.ts b/packages/backend/src/server/api/endpoints/i/export-blocking.ts index 44d8a1cb3..aed4c2e0a 100644 --- a/packages/backend/src/server/api/endpoints/i/export-blocking.ts +++ b/packages/backend/src/server/api/endpoints/i/export-blocking.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { createExportBlockingJob } from '@/queue/index'; +import define from '../../define.js'; +import { createExportBlockingJob } from '@/queue/index.js'; import ms from 'ms'; export const meta = { @@ -11,7 +11,13 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { createExportBlockingJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/i/export-following.ts b/packages/backend/src/server/api/endpoints/i/export-following.ts index 5d1617d57..058d77b3c 100644 --- a/packages/backend/src/server/api/endpoints/i/export-following.ts +++ b/packages/backend/src/server/api/endpoints/i/export-following.ts @@ -1,6 +1,5 @@ -import $ from 'cafy'; -import define from '../../define'; -import { createExportFollowingJob } from '@/queue/index'; +import define from '../../define.js'; +import { createExportFollowingJob } from '@/queue/index.js'; import ms from 'ms'; export const meta = { @@ -10,19 +9,18 @@ export const meta = { duration: ms('1hour'), max: 1, }, - params: { - excludeMuting: { - validator: $.optional.bool, - default: false, - }, - excludeInactive: { - validator: $.optional.bool, - default: false, - }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + excludeMuting: { type: 'boolean', default: false }, + excludeInactive: { type: 'boolean', default: false }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { createExportFollowingJob(user, ps.excludeMuting, ps.excludeInactive); }); diff --git a/packages/backend/src/server/api/endpoints/i/export-mute.ts b/packages/backend/src/server/api/endpoints/i/export-mute.ts index 27ce8f0b2..c0216fac0 100644 --- a/packages/backend/src/server/api/endpoints/i/export-mute.ts +++ b/packages/backend/src/server/api/endpoints/i/export-mute.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { createExportMuteJob } from '@/queue/index'; +import define from '../../define.js'; +import { createExportMuteJob } from '@/queue/index.js'; import ms from 'ms'; export const meta = { @@ -11,7 +11,13 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { createExportMuteJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/i/export-notes.ts b/packages/backend/src/server/api/endpoints/i/export-notes.ts index 25b1849e8..4b85a4555 100644 --- a/packages/backend/src/server/api/endpoints/i/export-notes.ts +++ b/packages/backend/src/server/api/endpoints/i/export-notes.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { createExportNotesJob } from '@/queue/index'; +import define from '../../define.js'; +import { createExportNotesJob } from '@/queue/index.js'; import ms from 'ms'; export const meta = { @@ -11,7 +11,13 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { createExportNotesJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/i/export-user-lists.ts b/packages/backend/src/server/api/endpoints/i/export-user-lists.ts index d28b699c5..fa5c1f5e5 100644 --- a/packages/backend/src/server/api/endpoints/i/export-user-lists.ts +++ b/packages/backend/src/server/api/endpoints/i/export-user-lists.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { createExportUserListsJob } from '@/queue/index'; +import define from '../../define.js'; +import { createExportUserListsJob } from '@/queue/index.js'; import ms from 'ms'; export const meta = { @@ -11,7 +11,13 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { createExportUserListsJob(user); }); diff --git a/packages/backend/src/server/api/endpoints/i/favorites.ts b/packages/backend/src/server/api/endpoints/i/favorites.ts index 92c767876..3c420e4d0 100644 --- a/packages/backend/src/server/api/endpoints/i/favorites.ts +++ b/packages/backend/src/server/api/endpoints/i/favorites.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { NoteFavorites } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { NoteFavorites } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['account', 'notes', 'favorites'], @@ -11,21 +9,6 @@ export const meta = { kind: 'read:favorites', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -37,14 +20,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(NoteFavorites.createQueryBuilder('favorite'), ps.sinceId, ps.untilId) .andWhere(`favorite.userId = :meId`, { meId: user.id }) .leftJoinAndSelect('favorite.note', 'note'); const favorites = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await NoteFavorites.packMany(favorites, user); diff --git a/packages/backend/src/server/api/endpoints/i/gallery/likes.ts b/packages/backend/src/server/api/endpoints/i/gallery/likes.ts index f1c576359..a38383f30 100644 --- a/packages/backend/src/server/api/endpoints/i/gallery/likes.ts +++ b/packages/backend/src/server/api/endpoints/i/gallery/likes.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { GalleryLikes } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; +import define from '../../../define.js'; +import { GalleryLikes } from '@/models/index.js'; +import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { tags: ['account', 'gallery'], @@ -11,47 +9,46 @@ export const meta = { kind: 'read:gallery-likes', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { - type: 'object', + type: 'array', optional: false, nullable: false, - properties: { - id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + items: { + type: 'object', + optional: false, nullable: false, + properties: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + post: { + type: 'object', + optional: false, nullable: false, + ref: 'GalleryPost', + }, }, - page: { - type: 'object', - optional: false, nullable: false, - ref: 'GalleryPost', - }, - }, + } }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(GalleryLikes.createQueryBuilder('like'), ps.sinceId, ps.untilId) .andWhere(`like.userId = :meId`, { meId: user.id }) .leftJoinAndSelect('like.post', 'post'); const likes = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await GalleryLikes.packMany(likes, user); diff --git a/packages/backend/src/server/api/endpoints/i/gallery/posts.ts b/packages/backend/src/server/api/endpoints/i/gallery/posts.ts index d46d42f63..b4edb5f73 100644 --- a/packages/backend/src/server/api/endpoints/i/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/i/gallery/posts.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { GalleryPosts } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; +import define from '../../../define.js'; +import { GalleryPosts } from '@/models/index.js'; +import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { tags: ['account', 'gallery'], @@ -11,21 +9,6 @@ export const meta = { kind: 'read:gallery', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -37,13 +20,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId) .andWhere(`post.userId = :meId`, { meId: user.id }); const posts = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await GalleryPosts.packMany(posts, user); diff --git a/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts b/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts index 4e1a4d3db..bc3e0aff4 100644 --- a/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts +++ b/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { MutedNotes } from '@/models/index'; +import define from '../../define.js'; +import { MutedNotes } from '@/models/index.js'; export const meta = { tags: ['account'], @@ -8,9 +8,6 @@ export const meta = { kind: 'read:account', - params: { - }, - res: { type: 'object', optional: false, nullable: false, @@ -23,8 +20,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { return { count: await MutedNotes.count({ userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/i/import-blocking.ts b/packages/backend/src/server/api/endpoints/i/import-blocking.ts index acc579742..c70704f9a 100644 --- a/packages/backend/src/server/api/endpoints/i/import-blocking.ts +++ b/packages/backend/src/server/api/endpoints/i/import-blocking.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { createImportBlockingJob } from '@/queue/index'; +import define from '../../define.js'; +import { createImportBlockingJob } from '@/queue/index.js'; import ms from 'ms'; -import { ApiError } from '../../error'; -import { DriveFiles } from '@/models/index'; +import { ApiError } from '../../error.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { secure: true, @@ -15,12 +13,6 @@ export const meta = { max: 1, }, - params: { - fileId: { - validator: $.type(ID), - }, - }, - errors: { noSuchFile: { message: 'No such file.', @@ -48,8 +40,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOne(ps.fileId); if (file == null) throw new ApiError(meta.errors.noSuchFile); diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts index 35006746f..7e9175cbf 100644 --- a/packages/backend/src/server/api/endpoints/i/import-following.ts +++ b/packages/backend/src/server/api/endpoints/i/import-following.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { createImportFollowingJob } from '@/queue/index'; +import define from '../../define.js'; +import { createImportFollowingJob } from '@/queue/index.js'; import ms from 'ms'; -import { ApiError } from '../../error'; -import { DriveFiles } from '@/models/index'; +import { ApiError } from '../../error.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { secure: true, @@ -14,12 +12,6 @@ export const meta = { max: 1, }, - params: { - fileId: { - validator: $.type(ID), - }, - }, - errors: { noSuchFile: { message: 'No such file.', @@ -47,8 +39,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOne(ps.fileId); if (file == null) throw new ApiError(meta.errors.noSuchFile); diff --git a/packages/backend/src/server/api/endpoints/i/import-muting.ts b/packages/backend/src/server/api/endpoints/i/import-muting.ts index 7bbb2e008..abbf07212 100644 --- a/packages/backend/src/server/api/endpoints/i/import-muting.ts +++ b/packages/backend/src/server/api/endpoints/i/import-muting.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { createImportMutingJob } from '@/queue/index'; +import define from '../../define.js'; +import { createImportMutingJob } from '@/queue/index.js'; import ms from 'ms'; -import { ApiError } from '../../error'; -import { DriveFiles } from '@/models/index'; +import { ApiError } from '../../error.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { secure: true, @@ -15,12 +13,6 @@ export const meta = { max: 1, }, - params: { - fileId: { - validator: $.type(ID), - }, - }, - errors: { noSuchFile: { message: 'No such file.', @@ -48,8 +40,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOne(ps.fileId); if (file == null) throw new ApiError(meta.errors.noSuchFile); diff --git a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts index 759d41b6c..be162817f 100644 --- a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts +++ b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { createImportUserListsJob } from '@/queue/index'; +import define from '../../define.js'; +import { createImportUserListsJob } from '@/queue/index.js'; import ms from 'ms'; -import { ApiError } from '../../error'; -import { DriveFiles } from '@/models/index'; +import { ApiError } from '../../error.js'; +import { DriveFiles } from '@/models/index.js'; export const meta = { secure: true, @@ -14,12 +12,6 @@ export const meta = { max: 1, }, - params: { - fileId: { - validator: $.type(ID), - }, - }, - errors: { noSuchFile: { message: 'No such file.', @@ -47,8 +39,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const file = await DriveFiles.findOne(ps.fileId); if (file == null) throw new ApiError(meta.errors.noSuchFile); diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts index 59efd32bb..7d9bd44d1 100644 --- a/packages/backend/src/server/api/endpoints/i/notifications.ts +++ b/packages/backend/src/server/api/endpoints/i/notifications.ts @@ -1,12 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { readNotification } from '../../common/read-notification'; -import define from '../../define'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateMutedInstanceNotificationQuery } from '../../common/generate-muted-instance-query'; -import { Notifications, Followings, Mutings, Users } from '@/models/index'; -import { notificationTypes } from '@/types'; -import read from '@/services/note/read'; +import { readNotification } from '../../common/read-notification.js'; +import define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateMutedInstanceNotificationQuery } from '../../common/generate-muted-instance-query.js'; +import { Notifications, Followings, Mutings, Users } from '@/models/index.js'; +import { notificationTypes } from '@/types.js'; +import read from '@/services/note/read.js'; import { Brackets } from 'typeorm'; export const meta = { @@ -16,44 +14,6 @@ export const meta = { kind: 'read:notifications', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - following: { - validator: $.optional.bool, - default: false, - }, - - unreadOnly: { - validator: $.optional.bool, - default: false, - }, - - markAsRead: { - validator: $.optional.bool, - default: true, - }, - - includeTypes: { - validator: $.optional.arr($.str.or(notificationTypes as unknown as string[])), - }, - - excludeTypes: { - validator: $.optional.arr($.str.or(notificationTypes as unknown as string[])), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -65,8 +25,27 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + following: { type: 'boolean', default: false }, + unreadOnly: { type: 'boolean', default: false }, + markAsRead: { type: 'boolean', default: true }, + includeTypes: { type: 'array', items: { + type: 'string', enum: notificationTypes, + } }, + excludeTypes: { type: 'array', items: { + type: 'string', enum: notificationTypes, + } }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // includeTypes がįŠēぎ場合はクエãƒĒしãĒい if (ps.includeTypes && ps.includeTypes.length === 0) { return []; @@ -92,10 +71,16 @@ export default define(meta, async (ps, user) => { .leftJoinAndSelect('notification.notifier', 'notifier') .leftJoinAndSelect('notification.note', 'note') .leftJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); query.andWhere(new Brackets(qb => { qb .where(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`) @@ -125,7 +110,7 @@ export default define(meta, async (ps, user) => { query.andWhere(`notification.isRead = false`); } - const notifications = await query.take(ps.limit!).getMany(); + const notifications = await query.take(ps.limit).getMany(); // Mark all as read if (notifications.length > 0 && ps.markAsRead) { diff --git a/packages/backend/src/server/api/endpoints/i/page-likes.ts b/packages/backend/src/server/api/endpoints/i/page-likes.ts index 59239c744..71e326e2f 100644 --- a/packages/backend/src/server/api/endpoints/i/page-likes.ts +++ b/packages/backend/src/server/api/endpoints/i/page-likes.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { PageLikes } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { PageLikes } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['account', 'pages'], @@ -11,48 +9,46 @@ export const meta = { kind: 'read:page-likes', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { - type: 'object', + type: 'array', optional: false, nullable: false, - properties: { - id: { - type: 'string', - optional: false, nullable: false, - format: 'id', + items: { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + page: { + type: 'object', + optional: false, nullable: false, + ref: 'Page', + }, }, - page: { - type: 'object', - optional: false, nullable: false, - ref: 'Page', - }, - }, + } }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(PageLikes.createQueryBuilder('like'), ps.sinceId, ps.untilId) .andWhere(`like.userId = :meId`, { meId: user.id }) .leftJoinAndSelect('like.page', 'page'); const likes = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); - return await PageLikes.packMany(likes, user); + return PageLikes.packMany(likes, user); }); diff --git a/packages/backend/src/server/api/endpoints/i/pages.ts b/packages/backend/src/server/api/endpoints/i/pages.ts index bef775d06..f28aed3fd 100644 --- a/packages/backend/src/server/api/endpoints/i/pages.ts +++ b/packages/backend/src/server/api/endpoints/i/pages.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Pages } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Pages } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['account', 'pages'], @@ -11,21 +9,6 @@ export const meta = { kind: 'read:pages', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -37,13 +20,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(Pages.createQueryBuilder('page'), ps.sinceId, ps.untilId) .andWhere(`page.userId = :meId`, { meId: user.id }); const pages = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Pages.packMany(pages); diff --git a/packages/backend/src/server/api/endpoints/i/pin.ts b/packages/backend/src/server/api/endpoints/i/pin.ts index a940d1b99..67b7026be 100644 --- a/packages/backend/src/server/api/endpoints/i/pin.ts +++ b/packages/backend/src/server/api/endpoints/i/pin.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { addPinned } from '@/services/i/pin'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Users } from '@/models/index'; +import { addPinned } from '@/services/i/pin.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['account', 'notes'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -45,8 +37,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { await addPinned(user, ps.noteId).catch(e => { if (e.id === '70c4e51f-5bea-449c-a030-53bee3cce202') throw new ApiError(meta.errors.noSuchNote); if (e.id === '15a018eb-58e5-4da1-93be-330fcc5e4e1a') throw new ApiError(meta.errors.pinLimitExceeded); diff --git a/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts b/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts index 4e4fb3840..2e291a34a 100644 --- a/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts +++ b/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts @@ -1,6 +1,6 @@ -import { publishMainStream } from '@/services/stream'; -import define from '../../define'; -import { MessagingMessages, UserGroupJoinings } from '@/models/index'; +import { publishMainStream } from '@/services/stream.js'; +import define from '../../define.js'; +import { MessagingMessages, UserGroupJoinings } from '@/models/index.js'; export const meta = { tags: ['account', 'messaging'], @@ -8,13 +8,16 @@ export const meta = { requireCredential: true, kind: 'write:account', +} as const; - params: { - }, +export const paramDef = { + type: 'object', + properties: {}, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Update documents await MessagingMessages.update({ recipientId: user.id, diff --git a/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts b/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts index 99f17ddfc..49f3deb33 100644 --- a/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts +++ b/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts @@ -1,6 +1,6 @@ -import { publishMainStream } from '@/services/stream'; -import define from '../../define'; -import { NoteUnreads } from '@/models/index'; +import { publishMainStream } from '@/services/stream.js'; +import define from '../../define.js'; +import { NoteUnreads } from '@/models/index.js'; export const meta = { tags: ['account'], @@ -8,13 +8,16 @@ export const meta = { requireCredential: true, kind: 'write:account', +} as const; - params: { - }, +export const paramDef = { + type: 'object', + properties: {}, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Remove documents await NoteUnreads.delete({ userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/i/read-announcement.ts b/packages/backend/src/server/api/endpoints/i/read-announcement.ts index e9bb66264..647fa77fa 100644 --- a/packages/backend/src/server/api/endpoints/i/read-announcement.ts +++ b/packages/backend/src/server/api/endpoints/i/read-announcement.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { genId } from '@/misc/gen-id'; -import { AnnouncementReads, Announcements, Users } from '@/models/index'; -import { publishMainStream } from '@/services/stream'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { genId } from '@/misc/gen-id.js'; +import { AnnouncementReads, Announcements, Users } from '@/models/index.js'; +import { publishMainStream } from '@/services/stream.js'; export const meta = { tags: ['account'], @@ -13,12 +11,6 @@ export const meta = { kind: 'write:account', - params: { - announcementId: { - validator: $.type(ID), - }, - }, - errors: { noSuchAnnouncement: { message: 'No such announcement.', @@ -28,8 +20,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + announcementId: { type: 'string', format: 'misskey:id' }, + }, + required: ['announcementId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Check if announcement exists const announcement = await Announcements.findOne(ps.announcementId); diff --git a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts index a20719363..771c98b21 100644 --- a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts +++ b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts @@ -1,24 +1,25 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; -import { publishMainStream, publishUserEvent } from '@/services/stream'; -import generateUserToken from '../../common/generate-native-user-token'; -import define from '../../define'; -import { Users, UserProfiles } from '@/models/index'; +import bcrypt from 'bcryptjs'; +import { publishMainStream, publishUserEvent } from '@/services/stream.js'; +import generateUserToken from '../../common/generate-native-user-token.js'; +import define from '../../define.js'; +import { Users, UserProfiles } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - password: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + password: { type: 'string' }, }, + required: ['password'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts index 2941b441e..d0b16dbc4 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts @@ -1,22 +1,24 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { RegistryItems } from '@/models/index'; +import define from '../../../define.js'; +import { RegistryItems } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - scope: { - validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), - default: [], - }, +export const paramDef = { + type: 'object', + properties: { + scope: { type: 'array', default: [], items: { + type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + } }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = RegistryItems.createQueryBuilder('item') .where('item.domain IS NULL') .andWhere('item.userId = :userId', { userId: user.id }) diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts index 51371353c..cc5d5a8c6 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts @@ -1,24 +1,12 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { RegistryItems } from '@/models/index'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import { RegistryItems } from '@/models/index.js'; +import { ApiError } from '../../../error.js'; export const meta = { requireCredential: true, secure: true, - params: { - key: { - validator: $.str, - }, - - scope: { - validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), - default: [], - }, - }, - errors: { noSuchKey: { message: 'No such key.', @@ -28,8 +16,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + key: { type: 'string' }, + scope: { type: 'array', default: [], items: { + type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + } }, + }, + required: ['key'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = RegistryItems.createQueryBuilder('item') .where('item.domain IS NULL') .andWhere('item.userId = :userId', { userId: user.id }) diff --git a/packages/backend/src/server/api/endpoints/i/registry/get.ts b/packages/backend/src/server/api/endpoints/i/registry/get.ts index ac617defb..a79319744 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get.ts @@ -1,24 +1,12 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { RegistryItems } from '@/models/index'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import { RegistryItems } from '@/models/index.js'; +import { ApiError } from '../../../error.js'; export const meta = { requireCredential: true, secure: true, - params: { - key: { - validator: $.str, - }, - - scope: { - validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), - default: [], - }, - }, - errors: { noSuchKey: { message: 'No such key.', @@ -28,8 +16,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + key: { type: 'string' }, + scope: { type: 'array', default: [], items: { + type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + } }, + }, + required: ['key'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = RegistryItems.createQueryBuilder('item') .where('item.domain IS NULL') .andWhere('item.userId = :userId', { userId: user.id }) diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts index 044592218..ac209c06a 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts @@ -1,22 +1,24 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { RegistryItems } from '@/models/index'; +import define from '../../../define.js'; +import { RegistryItems } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - scope: { - validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), - default: [], - }, +export const paramDef = { + type: 'object', + properties: { + scope: { type: 'array', default: [], items: { + type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + } }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = RegistryItems.createQueryBuilder('item') .where('item.domain IS NULL') .andWhere('item.userId = :userId', { userId: user.id }) diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys.ts b/packages/backend/src/server/api/endpoints/i/registry/keys.ts index a3c9d0e5e..5ea1a9d34 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys.ts @@ -1,22 +1,24 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { RegistryItems } from '@/models/index'; +import define from '../../../define.js'; +import { RegistryItems } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - scope: { - validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), - default: [], - }, +export const paramDef = { + type: 'object', + properties: { + scope: { type: 'array', default: [], items: { + type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + } }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = RegistryItems.createQueryBuilder('item') .select('item.key') .where('item.domain IS NULL') diff --git a/packages/backend/src/server/api/endpoints/i/registry/remove.ts b/packages/backend/src/server/api/endpoints/i/registry/remove.ts index 08185f224..92473654c 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/remove.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/remove.ts @@ -1,24 +1,12 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { RegistryItems } from '@/models/index'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import { RegistryItems } from '@/models/index.js'; +import { ApiError } from '../../../error.js'; export const meta = { requireCredential: true, secure: true, - params: { - key: { - validator: $.str, - }, - - scope: { - validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), - default: [], - }, - }, - errors: { noSuchKey: { message: 'No such key.', @@ -28,8 +16,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + key: { type: 'string' }, + scope: { type: 'array', default: [], items: { + type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + } }, + }, + required: ['key'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = RegistryItems.createQueryBuilder('item') .where('item.domain IS NULL') .andWhere('item.userId = :userId', { userId: user.id }) diff --git a/packages/backend/src/server/api/endpoints/i/registry/scopes.ts b/packages/backend/src/server/api/endpoints/i/registry/scopes.ts index 9de68ac6e..de4b313e2 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/scopes.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/scopes.ts @@ -1,17 +1,20 @@ -import define from '../../../define'; -import { RegistryItems } from '@/models/index'; +import define from '../../../define.js'; +import { RegistryItems } from '@/models/index.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - }, +export const paramDef = { + type: 'object', + properties: {}, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = RegistryItems.createQueryBuilder('item') .select('item.scope') .where('item.domain IS NULL') diff --git a/packages/backend/src/server/api/endpoints/i/registry/set.ts b/packages/backend/src/server/api/endpoints/i/registry/set.ts index 27884046b..d380b428a 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/set.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/set.ts @@ -1,32 +1,28 @@ -import $ from 'cafy'; -import { publishMainStream } from '@/services/stream'; -import define from '../../../define'; -import { RegistryItems } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import { publishMainStream } from '@/services/stream.js'; +import define from '../../../define.js'; +import { RegistryItems } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - key: { - validator: $.str.min(1), - }, - - value: { - validator: $.nullable.any, - }, - - scope: { - validator: $.optional.arr($.str.match(/^[a-zA-Z0-9_]+$/)), - default: [], - }, +export const paramDef = { + type: 'object', + properties: { + key: { type: 'string', minLength: 1 }, + value: {}, + scope: { type: 'array', default: [], items: { + type: 'string', pattern: /^[a-zA-Z0-9_]+$/.toString().slice(1, -1), + } }, }, + required: ['key', 'value'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = RegistryItems.createQueryBuilder('item') .where('item.domain IS NULL') .andWhere('item.userId = :userId', { userId: user.id }) diff --git a/packages/backend/src/server/api/endpoints/i/revoke-token.ts b/packages/backend/src/server/api/endpoints/i/revoke-token.ts index 51721c5b5..b957fd079 100644 --- a/packages/backend/src/server/api/endpoints/i/revoke-token.ts +++ b/packages/backend/src/server/api/endpoints/i/revoke-token.ts @@ -1,23 +1,23 @@ -import $ from 'cafy'; -import define from '../../define'; -import { AccessTokens } from '@/models/index'; -import { ID } from '@/misc/cafy-id'; -import { publishUserEvent } from '@/services/stream'; +import define from '../../define.js'; +import { AccessTokens } from '@/models/index.js'; +import { publishUserEvent } from '@/services/stream.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - tokenId: { - validator: $.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + tokenId: { type: 'string', format: 'misskey:id' }, }, + required: ['tokenId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const token = await AccessTokens.findOne(ps.tokenId); if (token) { diff --git a/packages/backend/src/server/api/endpoints/i/signin-history.ts b/packages/backend/src/server/api/endpoints/i/signin-history.ts index 796e2ec30..ca3741166 100644 --- a/packages/backend/src/server/api/endpoints/i/signin-history.ts +++ b/packages/backend/src/server/api/endpoints/i/signin-history.ts @@ -1,36 +1,29 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Signins } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Signins } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { requireCredential: true, secure: true, +} as const; - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, }, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(Signins.createQueryBuilder('signin'), ps.sinceId, ps.untilId) .andWhere(`signin.userId = :meId`, { meId: user.id }); - const history = await query.take(ps.limit!).getMany(); + const history = await query.take(ps.limit).getMany(); return await Promise.all(history.map(record => Signins.pack(record))); }); diff --git a/packages/backend/src/server/api/endpoints/i/unpin.ts b/packages/backend/src/server/api/endpoints/i/unpin.ts index 9c82b7496..9912689da 100644 --- a/packages/backend/src/server/api/endpoints/i/unpin.ts +++ b/packages/backend/src/server/api/endpoints/i/unpin.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { removePinned } from '@/services/i/pin'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Users } from '@/models/index'; +import { removePinned } from '@/services/i/pin.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['account', 'notes'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -33,8 +25,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { await removePinned(user, ps.noteId).catch(e => { if (e.id === 'b302d4cf-c050-400a-bbb3-be208681f40c') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts index b4479aa50..389ff1b81 100644 --- a/packages/backend/src/server/api/endpoints/i/update-email.ts +++ b/packages/backend/src/server/api/endpoints/i/update-email.ts @@ -1,14 +1,13 @@ -import $ from 'cafy'; -import { publishMainStream } from '@/services/stream'; -import define from '../../define'; +import { publishMainStream } from '@/services/stream.js'; +import define from '../../define.js'; import rndstr from 'rndstr'; -import config from '@/config/index'; +import config from '@/config/index.js'; import ms from 'ms'; -import * as bcrypt from 'bcryptjs'; -import { Users, UserProfiles } from '@/models/index'; -import { sendEmail } from '@/services/send-email'; -import { ApiError } from '../../error'; -import { validateEmailForAccount } from '@/services/validate-email-for-account'; +import bcrypt from 'bcryptjs'; +import { Users, UserProfiles } from '@/models/index.js'; +import { sendEmail } from '@/services/send-email.js'; +import { ApiError } from '../../error.js'; +import { validateEmailForAccount } from '@/services/validate-email-for-account.js'; export const meta = { requireCredential: true, @@ -20,16 +19,6 @@ export const meta = { max: 3, }, - params: { - password: { - validator: $.str, - }, - - email: { - validator: $.optional.nullable.str, - }, - }, - errors: { incorrectPassword: { message: 'Incorrect password.', @@ -45,8 +34,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + password: { type: 'string' }, + email: { type: 'string', nullable: true }, + }, + required: ['password'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 6b7e53aa1..85d0a6254 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -1,20 +1,19 @@ -import $ from 'cafy'; +import RE2 from 're2'; import * as mfm from 'mfm-js'; -import { ID } from '@/misc/cafy-id'; -import { publishMainStream, publishUserEvent } from '@/services/stream'; -import acceptAllFollowRequests from '@/services/following/requests/accept-all'; -import { publishToFollowers } from '@/services/i/update'; -import define from '../../define'; -import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm'; -import { extractHashtags } from '@/misc/extract-hashtags'; -import * as langmap from 'langmap'; -import { updateUsertags } from '@/services/update-hashtag'; -import { ApiError } from '../../error'; -import { Users, DriveFiles, UserProfiles, Pages } from '@/models/index'; -import { User } from '@/models/entities/user'; -import { UserProfile } from '@/models/entities/user-profile'; -import { notificationTypes } from '@/types'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; +import { publishMainStream, publishUserEvent } from '@/services/stream.js'; +import acceptAllFollowRequests from '@/services/following/requests/accept-all.js'; +import { publishToFollowers } from '@/services/i/update.js'; +import define from '../../define.js'; +import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js'; +import { extractHashtags } from '@/misc/extract-hashtags.js'; +import { updateUsertags } from '@/services/update-hashtag.js'; +import { ApiError } from '../../error.js'; +import { Users, DriveFiles, UserProfiles, Pages } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; +import { UserProfile } from '@/models/entities/user-profile.js'; +import { notificationTypes } from '@/types.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import { langmap } from '@/misc/langmap.js'; export const meta = { tags: ['account'], @@ -23,112 +22,6 @@ export const meta = { kind: 'write:account', - params: { - name: { - validator: $.optional.nullable.use(Users.validateName), - }, - - description: { - validator: $.optional.nullable.use(Users.validateDescription), - }, - - lang: { - validator: $.optional.nullable.str.or(Object.keys(langmap)), - }, - - location: { - validator: $.optional.nullable.use(Users.validateLocation), - }, - - birthday: { - validator: $.optional.nullable.use(Users.validateBirthday), - }, - - avatarId: { - validator: $.optional.nullable.type(ID), - }, - - bannerId: { - validator: $.optional.nullable.type(ID), - }, - - fields: { - validator: $.optional.arr($.object()).range(1, 4), - }, - - isLocked: { - validator: $.optional.bool, - }, - - isExplorable: { - validator: $.optional.bool, - }, - - hideOnlineStatus: { - validator: $.optional.bool, - }, - - publicReactions: { - validator: $.optional.bool, - }, - - ffVisibility: { - validator: $.optional.str, - }, - - carefulBot: { - validator: $.optional.bool, - }, - - autoAcceptFollowed: { - validator: $.optional.bool, - }, - - noCrawle: { - validator: $.optional.bool, - }, - - isBot: { - validator: $.optional.bool, - }, - - isCat: { - validator: $.optional.bool, - }, - - injectFeaturedNote: { - validator: $.optional.bool, - }, - - receiveAnnouncementEmail: { - validator: $.optional.bool, - }, - - alwaysMarkNsfw: { - validator: $.optional.bool, - }, - - pinnedPageId: { - validator: $.optional.nullable.type(ID), - }, - - mutedWords: { - validator: $.optional.arr($.arr($.str)), - }, - - mutedInstances: { - validator: $.optional.arr($.str), - }, - - mutingNotificationTypes: { - validator: $.optional.arr($.str.or(notificationTypes as unknown as string[])), - }, - - emailNotificationTypes: { - validator: $.optional.arr($.str), - }, - }, - errors: { noSuchAvatar: { message: 'No such avatar file.', @@ -159,6 +52,12 @@ export const meta = { code: 'NO_SUCH_PAGE', id: '8e01b590-7eb9-431b-a239-860e086c408e', }, + + invalidRegexp: { + message: 'Invalid Regular Expression.', + code: 'INVALID_REGEXP', + id: '0d786918-10df-41cd-8f33-8dec7d9a89a5', + } }, res: { @@ -168,8 +67,60 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { ...Users.nameSchema, nullable: true }, + description: { ...Users.descriptionSchema, nullable: true }, + location: { ...Users.locationSchema, nullable: true }, + birthday: { ...Users.birthdaySchema, nullable: true }, + lang: { type: 'string', enum: [null, ...Object.keys(langmap)], nullable: true }, + avatarId: { type: 'string', format: 'misskey:id', nullable: true }, + bannerId: { type: 'string', format: 'misskey:id', nullable: true }, + fields: { type: 'array', + minItems: 0, + maxItems: 16, + items: { + type: 'object', + properties: { + name: { type: 'string' }, + value: { type: 'string' }, + }, + required: ['name', 'value'], + }, + }, + isLocked: { type: 'boolean' }, + isExplorable: { type: 'boolean' }, + hideOnlineStatus: { type: 'boolean' }, + publicReactions: { type: 'boolean' }, + carefulBot: { type: 'boolean' }, + autoAcceptFollowed: { type: 'boolean' }, + noCrawle: { type: 'boolean' }, + isBot: { type: 'boolean' }, + isCat: { type: 'boolean' }, + showTimelineReplies: { type: 'boolean' }, + injectFeaturedNote: { type: 'boolean' }, + receiveAnnouncementEmail: { type: 'boolean' }, + alwaysMarkNsfw: { type: 'boolean' }, + ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, + pinnedPageId: { type: 'array', items: { + type: 'string', format: 'misskey:id', + } }, + mutedWords: { type: 'array' }, + mutedInstances: { type: 'array', items: { + type: 'string', + } }, + mutingNotificationTypes: { type: 'array', items: { + type: 'string', enum: notificationTypes, + } }, + emailNotificationTypes: { type: 'array', items: { + type: 'string', + } }, + }, +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, _user, token) => { +export default define(meta, paramDef, async (ps, _user, token) => { const user = await Users.findOneOrFail(_user.id); const isSecure = token == null; @@ -187,6 +138,18 @@ export default define(meta, async (ps, _user, token) => { if (ps.avatarId !== undefined) updates.avatarId = ps.avatarId; if (ps.bannerId !== undefined) updates.bannerId = ps.bannerId; if (ps.mutedWords !== undefined) { + // validate regular expression syntax + ps.mutedWords.filter(x => !Array.isArray(x)).forEach(x => { + const regexp = x.match(/^\/(.+)\/(.*)$/); + if (!regexp) throw new ApiError(meta.errors.invalidRegexp); + + try { + new RE2(regexp[1], regexp[2]); + } catch (err) { + throw new ApiError(meta.errors.invalidRegexp); + } + }); + profileUpdates.mutedWords = ps.mutedWords; profileUpdates.enableWordMute = ps.mutedWords.length > 0; } @@ -197,6 +160,7 @@ export default define(meta, async (ps, _user, token) => { if (typeof ps.hideOnlineStatus === 'boolean') updates.hideOnlineStatus = ps.hideOnlineStatus; if (typeof ps.publicReactions === 'boolean') profileUpdates.publicReactions = ps.publicReactions; if (typeof ps.isBot === 'boolean') updates.isBot = ps.isBot; + if (typeof ps.showTimelineReplies === 'boolean') updates.showTimelineReplies = ps.showTimelineReplies; if (typeof ps.carefulBot === 'boolean') profileUpdates.carefulBot = ps.carefulBot; if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; @@ -211,12 +175,6 @@ export default define(meta, async (ps, _user, token) => { if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar); if (!avatar.type.startsWith('image/')) throw new ApiError(meta.errors.avatarNotAnImage); - - updates.avatarUrl = DriveFiles.getPublicUrl(avatar, true); - - if (avatar.blurhash) { - updates.avatarBlurhash = avatar.blurhash; - } } if (ps.bannerId) { @@ -224,12 +182,6 @@ export default define(meta, async (ps, _user, token) => { if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner); if (!banner.type.startsWith('image/')) throw new ApiError(meta.errors.bannerNotAnImage); - - updates.bannerUrl = DriveFiles.getPublicUrl(banner, false); - - if (banner.blurhash) { - updates.bannerBlurhash = banner.blurhash; - } } if (ps.pinnedPageId) { diff --git a/packages/backend/src/server/api/endpoints/i/user-group-invites.ts b/packages/backend/src/server/api/endpoints/i/user-group-invites.ts index 76a3131e6..1d7e4a16b 100644 --- a/packages/backend/src/server/api/endpoints/i/user-group-invites.ts +++ b/packages/backend/src/server/api/endpoints/i/user-group-invites.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { UserGroupInvitations } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { UserGroupInvitations } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['account', 'groups'], @@ -11,21 +9,6 @@ export const meta = { kind: 'read:user-groups', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -48,14 +31,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(UserGroupInvitations.createQueryBuilder('invitation'), ps.sinceId, ps.untilId) .andWhere(`invitation.userId = :meId`, { meId: user.id }) .leftJoinAndSelect('invitation.userGroup', 'user_group'); const invitations = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await UserGroupInvitations.packMany(invitations); diff --git a/packages/backend/src/server/api/endpoints/messaging/history.ts b/packages/backend/src/server/api/endpoints/messaging/history.ts index 5ac49cf96..14de4e102 100644 --- a/packages/backend/src/server/api/endpoints/messaging/history.ts +++ b/packages/backend/src/server/api/endpoints/messaging/history.ts @@ -1,7 +1,6 @@ -import $ from 'cafy'; -import define from '../../define'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { MessagingMessages, Mutings, UserGroupJoinings } from '@/models/index'; +import define from '../../define.js'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import { MessagingMessages, Mutings, UserGroupJoinings } from '@/models/index.js'; import { Brackets } from 'typeorm'; export const meta = { @@ -11,18 +10,6 @@ export const meta = { kind: 'read:messaging', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - group: { - validator: $.optional.bool, - default: false, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -34,8 +21,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + group: { type: 'boolean', default: false }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const mute = await Mutings.find({ muterId: user.id, }); @@ -50,7 +46,7 @@ export default define(meta, async (ps, user) => { const history: MessagingMessage[] = []; - for (let i = 0; i < ps.limit!; i++) { + for (let i = 0; i < ps.limit; i++) { const found = ps.group ? history.map(m => m.groupId!) : history.map(m => (m.userId === user.id) ? m.recipientId! : m.userId!); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages.ts b/packages/backend/src/server/api/endpoints/messaging/messages.ts index 7dbddd80e..49ace2160 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages.ts @@ -1,12 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { MessagingMessages, UserGroups, UserGroupJoinings, Users } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { MessagingMessages, UserGroups, UserGroupJoinings, Users } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; import { Brackets } from 'typeorm'; -import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivity } from '../../common/read-messaging-message'; +import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivity } from '../../common/read-messaging-message.js'; export const meta = { tags: ['messaging'], @@ -15,34 +13,6 @@ export const meta = { kind: 'read:messaging', - params: { - userId: { - validator: $.optional.type(ID), - }, - - groupId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - markAsRead: { - validator: $.optional.bool, - default: true, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -74,8 +44,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + groupId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + markAsRead: { type: 'boolean', default: true }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { if (ps.userId != null) { // Fetch recipient (user) const recipient = await getUser(ps.userId).catch(e => { @@ -97,7 +80,7 @@ export default define(meta, async (ps, user) => { .setParameter('meId', user.id) .setParameter('recipientId', recipient.id); - const messages = await query.take(ps.limit!).getMany(); + const messages = await query.take(ps.limit).getMany(); // Mark all as read if (ps.markAsRead) { @@ -133,7 +116,7 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(MessagingMessages.createQueryBuilder('message'), ps.sinceId, ps.untilId) .andWhere(`message.groupId = :groupId`, { groupId: recipientGroup.id }); - const messages = await query.take(ps.limit!).getMany(); + const messages = await query.take(ps.limit).getMany(); // Mark all as read if (ps.markAsRead) { diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/create.ts b/packages/backend/src/server/api/endpoints/messaging/messages/create.ts index 5ec16f5e5..a9b926c4f 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/create.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/create.ts @@ -1,12 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { MessagingMessages, DriveFiles, UserGroups, UserGroupJoinings, Blockings } from '@/models/index'; -import { User } from '@/models/entities/user'; -import { UserGroup } from '@/models/entities/user-group'; -import { createMessage } from '@/services/messages/create'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; +import { MessagingMessages, DriveFiles, UserGroups, UserGroupJoinings, Blockings } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { createMessage } from '@/services/messages/create.js'; export const meta = { tags: ['messaging'], @@ -15,24 +13,6 @@ export const meta = { kind: 'write:messaging', - params: { - userId: { - validator: $.optional.type(ID), - }, - - groupId: { - validator: $.optional.type(ID), - }, - - text: { - validator: $.optional.str.pipe(MessagingMessages.validateText), - }, - - fileId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -84,8 +64,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + groupId: { type: 'string', format: 'misskey:id' }, + text: { type: 'string', nullable: true, maxLength: 3000 }, + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { let recipientUser: User | undefined; let recipientGroup: UserGroup | undefined; diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts b/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts index 2975419ce..a0945af51 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; +import define from '../../../define.js'; import ms from 'ms'; -import { ApiError } from '../../../error'; -import { MessagingMessages } from '@/models/index'; -import { deleteMessage } from '@/services/messages/delete'; +import { ApiError } from '../../../error.js'; +import { MessagingMessages } from '@/models/index.js'; +import { deleteMessage } from '@/services/messages/delete.js'; export const meta = { tags: ['messaging'], @@ -19,12 +17,6 @@ export const meta = { minInterval: ms('1sec'), }, - params: { - messageId: { - validator: $.type(ID), - }, - }, - errors: { noSuchMessage: { message: 'No such message.', @@ -34,8 +26,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + messageId: { type: 'string', format: 'misskey:id' }, + }, + required: ['messageId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const message = await MessagingMessages.findOne({ id: ps.messageId, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/read.ts b/packages/backend/src/server/api/endpoints/messaging/messages/read.ts index 42c3f49f6..8d38e509a 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/read.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/read.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { MessagingMessages } from '@/models/index'; -import { readUserMessagingMessage, readGroupMessagingMessage } from '../../../common/read-messaging-message'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { MessagingMessages } from '@/models/index.js'; +import { readUserMessagingMessage, readGroupMessagingMessage } from '../../../common/read-messaging-message.js'; export const meta = { tags: ['messaging'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:messaging', - params: { - messageId: { - validator: $.type(ID), - }, - }, - errors: { noSuchMessage: { message: 'No such message.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + messageId: { type: 'string', format: 'misskey:id' }, + }, + required: ['messageId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const message = await MessagingMessages.findOne(ps.messageId); if (message == null) { diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 693a7a04e..6231c35ab 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -1,23 +1,16 @@ -import $ from 'cafy'; -import config from '@/config/index'; -import define from '../define'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Ads, Emojis, Users } from '@/models/index'; -import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits'; +import config from '@/config/index.js'; +import define from '../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Ads, Emojis, Users } from '@/models/index.js'; +import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits.js'; import { MoreThan } from 'typeorm'; +import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; export const meta = { tags: ['meta'], requireCredential: false, - params: { - detail: { - validator: $.optional.bool, - default: true, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -76,6 +69,14 @@ export const meta = { optional: false, nullable: false, default: false, }, + defaultDarkTheme: { + type: 'string', + optional: false, nullable: true, + }, + defaultLightTheme: { + type: 'string', + optional: false, nullable: true, + }, disableRegistration: { type: 'boolean', optional: false, nullable: false, @@ -100,10 +101,6 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, - proxyRemoteFiles: { - type: 'boolean', - optional: false, nullable: false, - }, emailRequiredForSignup: { type: 'boolean', optional: false, nullable: false, @@ -149,7 +146,6 @@ export const meta = { maxNoteTextLength: { type: 'number', optional: false, nullable: false, - default: 500, }, emojis: { type: 'array', @@ -448,8 +444,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + detail: { type: 'boolean', default: true }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const instance = await fetchMeta(true); const emojis = await Emojis.find({ @@ -499,14 +503,17 @@ export default define(meta, async (ps, me) => { enableRecaptcha: instance.enableRecaptcha, recaptchaSiteKey: instance.recaptchaSiteKey, swPublickey: instance.swPublicKey, + themeColor: instance.themeColor, mascotImageUrl: instance.mascotImageUrl, bannerUrl: instance.bannerUrl, errorImageUrl: instance.errorImageUrl, iconUrl: instance.iconUrl, backgroundImageUrl: instance.backgroundImageUrl, logoImageUrl: instance.logoImageUrl, - maxNoteTextLength: Math.min(instance.maxNoteTextLength, DB_MAX_NOTE_TEXT_LENGTH), + maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 垌斚äē’換性ぎため emojis: await Emojis.packMany(emojis), + defaultLightTheme: instance.defaultLightTheme, + defaultDarkTheme: instance.defaultDarkTheme, ads: ads.map(ad => ({ id: ad.id, url: ad.url, @@ -528,7 +535,6 @@ export default define(meta, async (ps, me) => { pinnedPages: instance.pinnedPages, pinnedClipId: instance.pinnedClipId, cacheRemoteFiles: instance.cacheRemoteFiles, - proxyRemoteFiles: instance.proxyRemoteFiles, requireSetup: (await Users.count({ host: null, })) === 0, diff --git a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts index 158c8877e..73ecdaeb0 100644 --- a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts +++ b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts @@ -1,8 +1,7 @@ -import $ from 'cafy'; -import define from '../../define'; -import { AccessTokens } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { secureRndstr } from '@/misc/secure-rndstr'; +import define from '../../define.js'; +import { AccessTokens } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { secureRndstr } from '@/misc/secure-rndstr.js'; export const meta = { tags: ['auth'], @@ -11,28 +10,6 @@ export const meta = { secure: true, - params: { - session: { - validator: $.nullable.str, - }, - - name: { - validator: $.nullable.optional.str, - }, - - description: { - validator: $.nullable.optional.str, - }, - - iconUrl: { - validator: $.nullable.optional.str, - }, - - permission: { - validator: $.arr($.str).unique(), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -45,8 +22,22 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + session: { type: 'string', nullable: true }, + name: { type: 'string', nullable: true }, + description: { type: 'string', nullable: true }, + iconUrl: { type: 'string', nullable: true }, + permission: { type: 'array', uniqueItems: true, items: { + type: 'string', + } }, + }, + required: ['session', 'permission'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Generate access token const accessToken = secureRndstr(32, true); diff --git a/packages/backend/src/server/api/endpoints/mute/create.ts b/packages/backend/src/server/api/endpoints/mute/create.ts index 6ba5a453c..0178aab14 100644 --- a/packages/backend/src/server/api/endpoints/mute/create.ts +++ b/packages/backend/src/server/api/endpoints/mute/create.ts @@ -1,12 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { genId } from '@/misc/gen-id'; -import { Mutings, NoteWatchings } from '@/models/index'; -import { Muting } from '@/models/entities/muting'; -import { publishUserEvent } from '@/services/stream'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { genId } from '@/misc/gen-id.js'; +import { Mutings, NoteWatchings } from '@/models/index.js'; +import { Muting } from '@/models/entities/muting.js'; +import { publishUserEvent } from '@/services/stream.js'; export const meta = { tags: ['account'], @@ -15,12 +13,6 @@ export const meta = { kind: 'write:mutes', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -42,8 +34,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const muter = user; // č‡Ē分č‡ĒčēĢ diff --git a/packages/backend/src/server/api/endpoints/mute/delete.ts b/packages/backend/src/server/api/endpoints/mute/delete.ts index 21948dc3d..a8cf2a666 100644 --- a/packages/backend/src/server/api/endpoints/mute/delete.ts +++ b/packages/backend/src/server/api/endpoints/mute/delete.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { Mutings } from '@/models/index'; -import { publishUserEvent } from '@/services/stream'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { Mutings } from '@/models/index.js'; +import { publishUserEvent } from '@/services/stream.js'; export const meta = { tags: ['account'], @@ -13,12 +11,6 @@ export const meta = { kind: 'write:mutes', - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -40,8 +32,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const muter = user; // Check if the mutee is yourself diff --git a/packages/backend/src/server/api/endpoints/mute/list.ts b/packages/backend/src/server/api/endpoints/mute/list.ts index 4c6a81b63..31283cf4c 100644 --- a/packages/backend/src/server/api/endpoints/mute/list.ts +++ b/packages/backend/src/server/api/endpoints/mute/list.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { Mutings } from '@/models/index'; +import define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Mutings } from '@/models/index.js'; export const meta = { tags: ['account'], @@ -11,21 +9,6 @@ export const meta = { kind: 'read:mutes', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 30, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -37,13 +20,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(Mutings.createQueryBuilder('muting'), ps.sinceId, ps.untilId) .andWhere(`muting.muterId = :meId`, { meId: me.id }); const mutings = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Mutings.packMany(mutings, me); diff --git a/packages/backend/src/server/api/endpoints/my/apps.ts b/packages/backend/src/server/api/endpoints/my/apps.ts index 42bd5c5f7..85b75c15d 100644 --- a/packages/backend/src/server/api/endpoints/my/apps.ts +++ b/packages/backend/src/server/api/endpoints/my/apps.ts @@ -1,83 +1,40 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Apps } from '@/models/index'; +import define from '../../define.js'; +import { Apps } from '@/models/index.js'; export const meta = { tags: ['account', 'app'], requireCredential: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - }, - res: { type: 'array', optional: false, nullable: false, items: { type: 'object', optional: false, nullable: false, - properties: { - id: { - type: 'string', - optional: false, nullable: false, - }, - name: { - type: 'string', - optional: false, nullable: false, - }, - callbackUrl: { - type: 'string', - optional: false, nullable: false, - }, - permission: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'string', - optional: false, nullable: false, - }, - }, - secret: { - type: 'string', - optional: true, nullable: false, - }, - isAuthorized: { - type: 'object', - optional: true, nullable: false, - properties: { - appId: { - type: 'string', - optional: false, nullable: false, - }, - userId: { - type: 'string', - optional: false, nullable: false, - }, - }, - }, - }, + ref: 'App', }, }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = { userId: user.id, }; const apps = await Apps.find({ where: query, - take: ps.limit!, + take: ps.limit, skip: ps.offset, }); diff --git a/packages/backend/src/server/api/endpoints/notes.ts b/packages/backend/src/server/api/endpoints/notes.ts index 9edc6cb11..96657f8d3 100644 --- a/packages/backend/src/server/api/endpoints/notes.ts +++ b/packages/backend/src/server/api/endpoints/notes.ts @@ -1,47 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../define'; -import { makePaginationQuery } from '../common/make-pagination-query'; -import { Notes } from '@/models/index'; +import define from '../define.js'; +import { makePaginationQuery } from '../common/make-pagination-query.js'; +import { Notes } from '@/models/index.js'; export const meta = { tags: ['notes'], - params: { - local: { - validator: $.optional.bool, - }, - - reply: { - validator: $.optional.bool, - }, - - renote: { - validator: $.optional.bool, - }, - - withFiles: { - validator: $.optional.bool, - }, - - poll: { - validator: $.optional.bool, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -53,16 +16,37 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + local: { type: 'boolean' }, + reply: { type: 'boolean' }, + renote: { type: 'boolean' }, + withFiles: { type: 'boolean' }, + poll: { type: 'boolean' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.visibility = 'public'`) .andWhere(`note.localOnly = FALSE`) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); if (ps.local) { query.andWhere('note.userHost IS NULL'); @@ -89,7 +73,7 @@ export default define(meta, async (ps) => { // query.isBot = bot; //} - const notes = await query.take(ps.limit!).getMany(); + const notes = await query.take(ps.limit).getMany(); return await Notes.packMany(notes); }); diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts index 088ef65e9..86dde30d6 100644 --- a/packages/backend/src/server/api/endpoints/notes/children.ts +++ b/packages/backend/src/server/api/endpoints/notes/children.ts @@ -1,38 +1,17 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; +import define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; import { Brackets } from 'typeorm'; -import { Notes } from '@/models/index'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; -import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query'; +import { Notes } from '@/models/index.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -44,8 +23,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(new Brackets(qb => { qb .where(`note.replyId = :noteId`, { noteId: ps.noteId }) @@ -59,17 +49,23 @@ export default define(meta, async (ps, user) => { })); })) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); if (user) generateMutedInstanceQuery(query, user); - const notes = await query.take(ps.limit!).getMany(); + const notes = await query.take(ps.limit).getMany(); return await Notes.packMany(notes, user); }); diff --git a/packages/backend/src/server/api/endpoints/notes/clips.ts b/packages/backend/src/server/api/endpoints/notes/clips.ts index b89c6db4a..9a863b714 100644 --- a/packages/backend/src/server/api/endpoints/notes/clips.ts +++ b/packages/backend/src/server/api/endpoints/notes/clips.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ClipNotes, Clips } from '@/models/index'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; +import define from '../../define.js'; +import { ClipNotes, Clips } from '@/models/index.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; import { In } from 'typeorm'; export const meta = { @@ -11,12 +9,6 @@ export const meta = { requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -36,8 +28,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index 4bd89c32e..2552c0f99 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -1,32 +1,14 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getNote } from '../../common/getters'; -import { Note } from '@/models/entities/note'; -import { Notes } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getNote } from '../../common/getters.js'; +import { Note } from '@/models/entities/note.js'; +import { Notes } from '@/models/index.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -46,8 +28,18 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; @@ -65,7 +57,7 @@ export default define(meta, async (ps, user) => { conversation.push(p); } - if (conversation.length == ps.limit!) { + if (conversation.length == ps.limit) { return; } diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 4efa76b24..e4a9b2889 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -1,26 +1,14 @@ -import $ from 'cafy'; import ms from 'ms'; -import { length } from 'stringz'; -import create from '@/services/note/create'; -import define from '../../define'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { ApiError } from '../../error'; -import { ID } from '@/misc/cafy-id'; -import { User } from '@/models/entities/user'; -import { Users, DriveFiles, Notes, Channels, Blockings } from '@/models/index'; -import { DriveFile } from '@/models/entities/drive-file'; -import { Note } from '@/models/entities/note'; -import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits'; -import { noteVisibilities } from '../../../../types'; -import { Channel } from '@/models/entities/channel'; - -let maxNoteTextLength = 500; - -setInterval(() => { - fetchMeta().then(m => { - maxNoteTextLength = m.maxNoteTextLength; - }); -}, 3000); +import create from '@/services/note/create.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { User } from '@/models/entities/user.js'; +import { Users, DriveFiles, Notes, Channels, Blockings } from '@/models/index.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { Note } from '@/models/entities/note.js'; +import { noteVisibilities } from '../../../../types.js'; +import { Channel } from '@/models/entities/channel.js'; +import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; export const meta = { tags: ['notes'], @@ -34,84 +22,6 @@ export const meta = { kind: 'write:notes', - params: { - visibility: { - validator: $.optional.str.or(noteVisibilities as unknown as string[]), - default: 'public', - }, - - visibleUserIds: { - validator: $.optional.arr($.type(ID)).unique().min(0), - }, - - text: { - validator: $.optional.nullable.str.pipe(text => - text.trim() != '' - && length(text.trim()) <= maxNoteTextLength - && Array.from(text.trim()).length <= DB_MAX_NOTE_TEXT_LENGTH, // DB limit - ), - default: null, - }, - - cw: { - validator: $.optional.nullable.str.pipe(Notes.validateCw), - }, - - localOnly: { - validator: $.optional.bool, - default: false, - }, - - noExtractMentions: { - validator: $.optional.bool, - default: false, - }, - - noExtractHashtags: { - validator: $.optional.bool, - default: false, - }, - - noExtractEmojis: { - validator: $.optional.bool, - default: false, - }, - - fileIds: { - validator: $.optional.arr($.type(ID)).unique().range(1, 16), - }, - - mediaIds: { - validator: $.optional.arr($.type(ID)).unique().range(1, 16), - deprecated: true, - }, - - replyId: { - validator: $.optional.nullable.type(ID), - }, - - renoteId: { - validator: $.optional.nullable.type(ID), - }, - - channelId: { - validator: $.optional.nullable.type(ID), - }, - - poll: { - validator: $.optional.nullable.obj({ - choices: $.arr($.str) - .unique() - .range(2, 10) - .each(c => c.length > 0 && c.length < 50), - multiple: $.optional.bool, - expiresAt: $.optional.nullable.num.int(), - expiredAfter: $.optional.nullable.num.int().min(1), - }).strict(), - ref: 'poll', - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -175,8 +85,49 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], default: "public" }, + visibleUserIds: { type: 'array', uniqueItems: true, items: { + type: 'string', format: 'misskey:id', + } }, + text: { type: 'string', nullable: true, maxLength: MAX_NOTE_TEXT_LENGTH, default: null }, + cw: { type: 'string', nullable: true, maxLength: 100 }, + localOnly: { type: 'boolean', default: false }, + noExtractMentions: { type: 'boolean', default: false }, + noExtractHashtags: { type: 'boolean', default: false }, + noExtractEmojis: { type: 'boolean', default: false }, + fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 16, items: { + type: 'string', format: 'misskey:id', + } }, + mediaIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 16, items: { + type: 'string', format: 'misskey:id', + } }, + replyId: { type: 'string', format: 'misskey:id', nullable: true }, + renoteId: { type: 'string', format: 'misskey:id', nullable: true }, + channelId: { type: 'string', format: 'misskey:id', nullable: true }, + poll: { + type: 'object', nullable: true, + properties: { + choices: { + type: 'array', uniqueItems: true, minItems: 2, maxItems: 10, + items: { + type: 'string', minLength: 1, maxLength: 50, + }, + }, + multiple: { type: 'boolean', default: false }, + expiresAt: { type: 'integer', nullable: true }, + expiredAfter: { type: 'integer', nullable: true, minimum: 1 }, + }, + required: ['choices'], + }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { let visibleUsers: User[] = []; if (ps.visibleUserIds) { visibleUsers = (await Promise.all(ps.visibleUserIds.map(id => Users.findOne(id)))) diff --git a/packages/backend/src/server/api/endpoints/notes/delete.ts b/packages/backend/src/server/api/endpoints/notes/delete.ts index 9e080d9e9..22ff2275c 100644 --- a/packages/backend/src/server/api/endpoints/notes/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/delete.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import deleteNote from '@/services/note/delete'; -import define from '../../define'; +import deleteNote from '@/services/note/delete.js'; +import define from '../../define.js'; import ms from 'ms'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; -import { Users } from '@/models/index'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['notes'], @@ -20,12 +18,6 @@ export const meta = { minInterval: ms('1sec'), }, - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -41,8 +33,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts index 78da6a3b0..bcc2c44c0 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getNote } from '../../../common/getters'; -import { NoteFavorites } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getNote } from '../../../common/getters.js'; +import { NoteFavorites } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['notes', 'favorites'], @@ -13,12 +11,6 @@ export const meta = { kind: 'write:favorites', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -34,8 +26,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Get favoritee const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts index 3f3d50f0d..d41fab22d 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getNote } from '../../../common/getters'; -import { NoteFavorites } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getNote } from '../../../common/getters.js'; +import { NoteFavorites } from '@/models/index.js'; export const meta = { tags: ['notes', 'favorites'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:favorites', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -33,8 +25,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Get favoritee const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index 5a47fb9e0..6308d2369 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -1,26 +1,13 @@ -import $ from 'cafy'; -import define from '../../define'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { Notes } from '@/models/index'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import define from '../../define.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { Notes } from '@/models/index.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -32,8 +19,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const max = 30; const day = 1000 * 60 * 60 * 24 * 3; // 3æ—Ĩ前ぞで @@ -44,10 +40,16 @@ export default define(meta, async (ps, user) => { .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index cac8b7d8a..26aaa0919 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -1,47 +1,18 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { ApiError } from '../../error'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { Notes } from '@/models/index'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query'; -import { activeUsersChart } from '@/services/chart/index'; -import { generateRepliesQuery } from '../../common/generate-replies-query'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { ApiError } from '../../error.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Notes } from '@/models/index.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; +import { generateRepliesQuery } from '../../common/generate-replies-query.js'; +import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], - params: { - withFiles: { - validator: $.optional.bool, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -61,8 +32,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + withFiles: { type: 'boolean' }, + 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: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableGlobalTimeline) { if (user == null || (!user.isAdmin && !user.isModerator)) { @@ -76,10 +60,16 @@ export default define(meta, async (ps, user) => { .andWhere('note.visibility = \'public\'') .andWhere('note.channelId IS NULL') .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateRepliesQuery(query, user); if (user) generateMutedUserQuery(query, user); @@ -92,11 +82,11 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); process.nextTick(() => { if (user) { - activeUsersChart.update(user); + activeUsersChart.read(user); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 9683df461..9bcb64b65 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -1,67 +1,23 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { ApiError } from '../../error'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { Followings, Notes } from '@/models/index'; +import define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { ApiError } from '../../error.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Followings, Notes } from '@/models/index.js'; import { Brackets } from 'typeorm'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query'; -import { activeUsersChart } from '@/services/chart/index'; -import { generateRepliesQuery } from '../../common/generate-replies-query'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query'; -import { generateChannelQuery } from '../../common/generate-channel-query'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; +import { generateRepliesQuery } from '../../common/generate-replies-query.js'; +import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; +import { generateChannelQuery } from '../../common/generate-channel-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - - includeMyRenotes: { - validator: $.optional.bool, - default: true, - }, - - includeRenotedMyNotes: { - validator: $.optional.bool, - default: true, - }, - - includeLocalRenotes: { - validator: $.optional.bool, - default: true, - }, - - withFiles: { - validator: $.optional.bool, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -81,8 +37,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + 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' }, + includeMyRenotes: { type: 'boolean', default: true }, + includeRenotedMyNotes: { type: 'boolean', default: true }, + includeLocalRenotes: { type: 'boolean', default: true }, + withFiles: { type: 'boolean' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { throw new ApiError(meta.errors.stlDisabled); @@ -100,10 +72,16 @@ export default define(meta, async (ps, user) => { .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); })) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); @@ -149,11 +127,11 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); process.nextTick(() => { if (user) { - activeUsersChart.update(user); + activeUsersChart.read(user); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index 777664412..12fc88b1f 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -1,58 +1,20 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { ApiError } from '../../error'; -import { Notes } from '@/models/index'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { activeUsersChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { ApiError } from '../../error.js'; +import { Notes } from '@/models/index.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; import { Brackets } from 'typeorm'; -import { generateRepliesQuery } from '../../common/generate-replies-query'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query'; -import { generateChannelQuery } from '../../common/generate-channel-query'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import { generateRepliesQuery } from '../../common/generate-replies-query.js'; +import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; +import { generateChannelQuery } from '../../common/generate-channel-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], - params: { - withFiles: { - validator: $.optional.bool, - }, - - fileType: { - validator: $.optional.arr($.str), - }, - - excludeNsfw: { - validator: $.optional.bool, - default: false, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -72,8 +34,25 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + withFiles: { type: 'boolean' }, + fileType: { type: 'array', items: { + type: 'string', + } }, + excludeNsfw: { type: 'boolean', default: false }, + 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: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableLocalTimeline) { if (user == null || (!user.isAdmin && !user.isModerator)) { @@ -86,10 +65,16 @@ export default define(meta, async (ps, user) => { ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateChannelQuery(query, user); generateRepliesQuery(query, user); @@ -118,11 +103,11 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); process.nextTick(() => { if (user) { - activeUsersChart.update(user); + activeUsersChart.read(user); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/mentions.ts b/packages/backend/src/server/api/endpoints/notes/mentions.ts index 81b384436..eafbba322 100644 --- a/packages/backend/src/server/api/endpoints/notes/mentions.ts +++ b/packages/backend/src/server/api/endpoints/notes/mentions.ts @@ -1,44 +1,18 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import read from '@/services/note/read'; -import { Notes, Followings } from '@/models/index'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import read from '@/services/note/read.js'; +import { Notes, Followings } from '@/models/index.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; import { Brackets } from 'typeorm'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; -import { generateMutedNoteThreadQuery } from '../../common/generate-muted-note-thread-query'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { generateMutedNoteThreadQuery } from '../../common/generate-muted-note-thread-query.js'; export const meta = { tags: ['notes'], requireCredential: true, - params: { - following: { - validator: $.optional.bool, - default: false, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - visibility: { - validator: $.optional.str, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -50,8 +24,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + following: { type: 'boolean', default: false }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + visibility: { type: 'string' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const followingQuery = Followings.createQueryBuilder('following') .select('following.followeeId') .where('following.followerId = :followerId', { followerId: user.id }); @@ -62,10 +48,16 @@ export default define(meta, async (ps, user) => { .orWhere(`'{"${user.id}"}' <@ note.visibleUserIds`); })) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, user); generateMutedUserQuery(query, user); @@ -81,7 +73,7 @@ export default define(meta, async (ps, user) => { query.setParameters(followingQuery.getParameters()); } - const mentions = await query.take(ps.limit!).getMany(); + const mentions = await query.take(ps.limit).getMany(); read(user.id, mentions); diff --git a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts index 79b558e65..bdd1aeecd 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts @@ -1,6 +1,5 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Polls, Mutings, Notes, PollVotes } from '@/models/index'; +import define from '../../../define.js'; +import { Polls, Mutings, Notes, PollVotes } from '@/models/index.js'; import { Brackets, In } from 'typeorm'; export const meta = { @@ -8,18 +7,6 @@ export const meta = { requireCredential: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -31,8 +18,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = Polls.createQueryBuilder('poll') .where('poll.userHost IS NULL') .andWhere(`poll.userId != :meId`, { meId: user.id }) @@ -64,7 +60,7 @@ export default define(meta, async (ps, user) => { query.setParameters(mutingQuery.getParameters()); //#endregion - const polls = await query.take(ps.limit!).skip(ps.offset).getMany(); + const polls = await query.take(ps.limit).skip(ps.offset).getMany(); if (polls.length === 0) return []; diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index 77387cacb..ef52d0366 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -1,18 +1,16 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { publishNoteStream } from '@/services/stream'; -import { createNotification } from '@/services/create-notification'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getNote } from '../../../common/getters'; -import { deliver } from '@/queue/index'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderVote from '@/remote/activitypub/renderer/vote'; -import { deliverQuestionUpdate } from '@/services/note/polls/update'; -import { PollVotes, NoteWatchings, Users, Polls, Blockings } from '@/models/index'; +import { publishNoteStream } from '@/services/stream.js'; +import { createNotification } from '@/services/create-notification.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getNote } from '../../../common/getters.js'; +import { deliver } from '@/queue/index.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderVote from '@/remote/activitypub/renderer/vote.js'; +import { deliverQuestionUpdate } from '@/services/note/polls/update.js'; +import { PollVotes, NoteWatchings, Users, Polls, Blockings } from '@/models/index.js'; import { Not } from 'typeorm'; -import { IRemoteUser } from '@/models/entities/user'; -import { genId } from '@/misc/gen-id'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['notes'], @@ -21,16 +19,6 @@ export const meta = { kind: 'write:votes', - params: { - noteId: { - validator: $.type(ID), - }, - - choice: { - validator: $.num, - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -70,8 +58,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + choice: { type: 'integer' }, + }, + required: ['noteId', 'choice'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const createdAt = new Date(); // Get votee diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index 5205a7817..43e5d1ef6 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -1,45 +1,15 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; -import { NoteReactions } from '@/models/index'; +import define from '../../define.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { NoteReactions } from '@/models/index.js'; import { DeepPartial } from 'typeorm'; -import { NoteReaction } from '@/models/entities/note-reaction'; +import { NoteReaction } from '@/models/entities/note-reaction.js'; export const meta = { tags: ['notes', 'reactions'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - - type: { - validator: $.optional.nullable.str, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num, - default: 0, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -59,8 +29,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + type: { type: 'string', nullable: true }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; @@ -80,11 +63,12 @@ export default define(meta, async (ps, user) => { const reactions = await NoteReactions.find({ where: query, - take: ps.limit!, + take: ps.limit, skip: ps.offset, order: { id: -1, }, + relations: ['user', 'user.avatar', 'user.banner', 'note'], }); return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, user))); diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts index 1b42781ce..07e52a926 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import createReaction from '@/services/note/reaction/create'; -import define from '../../../define'; -import { getNote } from '../../../common/getters'; -import { ApiError } from '../../../error'; +import createReaction from '@/services/note/reaction/create.js'; +import define from '../../../define.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['reactions', 'notes'], @@ -12,16 +10,6 @@ export const meta = { kind: 'write:reactions', - params: { - noteId: { - validator: $.type(ID), - }, - - reaction: { - validator: $.str, - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -43,8 +31,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + reaction: { type: 'string' }, + }, + required: ['noteId', 'reaction'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts index 1d686b597..639ecae26 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; +import define from '../../../define.js'; import ms from 'ms'; -import deleteReaction from '@/services/note/reaction/delete'; -import { getNote } from '../../../common/getters'; -import { ApiError } from '../../../error'; +import deleteReaction from '@/services/note/reaction/delete.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['reactions', 'notes'], @@ -19,12 +17,6 @@ export const meta = { minInterval: ms('3sec'), }, - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -40,8 +32,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts index f71d23146..87c855a5e 100644 --- a/packages/backend/src/server/api/endpoints/notes/renotes.ts +++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts @@ -1,38 +1,17 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { Notes } from '@/models/index'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import define from '../../define.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Notes } from '@/models/index.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -52,8 +31,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; @@ -62,16 +52,22 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.renoteId = :renoteId`, { renoteId: note.id }) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); - const renotes = await query.take(ps.limit!).getMany(); + const renotes = await query.take(ps.limit).getMany(); return await Notes.packMany(renotes, user); }); diff --git a/packages/backend/src/server/api/endpoints/notes/replies.ts b/packages/backend/src/server/api/endpoints/notes/replies.ts index 62c56534e..3053eabe3 100644 --- a/packages/backend/src/server/api/endpoints/notes/replies.ts +++ b/packages/backend/src/server/api/endpoints/notes/replies.ts @@ -1,36 +1,15 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Notes } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import define from '../../define.js'; +import { Notes } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -42,21 +21,38 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere('note.replyId = :replyId', { replyId: ps.noteId }) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); return await Notes.packMany(timeline, user); }); diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index 87eaffe2f..c6503eb05 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -1,60 +1,16 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { Notes } from '@/models/index'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; +import define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Notes } from '@/models/index.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; import { Brackets } from 'typeorm'; -import { safeForSql } from '@/misc/safe-for-sql'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import { safeForSql } from '@/misc/safe-for-sql.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes', 'hashtags'], - params: { - tag: { - validator: $.optional.str, - }, - - query: { - validator: $.optional.arr($.arr($.str)), - }, - - reply: { - validator: $.optional.nullable.bool, - default: null, - }, - - renote: { - validator: $.optional.nullable.bool, - default: null, - }, - - withFiles: { - validator: $.optional.bool, - }, - - poll: { - validator: $.optional.nullable.bool, - default: null, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -66,14 +22,40 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + tag: { type: 'string' }, + query: { type: 'array', items: { + type: 'array', items: { + type: 'string', + }, + } }, + reply: { type: 'boolean', nullable: true, default: null }, + renote: { type: 'boolean', nullable: true, default: null }, + withFiles: { type: 'boolean' }, + poll: { type: 'boolean', nullable: true, default: null }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); @@ -129,7 +111,7 @@ export default define(meta, async (ps, me) => { } // Search notes - const notes = await query.take(ps.limit!).getMany(); + const notes = await query.take(ps.limit).getMany(); return await Notes.packMany(notes, me); }); diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index e75212b14..e77892b15 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -1,54 +1,18 @@ -import $ from 'cafy'; -import es from '../../../../db/elasticsearch'; -import define from '../../define'; -import { Notes } from '@/models/index'; +import es from '../../../../db/elasticsearch.js'; +import define from '../../define.js'; +import { Notes } from '@/models/index.js'; import { In } from 'typeorm'; -import { ID } from '@/misc/cafy-id'; -import config from '@/config/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import config from '@/config/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - query: { - validator: $.str, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - host: { - validator: $.optional.nullable.str, - default: undefined, - }, - - userId: { - validator: $.optional.nullable.type(ID), - default: null, - }, - - channelId: { - validator: $.optional.nullable.type(ID), - default: null, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -63,8 +27,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + query: { type: 'string' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + host: { type: 'string', nullable: true }, + userId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + channelId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + }, + required: ['query'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { if (es == null) { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId); @@ -77,16 +56,22 @@ export default define(meta, async (ps, me) => { query .andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); if (me) generateBlockedUserQuery(query, me); - const notes = await query.take(ps.limit!).getMany(); + const notes = await query.take(ps.limit).getMany(); return await Notes.packMany(notes, me); } else { @@ -115,7 +100,7 @@ export default define(meta, async (ps, me) => { const result = await es.search({ index: config.elasticsearch.index || 'misskey_note', body: { - size: ps.limit!, + size: ps.limit, from: ps.offset, query: { bool: { diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index feb94be1a..d6692923c 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -1,21 +1,13 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; -import { Notes } from '@/models/index'; +import define from '../../define.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { Notes } from '@/models/index.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -31,8 +23,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/state.ts b/packages/backend/src/server/api/endpoints/notes/state.ts index c3e9090bb..6fdb8e88f 100644 --- a/packages/backend/src/server/api/endpoints/notes/state.ts +++ b/packages/backend/src/server/api/endpoints/notes/state.ts @@ -1,19 +1,11 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { NoteFavorites, Notes, NoteThreadMutings, NoteWatchings } from '@/models/index'; +import define from '../../define.js'; +import { NoteFavorites, Notes, NoteThreadMutings, NoteWatchings } from '@/models/index.js'; export const meta = { tags: ['notes'], requireCredential: true, - params: { - noteId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -34,8 +26,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await Notes.findOneOrFail(ps.noteId); const [favorite, watching, threadMuting] = await Promise.all([ diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts index a8b50d90f..e48a2cf57 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { getNote } from '../../../common/getters'; -import { ApiError } from '../../../error'; -import { Notes, NoteThreadMutings } from '@/models'; -import { genId } from '@/misc/gen-id'; -import readNote from '@/services/note/read'; +import define from '../../../define.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; +import { Notes, NoteThreadMutings } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import readNote from '@/services/note/read.js'; export const meta = { tags: ['notes'], @@ -14,12 +12,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -29,8 +21,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts index f76b526ce..4fb3137a5 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { getNote } from '../../../common/getters'; -import { ApiError } from '../../../error'; -import { NoteThreadMutings } from '@/models'; +import define from '../../../define.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; +import { NoteThreadMutings } from '@/models/index.js'; export const meta = { tags: ['notes'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index 8be2861ae..fde66b241 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -1,65 +1,21 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { Notes, Followings } from '@/models/index'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query'; -import { activeUsersChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Notes, Followings } from '@/models/index.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; import { Brackets } from 'typeorm'; -import { generateRepliesQuery } from '../../common/generate-replies-query'; -import { generateMutedNoteQuery } from '../../common/generate-muted-note-query'; -import { generateChannelQuery } from '../../common/generate-channel-query'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; +import { generateRepliesQuery } from '../../common/generate-replies-query.js'; +import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; +import { generateChannelQuery } from '../../common/generate-channel-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - - includeMyRenotes: { - validator: $.optional.bool, - default: true, - }, - - includeRenotedMyNotes: { - validator: $.optional.bool, - default: true, - }, - - includeLocalRenotes: { - validator: $.optional.bool, - default: true, - }, - - withFiles: { - validator: $.optional.bool, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -71,8 +27,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + 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' }, + includeMyRenotes: { type: 'boolean', default: true }, + includeRenotedMyNotes: { type: 'boolean', default: true }, + includeLocalRenotes: { type: 'boolean', default: true }, + withFiles: { type: 'boolean' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const hasFollowing = (await Followings.count({ where: { followerId: user.id, @@ -92,10 +64,16 @@ export default define(meta, async (ps, user) => { if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); })) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); @@ -141,11 +119,11 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); process.nextTick(() => { if (user) { - activeUsersChart.update(user); + activeUsersChart.read(user); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index ed069cb75..068df6940 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -1,29 +1,18 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; +import define from '../../define.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; import fetch from 'node-fetch'; -import config from '@/config/index'; -import { getAgentByUrl } from '@/misc/fetch'; -import { URLSearchParams } from 'url'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Notes } from '@/models'; +import config from '@/config/index.js'; +import { getAgentByUrl } from '@/misc/fetch.js'; +import { URLSearchParams } from 'node:url'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Notes } from '@/models/index.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - targetLang: { - validator: $.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -38,8 +27,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + targetLang: { type: 'string' }, + }, + required: ['noteId', 'targetLang'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/unrenote.ts b/packages/backend/src/server/api/endpoints/notes/unrenote.ts index 8db543d32..a9aadba33 100644 --- a/packages/backend/src/server/api/endpoints/notes/unrenote.ts +++ b/packages/backend/src/server/api/endpoints/notes/unrenote.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import deleteNote from '@/services/note/delete'; -import define from '../../define'; +import deleteNote from '@/services/note/delete.js'; +import define from '../../define.js'; import ms from 'ms'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; -import { Notes, Users } from '@/models/index'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { Notes, Users } from '@/models/index.js'; export const meta = { tags: ['notes'], @@ -20,12 +18,6 @@ export const meta = { minInterval: ms('1sec'), }, - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -35,8 +27,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index 89de73fb9..0829d0e4c 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { UserLists, UserListJoinings, Notes } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { activeUsersChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { UserLists, UserListJoinings, Notes } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; import { Brackets } from 'typeorm'; export const meta = { @@ -13,52 +11,6 @@ export const meta = { requireCredential: true, - params: { - listId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - - includeMyRenotes: { - validator: $.optional.bool, - default: true, - }, - - includeRenotedMyNotes: { - validator: $.optional.bool, - default: true, - }, - - includeLocalRenotes: { - validator: $.optional.bool, - default: true, - }, - - withFiles: { - validator: $.optional.bool, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -78,8 +30,25 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + 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' }, + includeMyRenotes: { type: 'boolean', default: true }, + includeRenotedMyNotes: { type: 'boolean', default: true }, + includeLocalRenotes: { type: 'boolean', default: true }, + withFiles: { type: 'boolean' }, + }, + required: ['listId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const list = await UserLists.findOne({ id: ps.listId, userId: user.id, @@ -97,10 +66,16 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.userId IN (${ listQuery.getQuery() })`) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .setParameters(listQuery.getParameters()); generateVisibilityQuery(query, user); @@ -140,9 +115,9 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); - activeUsersChart.update(user); + activeUsersChart.read(user); return await Notes.packMany(timeline, user); }); diff --git a/packages/backend/src/server/api/endpoints/notes/watching/create.ts b/packages/backend/src/server/api/endpoints/notes/watching/create.ts index 6433c6bc2..8fdf84624 100644 --- a/packages/backend/src/server/api/endpoints/notes/watching/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/watching/create.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import watch from '@/services/note/watch'; -import { getNote } from '../../../common/getters'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import watch from '@/services/note/watch.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['notes'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notes/watching/delete.ts b/packages/backend/src/server/api/endpoints/notes/watching/delete.ts index 3e9faa2b2..d58f09797 100644 --- a/packages/backend/src/server/api/endpoints/notes/watching/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/watching/delete.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import unwatch from '@/services/note/unwatch'; -import { getNote } from '../../../common/getters'; -import { ApiError } from '../../../error'; +import define from '../../../define.js'; +import unwatch from '@/services/note/unwatch.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['notes'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/notifications/create.ts b/packages/backend/src/server/api/endpoints/notifications/create.ts index bd8a7ba1b..b339c8723 100644 --- a/packages/backend/src/server/api/endpoints/notifications/create.ts +++ b/packages/backend/src/server/api/endpoints/notifications/create.ts @@ -1,6 +1,5 @@ -import $ from 'cafy'; -import define from '../../define'; -import { createNotification } from '@/services/create-notification'; +import define from '../../define.js'; +import { createNotification } from '@/services/create-notification.js'; export const meta = { tags: ['notifications'], @@ -9,26 +8,22 @@ export const meta = { kind: 'write:notifications', - params: { - body: { - validator: $.str, - }, - - header: { - validator: $.optional.nullable.str, - }, - - icon: { - validator: $.optional.nullable.str, - }, - }, - errors: { }, } as const; +export const paramDef = { + type: 'object', + properties: { + body: { type: 'string' }, + header: { type: 'string', nullable: true }, + icon: { type: 'string', nullable: true }, + }, + required: ['body'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user, token) => { +export default define(meta, paramDef, async (ps, user, token) => { createNotification(user.id, 'app', { appAccessTokenId: token ? token.id : null, customBody: ps.body, diff --git a/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts b/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts index 4cec38a95..abefe07be 100644 --- a/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts +++ b/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts @@ -1,6 +1,6 @@ -import { publishMainStream } from '@/services/stream'; -import define from '../../define'; -import { Notifications } from '@/models/index'; +import { publishMainStream } from '@/services/stream.js'; +import define from '../../define.js'; +import { Notifications } from '@/models/index.js'; export const meta = { tags: ['notifications', 'account'], @@ -10,8 +10,14 @@ export const meta = { kind: 'write:notifications', } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Update documents await Notifications.update({ notifieeId: user.id, diff --git a/packages/backend/src/server/api/endpoints/notifications/read.ts b/packages/backend/src/server/api/endpoints/notifications/read.ts index 7e23bc234..34f4c155f 100644 --- a/packages/backend/src/server/api/endpoints/notifications/read.ts +++ b/packages/backend/src/server/api/endpoints/notifications/read.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { publishMainStream } from '@/services/stream'; -import define from '../../define'; -import { Notifications } from '@/models/index'; -import { readNotification } from '../../common/read-notification'; -import { ApiError } from '../../error'; +import { publishMainStream } from '@/services/stream.js'; +import define from '../../define.js'; +import { Notifications } from '@/models/index.js'; +import { readNotification } from '../../common/read-notification.js'; +import { ApiError } from '../../error.js'; export const meta = { tags: ['notifications', 'account'], @@ -13,12 +11,6 @@ export const meta = { kind: 'write:notifications', - params: { - notificationId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNotification: { message: 'No such notification.', @@ -28,8 +20,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + notificationId: { type: 'string', format: 'misskey:id' }, + }, + required: ['notificationId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const notification = await Notifications.findOne({ notifieeId: user.id, id: ps.notificationId, diff --git a/packages/backend/src/server/api/endpoints/page-push.ts b/packages/backend/src/server/api/endpoints/page-push.ts index 61c0160f8..acaa11847 100644 --- a/packages/backend/src/server/api/endpoints/page-push.ts +++ b/packages/backend/src/server/api/endpoints/page-push.ts @@ -1,28 +1,12 @@ -import $ from 'cafy'; -import define from '../define'; -import { ID } from '@/misc/cafy-id'; -import { publishMainStream } from '@/services/stream'; -import { Users, Pages } from '@/models/index'; -import { ApiError } from '../error'; +import define from '../define.js'; +import { publishMainStream } from '@/services/stream.js'; +import { Users, Pages } from '@/models/index.js'; +import { ApiError } from '../error.js'; export const meta = { requireCredential: true, secure: true, - params: { - pageId: { - validator: $.type(ID), - }, - - event: { - validator: $.str, - }, - - var: { - validator: $.optional.nullable.any, - }, - }, - errors: { noSuchPage: { message: 'No such page.', @@ -32,8 +16,18 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + pageId: { type: 'string', format: 'misskey:id' }, + event: { type: 'string' }, + var: {}, + }, + required: ['pageId', 'event'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOne(ps.pageId); if (page == null) { throw new ApiError(meta.errors.noSuchPage); diff --git a/packages/backend/src/server/api/endpoints/pages/create.ts b/packages/backend/src/server/api/endpoints/pages/create.ts index 7ee50fbdf..7cac53060 100644 --- a/packages/backend/src/server/api/endpoints/pages/create.ts +++ b/packages/backend/src/server/api/endpoints/pages/create.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; import ms from 'ms'; -import define from '../../define'; -import { ID } from '@/misc/cafy-id'; -import { Pages, DriveFiles } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { Page } from '@/models/entities/page'; -import { ApiError } from '../../error'; +import define from '../../define.js'; +import { Pages, DriveFiles } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { Page } from '@/models/entities/page.js'; +import { ApiError } from '../../error.js'; export const meta = { tags: ['pages'], @@ -19,51 +17,6 @@ export const meta = { max: 300, }, - params: { - title: { - validator: $.str, - }, - - name: { - validator: $.str.min(1), - }, - - summary: { - validator: $.optional.nullable.str, - }, - - content: { - validator: $.arr($.obj()), - }, - - variables: { - validator: $.arr($.obj()), - }, - - script: { - validator: $.str, - }, - - eyeCatchingImageId: { - validator: $.optional.nullable.type(ID), - }, - - font: { - validator: $.optional.str.or(['serif', 'sans-serif']), - default: 'sans-serif', - }, - - alignCenter: { - validator: $.optional.bool, - default: false, - }, - - hideTitleWhenPinned: { - validator: $.optional.bool, - default: false, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -84,8 +37,29 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + title: { type: 'string' }, + name: { type: 'string', minLength: 1 }, + summary: { type: 'string', nullable: true }, + content: { type: 'array', items: { + type: 'object', additionalProperties: true, + } }, + variables: { type: 'array', items: { + type: 'object', additionalProperties: true, + } }, + script: { type: 'string' }, + eyeCatchingImageId: { type: 'string', format: 'misskey:id', nullable: true }, + font: { type: 'string', enum: ['serif', 'sans-serif'], default: "sans-serif" }, + alignCenter: { type: 'boolean', default: false }, + hideTitleWhenPinned: { type: 'boolean', default: false }, + }, + required: ['title', 'name', 'content', 'variables', 'script'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { let eyeCatchingImage = null; if (ps.eyeCatchingImageId != null) { eyeCatchingImage = await DriveFiles.findOne({ diff --git a/packages/backend/src/server/api/endpoints/pages/delete.ts b/packages/backend/src/server/api/endpoints/pages/delete.ts index aeda823e5..ddf691f53 100644 --- a/packages/backend/src/server/api/endpoints/pages/delete.ts +++ b/packages/backend/src/server/api/endpoints/pages/delete.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Pages } from '@/models/index'; -import { ID } from '@/misc/cafy-id'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Pages } from '@/models/index.js'; export const meta = { tags: ['pages'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:pages', - params: { - pageId: { - validator: $.type(ID), - }, - }, - errors: { noSuchPage: { message: 'No such page.', @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + pageId: { type: 'string', format: 'misskey:id' }, + }, + required: ['pageId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOne(ps.pageId); if (page == null) { throw new ApiError(meta.errors.noSuchPage); diff --git a/packages/backend/src/server/api/endpoints/pages/featured.ts b/packages/backend/src/server/api/endpoints/pages/featured.ts index 7f0d58b35..eeb6d509c 100644 --- a/packages/backend/src/server/api/endpoints/pages/featured.ts +++ b/packages/backend/src/server/api/endpoints/pages/featured.ts @@ -1,5 +1,5 @@ -import define from '../../define'; -import { Pages } from '@/models/index'; +import define from '../../define.js'; +import { Pages } from '@/models/index.js'; export const meta = { tags: ['pages'], @@ -17,8 +17,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = Pages.createQueryBuilder('page') .where('page.visibility = \'public\'') .andWhere('page.likedCount > 0') diff --git a/packages/backend/src/server/api/endpoints/pages/like.ts b/packages/backend/src/server/api/endpoints/pages/like.ts index c479f637a..cab78e576 100644 --- a/packages/backend/src/server/api/endpoints/pages/like.ts +++ b/packages/backend/src/server/api/endpoints/pages/like.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Pages, PageLikes } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Pages, PageLikes } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['pages'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:page-likes', - params: { - pageId: { - validator: $.type(ID), - }, - }, - errors: { noSuchPage: { message: 'No such page.', @@ -39,8 +31,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + pageId: { type: 'string', format: 'misskey:id' }, + }, + required: ['pageId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOne(ps.pageId); if (page == null) { throw new ApiError(meta.errors.noSuchPage); diff --git a/packages/backend/src/server/api/endpoints/pages/show.ts b/packages/backend/src/server/api/endpoints/pages/show.ts index 5cda5386d..4e3facae5 100644 --- a/packages/backend/src/server/api/endpoints/pages/show.ts +++ b/packages/backend/src/server/api/endpoints/pages/show.ts @@ -1,29 +1,13 @@ -import $ from 'cafy'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Pages, Users } from '@/models/index'; -import { ID } from '@/misc/cafy-id'; -import { Page } from '@/models/entities/page'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Pages, Users } from '@/models/index.js'; +import { Page } from '@/models/entities/page.js'; export const meta = { tags: ['pages'], requireCredential: false, - params: { - pageId: { - validator: $.optional.type(ID), - }, - - name: { - validator: $.optional.str, - }, - - username: { - validator: $.optional.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -39,8 +23,18 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + pageId: { type: 'string', format: 'misskey:id' }, + name: { type: 'string' }, + username: { type: 'string' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { let page: Page | undefined; if (ps.pageId) { diff --git a/packages/backend/src/server/api/endpoints/pages/unlike.ts b/packages/backend/src/server/api/endpoints/pages/unlike.ts index cca5e5b5a..31cd1a335 100644 --- a/packages/backend/src/server/api/endpoints/pages/unlike.ts +++ b/packages/backend/src/server/api/endpoints/pages/unlike.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Pages, PageLikes } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Pages, PageLikes } from '@/models/index.js'; export const meta = { tags: ['pages'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:page-likes', - params: { - pageId: { - validator: $.type(ID), - }, - }, - errors: { noSuchPage: { message: 'No such page.', @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + pageId: { type: 'string', format: 'misskey:id' }, + }, + required: ['pageId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOne(ps.pageId); if (page == null) { throw new ApiError(meta.errors.noSuchPage); diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts index 991085ee0..24c8f467e 100644 --- a/packages/backend/src/server/api/endpoints/pages/update.ts +++ b/packages/backend/src/server/api/endpoints/pages/update.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; import ms from 'ms'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Pages, DriveFiles } from '@/models/index'; -import { ID } from '@/misc/cafy-id'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Pages, DriveFiles } from '@/models/index.js'; import { Not } from 'typeorm'; export const meta = { @@ -18,52 +16,6 @@ export const meta = { max: 300, }, - params: { - pageId: { - validator: $.type(ID), - }, - - title: { - validator: $.str, - }, - - name: { - validator: $.str.min(1), - }, - - summary: { - validator: $.optional.nullable.str, - }, - - content: { - validator: $.arr($.obj()), - }, - - variables: { - validator: $.arr($.obj()), - }, - - script: { - validator: $.str, - }, - - eyeCatchingImageId: { - validator: $.optional.nullable.type(ID), - }, - - font: { - validator: $.optional.str.or(['serif', 'sans-serif']), - }, - - alignCenter: { - validator: $.optional.bool, - }, - - hideTitleWhenPinned: { - validator: $.optional.bool, - }, - }, - errors: { noSuchPage: { message: 'No such page.', @@ -90,8 +42,30 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + pageId: { type: 'string', format: 'misskey:id' }, + title: { type: 'string' }, + name: { type: 'string', minLength: 1 }, + summary: { type: 'string', nullable: true }, + content: { type: 'array', items: { + type: 'object', additionalProperties: true, + } }, + variables: { type: 'array', items: { + type: 'object', additionalProperties: true, + } }, + script: { type: 'string' }, + eyeCatchingImageId: { type: 'string', format: 'misskey:id', nullable: true }, + font: { type: 'string', enum: ['serif', 'sans-serif'] }, + alignCenter: { type: 'boolean' }, + hideTitleWhenPinned: { type: 'boolean' }, + }, + required: ['pageId', 'title', 'name', 'content', 'variables', 'script'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const page = await Pages.findOne(ps.pageId); if (page == null) { throw new ApiError(meta.errors.noSuchPage); diff --git a/packages/backend/src/server/api/endpoints/ping.ts b/packages/backend/src/server/api/endpoints/ping.ts index 3eab70ae2..2891a0860 100644 --- a/packages/backend/src/server/api/endpoints/ping.ts +++ b/packages/backend/src/server/api/endpoints/ping.ts @@ -1,13 +1,10 @@ -import define from '../define'; +import define from '../define.js'; export const meta = { requireCredential: false, tags: ['meta'], - params: { - }, - res: { type: 'object', optional: false, nullable: false, @@ -20,8 +17,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { return { pong: Date.now(), }; diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index ff0e22555..1d26ab266 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -1,17 +1,14 @@ -import define from '../define'; -import { Users } from '@/models/index'; -import { fetchMeta } from '@/misc/fetch-meta'; -import * as Acct from 'misskey-js/built/acct'; -import { User } from '@/models/entities/user'; +import define from '../define.js'; +import { Users } from '@/models/index.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import * as Acct from '@/misc/acct.js'; +import { User } from '@/models/entities/user.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - }, - res: { type: 'array', optional: false, nullable: false, @@ -23,8 +20,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const meta = await fetchMeta(); const users = await Promise.all(meta.pinnedUsers.map(acct => Users.findOne(Acct.parse(acct)))); diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts index 8d8c60d75..ea34ca3aa 100644 --- a/packages/backend/src/server/api/endpoints/promo/read.ts +++ b/packages/backend/src/server/api/endpoints/promo/read.ts @@ -1,22 +1,14 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getNote } from '../../common/getters'; -import { PromoReads } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getNote } from '../../common/getters.js'; +import { PromoReads } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['notes'], requireCredential: true, - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -26,8 +18,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await getNote(ps.noteId).catch(e => { if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw e; diff --git a/packages/backend/src/server/api/endpoints/request-reset-password.ts b/packages/backend/src/server/api/endpoints/request-reset-password.ts index af1aeb431..18cd98b16 100644 --- a/packages/backend/src/server/api/endpoints/request-reset-password.ts +++ b/packages/backend/src/server/api/endpoints/request-reset-password.ts @@ -1,13 +1,12 @@ -import $ from 'cafy'; -import { publishMainStream } from '@/services/stream'; -import define from '../define'; +import { publishMainStream } from '@/services/stream.js'; +import define from '../define.js'; import rndstr from 'rndstr'; -import config from '@/config/index'; +import config from '@/config/index.js'; import ms from 'ms'; -import { Users, UserProfiles, PasswordResetRequests } from '@/models/index'; -import { sendEmail } from '@/services/send-email'; -import { ApiError } from '../error'; -import { genId } from '@/misc/gen-id'; +import { Users, UserProfiles, PasswordResetRequests } from '@/models/index.js'; +import { sendEmail } from '@/services/send-email.js'; +import { ApiError } from '../error.js'; +import { genId } from '@/misc/gen-id.js'; import { IsNull } from 'typeorm'; export const meta = { @@ -18,23 +17,22 @@ export const meta = { max: 3, }, - params: { - username: { - validator: $.str, - }, - - email: { - validator: $.str, - }, - }, - errors: { }, } as const; +export const paramDef = { + type: 'object', + properties: { + username: { type: 'string' }, + email: { type: 'string' }, + }, + required: ['username', 'email'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { const user = await Users.findOne({ usernameLower: ps.username.toLowerCase(), host: IsNull(), diff --git a/packages/backend/src/server/api/endpoints/reset-db.ts b/packages/backend/src/server/api/endpoints/reset-db.ts index e99dc9db1..dbe64e9a1 100644 --- a/packages/backend/src/server/api/endpoints/reset-db.ts +++ b/packages/backend/src/server/api/endpoints/reset-db.ts @@ -1,21 +1,23 @@ -import $ from 'cafy'; -import define from '../define'; -import { ApiError } from '../error'; -import { resetDb } from '@/db/postgre'; +import define from '../define.js'; +import { ApiError } from '../error.js'; +import { resetDb } from '@/db/postgre.js'; export const meta = { requireCredential: false, - params: { - }, - errors: { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { if (process.env.NODE_ENV !== 'test') throw 'NODE_ENV is not a test'; await resetDb(); diff --git a/packages/backend/src/server/api/endpoints/reset-password.ts b/packages/backend/src/server/api/endpoints/reset-password.ts index a7366584b..3abf232af 100644 --- a/packages/backend/src/server/api/endpoints/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/reset-password.ts @@ -1,30 +1,28 @@ -import $ from 'cafy'; -import * as bcrypt from 'bcryptjs'; -import { publishMainStream } from '@/services/stream'; -import define from '../define'; -import { Users, UserProfiles, PasswordResetRequests } from '@/models/index'; -import { ApiError } from '../error'; +import bcrypt from 'bcryptjs'; +import { publishMainStream } from '@/services/stream.js'; +import define from '../define.js'; +import { Users, UserProfiles, PasswordResetRequests } from '@/models/index.js'; +import { ApiError } from '../error.js'; export const meta = { requireCredential: false, - params: { - token: { - validator: $.str, - }, - - password: { - validator: $.str, - }, - }, - errors: { }, } as const; +export const paramDef = { + type: 'object', + properties: { + token: { type: 'string' }, + password: { type: 'string' }, + }, + required: ['token', 'password'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const req = await PasswordResetRequests.findOneOrFail({ token: ps.token, }); diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index 1ad2c54ab..99f3730e9 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -1,21 +1,21 @@ -import * as os from 'os'; -import * as si from 'systeminformation'; -import define from '../define'; +import * as os from 'node:os'; +import si from 'systeminformation'; +import define from '../define.js'; export const meta = { requireCredential: false, - desc: { - }, - tags: ['meta'], +} as const; - params: { - }, +export const paramDef = { + type: 'object', + properties: {}, + required: [], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { const memStats = await si.mem(); const fsStats = await si.fsSize(); diff --git a/packages/backend/src/server/api/endpoints/stats.ts b/packages/backend/src/server/api/endpoints/stats.ts index 9879ef2ad..92fea4de6 100644 --- a/packages/backend/src/server/api/endpoints/stats.ts +++ b/packages/backend/src/server/api/endpoints/stats.ts @@ -1,15 +1,12 @@ -import define from '../define'; -import { NoteReactions, Notes, Users } from '@/models/index'; -import { federationChart, driveChart } from '@/services/chart/index'; +import define from '../define.js'; +import { Instances, NoteReactions, Notes, Users } from '@/models/index.js'; +import { } from '@/services/chart/index.js'; export const meta = { requireCredential: false, tags: ['meta'], - params: { - }, - res: { type: 'object', optional: false, nullable: false, @@ -46,8 +43,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async () => { +export default define(meta, paramDef, async () => { const [ notesCount, originalNotesCount, @@ -56,8 +59,6 @@ export default define(meta, async () => { reactionsCount, //originalReactionsCount, instances, - driveUsageLocal, - driveUsageRemote, ] = await Promise.all([ Notes.count({ cache: 3600000 }), // 1 hour Notes.count({ where: { userHost: null }, cache: 3600000 }), @@ -65,9 +66,7 @@ export default define(meta, async () => { Users.count({ where: { host: null }, cache: 3600000 }), NoteReactions.count({ cache: 3600000 }), // 1 hour //NoteReactions.count({ where: { userHost: null }, cache: 3600000 }), - federationChart.getChart('hour', 1, null).then(chart => chart.instance.total[0]), - driveChart.getChart('hour', 1, null).then(chart => chart.local.totalSize[0]), - driveChart.getChart('hour', 1, null).then(chart => chart.remote.totalSize[0]), + Instances.count({ cache: 3600000 }), ]); return { @@ -78,7 +77,7 @@ export default define(meta, async () => { reactionsCount, //originalReactionsCount, instances, - driveUsageLocal, - driveUsageRemote, + driveUsageLocal: 0, + driveUsageRemote: 0, }; }); diff --git a/packages/backend/src/server/api/endpoints/sw/register.ts b/packages/backend/src/server/api/endpoints/sw/register.ts index ae3e9ce77..6c7714e19 100644 --- a/packages/backend/src/server/api/endpoints/sw/register.ts +++ b/packages/backend/src/server/api/endpoints/sw/register.ts @@ -1,47 +1,42 @@ -import $ from 'cafy'; -import define from '../../define'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { genId } from '@/misc/gen-id'; -import { SwSubscriptions } from '@/models/index'; +import define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { genId } from '@/misc/gen-id.js'; +import { SwSubscriptions } from '@/models/index.js'; export const meta = { tags: ['account'], requireCredential: true, - params: { - endpoint: { - validator: $.str, - }, - - auth: { - validator: $.str, - }, - - publickey: { - validator: $.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, properties: { state: { type: 'string', - optional: false, nullable: false, + optional: true, nullable: false, enum: ['already-subscribed', 'subscribed'], }, key: { type: 'string', - optional: false, nullable: false, + optional: false, nullable: true, }, }, }, } as const; +export const paramDef = { + type: 'object', + properties: { + endpoint: { type: 'string' }, + auth: { type: 'string' }, + publickey: { type: 'string' }, + }, + required: ['endpoint', 'auth', 'publickey'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // if already subscribed const exist = await SwSubscriptions.findOne({ userId: user.id, @@ -54,7 +49,7 @@ export default define(meta, async (ps, user) => { if (exist != null) { return { - state: 'already-subscribed', + state: 'already-subscribed' as const, key: instance.swPublicKey, }; } @@ -69,7 +64,7 @@ export default define(meta, async (ps, user) => { }); return { - state: 'subscribed', + state: 'subscribed' as const, key: instance.swPublicKey, }; }); diff --git a/packages/backend/src/server/api/endpoints/sw/unregister.ts b/packages/backend/src/server/api/endpoints/sw/unregister.ts index 6f569e941..9748f2a22 100644 --- a/packages/backend/src/server/api/endpoints/sw/unregister.ts +++ b/packages/backend/src/server/api/endpoints/sw/unregister.ts @@ -1,21 +1,22 @@ -import $ from 'cafy'; -import define from '../../define'; -import { SwSubscriptions } from '../../../../models'; +import define from '../../define.js'; +import { SwSubscriptions } from '@/models/index.js'; export const meta = { tags: ['account'], requireCredential: true, +} as const; - params: { - endpoint: { - validator: $.str, - }, +export const paramDef = { + type: 'object', + properties: { + endpoint: { type: 'string' }, }, + required: ['endpoint'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { await SwSubscriptions.delete({ userId: user.id, endpoint: ps.endpoint, diff --git a/packages/backend/src/server/api/endpoints/test.ts b/packages/backend/src/server/api/endpoints/test.ts new file mode 100644 index 000000000..256da1a66 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/test.ts @@ -0,0 +1,22 @@ +import define from '../define.js'; + +export const meta = { + requireCredential: false, +} as const; + +export const paramDef = { + type: 'object', + properties: { + required: { type: 'boolean' }, + string: { type: 'string' }, + default: { type: 'string', default: 'hello' }, + nullableDefault: { type: 'string', nullable: true, default: 'hello' }, + id: { type: 'string', format: 'misskey:id' }, + }, + required: ['required'], +} as const; + +// eslint-disable-next-line import/no-default-export +export default define(meta, paramDef, async (ps, me) => { + return ps; +}); diff --git a/packages/backend/src/server/api/endpoints/username/available.ts b/packages/backend/src/server/api/endpoints/username/available.ts index 74120fc40..5a1c4128a 100644 --- a/packages/backend/src/server/api/endpoints/username/available.ts +++ b/packages/backend/src/server/api/endpoints/username/available.ts @@ -1,18 +1,11 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Users, UsedUsernames } from '@/models/index'; +import define from '../../define.js'; +import { Users, UsedUsernames } from '@/models/index.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - username: { - validator: $.use(Users.validateLocalUsername), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -25,8 +18,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + username: Users.localUsernameSchema, + }, + required: ['username'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps) => { +export default define(meta, paramDef, async (ps) => { // Get exist const exist = await Users.count({ host: null, diff --git a/packages/backend/src/server/api/endpoints/users.ts b/packages/backend/src/server/api/endpoints/users.ts index 6b11ec0f0..10527d15c 100644 --- a/packages/backend/src/server/api/endpoints/users.ts +++ b/packages/backend/src/server/api/endpoints/users.ts @@ -1,57 +1,13 @@ -import $ from 'cafy'; -import define from '../define'; -import { Users } from '@/models/index'; -import { generateMutedUserQueryForUsers } from '../common/generate-muted-user-query'; -import { generateBlockQueryForUsers } from '../common/generate-block-query'; +import define from '../define.js'; +import { Users } from '@/models/index.js'; +import { generateMutedUserQueryForUsers } from '../common/generate-muted-user-query.js'; +import { generateBlockQueryForUsers } from '../common/generate-block-query.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - - sort: { - validator: $.optional.str.or([ - '+follower', - '-follower', - '+createdAt', - '-createdAt', - '+updatedAt', - '-updatedAt', - ]), - }, - - state: { - validator: $.optional.str.or([ - 'all', - 'admin', - 'moderator', - 'adminOrModerator', - 'alive', - ]), - default: 'all', - }, - - origin: { - validator: $.optional.str.or([ - 'combined', - 'local', - 'remote', - ]), - default: 'local', - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -63,8 +19,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt'] }, + state: { type: 'string', enum: ['all', 'admin', 'moderator', 'adminOrModerator', 'alive'], default: "all" }, + origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "local" }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = Users.createQueryBuilder('user'); query.where('user.isExplorable = TRUE'); @@ -93,7 +61,7 @@ export default define(meta, async (ps, me) => { if (me) generateMutedUserQueryForUsers(query, me); if (me) generateBlockQueryForUsers(query, me); - query.take(ps.limit!); + query.take(ps.limit); query.skip(ps.offset); const users = await query.getMany(); diff --git a/packages/backend/src/server/api/endpoints/users/clips.ts b/packages/backend/src/server/api/endpoints/users/clips.ts index d4152fbf5..424c59474 100644 --- a/packages/backend/src/server/api/endpoints/users/clips.ts +++ b/packages/backend/src/server/api/endpoints/users/clips.ts @@ -1,40 +1,30 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Clips } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Clips } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['users', 'clips'], +} as const; - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(Clips.createQueryBuilder('clip'), ps.sinceId, ps.untilId) .andWhere(`clip.userId = :userId`, { userId: ps.userId }) .andWhere('clip.isPublic = true'); const clips = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Clips.packMany(clips); diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index 6214ab40b..1e104b6bc 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -1,43 +1,14 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Users, Followings, UserProfiles } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { toPunyNullable } from '@/misc/convert-host'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Users, Followings, UserProfiles } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { toPunyNullable } from '@/misc/convert-host.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - userId: { - validator: $.optional.type(ID), - }, - - username: { - validator: $.optional.str, - }, - - host: { - validator: $.optional.nullable.str, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -63,8 +34,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + username: { type: 'string' }, + host: { type: 'string', nullable: true }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId != null ? { id: ps.userId } : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) }); @@ -98,7 +82,7 @@ export default define(meta, async (ps, me) => { .innerJoinAndSelect('following.follower', 'follower'); const followings = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Followings.packMany(followings, me, { populateFollower: true }); diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 76112eab2..b0a1036c7 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -1,43 +1,14 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Users, Followings, UserProfiles } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { toPunyNullable } from '@/misc/convert-host'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { Users, Followings, UserProfiles } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { toPunyNullable } from '@/misc/convert-host.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - userId: { - validator: $.optional.type(ID), - }, - - username: { - validator: $.optional.str, - }, - - host: { - validator: $.optional.nullable.str, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -63,8 +34,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + username: { type: 'string' }, + host: { type: 'string', nullable: true }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId != null ? { id: ps.userId } : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) }); @@ -98,7 +82,7 @@ export default define(meta, async (ps, me) => { .innerJoinAndSelect('following.followee', 'followee'); const followings = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Followings.packMany(followings, me, { populateFollowee: true }); diff --git a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts index c5f08b4c9..d7c435256 100644 --- a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts @@ -1,39 +1,29 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { GalleryPosts } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; +import define from '../../../define.js'; +import { GalleryPosts } from '@/models/index.js'; +import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { tags: ['users', 'gallery'], +} as const; - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId) .andWhere(`post.userId = :userId`, { userId: ps.userId }); const posts = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await GalleryPosts.packMany(posts, user); diff --git a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts index d886d3355..73cadc0df 100644 --- a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts +++ b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts @@ -1,28 +1,15 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { maximum } from '@/prelude/array'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; +import define from '../../define.js'; +import { maximum } from '@/prelude/array.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; import { Not, In, IsNull } from 'typeorm'; -import { Notes, Users } from '@/models/index'; +import { Notes, Users } from '@/models/index.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -52,8 +39,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Lookup user const user = await getUser(ps.userId).catch(e => { if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); @@ -104,7 +100,7 @@ export default define(meta, async (ps, me) => { const repliedUsersSorted = Object.keys(repliedUsers).sort((a, b) => repliedUsers[b] - repliedUsers[a]); // Extract top replied users - const topRepliedUsers = repliedUsersSorted.slice(0, ps.limit!); + const topRepliedUsers = repliedUsersSorted.slice(0, ps.limit); // Make replies object (includes weights) const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({ diff --git a/packages/backend/src/server/api/endpoints/users/groups/create.ts b/packages/backend/src/server/api/endpoints/users/groups/create.ts index 25e29de01..9f6d8464d 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/create.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/create.ts @@ -1,9 +1,8 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { UserGroup } from '@/models/entities/user-group'; -import { UserGroupJoining } from '@/models/entities/user-group-joining'; +import define from '../../../define.js'; +import { UserGroups, UserGroupJoinings } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { UserGroupJoining } from '@/models/entities/user-group-joining.js'; export const meta = { tags: ['groups'], @@ -12,12 +11,6 @@ export const meta = { kind: 'write:user-groups', - params: { - name: { - validator: $.str.range(1, 100), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -25,8 +18,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string', minLength: 1, maxLength: 100 }, + }, + required: ['name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const userGroup = await UserGroups.insert({ id: genId(), createdAt: new Date(), diff --git a/packages/backend/src/server/api/endpoints/users/groups/delete.ts b/packages/backend/src/server/api/endpoints/users/groups/delete.ts index f30ab78ca..f4898a3c7 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/delete.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/delete.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserGroups } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { UserGroups } from '@/models/index.js'; export const meta = { tags: ['groups'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:user-groups', - params: { - groupId: { - validator: $.type(ID), - }, - }, - errors: { noSuchGroup: { message: 'No such group.', @@ -26,8 +18,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + groupId: { type: 'string', format: 'misskey:id' }, + }, + required: ['groupId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const userGroup = await UserGroups.findOne({ id: ps.groupId, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts index 7061db538..efbdf968f 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../../define'; -import { ApiError } from '../../../../error'; -import { UserGroupJoinings, UserGroupInvitations } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { UserGroupJoining } from '@/models/entities/user-group-joining'; +import define from '../../../../define.js'; +import { ApiError } from '../../../../error.js'; +import { UserGroupJoinings, UserGroupInvitations } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { UserGroupJoining } from '@/models/entities/user-group-joining.js'; export const meta = { tags: ['groups', 'users'], @@ -13,12 +11,6 @@ export const meta = { kind: 'write:user-groups', - params: { - invitationId: { - validator: $.type(ID), - }, - }, - errors: { noSuchInvitation: { message: 'No such invitation.', @@ -28,8 +20,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + invitationId: { type: 'string', format: 'misskey:id' }, + }, + required: ['invitationId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch the invitation const invitation = await UserGroupInvitations.findOne({ id: ps.invitationId, diff --git a/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts index f5ca3dec8..fe5d431ea 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../../define'; -import { ApiError } from '../../../../error'; -import { UserGroupInvitations } from '@/models/index'; +import define from '../../../../define.js'; +import { ApiError } from '../../../../error.js'; +import { UserGroupInvitations } from '@/models/index.js'; export const meta = { tags: ['groups', 'users'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:user-groups', - params: { - invitationId: { - validator: $.type(ID), - }, - }, - errors: { noSuchInvitation: { message: 'No such invitation.', @@ -26,8 +18,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + invitationId: { type: 'string', format: 'misskey:id' }, + }, + required: ['invitationId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch the invitation const invitation = await UserGroupInvitations.findOne({ id: ps.invitationId, diff --git a/packages/backend/src/server/api/endpoints/users/groups/invite.ts b/packages/backend/src/server/api/endpoints/users/groups/invite.ts index 3b7a4edb8..10bfb7eca 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invite.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invite.ts @@ -1,12 +1,10 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { UserGroups, UserGroupJoinings, UserGroupInvitations } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { UserGroupInvitation } from '@/models/entities/user-group-invitation'; -import { createNotification } from '@/services/create-notification'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; +import { UserGroups, UserGroupJoinings, UserGroupInvitations } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js'; +import { createNotification } from '@/services/create-notification.js'; export const meta = { tags: ['groups', 'users'], @@ -15,16 +13,6 @@ export const meta = { kind: 'write:user-groups', - params: { - groupId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchGroup: { message: 'No such group.', @@ -52,8 +40,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + groupId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['groupId', 'userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOne({ id: ps.groupId, diff --git a/packages/backend/src/server/api/endpoints/users/groups/joined.ts b/packages/backend/src/server/api/endpoints/users/groups/joined.ts index ab48b1910..e52de7859 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/joined.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/joined.ts @@ -1,5 +1,5 @@ -import define from '../../../define'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; +import define from '../../../define.js'; +import { UserGroups, UserGroupJoinings } from '@/models/index.js'; import { Not, In } from 'typeorm'; export const meta = { @@ -20,8 +20,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const ownedGroups = await UserGroups.find({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/leave.ts b/packages/backend/src/server/api/endpoints/users/groups/leave.ts index d2fcdab30..c1a8c2c02 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/leave.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/leave.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { UserGroups, UserGroupJoinings } from '@/models/index.js'; export const meta = { tags: ['groups', 'users'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:user-groups', - params: { - groupId: { - validator: $.type(ID), - }, - }, - errors: { noSuchGroup: { message: 'No such group.', @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + groupId: { type: 'string', format: 'misskey:id' }, + }, + required: ['groupId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOne({ id: ps.groupId, diff --git a/packages/backend/src/server/api/endpoints/users/groups/owned.ts b/packages/backend/src/server/api/endpoints/users/groups/owned.ts index 6193a7101..11aad0f73 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/owned.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/owned.ts @@ -1,5 +1,5 @@ -import define from '../../../define'; -import { UserGroups } from '@/models/index'; +import define from '../../../define.js'; +import { UserGroups } from '@/models/index.js'; export const meta = { tags: ['groups', 'account'], @@ -19,8 +19,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const userGroups = await UserGroups.find({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/pull.ts b/packages/backend/src/server/api/endpoints/users/groups/pull.ts index 785bea140..55ec9f915 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/pull.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/pull.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; +import { UserGroups, UserGroupJoinings } from '@/models/index.js'; export const meta = { tags: ['groups', 'users'], @@ -12,16 +10,6 @@ export const meta = { kind: 'write:user-groups', - params: { - groupId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchGroup: { message: 'No such group.', @@ -43,8 +31,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + groupId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['groupId', 'userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOne({ id: ps.groupId, diff --git a/packages/backend/src/server/api/endpoints/users/groups/show.ts b/packages/backend/src/server/api/endpoints/users/groups/show.ts index eb26eac2a..28ca1162c 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/show.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/show.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { UserGroups, UserGroupJoinings } from '@/models/index.js'; export const meta = { tags: ['groups', 'account'], @@ -11,12 +9,6 @@ export const meta = { kind: 'read:user-groups', - params: { - groupId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + groupId: { type: 'string', format: 'misskey:id' }, + }, + required: ['groupId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOne({ id: ps.groupId, diff --git a/packages/backend/src/server/api/endpoints/users/groups/transfer.ts b/packages/backend/src/server/api/endpoints/users/groups/transfer.ts index 4b1c8fbbd..f48e1ddbf 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/transfer.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/transfer.ts @@ -1,9 +1,7 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; +import { UserGroups, UserGroupJoinings } from '@/models/index.js'; export const meta = { tags: ['groups', 'users'], @@ -12,16 +10,6 @@ export const meta = { kind: 'write:user-groups', - params: { - groupId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -49,8 +37,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + groupId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['groupId', 'userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOne({ id: ps.groupId, diff --git a/packages/backend/src/server/api/endpoints/users/groups/update.ts b/packages/backend/src/server/api/endpoints/users/groups/update.ts index 6caf90355..b3e17dfd9 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/update.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/update.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserGroups } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { UserGroups } from '@/models/index.js'; export const meta = { tags: ['groups'], @@ -11,16 +9,6 @@ export const meta = { kind: 'write:user-groups', - params: { - groupId: { - validator: $.type(ID), - }, - - name: { - validator: $.str.range(1, 100), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -36,8 +24,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + groupId: { type: 'string', format: 'misskey:id' }, + name: { type: 'string', minLength: 1, maxLength: 100 }, + }, + required: ['groupId', 'name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the group const userGroup = await UserGroups.findOne({ id: ps.groupId, diff --git a/packages/backend/src/server/api/endpoints/users/lists/create.ts b/packages/backend/src/server/api/endpoints/users/lists/create.ts index 945b51162..1a0599f9e 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create.ts @@ -1,8 +1,7 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { UserLists } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { UserList } from '@/models/entities/user-list'; +import define from '../../../define.js'; +import { UserLists } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { UserList } from '@/models/entities/user-list.js'; export const meta = { tags: ['lists'], @@ -11,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - name: { - validator: $.str.range(1, 100), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -24,8 +17,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string', minLength: 1, maxLength: 100 }, + }, + required: ['name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const userList = await UserLists.insert({ id: genId(), createdAt: new Date(), diff --git a/packages/backend/src/server/api/endpoints/users/lists/delete.ts b/packages/backend/src/server/api/endpoints/users/lists/delete.ts index 3183d2a09..aeefb98c8 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/delete.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/delete.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserLists } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { UserLists } from '@/models/index.js'; export const meta = { tags: ['lists'], @@ -11,12 +9,6 @@ export const meta = { kind: 'write:account', - params: { - listId: { - validator: $.type(ID), - }, - }, - errors: { noSuchList: { message: 'No such list.', @@ -26,8 +18,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + }, + required: ['listId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const userList = await UserLists.findOne({ id: ps.listId, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/users/lists/list.ts b/packages/backend/src/server/api/endpoints/users/lists/list.ts index ae66b0aac..a8663ada8 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/list.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/list.ts @@ -1,5 +1,5 @@ -import define from '../../../define'; -import { UserLists } from '@/models/index'; +import define from '../../../define.js'; +import { UserLists } from '@/models/index.js'; export const meta = { tags: ['lists', 'account'], @@ -19,8 +19,14 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const userLists = await UserLists.find({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/pull.ts b/packages/backend/src/server/api/endpoints/users/lists/pull.ts index 4c74aefa8..2c4c61d51 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/pull.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/pull.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { publishUserListStream } from '@/services/stream'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { UserLists, UserListJoinings, Users } from '@/models/index'; +import { publishUserListStream } from '@/services/stream.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; +import { UserLists, UserListJoinings, Users } from '@/models/index.js'; export const meta = { tags: ['lists', 'users'], @@ -13,16 +11,6 @@ export const meta = { kind: 'write:account', - params: { - listId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchList: { message: 'No such list.', @@ -38,8 +26,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['listId', 'userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the list const userList = await UserLists.findOne({ id: ps.listId, diff --git a/packages/backend/src/server/api/endpoints/users/lists/push.ts b/packages/backend/src/server/api/endpoints/users/lists/push.ts index 8b50c475b..034a9d2db 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/push.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/push.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { pushUserToUserList } from '@/services/user-list/push'; -import { UserLists, UserListJoinings, Blockings } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getUser } from '../../../common/getters.js'; +import { pushUserToUserList } from '@/services/user-list/push.js'; +import { UserLists, UserListJoinings, Blockings } from '@/models/index.js'; export const meta = { tags: ['lists', 'users'], @@ -13,16 +11,6 @@ export const meta = { kind: 'write:account', - params: { - listId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchList: { message: 'No such list.', @@ -50,8 +38,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['listId', 'userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the list const userList = await UserLists.findOne({ id: ps.listId, diff --git a/packages/backend/src/server/api/endpoints/users/lists/show.ts b/packages/backend/src/server/api/endpoints/users/lists/show.ts index 06555c1a8..fadb94c90 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/show.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/show.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserLists } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { UserLists } from '@/models/index.js'; export const meta = { tags: ['lists', 'account'], @@ -11,12 +9,6 @@ export const meta = { kind: 'read:account', - params: { - listId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -32,8 +24,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + }, + required: ['listId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Fetch the list const userList = await UserLists.findOne({ id: ps.listId, diff --git a/packages/backend/src/server/api/endpoints/users/lists/update.ts b/packages/backend/src/server/api/endpoints/users/lists/update.ts index 02b0d5fe1..5ec99031e 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/update.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/update.ts @@ -1,8 +1,6 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserLists } from '@/models/index'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { UserLists } from '@/models/index.js'; export const meta = { tags: ['lists'], @@ -11,16 +9,6 @@ export const meta = { kind: 'write:account', - params: { - listId: { - validator: $.type(ID), - }, - - name: { - validator: $.str.range(1, 100), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -36,8 +24,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + name: { type: 'string', minLength: 1, maxLength: 100 }, + }, + required: ['listId', 'name'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { // Fetch the list const userList = await UserLists.findOne({ id: ps.listId, diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 99158fb0a..16318d222 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -1,70 +1,17 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { Notes } from '@/models/index'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { Notes } from '@/models/index.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; import { Brackets } from 'typeorm'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; -import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; export const meta = { tags: ['users', 'notes'], - params: { - userId: { - validator: $.type(ID), - }, - - includeReplies: { - validator: $.optional.bool, - default: true, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - - includeMyRenotes: { - validator: $.optional.bool, - default: true, - }, - - withFiles: { - validator: $.optional.bool, - default: false, - }, - - fileType: { - validator: $.optional.arr($.str), - }, - - excludeNsfw: { - validator: $.optional.bool, - default: false, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -84,8 +31,28 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + includeReplies: { type: 'boolean', default: true }, + 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' }, + includeMyRenotes: { type: 'boolean', default: true }, + withFiles: { type: 'boolean', default: false }, + fileType: { type: 'array', items: { + type: 'string', + } }, + excludeNsfw: { type: 'boolean', default: false }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Lookup user const user = await getUser(ps.userId).catch(e => { if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); @@ -96,10 +63,16 @@ export default define(meta, async (ps, me) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('note.userId = :userId', { userId: user.id }) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me, user); @@ -141,7 +114,7 @@ export default define(meta, async (ps, me) => { //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); return await Notes.packMany(timeline, me); }); diff --git a/packages/backend/src/server/api/endpoints/users/pages.ts b/packages/backend/src/server/api/endpoints/users/pages.ts index 6e003dd1a..b8b3e8192 100644 --- a/packages/backend/src/server/api/endpoints/users/pages.ts +++ b/packages/backend/src/server/api/endpoints/users/pages.ts @@ -1,40 +1,30 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Pages } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; +import define from '../../define.js'; +import { Pages } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; export const meta = { tags: ['users', 'pages'], +} as const; - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, }, + required: ['userId'], } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = makePaginationQuery(Pages.createQueryBuilder('page'), ps.sinceId, ps.untilId) .andWhere(`page.userId = :userId`, { userId: ps.userId }) .andWhere('page.visibility = \'public\''); const pages = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Pages.packMany(pages); diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 312d4dbf2..7b55a1671 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -1,43 +1,14 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { NoteReactions, UserProfiles } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { ApiError } from '../../error'; +import define from '../../define.js'; +import { NoteReactions, UserProfiles } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { ApiError } from '../../error.js'; export const meta = { tags: ['users', 'reactions'], requireCredential: false, - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -57,8 +28,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + 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: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const profile = await UserProfiles.findOneOrFail(ps.userId); if (me == null || (me.id !== ps.userId && !profile.publicReactions)) { @@ -73,7 +57,7 @@ export default define(meta, async (ps, me) => { generateVisibilityQuery(query, me); const reactions = await query - .take(ps.limit!) + .take(ps.limit) .getMany(); return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, me, { withNote: true }))); diff --git a/packages/backend/src/server/api/endpoints/users/recommendation.ts b/packages/backend/src/server/api/endpoints/users/recommendation.ts index 9ea39eb2d..a8f18de52 100644 --- a/packages/backend/src/server/api/endpoints/users/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/users/recommendation.ts @@ -1,9 +1,8 @@ import ms from 'ms'; -import $ from 'cafy'; -import define from '../../define'; -import { Users, Followings } from '@/models/index'; -import { generateMutedUserQueryForUsers } from '../../common/generate-muted-user-query'; -import { generateBlockedUserQuery, generateBlockQueryForUsers } from '../../common/generate-block-query'; +import define from '../../define.js'; +import { Users, Followings } from '@/models/index.js'; +import { generateMutedUserQueryForUsers } from '../../common/generate-muted-user-query.js'; +import { generateBlockedUserQuery, generateBlockQueryForUsers } from '../../common/generate-block-query.js'; export const meta = { tags: ['users'], @@ -12,18 +11,6 @@ export const meta = { kind: 'read:account', - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -35,8 +22,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = Users.createQueryBuilder('user') .where('user.isLocked = FALSE') .andWhere('user.isExplorable = TRUE') @@ -58,7 +54,7 @@ export default define(meta, async (ps, me) => { query.setParameters(followingQuery.getParameters()); - const users = await query.take(ps.limit!).skip(ps.offset).getMany(); + const users = await query.take(ps.limit).skip(ps.offset).getMany(); return await Users.packMany(users, me, { detail: true }); }); diff --git a/packages/backend/src/server/api/endpoints/users/relation.ts b/packages/backend/src/server/api/endpoints/users/relation.ts index 7e319ca10..c6262122d 100644 --- a/packages/backend/src/server/api/endpoints/users/relation.ts +++ b/packages/backend/src/server/api/endpoints/users/relation.ts @@ -1,19 +1,11 @@ -import $ from 'cafy'; -import define from '../../define'; -import { ID } from '@/misc/cafy-id'; -import { Users } from '@/models/index'; +import define from '../../define.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['users'], requireCredential: true, - params: { - userId: { - validator: $.either($.type(ID), $.arr($.type(ID)).unique()), - }, - }, - res: { optional: false, nullable: false, oneOf: [ @@ -101,8 +93,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { + anyOf: [ + { type: 'string', format: 'misskey:id' }, + { + type: 'array', + items: { type: 'string', format: 'misskey:id' }, + }, + ], + }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const ids = Array.isArray(ps.userId) ? ps.userId : [ps.userId]; const relations = await Promise.all(ids.map(id => Users.getRelation(me.id, id))); diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index ed2aa7bb2..e091b8e1b 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -1,30 +1,18 @@ -import $ from 'cafy'; import * as sanitizeHtml from 'sanitize-html'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { publishAdminStream } from '@/services/stream'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { AbuseUserReports, Users } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { sendEmail } from '@/services/send-email'; -import { fetchMeta } from '@/misc/fetch-meta'; +import define from '../../define.js'; +import { publishAdminStream } from '@/services/stream.js'; +import { ApiError } from '../../error.js'; +import { getUser } from '../../common/getters.js'; +import { AbuseUserReports, Users } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { sendEmail } from '@/services/send-email.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; export const meta = { tags: ['users'], requireCredential: true, - params: { - userId: { - validator: $.type(ID), - }, - - comment: { - validator: $.str.range(1, 2048), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -46,8 +34,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + comment: { type: 'string', minLength: 1, maxLength: 2048 }, + }, + required: ['userId', 'comment'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { // Lookup user const user = await getUser(ps.userId).catch(e => { if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index d67625e62..897b5de3f 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -1,35 +1,14 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Followings, Users } from '@/models/index'; +import define from '../../define.js'; +import { Followings, Users } from '@/models/index.js'; import { Brackets } from 'typeorm'; -import { USER_ACTIVE_THRESHOLD } from '@/const'; -import { User } from '@/models/entities/user'; +import { USER_ACTIVE_THRESHOLD } from '@/const.js'; +import { User } from '@/models/entities/user.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - username: { - validator: $.optional.nullable.str, - }, - - host: { - validator: $.optional.nullable.str, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - detail: { - validator: $.optional.bool, - default: true, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -41,8 +20,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + username: { type: 'string', nullable: true }, + host: { type: 'string', nullable: true }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + detail: { type: 'boolean', default: true }, + }, + required: [], +} as const; + +// TODO: avatar,bannerをJOINしたいけおエナãƒŧãĢãĒる + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30æ—Ĩ if (ps.host) { @@ -57,7 +49,7 @@ export default define(meta, async (ps, me) => { q.andWhere('user.updatedAt IS NOT NULL'); q.orderBy('user.updatedAt', 'DESC'); - const users = await q.take(ps.limit!).getMany(); + const users = await q.take(ps.limit).getMany(); return await Users.packMany(users, me, { detail: ps.detail }); } else if (ps.username) { @@ -82,10 +74,10 @@ export default define(meta, async (ps, me) => { users = await query .orderBy('user.usernameLower', 'ASC') - .take(ps.limit!) + .take(ps.limit) .getMany(); - if (users.length < ps.limit!) { + if (users.length < ps.limit) { const otherQuery = await Users.createQueryBuilder('user') .where(`user.id NOT IN (${ followingQuery.getQuery() })`) .andWhere(`user.id != :meId`, { meId: me.id }) @@ -97,7 +89,7 @@ export default define(meta, async (ps, me) => { const otherUsers = await otherQuery .orderBy('user.updatedAt', 'DESC') - .take(ps.limit! - users.length) + .take(ps.limit - users.length) .getMany(); users = users.concat(otherUsers); @@ -108,10 +100,12 @@ export default define(meta, async (ps, me) => { .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) .andWhere('user.updatedAt IS NOT NULL') .orderBy('user.updatedAt', 'DESC') - .take(ps.limit! - users.length) + .take(ps.limit - users.length) .getMany(); } return await Users.packMany(users, me, { detail: !!ps.detail }); } + + return []; }); diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index 26f818afc..a72a58a84 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -1,7 +1,6 @@ -import $ from 'cafy'; -import define from '../../define'; -import { UserProfiles, Users } from '@/models/index'; -import { User } from '@/models/entities/user'; +import define from '../../define.js'; +import { UserProfiles, Users } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; import { Brackets } from 'typeorm'; export const meta = { @@ -9,32 +8,6 @@ export const meta = { requireCredential: false, - params: { - query: { - validator: $.str, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - origin: { - validator: $.optional.str.or(['local', 'remote', 'combined']), - default: 'combined', - }, - - detail: { - validator: $.optional.bool, - default: true, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -46,8 +19,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + query: { type: 'string' }, + offset: { type: 'integer', default: 0 }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + origin: { type: 'string', enum: ['local', 'remote', 'combined'], default: "combined" }, + detail: { type: 'boolean', default: true }, + }, + required: ['query'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30æ—Ĩ const isUsername = ps.query.startsWith('@'); @@ -71,7 +56,7 @@ export default define(meta, async (ps, me) => { users = await usernameQuery .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .take(ps.limit!) + .take(ps.limit) .skip(ps.offset) .getMany(); } else { @@ -91,11 +76,11 @@ export default define(meta, async (ps, me) => { users = await nameQuery .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .take(ps.limit!) + .take(ps.limit) .skip(ps.offset) .getMany(); - if (users.length < ps.limit!) { + if (users.length < ps.limit) { const profQuery = UserProfiles.createQueryBuilder('prof') .select('prof.userId') .where('prof.description ILIKE :query', { query: '%' + ps.query + '%' }); @@ -117,7 +102,7 @@ export default define(meta, async (ps, me) => { users = users.concat(await query .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .take(ps.limit!) + .take(ps.limit) .skip(ps.offset) .getMany() ); diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 92910e9ed..263c102a7 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -1,36 +1,16 @@ -import $ from 'cafy'; -import { resolveUser } from '@/remote/resolve-user'; -import define from '../../define'; -import { apiLogger } from '../../logger'; -import { ApiError } from '../../error'; -import { ID } from '@/misc/cafy-id'; -import { Users } from '@/models/index'; +import { resolveUser } from '@/remote/resolve-user.js'; +import define from '../../define.js'; +import { apiLogger } from '../../logger.js'; +import { ApiError } from '../../error.js'; +import { Users } from '@/models/index.js'; import { In } from 'typeorm'; -import { User } from '@/models/entities/user'; +import { User } from '@/models/entities/user.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - userId: { - validator: $.optional.type(ID), - }, - - userIds: { - validator: $.optional.arr($.type(ID)).unique(), - }, - - username: { - validator: $.optional.str, - }, - - host: { - validator: $.optional.nullable.str, - }, - }, - res: { optional: false, nullable: false, oneOf: [ @@ -64,8 +44,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + userIds: { type: 'array', uniqueItems: true, items: { + type: 'string', format: 'misskey:id', + } }, + username: { type: 'string' }, + host: { type: 'string', nullable: true }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { let user; const isAdminOrModerator = me && (me.isAdmin || me.isModerator); diff --git a/packages/backend/src/server/api/endpoints/users/stats.ts b/packages/backend/src/server/api/endpoints/users/stats.ts index 381e43347..180a9386d 100644 --- a/packages/backend/src/server/api/endpoints/users/stats.ts +++ b/packages/backend/src/server/api/endpoints/users/stats.ts @@ -1,20 +1,12 @@ -import $ from 'cafy'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { ID } from '@/misc/cafy-id'; -import { DriveFiles, Followings, NoteFavorites, NoteReactions, Notes, PageLikes, PollVotes, Users } from '@/models/index'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { DriveFiles, Followings, NoteFavorites, NoteReactions, Notes, PageLikes, PollVotes, Users } from '@/models/index.js'; export const meta = { tags: ['users'], requireCredential: false, - params: { - userId: { - validator: $.type(ID), - }, - }, - errors: { noSuchUser: { message: 'No such user.', @@ -24,8 +16,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const user = await Users.findOne(ps.userId); if (user == null) { throw new ApiError(meta.errors.noSuchUser); diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts index 8f8a9d999..ba2a71951 100644 --- a/packages/backend/src/server/api/index.ts +++ b/packages/backend/src/server/api/index.ts @@ -2,22 +2,22 @@ * API Server */ -import * as Koa from 'koa'; -import * as Router from '@koa/router'; -import * as multer from '@koa/multer'; -import * as bodyParser from 'koa-bodyparser'; -import * as cors from '@koa/cors'; +import Koa from 'koa'; +import Router from '@koa/router'; +import multer from '@koa/multer'; +import bodyParser from 'koa-bodyparser'; +import cors from '@koa/cors'; -import endpoints from './endpoints'; -import handler from './api-handler'; -import signup from './private/signup'; -import signin from './private/signin'; -import signupPending from './private/signup-pending'; -import discord from './service/discord'; -import github from './service/github'; -import twitter from './service/twitter'; -import { Instances, AccessTokens, Users } from '@/models/index'; -import config from '@/config'; +import endpoints from './endpoints.js'; +import handler from './api-handler.js'; +import signup from './private/signup.js'; +import signin from './private/signin.js'; +import signupPending from './private/signup-pending.js'; +import discord from './service/discord.js'; +import github from './service/github.js'; +import twitter from './service/twitter.js'; +import { Instances, AccessTokens, Users } from '@/models/index.js'; +import config from '@/config/index.js'; // Init app const app = new Koa(); diff --git a/packages/backend/src/server/api/limiter.ts b/packages/backend/src/server/api/limiter.ts index 4721f6263..7e6b93b39 100644 --- a/packages/backend/src/server/api/limiter.ts +++ b/packages/backend/src/server/api/limiter.ts @@ -1,9 +1,9 @@ -import * as Limiter from 'ratelimiter'; -import { redisClient } from '../../db/redis'; -import { IEndpoint } from './endpoints'; -import * as Acct from 'misskey-js/built/acct'; -import { User } from '@/models/entities/user'; -import Logger from '@/services/logger'; +import Limiter from 'ratelimiter'; +import { redisClient } from '../../db/redis.js'; +import { IEndpoint } from './endpoints.js'; +import * as Acct from '@/misc/acct.js'; +import { User } from '@/models/entities/user.js'; +import Logger from '@/services/logger.js'; const logger = new Logger('limiter'); diff --git a/packages/backend/src/server/api/logger.ts b/packages/backend/src/server/api/logger.ts index 750defe54..ec22d6c3e 100644 --- a/packages/backend/src/server/api/logger.ts +++ b/packages/backend/src/server/api/logger.ts @@ -1,3 +1,3 @@ -import Logger from '@/services/logger'; +import Logger from '@/services/logger.js'; export const apiLogger = new Logger('api'); diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 1efef8d26..c6e557aef 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -1,8 +1,7 @@ -import endpoints from '../endpoints'; -import { Context } from 'cafy'; -import config from '@/config/index'; -import { errors as basicErrors } from './errors'; -import { schemas, convertSchemaToOpenApiSchema } from './schemas'; +import endpoints from '../endpoints.js'; +import config from '@/config/index.js'; +import { errors as basicErrors } from './errors.js'; +import { schemas, convertSchemaToOpenApiSchema } from './schemas.js'; export function genOpenapiSpec(lang = 'ja-JP') { const spec = { @@ -38,47 +37,7 @@ export function genOpenapiSpec(lang = 'ja-JP') { }, }; - function genProps(props: { [key: string]: Context; }) { - const properties = {} as any; - - for (const [k, v] of Object.entries(props)) { - properties[k] = genProp(v); - } - - return properties; - } - - function genProp(param: Context): any { - const required = param.name === 'Object' ? (param as any).props ? Object.entries((param as any).props).filter(([k, v]: any) => !v.isOptional).map(([k, v]) => k) : [] : []; - return { - description: (param.data || {}).desc, - default: (param.data || {}).default, - deprecated: (param.data || {}).deprecated, - ...((param.data || {}).default ? { default: (param.data || {}).default } : {}), - type: param.name === 'ID' ? 'string' : param.name.toLowerCase(), - ...(param.name === 'ID' ? { example: 'xxxxxxxxxx', format: 'id' } : {}), - nullable: param.isNullable, - ...(param.name === 'String' ? { - ...((param as any).enum ? { enum: (param as any).enum } : {}), - ...((param as any).minLength ? { minLength: (param as any).minLength } : {}), - ...((param as any).maxLength ? { maxLength: (param as any).maxLength } : {}), - } : {}), - ...(param.name === 'Number' ? { - ...((param as any).minimum ? { minimum: (param as any).minimum } : {}), - ...((param as any).maximum ? { maximum: (param as any).maximum } : {}), - } : {}), - ...(param.name === 'Object' ? { - ...(required.length > 0 ? { required } : {}), - properties: (param as any).props ? genProps((param as any).props) : {}, - } : {}), - ...(param.name === 'Array' ? { - items: (param as any).ctx ? genProp((param as any).ctx) : {}, - } : {}), - }; - } - for (const endpoint of endpoints.filter(ep => !ep.meta.secure)) { - const porops = {} as any; const errors = {} as any; if (endpoint.meta.errors) { @@ -91,21 +50,9 @@ export function genOpenapiSpec(lang = 'ja-JP') { } } - if (endpoint.meta.params) { - for (const [k, v] of Object.entries(endpoint.meta.params)) { - if (v.validator.data == null) v.validator.data = {}; - if (v.desc) v.validator.data.desc = v.desc[lang]; - if (v.deprecated) v.validator.data.deprecated = v.deprecated; - if (v.default) v.validator.data.default = v.default; - porops[k] = v.validator; - } - } - - const required = endpoint.meta.params ? Object.entries(endpoint.meta.params).filter(([k, v]) => !v.validator.isOptional).map(([k, v]) => k) : []; - const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res) : {}; - let desc = (endpoint.meta.desc ? endpoint.meta.desc[lang] : 'No description provided.') + '\n\n'; + let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n'; desc += `**Credential required**: *${endpoint.meta.requireCredential ? 'Yes' : 'No'}*`; if (endpoint.meta.kind) { const kind = endpoint.meta.kind; @@ -132,11 +79,7 @@ export function genOpenapiSpec(lang = 'ja-JP') { required: true, content: { 'application/json': { - schema: { - type: 'object', - ...(required.length > 0 ? { required } : {}), - properties: endpoint.meta.params ? genProps(porops) : {}, - }, + schema: endpoint.params, }, }, }, diff --git a/packages/backend/src/server/api/openapi/schemas.ts b/packages/backend/src/server/api/openapi/schemas.ts index eb42667fd..14bef9cab 100644 --- a/packages/backend/src/server/api/openapi/schemas.ts +++ b/packages/backend/src/server/api/openapi/schemas.ts @@ -1,6 +1,6 @@ -import { refs, MinimumSchema } from '@/misc/schema'; +import { refs, Schema } from '@/misc/schema.js'; -export function convertSchemaToOpenApiSchema(schema: MinimumSchema) { +export function convertSchemaToOpenApiSchema(schema: Schema) { const res: any = schema; if (schema.type === 'object' && schema.properties) { diff --git a/packages/backend/src/server/api/private/signin.ts b/packages/backend/src/server/api/private/signin.ts index 7b733b768..b0f88948a 100644 --- a/packages/backend/src/server/api/private/signin.ts +++ b/packages/backend/src/server/api/private/signin.ts @@ -1,13 +1,13 @@ -import * as Koa from 'koa'; -import * as bcrypt from 'bcryptjs'; +import Koa from 'koa'; +import bcrypt from 'bcryptjs'; import * as speakeasy from 'speakeasy'; -import signin from '../common/signin'; -import config from '@/config/index'; -import { Users, Signins, UserProfiles, UserSecurityKeys, AttestationChallenges } from '@/models/index'; -import { ILocalUser } from '@/models/entities/user'; -import { genId } from '@/misc/gen-id'; -import { verifyLogin, hash } from '../2fa'; -import { randomBytes } from 'crypto'; +import signin from '../common/signin.js'; +import config from '@/config/index.js'; +import { Users, Signins, UserProfiles, UserSecurityKeys, AttestationChallenges } from '@/models/index.js'; +import { ILocalUser } from '@/models/entities/user.js'; +import { genId } from '@/misc/gen-id.js'; +import { verifyLogin, hash } from '../2fa.js'; +import { randomBytes } from 'node:crypto'; export default async (ctx: Koa.Context) => { ctx.set('Access-Control-Allow-Origin', config.url); diff --git a/packages/backend/src/server/api/private/signup-pending.ts b/packages/backend/src/server/api/private/signup-pending.ts index c0638a1cd..1a667ddb4 100644 --- a/packages/backend/src/server/api/private/signup-pending.ts +++ b/packages/backend/src/server/api/private/signup-pending.ts @@ -1,7 +1,7 @@ -import * as Koa from 'koa'; -import { Users, UserPendings, UserProfiles } from '@/models/index'; -import { signup } from '../common/signup'; -import signin from '../common/signin'; +import Koa from 'koa'; +import { Users, UserPendings, UserProfiles } from '@/models/index.js'; +import { signup } from '../common/signup.js'; +import signin from '../common/signin.js'; export default async (ctx: Koa.Context) => { const body = ctx.request.body; diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts index eaab8e711..01f284a57 100644 --- a/packages/backend/src/server/api/private/signup.ts +++ b/packages/backend/src/server/api/private/signup.ts @@ -1,14 +1,14 @@ -import * as Koa from 'koa'; +import Koa from 'koa'; import rndstr from 'rndstr'; -import * as bcrypt from 'bcryptjs'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { verifyHcaptcha, verifyRecaptcha } from '@/misc/captcha'; -import { Users, RegistrationTickets, UserPendings } from '@/models/index'; -import { signup } from '../common/signup'; -import config from '@/config'; -import { sendEmail } from '@/services/send-email'; -import { genId } from '@/misc/gen-id'; -import { validateEmailForAccount } from '@/services/validate-email-for-account'; +import bcrypt from 'bcryptjs'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { verifyHcaptcha, verifyRecaptcha } from '@/misc/captcha.js'; +import { Users, RegistrationTickets, UserPendings } from '@/models/index.js'; +import { signup } from '../common/signup.js'; +import config from '@/config/index.js'; +import { sendEmail } from '@/services/send-email.js'; +import { genId } from '@/misc/gen-id.js'; +import { validateEmailForAccount } from '@/services/validate-email-for-account.js'; export default async (ctx: Koa.Context) => { const body = ctx.request.body; @@ -38,7 +38,7 @@ export default async (ctx: Koa.Context) => { const emailAddress = body['emailAddress']; if (instance.emailRequiredForSignup) { - if (emailAddress == null || typeof emailAddress != 'string') { + if (emailAddress == null || typeof emailAddress !== 'string') { ctx.status = 400; return; } @@ -51,7 +51,7 @@ export default async (ctx: Koa.Context) => { } if (instance.disableRegistration) { - if (invitationCode == null || typeof invitationCode != 'string') { + if (invitationCode == null || typeof invitationCode !== 'string') { ctx.status = 400; return; } diff --git a/packages/backend/src/server/api/service/discord.ts b/packages/backend/src/server/api/service/discord.ts index f574fe387..089f7de0c 100644 --- a/packages/backend/src/server/api/service/discord.ts +++ b/packages/backend/src/server/api/service/discord.ts @@ -1,28 +1,28 @@ -import * as Koa from 'koa'; -import * as Router from '@koa/router'; -import { getJson } from '@/misc/fetch'; +import Koa from 'koa'; +import Router from '@koa/router'; +import { getJson } from '@/misc/fetch.js'; import { OAuth2 } from 'oauth'; -import config from '@/config/index'; -import { publishMainStream } from '@/services/stream'; -import { redisClient } from '../../../db/redis'; +import config from '@/config/index.js'; +import { publishMainStream } from '@/services/stream.js'; +import { redisClient } from '../../../db/redis.js'; import { v4 as uuid } from 'uuid'; -import signin from '../common/signin'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Users, UserProfiles } from '@/models/index'; -import { ILocalUser } from '@/models/entities/user'; +import signin from '../common/signin.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Users, UserProfiles } from '@/models/index.js'; +import { ILocalUser } from '@/models/entities/user.js'; -function getUserToken(ctx: Koa.Context) { +function getUserToken(ctx: Koa.BaseContext): string | null { return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; } -function compareOrigin(ctx: Koa.Context) { - function normalizeUrl(url: string) { +function compareOrigin(ctx: Koa.BaseContext): boolean { + function normalizeUrl(url?: string): string { return url ? url.endsWith('/') ? url.substr(0, url.length - 1) : url : ''; } const referer = ctx.headers['referer']; - return (normalizeUrl(referer) == normalizeUrl(config.url)); + return (normalizeUrl(referer) === normalizeUrl(config.url)); } // Init router diff --git a/packages/backend/src/server/api/service/github.ts b/packages/backend/src/server/api/service/github.ts index 5e0839df9..ce032db18 100644 --- a/packages/backend/src/server/api/service/github.ts +++ b/packages/backend/src/server/api/service/github.ts @@ -1,28 +1,28 @@ -import * as Koa from 'koa'; -import * as Router from '@koa/router'; -import { getJson } from '@/misc/fetch'; +import Koa from 'koa'; +import Router from '@koa/router'; +import { getJson } from '@/misc/fetch.js'; import { OAuth2 } from 'oauth'; -import config from '@/config/index'; -import { publishMainStream } from '@/services/stream'; -import { redisClient } from '../../../db/redis'; +import config from '@/config/index.js'; +import { publishMainStream } from '@/services/stream.js'; +import { redisClient } from '../../../db/redis.js'; import { v4 as uuid } from 'uuid'; -import signin from '../common/signin'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Users, UserProfiles } from '@/models/index'; -import { ILocalUser } from '@/models/entities/user'; +import signin from '../common/signin.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Users, UserProfiles } from '@/models/index.js'; +import { ILocalUser } from '@/models/entities/user.js'; -function getUserToken(ctx: Koa.Context) { +function getUserToken(ctx: Koa.BaseContext): string | null { return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; } -function compareOrigin(ctx: Koa.Context) { - function normalizeUrl(url: string) { +function compareOrigin(ctx: Koa.BaseContext): boolean { + function normalizeUrl(url?: string): string { return url ? url.endsWith('/') ? url.substr(0, url.length - 1) : url : ''; } const referer = ctx.headers['referer']; - return (normalizeUrl(referer) == normalizeUrl(config.url)); + return (normalizeUrl(referer) === normalizeUrl(config.url)); } // Init router diff --git a/packages/backend/src/server/api/service/twitter.ts b/packages/backend/src/server/api/service/twitter.ts index 8659b82cb..e6e4398fa 100644 --- a/packages/backend/src/server/api/service/twitter.ts +++ b/packages/backend/src/server/api/service/twitter.ts @@ -1,27 +1,27 @@ -import * as Koa from 'koa'; -import * as Router from '@koa/router'; +import Koa from 'koa'; +import Router from '@koa/router'; import { v4 as uuid } from 'uuid'; import autwh from 'autwh'; -import { redisClient } from '../../../db/redis'; -import { publishMainStream } from '@/services/stream'; -import config from '@/config/index'; -import signin from '../common/signin'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Users, UserProfiles } from '@/models/index'; -import { ILocalUser } from '@/models/entities/user'; +import { redisClient } from '../../../db/redis.js'; +import { publishMainStream } from '@/services/stream.js'; +import config from '@/config/index.js'; +import signin from '../common/signin.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Users, UserProfiles } from '@/models/index.js'; +import { ILocalUser } from '@/models/entities/user.js'; -function getUserToken(ctx: Koa.Context) { +function getUserToken(ctx: Koa.BaseContext): string | null { return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; } -function compareOrigin(ctx: Koa.Context) { - function normalizeUrl(url: string) { - return url.endsWith('/') ? url.substr(0, url.length - 1) : url; +function compareOrigin(ctx: Koa.BaseContext): boolean { + function normalizeUrl(url?: string): string { + return url == null ? '' : url.endsWith('/') ? url.substr(0, url.length - 1) : url; } const referer = ctx.headers['referer']; - return (normalizeUrl(referer) == normalizeUrl(config.url)); + return (normalizeUrl(referer) === normalizeUrl(config.url)); } // Init router diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts index 98337bb31..d2cc5122d 100644 --- a/packages/backend/src/server/api/stream/channel.ts +++ b/packages/backend/src/server/api/stream/channel.ts @@ -1,4 +1,3 @@ -import autobind from 'autobind-decorator'; import Connection from '.'; /** @@ -44,7 +43,6 @@ export default abstract class Channel { this.connection = connection; } - @autobind public send(typeOrPayload: any, payload?: any) { const type = payload === undefined ? typeOrPayload.type : typeOrPayload; const body = payload === undefined ? typeOrPayload.body : payload; diff --git a/packages/backend/src/server/api/stream/channels/admin.ts b/packages/backend/src/server/api/stream/channels/admin.ts index 1ff932d1d..945182ea1 100644 --- a/packages/backend/src/server/api/stream/channels/admin.ts +++ b/packages/backend/src/server/api/stream/channels/admin.ts @@ -1,12 +1,10 @@ -import autobind from 'autobind-decorator'; -import Channel from '../channel'; +import Channel from '../channel.js'; export default class extends Channel { public readonly chName = 'admin'; public static shouldShare = true; public static requireCredential = true; - @autobind public async init(params: any) { // Subscribe admin stream this.subscriber.on(`adminStream:${this.user!.id}`, data => { diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts index 3cbdfebb4..afd14946e 100644 --- a/packages/backend/src/server/api/stream/channels/antenna.ts +++ b/packages/backend/src/server/api/stream/channels/antenna.ts @@ -1,9 +1,8 @@ -import autobind from 'autobind-decorator'; -import Channel from '../channel'; -import { Notes } from '@/models/index'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import { isBlockerUserRelated } from '@/misc/is-blocker-user-related'; -import { StreamMessages } from '../types'; +import Channel from '../channel.js'; +import { Notes } from '@/models/index.js'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; +import { StreamMessages } from '../types.js'; export default class extends Channel { public readonly chName = 'antenna'; @@ -11,7 +10,11 @@ export default class extends Channel { public static requireCredential = false; private antennaId: string; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onEvent = this.onEvent.bind(this); + } + public async init(params: any) { this.antennaId = params.antennaId as string; @@ -19,7 +22,6 @@ export default class extends Channel { this.subscriber.on(`antennaStream:${this.antennaId}`, this.onEvent); } - @autobind private async onEvent(data: StreamMessages['antenna']['payload']) { if (data.type === 'note') { const note = await Notes.pack(data.body.id, this.user, { detail: true }); @@ -37,7 +39,6 @@ export default class extends Channel { } } - @autobind public dispose() { // Unsubscribe events this.subscriber.off(`antennaStream:${this.antennaId}`, this.onEvent); diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts index 1e51a81c4..16ad80939 100644 --- a/packages/backend/src/server/api/stream/channels/channel.ts +++ b/packages/backend/src/server/api/stream/channels/channel.ts @@ -1,11 +1,10 @@ -import autobind from 'autobind-decorator'; -import Channel from '../channel'; -import { Notes, Users } from '@/models/index'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import { isBlockerUserRelated } from '@/misc/is-blocker-user-related'; -import { User } from '@/models/entities/user'; -import { StreamMessages } from '../types'; -import { Packed } from '@/misc/schema'; +import Channel from '../channel.js'; +import { Notes, Users } from '@/models/index.js'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; +import { User } from '@/models/entities/user.js'; +import { StreamMessages } from '../types.js'; +import { Packed } from '@/misc/schema.js'; export default class extends Channel { public readonly chName = 'channel'; @@ -15,7 +14,11 @@ export default class extends Channel { private typers: Record = {}; private emitTypersIntervalId: ReturnType; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onNote = this.onNote.bind(this); + } + public async init(params: any) { this.channelId = params.channelId as string; @@ -25,7 +28,6 @@ export default class extends Channel { this.emitTypersIntervalId = setInterval(this.emitTypers, 5000); } - @autobind private async onNote(note: Packed<'Note'>) { if (note.channelId !== this.channelId) return; @@ -52,7 +54,6 @@ export default class extends Channel { this.send('note', note); } - @autobind private onEvent(data: StreamMessages['channel']['payload']) { if (data.type === 'typing') { const id = data.body; @@ -64,7 +65,6 @@ export default class extends Channel { } } - @autobind private async emitTypers() { const now = new Date(); @@ -81,7 +81,6 @@ export default class extends Channel { }); } - @autobind public dispose() { // Unsubscribe events this.subscriber.off('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/drive.ts b/packages/backend/src/server/api/stream/channels/drive.ts index 4112dd9b0..140255acd 100644 --- a/packages/backend/src/server/api/stream/channels/drive.ts +++ b/packages/backend/src/server/api/stream/channels/drive.ts @@ -1,12 +1,10 @@ -import autobind from 'autobind-decorator'; -import Channel from '../channel'; +import Channel from '../channel.js'; export default class extends Channel { public readonly chName = 'drive'; public static shouldShare = true; public static requireCredential = true; - @autobind public async init(params: any) { // Subscribe drive stream this.subscriber.on(`driveStream:${this.user!.id}`, data => { diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index f14f597aa..1c7e038ab 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -1,19 +1,22 @@ -import autobind from 'autobind-decorator'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import Channel from '../channel'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Notes } from '@/models/index'; -import { checkWordMute } from '@/misc/check-word-mute'; -import { isBlockerUserRelated } from '@/misc/is-blocker-user-related'; -import { isInstanceMuted } from '@/misc/is-instance-muted'; -import { Packed } from '@/misc/schema'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import Channel from '../channel.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Notes } from '@/models/index.js'; +import { checkWordMute } from '@/misc/check-word-mute.js'; +import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; +import { isInstanceMuted } from '@/misc/is-instance-muted.js'; +import { Packed } from '@/misc/schema.js'; export default class extends Channel { public readonly chName = 'globalTimeline'; public static shouldShare = true; public static requireCredential = false; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onNote = this.onNote.bind(this); + } + public async init(params: any) { const meta = await fetchMeta(); if (meta.disableGlobalTimeline) { @@ -24,7 +27,6 @@ export default class extends Channel { this.subscriber.on('notesStream', this.onNote); } - @autobind private async onNote(note: Packed<'Note'>) { if (note.visibility !== 'public') return; if (note.channelId != null) return; @@ -43,7 +45,7 @@ export default class extends Channel { } // é–ĸäŋ‚ãĒいčŋ”äŋĄã¯é™¤å¤– - if (note.reply) { + if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チãƒŖãƒŗネãƒĢæŽĨįļšä¸ģへぎčŋ”äŋĄã€ã§ã‚‚ãĒければ、「チãƒŖãƒŗネãƒĢæŽĨįļšä¸ģãŒčĄŒãŖたčŋ”äŋĄã€ã§ã‚‚ãĒければ、「投į¨ŋč€…ãŽæŠ•į¨ŋ者č‡ĒčēĢへぎčŋ”äŋĄã€ã§ã‚‚ãĒい場合 if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; @@ -69,7 +71,6 @@ export default class extends Channel { this.send('note', note); } - @autobind public dispose() { // Unsubscribe events this.subscriber.off('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts index 820095dfc..1b7a58022 100644 --- a/packages/backend/src/server/api/stream/channels/hashtag.ts +++ b/packages/backend/src/server/api/stream/channels/hashtag.ts @@ -1,10 +1,9 @@ -import autobind from 'autobind-decorator'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import Channel from '../channel'; -import { Notes } from '@/models/index'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; -import { isBlockerUserRelated } from '@/misc/is-blocker-user-related'; -import { Packed } from '@/misc/schema'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import Channel from '../channel.js'; +import { Notes } from '@/models/index.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; +import { Packed } from '@/misc/schema.js'; export default class extends Channel { public readonly chName = 'hashtag'; @@ -12,7 +11,11 @@ export default class extends Channel { public static requireCredential = false; private q: string[][]; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onNote = this.onNote.bind(this); + } + public async init(params: any) { this.q = params.q; @@ -22,7 +25,6 @@ export default class extends Channel { this.subscriber.on('notesStream', this.onNote); } - @autobind private async onNote(note: Packed<'Note'>) { const noteTags = note.tags ? note.tags.map((t: string) => t.toLowerCase()) : []; const matched = this.q.some(tags => tags.every(tag => noteTags.includes(normalizeForSearch(tag)))); @@ -45,7 +47,6 @@ export default class extends Channel { this.send('note', note); } - @autobind public dispose() { // Unsubscribe events this.subscriber.off('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 3bd491421..3a8e55202 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -1,24 +1,26 @@ -import autobind from 'autobind-decorator'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import Channel from '../channel'; -import { Notes } from '@/models/index'; -import { checkWordMute } from '@/misc/check-word-mute'; -import { isBlockerUserRelated } from '@/misc/is-blocker-user-related'; -import { isInstanceMuted } from '@/misc/is-instance-muted'; -import { Packed } from '@/misc/schema'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import Channel from '../channel.js'; +import { Notes } from '@/models/index.js'; +import { checkWordMute } from '@/misc/check-word-mute.js'; +import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; +import { isInstanceMuted } from '@/misc/is-instance-muted.js'; +import { Packed } from '@/misc/schema.js'; export default class extends Channel { public readonly chName = 'homeTimeline'; public static shouldShare = true; public static requireCredential = true; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onNote = this.onNote.bind(this); + } + public async init(params: any) { // Subscribe events this.subscriber.on('notesStream', this.onNote); } - @autobind private async onNote(note: Packed<'Note'>) { if (note.channelId) { if (!this.followingChannels.has(note.channelId)) return; @@ -54,7 +56,7 @@ export default class extends Channel { } // é–ĸäŋ‚ãĒいčŋ”äŋĄã¯é™¤å¤– - if (note.reply) { + if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チãƒŖãƒŗネãƒĢæŽĨįļšä¸ģへぎčŋ”äŋĄã€ã§ã‚‚ãĒければ、「チãƒŖãƒŗネãƒĢæŽĨįļšä¸ģãŒčĄŒãŖたčŋ”äŋĄã€ã§ã‚‚ãĒければ、「投į¨ŋč€…ãŽæŠ•į¨ŋ者č‡ĒčēĢへぎčŋ”äŋĄã€ã§ã‚‚ãĒい場合 if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; @@ -77,7 +79,6 @@ export default class extends Channel { this.send('note', note); } - @autobind public dispose() { // Unsubscribe events this.subscriber.off('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 0ae19aa7c..f3ceeffa1 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -1,19 +1,22 @@ -import autobind from 'autobind-decorator'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import Channel from '../channel'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Notes } from '@/models/index'; -import { checkWordMute } from '@/misc/check-word-mute'; -import { isBlockerUserRelated } from '@/misc/is-blocker-user-related'; -import { isInstanceMuted } from '@/misc/is-instance-muted'; -import { Packed } from '@/misc/schema'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import Channel from '../channel.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Notes } from '@/models/index.js'; +import { checkWordMute } from '@/misc/check-word-mute.js'; +import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; +import { isInstanceMuted } from '@/misc/is-instance-muted.js'; +import { Packed } from '@/misc/schema.js'; export default class extends Channel { public readonly chName = 'hybridTimeline'; public static shouldShare = true; public static requireCredential = true; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onNote = this.onNote.bind(this); + } + public async init(params: any) { const meta = await fetchMeta(); if (meta.disableLocalTimeline && !this.user!.isAdmin && !this.user!.isModerator) return; @@ -22,7 +25,6 @@ export default class extends Channel { this.subscriber.on('notesStream', this.onNote); } - @autobind private async onNote(note: Packed<'Note'>) { // チãƒŖãƒŗネãƒĢぎ投į¨ŋではãĒく、č‡Ē分č‡ĒčēĢぎ投į¨ŋ ぞたは // チãƒŖãƒŗネãƒĢぎ投į¨ŋではãĒく、そぎ投į¨ŋぎãƒĻãƒŧã‚ļãƒŧをフりロãƒŧしãĻいる ぞたは @@ -62,7 +64,7 @@ export default class extends Channel { if (isInstanceMuted(note, new Set(this.userProfile?.mutedInstances ?? []))) return; // é–ĸäŋ‚ãĒいčŋ”äŋĄã¯é™¤å¤– - if (note.reply) { + if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チãƒŖãƒŗネãƒĢæŽĨįļšä¸ģへぎčŋ”äŋĄã€ã§ã‚‚ãĒければ、「チãƒŖãƒŗネãƒĢæŽĨįļšä¸ģãŒčĄŒãŖたčŋ”äŋĄã€ã§ã‚‚ãĒければ、「投į¨ŋč€…ãŽæŠ•į¨ŋ者č‡ĒčēĢへぎčŋ”äŋĄã€ã§ã‚‚ãĒい場合 if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; @@ -85,7 +87,6 @@ export default class extends Channel { this.send('note', note); } - @autobind public dispose() { // Unsubscribe events this.subscriber.off('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/index.ts b/packages/backend/src/server/api/stream/channels/index.ts index f3826c4cf..d422edde8 100644 --- a/packages/backend/src/server/api/stream/channels/index.ts +++ b/packages/backend/src/server/api/stream/channels/index.ts @@ -1,18 +1,18 @@ -import main from './main'; -import homeTimeline from './home-timeline'; -import localTimeline from './local-timeline'; -import hybridTimeline from './hybrid-timeline'; -import globalTimeline from './global-timeline'; -import serverStats from './server-stats'; -import queueStats from './queue-stats'; -import userList from './user-list'; -import antenna from './antenna'; -import messaging from './messaging'; -import messagingIndex from './messaging-index'; -import drive from './drive'; -import hashtag from './hashtag'; -import channel from './channel'; -import admin from './admin'; +import main from './main.js'; +import homeTimeline from './home-timeline.js'; +import localTimeline from './local-timeline.js'; +import hybridTimeline from './hybrid-timeline.js'; +import globalTimeline from './global-timeline.js'; +import serverStats from './server-stats.js'; +import queueStats from './queue-stats.js'; +import userList from './user-list.js'; +import antenna from './antenna.js'; +import messaging from './messaging.js'; +import messagingIndex from './messaging-index.js'; +import drive from './drive.js'; +import hashtag from './hashtag.js'; +import channel from './channel.js'; +import admin from './admin.js'; export default { main, diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 3178b1d51..4e198482a 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -1,18 +1,21 @@ -import autobind from 'autobind-decorator'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import Channel from '../channel'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Notes } from '@/models/index'; -import { checkWordMute } from '@/misc/check-word-mute'; -import { isBlockerUserRelated } from '@/misc/is-blocker-user-related'; -import { Packed } from '@/misc/schema'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import Channel from '../channel.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Notes } from '@/models/index.js'; +import { checkWordMute } from '@/misc/check-word-mute.js'; +import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; +import { Packed } from '@/misc/schema.js'; export default class extends Channel { public readonly chName = 'localTimeline'; public static shouldShare = true; public static requireCredential = false; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onNote = this.onNote.bind(this); + } + public async init(params: any) { const meta = await fetchMeta(); if (meta.disableLocalTimeline) { @@ -23,7 +26,6 @@ export default class extends Channel { this.subscriber.on('notesStream', this.onNote); } - @autobind private async onNote(note: Packed<'Note'>) { if (note.user.host !== null) return; if (note.visibility !== 'public') return; @@ -43,7 +45,7 @@ export default class extends Channel { } // é–ĸäŋ‚ãĒいčŋ”äŋĄã¯é™¤å¤– - if (note.reply) { + if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; // 「チãƒŖãƒŗネãƒĢæŽĨįļšä¸ģへぎčŋ”äŋĄã€ã§ã‚‚ãĒければ、「チãƒŖãƒŗネãƒĢæŽĨįļšä¸ģãŒčĄŒãŖたčŋ”äŋĄã€ã§ã‚‚ãĒければ、「投į¨ŋč€…ãŽæŠ•į¨ŋ者č‡ĒčēĢへぎčŋ”äŋĄã€ã§ã‚‚ãĒい場合 if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; @@ -66,7 +68,6 @@ export default class extends Channel { this.send('note', note); } - @autobind public dispose() { // Unsubscribe events this.subscriber.off('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/main.ts b/packages/backend/src/server/api/stream/channels/main.ts index b41eae7c7..9cfea0bfc 100644 --- a/packages/backend/src/server/api/stream/channels/main.ts +++ b/packages/backend/src/server/api/stream/channels/main.ts @@ -1,14 +1,12 @@ -import autobind from 'autobind-decorator'; -import Channel from '../channel'; -import { Notes } from '@/models/index'; -import { isInstanceMuted, isUserFromMutedInstance } from '@/misc/is-instance-muted'; +import Channel from '../channel.js'; +import { Notes } from '@/models/index.js'; +import { isInstanceMuted, isUserFromMutedInstance } from '@/misc/is-instance-muted.js'; export default class extends Channel { public readonly chName = 'main'; public static shouldShare = true; public static requireCredential = true; - @autobind public async init(params: any) { // Subscribe main stream channel this.subscriber.on(`mainStream:${this.user!.id}`, async data => { diff --git a/packages/backend/src/server/api/stream/channels/messaging-index.ts b/packages/backend/src/server/api/stream/channels/messaging-index.ts index 0c495398a..b930785d2 100644 --- a/packages/backend/src/server/api/stream/channels/messaging-index.ts +++ b/packages/backend/src/server/api/stream/channels/messaging-index.ts @@ -1,12 +1,10 @@ -import autobind from 'autobind-decorator'; -import Channel from '../channel'; +import Channel from '../channel.js'; export default class extends Channel { public readonly chName = 'messagingIndex'; public static shouldShare = true; public static requireCredential = true; - @autobind public async init(params: any) { // Subscribe messaging index stream this.subscriber.on(`messagingIndexStream:${this.user!.id}`, data => { diff --git a/packages/backend/src/server/api/stream/channels/messaging.ts b/packages/backend/src/server/api/stream/channels/messaging.ts index d8fccf076..94bbdeca5 100644 --- a/packages/backend/src/server/api/stream/channels/messaging.ts +++ b/packages/backend/src/server/api/stream/channels/messaging.ts @@ -1,10 +1,9 @@ -import autobind from 'autobind-decorator'; -import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivity } from '../../common/read-messaging-message'; -import Channel from '../channel'; -import { UserGroupJoinings, Users, MessagingMessages } from '@/models/index'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user'; -import { UserGroup } from '@/models/entities/user-group'; -import { StreamMessages } from '../types'; +import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivity } from '../../common/read-messaging-message.js'; +import Channel from '../channel.js'; +import { UserGroupJoinings, Users, MessagingMessages } from '@/models/index.js'; +import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { StreamMessages } from '../types.js'; export default class extends Channel { public readonly chName = 'messaging'; @@ -18,7 +17,13 @@ export default class extends Channel { private typers: Record = {}; private emitTypersIntervalId: ReturnType; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onEvent = this.onEvent.bind(this); + this.onMessage = this.onMessage.bind(this); + this.emitTypers = this.emitTypers.bind(this); + } + public async init(params: any) { this.otherpartyId = params.otherparty; this.otherparty = this.otherpartyId ? await Users.findOneOrFail({ id: this.otherpartyId }) : null; @@ -46,7 +51,6 @@ export default class extends Channel { this.subscriber.on(this.subCh, this.onEvent); } - @autobind private onEvent(data: StreamMessages['messaging']['payload'] | StreamMessages['groupMessaging']['payload']) { if (data.type === 'typing') { const id = data.body; @@ -60,7 +64,6 @@ export default class extends Channel { } } - @autobind public onMessage(type: string, body: any) { switch (type) { case 'read': @@ -80,7 +83,6 @@ export default class extends Channel { } } - @autobind private async emitTypers() { const now = new Date(); @@ -97,7 +99,6 @@ export default class extends Channel { }); } - @autobind public dispose() { this.subscriber.off(this.subCh, this.onEvent); diff --git a/packages/backend/src/server/api/stream/channels/queue-stats.ts b/packages/backend/src/server/api/stream/channels/queue-stats.ts index be18438fa..043d03ab8 100644 --- a/packages/backend/src/server/api/stream/channels/queue-stats.ts +++ b/packages/backend/src/server/api/stream/channels/queue-stats.ts @@ -1,25 +1,27 @@ -import autobind from 'autobind-decorator'; -import Xev from 'xev'; -import Channel from '../channel'; +import { default as Xev } from 'xev'; +import Channel from '../channel.js'; -const ev = new Xev(); +const ev = new Xev.default(); export default class extends Channel { public readonly chName = 'queueStats'; public static shouldShare = true; public static requireCredential = false; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onStats = this.onStats.bind(this); + this.onMessage = this.onMessage.bind(this); + } + public async init(params: any) { ev.addListener('queueStats', this.onStats); } - @autobind private onStats(stats: any) { this.send('stats', stats); } - @autobind public onMessage(type: string, body: any) { switch (type) { case 'requestLog': @@ -34,7 +36,6 @@ export default class extends Channel { } } - @autobind public dispose() { ev.removeListener('queueStats', this.onStats); } diff --git a/packages/backend/src/server/api/stream/channels/server-stats.ts b/packages/backend/src/server/api/stream/channels/server-stats.ts index df89b4c75..0da189576 100644 --- a/packages/backend/src/server/api/stream/channels/server-stats.ts +++ b/packages/backend/src/server/api/stream/channels/server-stats.ts @@ -1,25 +1,27 @@ -import autobind from 'autobind-decorator'; -import Xev from 'xev'; -import Channel from '../channel'; +import { default as Xev } from 'xev'; +import Channel from '../channel.js'; -const ev = new Xev(); +const ev = new Xev.default(); export default class extends Channel { public readonly chName = 'serverStats'; public static shouldShare = true; public static requireCredential = false; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.onStats = this.onStats.bind(this); + this.onMessage = this.onMessage.bind(this); + } + public async init(params: any) { ev.addListener('serverStats', this.onStats); } - @autobind private onStats(stats: any) { this.send('stats', stats); } - @autobind public onMessage(type: string, body: any) { switch (type) { case 'requestLog': @@ -34,7 +36,6 @@ export default class extends Channel { } } - @autobind public dispose() { ev.removeListener('serverStats', this.onStats); } diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index b75920a18..57523c848 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -1,10 +1,9 @@ -import autobind from 'autobind-decorator'; -import Channel from '../channel'; -import { Notes, UserListJoinings, UserLists } from '@/models/index'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import { User } from '@/models/entities/user'; -import { isBlockerUserRelated } from '@/misc/is-blocker-user-related'; -import { Packed } from '@/misc/schema'; +import Channel from '../channel.js'; +import { Notes, UserListJoinings, UserLists } from '@/models/index.js'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import { User } from '@/models/entities/user.js'; +import { isBlockerUserRelated } from '@/misc/is-blocker-user-related.js'; +import { Packed } from '@/misc/schema.js'; export default class extends Channel { public readonly chName = 'userList'; @@ -14,7 +13,12 @@ export default class extends Channel { public listUsers: User['id'][] = []; private listUsersClock: NodeJS.Timer; - @autobind + constructor(id: string, connection: Channel['connection']) { + super(id, connection); + this.updateListUsers = this.updateListUsers.bind(this); + this.onNote = this.onNote.bind(this); + } + public async init(params: any) { this.listId = params.listId as string; @@ -34,7 +38,6 @@ export default class extends Channel { this.listUsersClock = setInterval(this.updateListUsers, 5000); } - @autobind private async updateListUsers() { const users = await UserListJoinings.find({ where: { @@ -46,7 +49,6 @@ export default class extends Channel { this.listUsers = users.map(x => x.userId); } - @autobind private async onNote(note: Packed<'Note'>) { if (!this.listUsers.includes(note.userId)) return; @@ -81,7 +83,6 @@ export default class extends Channel { this.send('note', note); } - @autobind public dispose() { // Unsubscribe events this.subscriber.off(`userListStream:${this.listId}`, this.send); diff --git a/packages/backend/src/server/api/stream/index.ts b/packages/backend/src/server/api/stream/index.ts index 84689bca1..0cb38e2a9 100644 --- a/packages/backend/src/server/api/stream/index.ts +++ b/packages/backend/src/server/api/stream/index.ts @@ -1,21 +1,20 @@ -import autobind from 'autobind-decorator'; import * as websocket from 'websocket'; -import { readNotification } from '../common/read-notification'; -import call from '../call'; -import readNote from '@/services/note/read'; -import Channel from './channel'; -import channels from './channels/index'; +import { readNotification } from '../common/read-notification.js'; +import call from '../call.js'; +import readNote from '@/services/note/read.js'; +import Channel from './channel.js'; +import channels from './channels/index.js'; import { EventEmitter } from 'events'; -import { User } from '@/models/entities/user'; -import { Channel as ChannelModel } from '@/models/entities/channel'; -import { Users, Followings, Mutings, UserProfiles, ChannelFollowings, Blockings } from '@/models/index'; -import { ApiError } from '../error'; -import { AccessToken } from '@/models/entities/access-token'; -import { UserProfile } from '@/models/entities/user-profile'; -import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '@/services/stream'; -import { UserGroup } from '@/models/entities/user-group'; -import { StreamEventEmitter, StreamMessages } from './types'; -import { Packed } from '@/misc/schema'; +import { User } from '@/models/entities/user.js'; +import { Channel as ChannelModel } from '@/models/entities/channel.js'; +import { Users, Followings, Mutings, UserProfiles, ChannelFollowings, Blockings } from '@/models/index.js'; +import { ApiError } from '../error.js'; +import { AccessToken } from '@/models/entities/access-token.js'; +import { UserProfile } from '@/models/entities/user-profile.js'; +import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '@/services/stream.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { StreamEventEmitter, StreamMessages } from './types.js'; +import { Packed } from '@/misc/schema.js'; /** * Main stream connection @@ -38,13 +37,18 @@ export default class Connection { wsConnection: websocket.connection, subscriber: EventEmitter, user: User | null | undefined, - token: AccessToken | null | undefined + token: AccessToken | null | undefined, ) { this.wsConnection = wsConnection; this.subscriber = subscriber; if (user) this.user = user; if (token) this.token = token; + this.onWsConnectionMessage = this.onWsConnectionMessage.bind(this); + this.onUserEvent = this.onUserEvent.bind(this); + this.onNoteStreamMessage = this.onNoteStreamMessage.bind(this); + this.onBroadcastMessage = this.onBroadcastMessage.bind(this); + this.wsConnection.on('message', this.onWsConnectionMessage); this.subscriber.on('broadcast', data => { @@ -62,7 +66,6 @@ export default class Connection { } } - @autobind private onUserEvent(data: StreamMessages['user']['payload']) { // { type, body }ã¨åą•é–‹ã™ã‚‹ã¨ãã‚Œãžã‚Œåž‹ãŒåˆ†é›ĸしãĻしぞう switch (data.type) { case 'follow': @@ -108,8 +111,8 @@ export default class Connection { /** * クナイã‚ĸãƒŗãƒˆã‹ã‚‰ãƒĄãƒƒã‚ģãƒŧジ受äŋĄæ™‚ */ - @autobind - private async onWsConnectionMessage(data: websocket.IMessage) { + private async onWsConnectionMessage(data: websocket.Message) { + if (data.type !== 'utf8') return; if (data.utf8Data == null) return; let obj: Record; @@ -143,12 +146,10 @@ export default class Connection { } } - @autobind private onBroadcastMessage(data: StreamMessages['broadcast']['payload']) { this.sendMessageToWs(data.type, data.body); } - @autobind public cacheNote(note: Packed<'Note'>) { const add = (note: Packed<'Note'>) => { const existIndex = this.cachedNotes.findIndex(n => n.id === note.id); @@ -168,7 +169,6 @@ export default class Connection { if (note.renote) add(note.renote); } - @autobind private readNote(body: any) { const id = body.id; @@ -186,7 +186,6 @@ export default class Connection { /** * APIãƒĒクエ゚トčĻæą‚時 */ - @autobind private async onApiRequest(payload: any) { // 新鎎ãĒデãƒŧã‚ŋを刊į”¨ã™ã‚‹ãŸã‚ãĢãƒĻãƒŧã‚ļãƒŧをフェッチ const user = this.user ? await Users.findOne(this.user.id) : null; @@ -209,7 +208,6 @@ export default class Connection { }); } - @autobind private onReadNotification(payload: any) { if (!payload.id) return; readNotification(this.user!.id, [payload.id]); @@ -218,7 +216,6 @@ export default class Connection { /** * 投į¨ŋčŗŧčĒ­čĻæą‚時 */ - @autobind private onSubscribeNote(payload: any) { if (!payload.id) return; @@ -236,7 +233,6 @@ export default class Connection { /** * 投į¨ŋčŗŧčĒ­č§Ŗ除čĻæą‚時 */ - @autobind private onUnsubscribeNote(payload: any) { if (!payload.id) return; @@ -247,7 +243,6 @@ export default class Connection { } } - @autobind private async onNoteStreamMessage(data: StreamMessages['note']['payload']) { this.sendMessageToWs('noteUpdated', { id: data.body.id, @@ -259,7 +254,6 @@ export default class Connection { /** * チãƒŖãƒŗネãƒĢæŽĨįļščĻæą‚時 */ - @autobind private onChannelConnectRequested(payload: any) { const { channel, id, params, pong } = payload; this.connectChannel(id, params, channel, pong); @@ -268,7 +262,6 @@ export default class Connection { /** * チãƒŖãƒŗネãƒĢ切断čĻæą‚時 */ - @autobind private onChannelDisconnectRequested(payload: any) { const { id } = payload; this.disconnectChannel(id); @@ -277,7 +270,6 @@ export default class Connection { /** * クナイã‚ĸãƒŗトãĢãƒĄãƒƒã‚ģãƒŧジ送äŋĄ */ - @autobind public sendMessageToWs(type: string, payload: any) { this.wsConnection.send(JSON.stringify({ type: type, @@ -288,7 +280,6 @@ export default class Connection { /** * チãƒŖãƒŗネãƒĢãĢæŽĨįļš */ - @autobind public connectChannel(id: string, params: any, channel: string, pong = false) { if ((channels as any)[channel].requireCredential && this.user == null) { return; @@ -314,7 +305,6 @@ export default class Connection { * チãƒŖãƒŗネãƒĢから切断 * @param id チãƒŖãƒŗネãƒĢã‚ŗãƒã‚¯ã‚ˇãƒ§ãƒŗID */ - @autobind public disconnectChannel(id: string) { const channel = this.channels.find(c => c.id === id); @@ -328,7 +318,6 @@ export default class Connection { * チãƒŖãƒŗネãƒĢã¸ãƒĄãƒƒã‚ģãƒŧジ送äŋĄčĻæą‚時 * @param data ãƒĄãƒƒã‚ģãƒŧジ */ - @autobind private onChannelMessageRequested(data: any) { const channel = this.channels.find(c => c.id === data.id); if (channel != null && channel.onMessage != null) { @@ -336,14 +325,12 @@ export default class Connection { } } - @autobind private typingOnChannel(channel: ChannelModel['id']) { if (this.user) { publishChannelStream(channel, 'typing', this.user.id); } } - @autobind private typingOnMessaging(param: { partner?: User['id']; group?: UserGroup['id']; }) { if (this.user) { if (param.partner) { @@ -354,7 +341,6 @@ export default class Connection { } } - @autobind private async updateFollowing() { const followings = await Followings.find({ where: { @@ -366,7 +352,6 @@ export default class Connection { this.following = new Set(followings.map(x => x.followeeId)); } - @autobind private async updateMuting() { const mutings = await Mutings.find({ where: { @@ -378,7 +363,6 @@ export default class Connection { this.muting = new Set(mutings.map(x => x.muteeId)); } - @autobind private async updateBlocking() { // ここでいうBlockingはčĸĢBlockingぎ意 const blockings = await Blockings.find({ where: { @@ -390,7 +374,6 @@ export default class Connection { this.blocking = new Set(blockings.map(x => x.blockerId)); } - @autobind private async updateFollowingChannels() { const followings = await ChannelFollowings.find({ where: { @@ -402,7 +385,6 @@ export default class Connection { this.followingChannels = new Set(followings.map(x => x.followeeId)); } - @autobind private async updateUserProfile() { this.userProfile = await UserProfiles.findOne({ userId: this.user!.id, @@ -412,7 +394,6 @@ export default class Connection { /** * ゚トãƒĒãƒŧムが切れたとき */ - @autobind public dispose() { for (const c of this.channels.filter(c => c.dispose)) { if (c.dispose) c.dispose(); diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index e70c26f5e..90cf59038 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -1,20 +1,20 @@ import { EventEmitter } from 'events'; import Emitter from 'strict-event-emitter-types'; -import { Channel } from '@/models/entities/channel'; -import { User } from '@/models/entities/user'; -import { UserProfile } from '@/models/entities/user-profile'; -import { Note } from '@/models/entities/note'; -import { Antenna } from '@/models/entities/antenna'; -import { DriveFile } from '@/models/entities/drive-file'; -import { DriveFolder } from '@/models/entities/drive-folder'; -import { Emoji } from '@/models/entities/emoji'; -import { UserList } from '@/models/entities/user-list'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { UserGroup } from '@/models/entities/user-group'; -import { AbuseUserReport } from '@/models/entities/abuse-user-report'; -import { Signin } from '@/models/entities/signin'; -import { Page } from '@/models/entities/page'; -import { Packed } from '@/misc/schema'; +import { Channel } from '@/models/entities/channel.js'; +import { User } from '@/models/entities/user.js'; +import { UserProfile } from '@/models/entities/user-profile.js'; +import { Note } from '@/models/entities/note.js'; +import { Antenna } from '@/models/entities/antenna.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { DriveFolder } from '@/models/entities/drive-folder.js'; +import { Emoji } from '@/models/entities/emoji.js'; +import { UserList } from '@/models/entities/user-list.js'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; +import { Signin } from '@/models/entities/signin.js'; +import { Page } from '@/models/entities/page.js'; +import { Packed } from '@/misc/schema.js'; //#region Stream type-body definitions export interface InternalStreamTypes { @@ -84,6 +84,7 @@ export interface MainStreamTypes { }; driveFileCreated: Packed<'DriveFile'>; readAntenna: Antenna; + receiveFollowRequest: Packed<'User'>; } export interface DriveStreamTypes { @@ -105,7 +106,10 @@ export interface NoteStreamTypes { }; reacted: { reaction: string; - emoji?: Emoji; + emoji?: { + name: string; + url: string; + } | null; userId: User['id']; }; unreacted: { diff --git a/packages/backend/src/server/api/streaming.ts b/packages/backend/src/server/api/streaming.ts index ad8731106..2a34edac6 100644 --- a/packages/backend/src/server/api/streaming.ts +++ b/packages/backend/src/server/api/streaming.ts @@ -1,14 +1,14 @@ import * as http from 'http'; import * as websocket from 'websocket'; -import MainStreamConnection from './stream/index'; +import MainStreamConnection from './stream/index.js'; import { ParsedUrlQuery } from 'querystring'; -import authenticate from './authenticate'; +import authenticate from './authenticate.js'; import { EventEmitter } from 'events'; -import { subsdcriber as redisClient } from '../../db/redis'; -import { Users } from '@/models/index'; +import { subsdcriber as redisClient } from '../../db/redis.js'; +import { Users } from '@/models/index.js'; -module.exports = (server: http.Server) => { +export const initializeStreamingServer = (server: http.Server) => { // Init websocket server const ws = new websocket.server({ httpServer: server, @@ -59,7 +59,7 @@ module.exports = (server: http.Server) => { }); connection.on('message', async (data) => { - if (data.utf8Data === 'ping') { + if (data.type === 'utf8' && data.utf8Data === 'ping') { connection.send('pong'); } }); diff --git a/packages/backend/src/server/file/index.ts b/packages/backend/src/server/file/index.ts index a455acd1c..07a493700 100644 --- a/packages/backend/src/server/file/index.ts +++ b/packages/backend/src/server/file/index.ts @@ -2,23 +2,22 @@ * File Server */ -import * as fs from 'fs'; -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; -import * as Koa from 'koa'; -import * as cors from '@koa/cors'; -import * as Router from '@koa/router'; -import sendDriveFile from './send-drive-file'; +import * as fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; +import Koa from 'koa'; +import cors from '@koa/cors'; +import Router from '@koa/router'; +import sendDriveFile from './send-drive-file.js'; -//const _filename = fileURLToPath(import.meta.url); -const _filename = __filename; +const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); // Init app const app = new Koa(); app.use(cors()); app.use(async (ctx, next) => { - ctx.set('Content-Security-Policy', `default-src 'none'; style-src 'unsafe-inline'`); + ctx.set('Content-Security-Policy', `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`); await next(); }); @@ -38,4 +37,4 @@ router.get('/:key/(.*)', sendDriveFile); // Register router app.use(router.routes()); -module.exports = app; +export default app; diff --git a/packages/backend/src/server/file/send-drive-file.ts b/packages/backend/src/server/file/send-drive-file.ts index f3c6c518f..4e2bba0e2 100644 --- a/packages/backend/src/server/file/send-drive-file.ts +++ b/packages/backend/src/server/file/send-drive-file.ts @@ -1,23 +1,22 @@ -import * as fs from 'fs'; -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; -import * as Koa from 'koa'; +import * as fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; +import Koa from 'koa'; import * as send from 'koa-send'; -import * as rename from 'rename'; +import rename from 'rename'; import * as tmp from 'tmp'; -import { serverLogger } from '../index'; -import { contentDisposition } from '@/misc/content-disposition'; -import { DriveFiles } from '@/models/index'; -import { InternalStorage } from '@/services/drive/internal-storage'; -import { downloadUrl } from '@/misc/download-url'; -import { detectType } from '@/misc/get-file-info'; -import { convertToJpeg, convertToPng, convertToPngOrJpeg } from '@/services/drive/image-processor'; -import { GenerateVideoThumbnail } from '@/services/drive/generate-video-thumbnail'; -import { StatusError } from '@/misc/fetch'; -import { FILE_TYPE_BROWSERSAFE } from '@/const'; +import { serverLogger } from '../index.js'; +import { contentDisposition } from '@/misc/content-disposition.js'; +import { DriveFiles } from '@/models/index.js'; +import { InternalStorage } from '@/services/drive/internal-storage.js'; +import { downloadUrl } from '@/misc/download-url.js'; +import { detectType } from '@/misc/get-file-info.js'; +import { convertToJpeg, convertToPng, convertToPngOrJpeg } from '@/services/drive/image-processor.js'; +import { GenerateVideoThumbnail } from '@/services/drive/generate-video-thumbnail.js'; +import { StatusError } from '@/misc/fetch.js'; +import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; -//const _filename = fileURLToPath(import.meta.url); -const _filename = __filename; +const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); const assets = `${_dirname}/../../server/file/assets/`; diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 764306c7d..80130e884 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -2,31 +2,32 @@ * Core Server */ -import * as fs from 'fs'; +import * as fs from 'node:fs'; import * as http from 'http'; import * as http2 from 'http2'; import * as https from 'https'; -import * as Koa from 'koa'; -import * as Router from '@koa/router'; -import * as mount from 'koa-mount'; -import * as koaLogger from 'koa-logger'; -import * as requestStats from 'request-stats'; +import Koa from 'koa'; +import Router from '@koa/router'; +import mount from 'koa-mount'; +import koaLogger from 'koa-logger'; import * as slow from 'koa-slow'; -import activityPub from './activitypub'; -import nodeinfo from './nodeinfo'; -import wellKnown from './well-known'; -import config from '@/config/index'; -import apiServer from './api/index'; -import { sum } from '@/prelude/array'; -import Logger from '@/services/logger'; -import { envOption } from '../env'; -import { UserProfiles, Users } from '@/models/index'; -import { networkChart } from '@/services/chart/index'; -import { genIdenticon } from '@/misc/gen-identicon'; -import { createTemp } from '@/misc/create-temp'; -import { publishMainStream } from '@/services/stream'; -import * as Acct from 'misskey-js/built/acct'; +import activityPub from './activitypub.js'; +import nodeinfo from './nodeinfo.js'; +import wellKnown from './well-known.js'; +import config from '@/config/index.js'; +import apiServer from './api/index.js'; +import fileServer from './file/index.js'; +import proxyServer from './proxy/index.js'; +import webServer from './web/index.js'; +import Logger from '@/services/logger.js'; +import { envOption } from '../env.js'; +import { UserProfiles, Users } from '@/models/index.js'; +import { genIdenticon } from '@/misc/gen-identicon.js'; +import { createTemp } from '@/misc/create-temp.js'; +import { publishMainStream } from '@/services/stream.js'; +import * as Acct from '@/misc/acct.js'; +import { initializeStreamingServer } from './api/streaming.js'; export const serverLogger = new Logger('server', 'gray', false); @@ -58,8 +59,8 @@ if (config.url.startsWith('https') && !config.disableHsts) { } app.use(mount('/api', apiServer)); -app.use(mount('/files', require('./file'))); -app.use(mount('/proxy', require('./proxy'))); +app.use(mount('/files', fileServer)); +app.use(mount('/proxy', proxyServer)); // Init router const router = new Router(); @@ -75,6 +76,8 @@ router.get('/avatar/@:acct', async ctx => { usernameLower: username.toLowerCase(), host: host === config.host ? null : host, isSuspended: false, + }, { + relations: ['avatar'], }); if (user) { @@ -117,7 +120,7 @@ router.get('/verify-email/:code', async ctx => { // Register router app.use(router.routes()); -app.use(mount(require('./web'))); +app.use(mount(webServer)); function createServer() { if (config.https) { @@ -136,10 +139,8 @@ function createServer() { export const startServer = () => { const server = createServer(); - // Init stream server - require('./api/streaming')(server); + initializeStreamingServer(server); - // Listen server.listen(config.port); return server; @@ -148,32 +149,7 @@ export const startServer = () => { export default () => new Promise(resolve => { const server = createServer(); - // Init stream server - require('./api/streaming')(server); + initializeStreamingServer(server); - // Listen server.listen(config.port, resolve); - - //#region Network stats - let queue: any[] = []; - - requestStats(server, (stats: any) => { - if (stats.ok) { - queue.push(stats); - } - }); - - // Bulk write - setInterval(() => { - if (queue.length === 0) return; - - const requests = queue.length; - const time = sum(queue.map(x => x.time)); - const incomingBytes = sum(queue.map(x => x.req.byets)); - const outgoingBytes = sum(queue.map(x => x.res.byets)); - queue = []; - - networkChart.update(requests, time, incomingBytes, outgoingBytes); - }, 5000); - //#endregion }); diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts index 44f32bf88..f4b56fc8a 100644 --- a/packages/backend/src/server/nodeinfo.ts +++ b/packages/backend/src/server/nodeinfo.ts @@ -1,8 +1,9 @@ -import * as Router from '@koa/router'; -import config from '@/config/index'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Users, Notes } from '@/models/index'; -import { Not, IsNull, MoreThan } from 'typeorm'; +import Router from '@koa/router'; +import config from '@/config/index.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Users, Notes } from '@/models/index.js'; +import { MoreThan } from 'typeorm'; +import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; const router = new Router(); @@ -25,14 +26,12 @@ const nodeinfo2 = async () => { activeHalfyear, activeMonth, localPosts, - localComments, ] = await Promise.all([ fetchMeta(true), Users.count({ where: { host: null } }), - Users.count({ where: { host: null, updatedAt: MoreThan(new Date(now - 15552000000)) } }), - Users.count({ where: { host: null, updatedAt: MoreThan(new Date(now - 2592000000)) } }), - Notes.count({ where: { userHost: null, replyId: null } }), - Notes.count({ where: { userHost: null, replyId: Not(IsNull()) } }), + Users.count({ where: { host: null, lastActiveDate: MoreThan(new Date(now - 15552000000)) } }), + Users.count({ where: { host: null, lastActiveDate: MoreThan(new Date(now - 2592000000)) } }), + Notes.count({ where: { userHost: null } }), ]); const proxyAccount = meta.proxyAccountId ? await Users.pack(meta.proxyAccountId).catch(() => null) : null; @@ -52,7 +51,7 @@ const nodeinfo2 = async () => { usage: { users: { total, activeHalfyear, activeMonth }, localPosts, - localComments, + localComments: 0, }, metadata: { nodeName: meta.name, @@ -71,7 +70,7 @@ const nodeinfo2 = async () => { emailRequiredForSignup: meta.emailRequiredForSignup, enableHcaptcha: meta.enableHcaptcha, enableRecaptcha: meta.enableRecaptcha, - maxNoteTextLength: meta.maxNoteTextLength, + maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, enableTwitterIntegration: meta.enableTwitterIntegration, enableGithubIntegration: meta.enableGithubIntegration, enableDiscordIntegration: meta.enableDiscordIntegration, diff --git a/packages/backend/src/server/proxy/index.ts b/packages/backend/src/server/proxy/index.ts index b8993f19f..506ba10ef 100644 --- a/packages/backend/src/server/proxy/index.ts +++ b/packages/backend/src/server/proxy/index.ts @@ -2,16 +2,16 @@ * Media Proxy */ -import * as Koa from 'koa'; -import * as cors from '@koa/cors'; -import * as Router from '@koa/router'; -import { proxyMedia } from './proxy-media'; +import Koa from 'koa'; +import cors from '@koa/cors'; +import Router from '@koa/router'; +import { proxyMedia } from './proxy-media.js'; // Init app const app = new Koa(); app.use(cors()); app.use(async (ctx, next) => { - ctx.set('Content-Security-Policy', `default-src 'none'; style-src 'unsafe-inline'`); + ctx.set('Content-Security-Policy', `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`); await next(); }); @@ -23,4 +23,4 @@ router.get('/:url*', proxyMedia); // Register router app.use(router.routes()); -module.exports = app; +export default app; diff --git a/packages/backend/src/server/proxy/proxy-media.ts b/packages/backend/src/server/proxy/proxy-media.ts index c234b70c5..3cc5b827a 100644 --- a/packages/backend/src/server/proxy/proxy-media.ts +++ b/packages/backend/src/server/proxy/proxy-media.ts @@ -1,16 +1,21 @@ -import * as fs from 'fs'; -import * as Koa from 'koa'; -import { serverLogger } from '../index'; -import { IImage, convertToPng, convertToJpeg } from '@/services/drive/image-processor'; -import { createTemp } from '@/misc/create-temp'; -import { downloadUrl } from '@/misc/download-url'; -import { detectType } from '@/misc/get-file-info'; -import { StatusError } from '@/misc/fetch'; -import { FILE_TYPE_BROWSERSAFE } from '@/const'; +import * as fs from 'node:fs'; +import Koa from 'koa'; +import { serverLogger } from '../index.js'; +import { IImage, convertToPng, convertToJpeg } from '@/services/drive/image-processor.js'; +import { createTemp } from '@/misc/create-temp.js'; +import { downloadUrl } from '@/misc/download-url.js'; +import { detectType } from '@/misc/get-file-info.js'; +import { StatusError } from '@/misc/fetch.js'; +import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; export async function proxyMedia(ctx: Koa.Context) { const url = 'url' in ctx.query ? ctx.query.url : 'https://' + ctx.params.url; + if (typeof url !== 'string') { + ctx.status = 400; + return; + } + // Create temp file const [path, cleanup] = await createTemp(); diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index db589e086..b98e3f8bf 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -1,7 +1,7 @@ import { Feed } from 'feed'; -import config from '@/config/index'; -import { User } from '@/models/entities/user'; -import { Notes, DriveFiles, UserProfiles } from '@/models/index'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; +import { Notes, DriveFiles, UserProfiles } from '@/models/index.js'; import { In } from 'typeorm'; export default async function(user: User) { diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index e95a115ae..cc4c2cc9c 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -2,24 +2,26 @@ * Web Client Server */ -import { dirname } from 'path'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import ms from 'ms'; -import * as Koa from 'koa'; -import * as Router from '@koa/router'; -import * as send from 'koa-send'; -import * as favicon from 'koa-favicon'; -import * as views from 'koa-views'; +import Koa from 'koa'; +import Router from '@koa/router'; +import send from 'koa-send'; +import favicon from 'koa-favicon'; +import views from 'koa-views'; -import packFeed from './feed'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { genOpenapiSpec } from '../api/openapi/gen-spec'; -import config from '@/config/index'; -import { Users, Notes, UserProfiles, Pages, Channels, Clips, GalleryPosts } from '@/models/index'; -import * as Acct from 'misskey-js/built/acct'; -import { getNoteSummary } from '@/misc/get-note-summary'; +import packFeed from './feed.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { genOpenapiSpec } from '../api/openapi/gen-spec.js'; +import config from '@/config/index.js'; +import { Users, Notes, UserProfiles, Pages, Channels, Clips, GalleryPosts } from '@/models/index.js'; +import * as Acct from '@/misc/acct.js'; +import { getNoteSummary } from '@/misc/get-note-summary.js'; +import { urlPreviewHandler } from './url-preview.js'; +import { manifestHandler } from './manifest.js'; -//const _filename = fileURLToPath(import.meta.url); -const _filename = __filename; +const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); const staticAssets = `${_dirname}/../../../assets/`; @@ -105,7 +107,7 @@ router.get('/sw.js', async ctx => { }); // Manifest -router.get('/manifest.json', require('./manifest')); +router.get('/manifest.json', manifestHandler); router.get('/robots.txt', async ctx => { await send(ctx as any, '/robots.txt', { @@ -123,7 +125,7 @@ router.get('/api-doc', async ctx => { }); // URL preview endpoint -router.get('/url', require('./url-preview')); +router.get('/url', urlPreviewHandler); router.get('/api.json', async ctx => { ctx.body = genOpenapiSpec(); @@ -200,6 +202,7 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => { sub: ctx.params.sub, instanceName: meta.name || 'Misskey', icon: meta.iconUrl, + themeColor: meta.themeColor, }); ctx.set('Cache-Control', 'public, max-age=30'); } else { @@ -239,6 +242,7 @@ router.get('/notes/:note', async (ctx, next) => { summary: getNoteSummary(_note), instanceName: meta.name || 'Misskey', icon: meta.iconUrl, + themeColor: meta.themeColor, }); if (['public', 'home'].includes(note.visibility)) { @@ -276,6 +280,8 @@ router.get('/@:user/pages/:page', async (ctx, next) => { page: _page, profile, instanceName: meta.name || 'Misskey', + icon: meta.iconUrl, + themeColor: meta.themeColor, }); if (['public'].includes(page.visibility)) { @@ -305,6 +311,8 @@ router.get('/clips/:clip', async (ctx, next) => { clip: _clip, profile, instanceName: meta.name || 'Misskey', + icon: meta.iconUrl, + themeColor: meta.themeColor, }); ctx.set('Cache-Control', 'public, max-age=180'); @@ -328,6 +336,7 @@ router.get('/gallery/:post', async (ctx, next) => { profile, instanceName: meta.name || 'Misskey', icon: meta.iconUrl, + themeColor: meta.themeColor, }); ctx.set('Cache-Control', 'public, max-age=180'); @@ -350,6 +359,8 @@ router.get('/channels/:channel', async (ctx, next) => { await ctx.render('channel', { channel: _channel, instanceName: meta.name || 'Misskey', + icon: meta.iconUrl, + themeColor: meta.themeColor, }); ctx.set('Cache-Control', 'public, max-age=180'); @@ -409,6 +420,7 @@ router.get('(.*)', async ctx => { instanceName: meta.name || 'Misskey', desc: meta.description, icon: meta.iconUrl, + themeColor: meta.themeColor, }); ctx.set('Cache-Control', 'public, max-age=300'); }); @@ -416,4 +428,4 @@ router.get('(.*)', async ctx => { // Register router app.use(router.routes()); -module.exports = app; +export default app; diff --git a/packages/backend/src/server/web/manifest.ts b/packages/backend/src/server/web/manifest.ts index 918fe27c0..bcbf9b76a 100644 --- a/packages/backend/src/server/web/manifest.ts +++ b/packages/backend/src/server/web/manifest.ts @@ -1,14 +1,15 @@ -import * as Koa from 'koa'; -import * as manifest from './manifest.json'; -import { fetchMeta } from '@/misc/fetch-meta'; +import Koa from 'koa'; +import manifest from './manifest.json' assert { type: 'json' }; +import { fetchMeta } from '@/misc/fetch-meta.js'; -module.exports = async (ctx: Koa.Context) => { +export const manifestHandler = async (ctx: Koa.Context) => { const json = JSON.parse(JSON.stringify(manifest)); const instance = await fetchMeta(true); json.short_name = instance.name || 'Misskey'; json.name = instance.name || 'Misskey'; + if (instance.themeColor) json.theme_color = instance.themeColor; ctx.set('Cache-Control', 'max-age=300'); ctx.body = json; diff --git a/packages/backend/src/server/web/url-preview.ts b/packages/backend/src/server/web/url-preview.ts index 71465c808..6bd8ead5b 100644 --- a/packages/backend/src/server/web/url-preview.ts +++ b/packages/backend/src/server/web/url-preview.ts @@ -1,30 +1,42 @@ -import * as Koa from 'koa'; +import Koa from 'koa'; import summaly from 'summaly'; -import { fetchMeta } from '@/misc/fetch-meta'; -import Logger from '@/services/logger'; -import config from '@/config/index'; -import { query } from '@/prelude/url'; -import { getJson } from '@/misc/fetch'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import Logger from '@/services/logger.js'; +import config from '@/config/index.js'; +import { query } from '@/prelude/url.js'; +import { getJson } from '@/misc/fetch.js'; const logger = new Logger('url-preview'); -module.exports = async (ctx: Koa.Context) => { +export const urlPreviewHandler = async (ctx: Koa.Context) => { + const url = ctx.query.url; + if (typeof url !== 'string') { + ctx.status = 400; + return; + } + + const lang = ctx.query.lang; + if (Array.isArray(lang)) { + ctx.status = 400; + return; + } + const meta = await fetchMeta(); logger.info(meta.summalyProxy - ? `(Proxy) Getting preview of ${ctx.query.url}@${ctx.query.lang} ...` - : `Getting preview of ${ctx.query.url}@${ctx.query.lang} ...`); + ? `(Proxy) Getting preview of ${url}@${lang} ...` + : `Getting preview of ${url}@${lang} ...`); try { const summary = meta.summalyProxy ? await getJson(`${meta.summalyProxy}?${query({ - url: ctx.query.url, - lang: ctx.query.lang || 'ja-JP', - })}`) : await summaly(ctx.query.url, { + url: url, + lang: lang ?? 'ja-JP', + })}`) : await summaly.default(url, { followRedirects: false, - lang: ctx.query.lang || 'ja-JP', + lang: lang ?? 'ja-JP', }); - logger.succ(`Got preview of ${ctx.query.url}: ${summary.title}`); + logger.succ(`Got preview of ${url}: ${summary.title}`); summary.icon = wrap(summary.icon); summary.thumbnail = wrap(summary.thumbnail); @@ -33,8 +45,8 @@ module.exports = async (ctx: Koa.Context) => { ctx.set('Cache-Control', 'max-age=604800, immutable'); ctx.body = summary; - } catch (e) { - logger.warn(`Failed to get preview of ${ctx.query.url}: ${e}`); + } catch (err) { + logger.warn(`Failed to get preview of ${url}: ${err}`); ctx.status = 200; ctx.set('Cache-Control', 'max-age=86400, immutable'); ctx.body = '{}'; diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index 42c068c40..e1cb2cfa9 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -19,8 +19,9 @@ html meta(charset='utf-8') meta(name='application-name' content='Misskey') meta(name='referrer' content='origin') - meta(name='theme-color' content='#86b300') - meta(name='theme-color-orig' content='#86b300') + meta(name='theme-color' content= themeColor || '#86b300') + meta(name='theme-color-orig' content= themeColor || '#86b300') + meta(property='twitter:card' content='summary') meta(property='og:site_name' content= instanceName || 'Misskey') meta(name='viewport' content='width=device-width, initial-scale=1') link(rel='icon' href= icon || '/favicon.ico') @@ -29,8 +30,8 @@ html link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg') - link(rel='preload' href='https://use.fontawesome.com/releases/v5.15.3/css/all.css' as='style') - link(rel='stylesheet' href='https://use.fontawesome.com/releases/v5.15.3/css/all.css') + link(rel='preload' href='/assets/fontawesome/css/all.css' as='style') + link(rel='stylesheet' href='/assets/fontawesome/css/all.css') title block title @@ -42,7 +43,9 @@ html block meta block og - meta(property='og:image' content=img) + meta(property='og:title' content= title || 'Misskey') + meta(property='og:description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨') + meta(property='og:image' content= img) style include ../style.css diff --git a/packages/backend/src/server/web/views/channel.pug b/packages/backend/src/server/web/views/channel.pug index 273632f0e..486f0ecc4 100644 --- a/packages/backend/src/server/web/views/channel.pug +++ b/packages/backend/src/server/web/views/channel.pug @@ -16,6 +16,3 @@ block og meta(property='og:description' content= channel.description) meta(property='og:url' content= url) meta(property='og:image' content= channel.bannerUrl) - -block meta - meta(name='twitter:card' content='summary') diff --git a/packages/backend/src/server/web/views/clip.pug b/packages/backend/src/server/web/views/clip.pug index 8de53f19d..7a84d50f6 100644 --- a/packages/backend/src/server/web/views/clip.pug +++ b/packages/backend/src/server/web/views/clip.pug @@ -26,8 +26,6 @@ block meta meta(name='misskey:user-id' content=user.id) meta(name='misskey:clip-id' content=clip.id) - meta(name='twitter:card' content='summary') - // todo if user.twitter meta(name='twitter:creator' content=`@${user.twitter.screenName}`) diff --git a/packages/backend/src/server/web/views/gallery-post.pug b/packages/backend/src/server/web/views/gallery-post.pug index 95bbb2437..ca0663a48 100644 --- a/packages/backend/src/server/web/views/gallery-post.pug +++ b/packages/backend/src/server/web/views/gallery-post.pug @@ -25,8 +25,6 @@ block meta meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) - meta(name='twitter:card' content='summary') - // todo if user.twitter meta(name='twitter:creator' content=`@${user.twitter.screenName}`) diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug index fce91bdab..34b03f983 100644 --- a/packages/backend/src/server/web/views/note.pug +++ b/packages/backend/src/server/web/views/note.pug @@ -26,9 +26,7 @@ block meta meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) meta(name='misskey:note-id' content=note.id) - - meta(name='twitter:card' content='summary') - + // todo if user.twitter meta(name='twitter:creator' content=`@${user.twitter.screenName}`) diff --git a/packages/backend/src/server/web/views/page.pug b/packages/backend/src/server/web/views/page.pug index cb9e1039e..b6c954802 100644 --- a/packages/backend/src/server/web/views/page.pug +++ b/packages/backend/src/server/web/views/page.pug @@ -26,8 +26,6 @@ block meta meta(name='misskey:user-id' content=user.id) meta(name='misskey:page-id' content=page.id) - meta(name='twitter:card' content='summary') - // todo if user.twitter meta(name='twitter:creator' content=`@${user.twitter.screenName}`) diff --git a/packages/backend/src/server/web/views/user.pug b/packages/backend/src/server/web/views/user.pug index 1a8a6b441..2adec0f88 100644 --- a/packages/backend/src/server/web/views/user.pug +++ b/packages/backend/src/server/web/views/user.pug @@ -25,8 +25,6 @@ block meta meta(name='misskey:user-username' content=user.username) meta(name='misskey:user-id' content=user.id) - meta(name='twitter:card' content='summary') - if profile.twitter meta(name='twitter:creator' content=`@${profile.twitter.screenName}`) diff --git a/packages/backend/src/server/well-known.ts b/packages/backend/src/server/well-known.ts index d1f13b70b..7a5d08541 100644 --- a/packages/backend/src/server/well-known.ts +++ b/packages/backend/src/server/well-known.ts @@ -1,11 +1,11 @@ -import * as Router from '@koa/router'; +import Router from '@koa/router'; -import config from '@/config/index'; -import * as Acct from 'misskey-js/built/acct'; -import { links } from './nodeinfo'; -import { escapeAttribute, escapeValue } from '@/prelude/xml'; -import { Users } from '@/models/index'; -import { User } from '@/models/entities/user'; +import config from '@/config/index.js'; +import * as Acct from '@/misc/acct.js'; +import { links } from './nodeinfo.js'; +import { escapeAttribute, escapeValue } from '@/prelude/xml.js'; +import { Users } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; // Init router const router = new Router(); diff --git a/packages/backend/src/services/add-note-to-antenna.ts b/packages/backend/src/services/add-note-to-antenna.ts index 168e3a614..e88c38723 100644 --- a/packages/backend/src/services/add-note-to-antenna.ts +++ b/packages/backend/src/services/add-note-to-antenna.ts @@ -1,10 +1,10 @@ -import { Antenna } from '@/models/entities/antenna'; -import { Note } from '@/models/entities/note'; -import { AntennaNotes, Mutings, Notes } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { isMutedUserRelated } from '@/misc/is-muted-user-related'; -import { publishAntennaStream, publishMainStream } from '@/services/stream'; -import { User } from '@/models/entities/user'; +import { Antenna } from '@/models/entities/antenna.js'; +import { Note } from '@/models/entities/note.js'; +import { AntennaNotes, Mutings, Notes } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { isMutedUserRelated } from '@/misc/is-muted-user-related.js'; +import { publishAntennaStream, publishMainStream } from '@/services/stream.js'; +import { User } from '@/models/entities/user.js'; export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: { id: User['id']; }) { // 通įŸĨしãĒã„č¨­åŽšãĢãĒãŖãĻいるか、č‡Ē分č‡ĒčēĢぎ投į¨ŋãĒらæ—ĸčĒ­ãĢする diff --git a/packages/backend/src/services/blocking/create.ts b/packages/backend/src/services/blocking/create.ts index 907e4c311..198d28705 100644 --- a/packages/backend/src/services/blocking/create.ts +++ b/packages/backend/src/services/blocking/create.ts @@ -1,15 +1,15 @@ -import { publishMainStream, publishUserEvent } from '@/services/stream'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderFollow from '@/remote/activitypub/renderer/follow'; -import renderUndo from '@/remote/activitypub/renderer/undo'; -import renderBlock from '@/remote/activitypub/renderer/block'; -import { deliver } from '@/queue/index'; -import renderReject from '@/remote/activitypub/renderer/reject'; -import { User } from '@/models/entities/user'; -import { Blockings, Users, FollowRequests, Followings, UserListJoinings, UserLists } from '@/models/index'; -import { perUserFollowingChart } from '@/services/chart/index'; -import { genId } from '@/misc/gen-id'; -import { IdentifiableError } from '@/misc/identifiable-error'; +import { publishMainStream, publishUserEvent } from '@/services/stream.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import renderUndo from '@/remote/activitypub/renderer/undo.js'; +import renderBlock from '@/remote/activitypub/renderer/block.js'; +import { deliver } from '@/queue/index.js'; +import renderReject from '@/remote/activitypub/renderer/reject.js'; +import { User } from '@/models/entities/user.js'; +import { Blockings, Users, FollowRequests, Followings, UserListJoinings, UserLists } from '@/models/index.js'; +import { perUserFollowingChart } from '@/services/chart/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; export default async function(blocker: User, blockee: User) { await Promise.all([ diff --git a/packages/backend/src/services/blocking/delete.ts b/packages/backend/src/services/blocking/delete.ts index 271bf4854..c4f3784b0 100644 --- a/packages/backend/src/services/blocking/delete.ts +++ b/packages/backend/src/services/blocking/delete.ts @@ -1,10 +1,10 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderBlock from '@/remote/activitypub/renderer/block'; -import renderUndo from '@/remote/activitypub/renderer/undo'; -import { deliver } from '@/queue/index'; -import Logger from '../logger'; -import { User } from '@/models/entities/user'; -import { Blockings, Users } from '@/models/index'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderBlock from '@/remote/activitypub/renderer/block.js'; +import renderUndo from '@/remote/activitypub/renderer/undo.js'; +import { deliver } from '@/queue/index.js'; +import Logger from '../logger.js'; +import { User } from '@/models/entities/user.js'; +import { Blockings, Users } from '@/models/index.js'; const logger = new Logger('blocking/delete'); diff --git a/packages/backend/src/services/chart/charts/active-users.ts b/packages/backend/src/services/chart/charts/active-users.ts index 9490101e3..d952ea53b 100644 --- a/packages/backend/src/services/chart/charts/active-users.ts +++ b/packages/backend/src/services/chart/charts/active-users.ts @@ -1,51 +1,44 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { User } from '@/models/entities/user'; -import { SchemaType } from '@/misc/schema'; -import { Users } from '@/models/index'; -import { name, schema } from './entities/active-users'; +import Chart, { KVs } from '../core.js'; +import { User } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; +import { name, schema } from './entities/active-users.js'; -type ActiveUsersLog = SchemaType; +const week = 1000 * 60 * 60 * 24 * 7; +const month = 1000 * 60 * 60 * 24 * 30; +const year = 1000 * 60 * 60 * 24 * 365; /** * ã‚ĸクテã‚ŖブãƒĻãƒŧã‚ļãƒŧãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class ActiveUsersChart extends Chart { +export default class ActiveUsersChart extends Chart { constructor() { super(name, schema); } - @autobind - protected genNewLog(latest: ActiveUsersLog): DeepPartial { + protected async tickMajor(): Promise>> { return {}; } - @autobind - protected aggregate(logs: ActiveUsersLog[]): ActiveUsersLog { - return { - local: { - users: logs.reduce((a, b) => a.concat(b.local.users), [] as ActiveUsersLog['local']['users']), - }, - remote: { - users: logs.reduce((a, b) => a.concat(b.remote.users), [] as ActiveUsersLog['remote']['users']), - }, - }; - } - - @autobind - protected async fetchActual(): Promise> { + protected async tickMinor(): Promise>> { return {}; } - @autobind - public async update(user: { id: User['id'], host: User['host'] }): Promise { - const update: Obj = { - users: [user.id], - }; + public async read(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise { + await this.commit({ + 'read': [user.id], + 'registeredWithinWeek': (Date.now() - user.createdAt.getTime() < week) ? [user.id] : [], + 'registeredWithinMonth': (Date.now() - user.createdAt.getTime() < month) ? [user.id] : [], + 'registeredWithinYear': (Date.now() - user.createdAt.getTime() < year) ? [user.id] : [], + 'registeredOutsideWeek': (Date.now() - user.createdAt.getTime() > week) ? [user.id] : [], + 'registeredOutsideMonth': (Date.now() - user.createdAt.getTime() > month) ? [user.id] : [], + 'registeredOutsideYear': (Date.now() - user.createdAt.getTime() > year) ? [user.id] : [], + }); + } - await this.inc({ - [Users.isLocalUser(user) ? 'local' : 'remote']: update, + public async write(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise { + await this.commit({ + 'write': [user.id], }); } } diff --git a/packages/backend/src/services/chart/charts/ap-request.ts b/packages/backend/src/services/chart/charts/ap-request.ts new file mode 100644 index 000000000..e9e42ade7 --- /dev/null +++ b/packages/backend/src/services/chart/charts/ap-request.ts @@ -0,0 +1,38 @@ +import Chart, { KVs } from '../core.js'; +import { name, schema } from './entities/ap-request.js'; + +/** + * Chart about ActivityPub requests + */ +// eslint-disable-next-line import/no-default-export +export default class ApRequestChart extends Chart { + constructor() { + super(name, schema); + } + + protected async tickMajor(): Promise>> { + return {}; + } + + protected async tickMinor(): Promise>> { + return {}; + } + + public async deliverSucc(): Promise { + await this.commit({ + 'deliverSucceeded': 1, + }); + } + + public async deliverFail(): Promise { + await this.commit({ + 'deliverFailed': 1, + }); + } + + public async inbox(): Promise { + await this.commit({ + 'inboxReceived': 1, + }); + } +} diff --git a/packages/backend/src/services/chart/charts/drive.ts b/packages/backend/src/services/chart/charts/drive.ts index 06cf7ebee..0eeba90dd 100644 --- a/packages/backend/src/services/chart/charts/drive.ts +++ b/packages/backend/src/services/chart/charts/drive.ts @@ -1,95 +1,38 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { DriveFiles } from '@/models/index'; +import Chart, { KVs } from '../core.js'; +import { DriveFiles } from '@/models/index.js'; import { Not, IsNull } from 'typeorm'; -import { DriveFile } from '@/models/entities/drive-file'; -import { name, schema } from './entities/drive'; - -type DriveLog = SchemaType; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { name, schema } from './entities/drive.js'; /** * ドナイブãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class DriveChart extends Chart { +export default class DriveChart extends Chart { constructor() { super(name, schema); } - @autobind - protected genNewLog(latest: DriveLog): DeepPartial { - return { - local: { - totalCount: latest.local.totalCount, - totalSize: latest.local.totalSize, - }, - remote: { - totalCount: latest.remote.totalCount, - totalSize: latest.remote.totalSize, - }, - }; + protected async tickMajor(): Promise>> { + return {}; } - @autobind - protected aggregate(logs: DriveLog[]): DriveLog { - return { - local: { - totalCount: logs[0].local.totalCount, - totalSize: logs[0].local.totalSize, - incCount: logs.reduce((a, b) => a + b.local.incCount, 0), - incSize: logs.reduce((a, b) => a + b.local.incSize, 0), - decCount: logs.reduce((a, b) => a + b.local.decCount, 0), - decSize: logs.reduce((a, b) => a + b.local.decSize, 0), - }, - remote: { - totalCount: logs[0].remote.totalCount, - totalSize: logs[0].remote.totalSize, - incCount: logs.reduce((a, b) => a + b.remote.incCount, 0), - incSize: logs.reduce((a, b) => a + b.remote.incSize, 0), - decCount: logs.reduce((a, b) => a + b.remote.decCount, 0), - decSize: logs.reduce((a, b) => a + b.remote.decSize, 0), - }, - }; + protected async tickMinor(): Promise>> { + return {}; } - @autobind - protected async fetchActual(): Promise> { - const [localCount, remoteCount, localSize, remoteSize] = await Promise.all([ - DriveFiles.count({ userHost: null }), - DriveFiles.count({ userHost: Not(IsNull()) }), - DriveFiles.calcDriveUsageOfLocal(), - DriveFiles.calcDriveUsageOfRemote(), - ]); - - return { - local: { - totalCount: localCount, - totalSize: localSize, - }, - remote: { - totalCount: remoteCount, - totalSize: remoteSize, - }, - }; - } - - @autobind public async update(file: DriveFile, isAdditional: boolean): Promise { - const update: Obj = {}; - - update.totalCount = isAdditional ? 1 : -1; - update.totalSize = isAdditional ? file.size : -file.size; - if (isAdditional) { - update.incCount = 1; - update.incSize = file.size; - } else { - update.decCount = 1; - update.decSize = file.size; - } - - await this.inc({ - [file.userHost === null ? 'local' : 'remote']: update, + const fileSizeKb = file.size / 1000; + await this.commit(file.userHost === null ? { + 'local.incCount': isAdditional ? 1 : 0, + 'local.incSize': isAdditional ? fileSizeKb : 0, + 'local.decCount': isAdditional ? 0 : 1, + 'local.decSize': isAdditional ? 0 : fileSizeKb, + } : { + 'remote.incCount': isAdditional ? 1 : 0, + 'remote.incSize': isAdditional ? fileSizeKb : 0, + 'remote.decCount': isAdditional ? 0 : 1, + 'remote.decSize': isAdditional ? 0 : fileSizeKb, }); } } diff --git a/packages/backend/src/services/chart/charts/entities/active-users.ts b/packages/backend/src/services/chart/charts/entities/active-users.ts index d6b49c86c..5767b76f8 100644 --- a/packages/backend/src/services/chart/charts/entities/active-users.ts +++ b/packages/backend/src/services/chart/charts/entities/active-users.ts @@ -1,36 +1,17 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'activeUsers'; -const logSchema = { - /** - * ã‚ĸクテã‚ŖブãƒĻãƒŧã‚ļãƒŧ - */ - users: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - }, -}; - export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - local: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - remote: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - }, -}; + 'readWrite': { intersection: ['read', 'write'], range: 'small' }, + 'read': { uniqueIncrement: true, range: 'small' }, + 'write': { uniqueIncrement: true, range: 'small' }, + 'registeredWithinWeek': { uniqueIncrement: true, range: 'small' }, + 'registeredWithinMonth': { uniqueIncrement: true, range: 'small' }, + 'registeredWithinYear': { uniqueIncrement: true, range: 'small' }, + 'registeredOutsideWeek': { uniqueIncrement: true, range: 'small' }, + 'registeredOutsideMonth': { uniqueIncrement: true, range: 'small' }, + 'registeredOutsideYear': { uniqueIncrement: true, range: 'small' }, +} as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/ap-request.ts b/packages/backend/src/services/chart/charts/entities/ap-request.ts new file mode 100644 index 000000000..3a9f3dacf --- /dev/null +++ b/packages/backend/src/services/chart/charts/entities/ap-request.ts @@ -0,0 +1,11 @@ +import Chart from '../../core.js'; + +export const name = 'apRequest'; + +export const schema = { + 'deliverFailed': { }, + 'deliverSucceeded': { }, + 'inboxReceived': { }, +} as const; + +export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/drive.ts b/packages/backend/src/services/chart/charts/entities/drive.ts index 3362cbd4c..4bf5bb729 100644 --- a/packages/backend/src/services/chart/charts/entities/drive.ts +++ b/packages/backend/src/services/chart/charts/entities/drive.ts @@ -1,72 +1,16 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'drive'; -const logSchema = { - /** - * é›†č¨ˆæœŸé–“æ™‚į‚šã§ãŽã€å…¨ãƒ‰ãƒŠã‚¤ãƒ–ãƒ•ã‚Ąã‚¤ãƒĢ数 - */ - totalCount: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * é›†č¨ˆæœŸé–“æ™‚į‚šã§ãŽã€å…¨ãƒ‰ãƒŠã‚¤ãƒ–ãƒ•ã‚Ąã‚¤ãƒĢãŽåˆč¨ˆã‚ĩイã‚ē - */ - totalSize: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * åĸ—åŠ ã—ãŸãƒ‰ãƒŠã‚¤ãƒ–ãƒ•ã‚Ąã‚¤ãƒĢ数 - */ - incCount: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * åĸ—加したドナイブäŊŋį”¨é‡ - */ - incSize: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * æ¸›å°‘ã—ãŸãƒ‰ãƒŠã‚¤ãƒ–ãƒ•ã‚Ąã‚¤ãƒĢ数 - */ - decCount: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * 減少したドナイブäŊŋį”¨é‡ - */ - decSize: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, -}; - export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - local: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - remote: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - }, -}; + 'local.incCount': {}, + 'local.incSize': {}, // in kilobyte + 'local.decCount': {}, + 'local.decSize': {}, // in kilobyte + 'remote.incCount': {}, + 'remote.incSize': {}, // in kilobyte + 'remote.decCount': {}, + 'remote.decSize': {}, // in kilobyte +} as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/federation.ts b/packages/backend/src/services/chart/charts/entities/federation.ts index 836116bd0..9d2b860b1 100644 --- a/packages/backend/src/services/chart/charts/entities/federation.ts +++ b/packages/backend/src/services/chart/charts/entities/federation.ts @@ -1,30 +1,14 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'federation'; export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - instance: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, -}; + 'deliveredInstances': { uniqueIncrement: true, range: 'small' }, + 'inboxInstances': { uniqueIncrement: true, range: 'small' }, + 'stalled': { uniqueIncrement: true, range: 'small' }, + 'sub': { accumulate: true, range: 'small' }, + 'pub': { accumulate: true, range: 'small' }, + 'pubsub': { accumulate: true, range: 'small' }, +} as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/hashtag.ts b/packages/backend/src/services/chart/charts/entities/hashtag.ts index 43e15456a..4d0403904 100644 --- a/packages/backend/src/services/chart/charts/entities/hashtag.ts +++ b/packages/backend/src/services/chart/charts/entities/hashtag.ts @@ -1,36 +1,10 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'hashtag'; -const logSchema = { - /** - * 投į¨ŋしたãƒĻãƒŧã‚ļãƒŧ - */ - users: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - }, -}; - export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - local: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - remote: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - }, -}; + 'local.users': { uniqueIncrement: true }, + 'remote.users': { uniqueIncrement: true }, +} as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/instance.ts b/packages/backend/src/services/chart/charts/entities/instance.ts index 9d1f651db..06962120e 100644 --- a/packages/backend/src/services/chart/charts/entities/instance.ts +++ b/packages/backend/src/services/chart/charts/entities/instance.ts @@ -1,158 +1,32 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'instance'; export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - requests: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - failed: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - succeeded: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - received: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - - notes: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - diffs: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - normal: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - reply: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - renote: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, - }, - - users: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - - following: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - - followers: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - - drive: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - totalFiles: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - totalUsage: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - incFiles: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - incUsage: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - decFiles: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - decUsage: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, -}; + 'requests.failed': { range: 'small' }, + 'requests.succeeded': { range: 'small' }, + 'requests.received': { range: 'small' }, + 'notes.total': { accumulate: true }, + 'notes.inc': {}, + 'notes.dec': {}, + 'notes.diffs.normal': {}, + 'notes.diffs.reply': {}, + 'notes.diffs.renote': {}, + 'notes.diffs.withFile': {}, + 'users.total': { accumulate: true }, + 'users.inc': { range: 'small' }, + 'users.dec': { range: 'small' }, + 'following.total': { accumulate: true }, + 'following.inc': { range: 'small' }, + 'following.dec': { range: 'small' }, + 'followers.total': { accumulate: true }, + 'followers.inc': { range: 'small' }, + 'followers.dec': { range: 'small' }, + 'drive.totalFiles': { accumulate: true }, + 'drive.incFiles': {}, + 'drive.decFiles': {}, + 'drive.incUsage': {}, // in kilobyte + 'drive.decUsage': {}, // in kilobyte +} as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/network.ts b/packages/backend/src/services/chart/charts/entities/network.ts deleted file mode 100644 index 3d4fffb85..000000000 --- a/packages/backend/src/services/chart/charts/entities/network.ts +++ /dev/null @@ -1,32 +0,0 @@ -import Chart from '../../core'; - -export const name = 'network'; - -export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - incomingRequests: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - outgoingRequests: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - totalTime: { // TIP: (totalTime / incomingRequests) ã§ã˛ã¨ã¤ãŽãƒĒクエ゚トãĢåšŗ均でおれくらいぎ時間がかかãŖたかįŸĨれる - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - incomingBytes: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - outgoingBytes: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, -}; - -export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/notes.ts b/packages/backend/src/services/chart/charts/entities/notes.ts index 554d3abe1..9387dbfb2 100644 --- a/packages/backend/src/services/chart/charts/entities/notes.ts +++ b/packages/backend/src/services/chart/charts/entities/notes.ts @@ -1,60 +1,22 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'notes'; -const logSchema = { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - diffs: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - normal: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - reply: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - renote: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, -}; - export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - local: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - remote: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - }, -}; + 'local.total': { accumulate: true }, + 'local.inc': {}, + 'local.dec': {}, + 'local.diffs.normal': {}, + 'local.diffs.reply': {}, + 'local.diffs.renote': {}, + 'local.diffs.withFile': {}, + 'remote.total': { accumulate: true }, + 'remote.inc': {}, + 'remote.dec': {}, + 'remote.diffs.normal': {}, + 'remote.diffs.reply': {}, + 'remote.diffs.renote': {}, + 'remote.diffs.withFile': {}, +} as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/per-user-drive.ts b/packages/backend/src/services/chart/charts/entities/per-user-drive.ts index ebf64e733..6111640ea 100644 --- a/packages/backend/src/services/chart/charts/entities/per-user-drive.ts +++ b/packages/backend/src/services/chart/charts/entities/per-user-drive.ts @@ -1,59 +1,14 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'perUserDrive'; export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - /** - * é›†č¨ˆæœŸé–“æ™‚į‚šã§ãŽã€å…¨ãƒ‰ãƒŠã‚¤ãƒ–ãƒ•ã‚Ąã‚¤ãƒĢ数 - */ - totalCount: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * é›†č¨ˆæœŸé–“æ™‚į‚šã§ãŽã€å…¨ãƒ‰ãƒŠã‚¤ãƒ–ãƒ•ã‚Ąã‚¤ãƒĢãŽåˆč¨ˆã‚ĩイã‚ē - */ - totalSize: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * åĸ—åŠ ã—ãŸãƒ‰ãƒŠã‚¤ãƒ–ãƒ•ã‚Ąã‚¤ãƒĢ数 - */ - incCount: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * åĸ—加したドナイブäŊŋį”¨é‡ - */ - incSize: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * æ¸›å°‘ã—ãŸãƒ‰ãƒŠã‚¤ãƒ–ãƒ•ã‚Ąã‚¤ãƒĢ数 - */ - decCount: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * 減少したドナイブäŊŋį”¨é‡ - */ - decSize: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, -}; + 'totalCount': { accumulate: true }, + 'totalSize': { accumulate: true }, // in kilobyte + 'incCount': { range: 'small' }, + 'incSize': {}, // in kilobyte + 'decCount': { range: 'small' }, + 'decSize': {}, // in kilobyte +} as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/per-user-following.ts b/packages/backend/src/services/chart/charts/entities/per-user-following.ts index 8016c5fe9..4118daa47 100644 --- a/packages/backend/src/services/chart/charts/entities/per-user-following.ts +++ b/packages/backend/src/services/chart/charts/entities/per-user-following.ts @@ -1,90 +1,20 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'perUserFollowing'; -const logSchema = { - /** - * フりロãƒŧしãĻいる - */ - followings: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - /** - * フりロãƒŧしãĻã„ã‚‹åˆč¨ˆ - */ - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * フりロãƒŧした数 - */ - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * フりロãƒŧč§Ŗ除した数 - */ - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - - /** - * フりロãƒŧされãĻいる - */ - followers: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - /** - * フりロãƒŧされãĻã„ã‚‹åˆč¨ˆ - */ - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * フりロãƒŧされた数 - */ - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * フりロãƒŧč§Ŗ除された数 - */ - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, -}; - export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - local: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - remote: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - }, -}; + 'local.followings.total': { accumulate: true }, + 'local.followings.inc': { range: 'small' }, + 'local.followings.dec': { range: 'small' }, + 'local.followers.total': { accumulate: true }, + 'local.followers.inc': { range: 'small' }, + 'local.followers.dec': { range: 'small' }, + 'remote.followings.total': { accumulate: true }, + 'remote.followings.inc': { range: 'small' }, + 'remote.followings.dec': { range: 'small' }, + 'remote.followers.total': { accumulate: true }, + 'remote.followers.inc': { range: 'small' }, + 'remote.followers.dec': { range: 'small' }, +} as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/per-user-notes.ts b/packages/backend/src/services/chart/charts/entities/per-user-notes.ts index d8f645b36..c1fa17445 100644 --- a/packages/backend/src/services/chart/charts/entities/per-user-notes.ts +++ b/packages/backend/src/services/chart/charts/entities/per-user-notes.ts @@ -1,47 +1,15 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'perUserNotes'; export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - diffs: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - normal: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - reply: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - renote: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, -}; + 'total': { accumulate: true }, + 'inc': { range: 'small' }, + 'dec': { range: 'small' }, + 'diffs.normal': { range: 'small' }, + 'diffs.reply': { range: 'small' }, + 'diffs.renote': { range: 'small' }, + 'diffs.withFile': { range: 'small' }, +} as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/per-user-reactions.ts b/packages/backend/src/services/chart/charts/entities/per-user-reactions.ts index bcb701266..5e1a6c7b3 100644 --- a/packages/backend/src/services/chart/charts/entities/per-user-reactions.ts +++ b/packages/backend/src/services/chart/charts/entities/per-user-reactions.ts @@ -1,32 +1,10 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'perUserReaction'; -const logSchema = { - /** - * čĸĢãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗ数 - */ - count: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, -}; - export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - local: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - remote: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - }, -}; + 'local.count': { range: 'small' }, + 'remote.count': { range: 'small' }, +} as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/test-grouped.ts b/packages/backend/src/services/chart/charts/entities/test-grouped.ts index ca1c8c570..66b6e8e86 100644 --- a/packages/backend/src/services/chart/charts/entities/test-grouped.ts +++ b/packages/backend/src/services/chart/charts/entities/test-grouped.ts @@ -1,32 +1,11 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'testGrouped'; export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - foo: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, -}; + 'foo.total': { accumulate: true }, + 'foo.inc': {}, + 'foo.dec': {}, +} as const; export const entity = Chart.schemaToEntity(name, schema, true); diff --git a/packages/backend/src/services/chart/charts/entities/test-intersection.ts b/packages/backend/src/services/chart/charts/entities/test-intersection.ts new file mode 100644 index 000000000..a3bdcb367 --- /dev/null +++ b/packages/backend/src/services/chart/charts/entities/test-intersection.ts @@ -0,0 +1,11 @@ +import Chart from '../../core.js'; + +export const name = 'testIntersection'; + +export const schema = { + 'a': { uniqueIncrement: true }, + 'b': { uniqueIncrement: true }, + 'aAndB': { intersection: ['a', 'b'] }, +} as const; + +export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/test-unique.ts b/packages/backend/src/services/chart/charts/entities/test-unique.ts index 2e917ee9e..b2cfb71b0 100644 --- a/packages/backend/src/services/chart/charts/entities/test-unique.ts +++ b/packages/backend/src/services/chart/charts/entities/test-unique.ts @@ -1,20 +1,9 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'testUnique'; export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - foo: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - }, - }, -}; + 'foo': { uniqueIncrement: true }, +} as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/test.ts b/packages/backend/src/services/chart/charts/entities/test.ts index fa536ff2c..7cba21e16 100644 --- a/packages/backend/src/services/chart/charts/entities/test.ts +++ b/packages/backend/src/services/chart/charts/entities/test.ts @@ -1,32 +1,11 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'test'; export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - foo: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, -}; + 'foo.total': { accumulate: true }, + 'foo.inc': {}, + 'foo.dec': {}, +} as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/entities/users.ts b/packages/backend/src/services/chart/charts/entities/users.ts index 08d51c941..c0b83094a 100644 --- a/packages/backend/src/services/chart/charts/entities/users.ts +++ b/packages/backend/src/services/chart/charts/entities/users.ts @@ -1,48 +1,14 @@ -import Chart from '../../core'; +import Chart from '../../core.js'; export const name = 'users'; -const logSchema = { - /** - * é›†č¨ˆæœŸé–“æ™‚į‚šã§ãŽã€å…¨ãƒĻãƒŧã‚ļãƒŧ数 - */ - total: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * åĸ—加したãƒĻãƒŧã‚ļãƒŧ数 - */ - inc: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - - /** - * 減少したãƒĻãƒŧã‚ļãƒŧ数 - */ - dec: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, -}; - export const schema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - local: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - remote: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: logSchema, - }, - }, -}; + 'local.total': { accumulate: true }, + 'local.inc': { range: 'small' }, + 'local.dec': { range: 'small' }, + 'remote.total': { accumulate: true }, + 'remote.inc': { range: 'small' }, + 'remote.dec': { range: 'small' }, +} as const; export const entity = Chart.schemaToEntity(name, schema); diff --git a/packages/backend/src/services/chart/charts/federation.ts b/packages/backend/src/services/chart/charts/federation.ts index 8abb18b51..4fbd297db 100644 --- a/packages/backend/src/services/chart/charts/federation.ts +++ b/packages/backend/src/services/chart/charts/federation.ts @@ -1,66 +1,64 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { Instances } from '@/models/index'; -import { name, schema } from './entities/federation'; - -type FederationLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { Followings } from '@/models/index.js'; +import { name, schema } from './entities/federation.js'; /** * フェデãƒŦãƒŧã‚ˇãƒ§ãƒŗãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class FederationChart extends Chart { +export default class FederationChart extends Chart { constructor() { super(name, schema); } - @autobind - protected genNewLog(latest: FederationLog): DeepPartial { + protected async tickMajor(): Promise>> { return { - instance: { - total: latest.instance.total, - }, }; } - @autobind - protected aggregate(logs: FederationLog[]): FederationLog { - return { - instance: { - total: logs[0].instance.total, - inc: logs.reduce((a, b) => a + b.instance.inc, 0), - dec: logs.reduce((a, b) => a + b.instance.dec, 0), - }, - }; - } + protected async tickMinor(): Promise>> { + const pubsubSubQuery = Followings.createQueryBuilder('f') + .select('f.followerHost') + .where('f.followerHost IS NOT NULL'); - @autobind - protected async fetchActual(): Promise> { - const [total] = await Promise.all([ - Instances.count({}), + const [sub, pub, pubsub] = await Promise.all([ + Followings.createQueryBuilder('following') + .select('COUNT(DISTINCT following.followeeHost)') + .where('following.followeeHost IS NOT NULL') + .getRawOne() + .then(x => parseInt(x.count, 10)), + Followings.createQueryBuilder('following') + .select('COUNT(DISTINCT following.followerHost)') + .where('following.followerHost IS NOT NULL') + .getRawOne() + .then(x => parseInt(x.count, 10)), + Followings.createQueryBuilder('following') + .select('COUNT(DISTINCT following.followeeHost)') + .where('following.followeeHost IS NOT NULL') + .andWhere(`following.followeeHost IN (${ pubsubSubQuery.getQuery() })`) + .setParameters(pubsubSubQuery.getParameters()) + .getRawOne() + .then(x => parseInt(x.count, 10)), ]); return { - instance: { - total: total, - }, + 'sub': sub, + 'pub': pub, + 'pubsub': pubsub, }; } - @autobind - public async update(isAdditional: boolean): Promise { - const update: Obj = {}; + public async deliverd(host: string, succeeded: boolean): Promise { + await this.commit(succeeded ? { + 'deliveredInstances': [host], + } : { + 'stalled': [host], + }); + } - update.total = isAdditional ? 1 : -1; - if (isAdditional) { - update.inc = 1; - } else { - update.dec = 1; - } - - await this.inc({ - instance: update, + public async inbox(host: string): Promise { + await this.commit({ + 'inboxInstances': [host], }); } } diff --git a/packages/backend/src/services/chart/charts/hashtag.ts b/packages/backend/src/services/chart/charts/hashtag.ts index 34e061464..31f7fa95d 100644 --- a/packages/backend/src/services/chart/charts/hashtag.ts +++ b/packages/backend/src/services/chart/charts/hashtag.ts @@ -1,51 +1,29 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { User } from '@/models/entities/user'; -import { SchemaType } from '@/misc/schema'; -import { Users } from '@/models/index'; -import { name, schema } from './entities/hashtag'; - -type HashtagLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { User } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; +import { name, schema } from './entities/hashtag.js'; /** * ãƒãƒƒã‚ˇãƒĨã‚ŋグãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class HashtagChart extends Chart { +export default class HashtagChart extends Chart { constructor() { super(name, schema, true); } - @autobind - protected genNewLog(latest: HashtagLog): DeepPartial { + protected async tickMajor(): Promise>> { return {}; } - @autobind - protected aggregate(logs: HashtagLog[]): HashtagLog { - return { - local: { - users: logs.reduce((a, b) => a.concat(b.local.users), [] as HashtagLog['local']['users']), - }, - remote: { - users: logs.reduce((a, b) => a.concat(b.remote.users), [] as HashtagLog['remote']['users']), - }, - }; - } - - @autobind - protected async fetchActual(): Promise> { + protected async tickMinor(): Promise>> { return {}; } - @autobind public async update(hashtag: string, user: { id: User['id'], host: User['host'] }): Promise { - const update: Obj = { - users: [user.id], - }; - - await this.inc({ - [Users.isLocalUser(user) ? 'local' : 'remote']: update, + await this.commit({ + 'local.users': Users.isLocalUser(user) ? [user.id] : [], + 'remote.users': Users.isLocalUser(user) ? [] : [user.id], }, hashtag); } } diff --git a/packages/backend/src/services/chart/charts/instance.ts b/packages/backend/src/services/chart/charts/instance.ts index 7f3419b69..593430f28 100644 --- a/packages/backend/src/services/chart/charts/instance.ts +++ b/packages/backend/src/services/chart/charts/instance.ts @@ -1,221 +1,105 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { DriveFiles, Followings, Users, Notes } from '@/models/index'; -import { DriveFile } from '@/models/entities/drive-file'; -import { Note } from '@/models/entities/note'; -import { toPuny } from '@/misc/convert-host'; -import { name, schema } from './entities/instance'; - -type InstanceLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { DriveFiles, Followings, Users, Notes } from '@/models/index.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { Note } from '@/models/entities/note.js'; +import { toPuny } from '@/misc/convert-host.js'; +import { name, schema } from './entities/instance.js'; /** * イãƒŗã‚šã‚ŋãƒŗ゚ごとぎチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class InstanceChart extends Chart { +export default class InstanceChart extends Chart { constructor() { super(name, schema, true); } - @autobind - protected genNewLog(latest: InstanceLog): DeepPartial { - return { - notes: { - total: latest.notes.total, - }, - users: { - total: latest.users.total, - }, - following: { - total: latest.following.total, - }, - followers: { - total: latest.followers.total, - }, - drive: { - totalFiles: latest.drive.totalFiles, - totalUsage: latest.drive.totalUsage, - }, - }; - } - - @autobind - protected aggregate(logs: InstanceLog[]): InstanceLog { - return { - requests: { - failed: logs.reduce((a, b) => a + b.requests.failed, 0), - succeeded: logs.reduce((a, b) => a + b.requests.succeeded, 0), - received: logs.reduce((a, b) => a + b.requests.received, 0), - }, - notes: { - total: logs[0].notes.total, - inc: logs.reduce((a, b) => a + b.notes.inc, 0), - dec: logs.reduce((a, b) => a + b.notes.dec, 0), - diffs: { - reply: logs.reduce((a, b) => a + b.notes.diffs.reply, 0), - renote: logs.reduce((a, b) => a + b.notes.diffs.renote, 0), - normal: logs.reduce((a, b) => a + b.notes.diffs.normal, 0), - }, - }, - users: { - total: logs[0].users.total, - inc: logs.reduce((a, b) => a + b.users.inc, 0), - dec: logs.reduce((a, b) => a + b.users.dec, 0), - }, - following: { - total: logs[0].following.total, - inc: logs.reduce((a, b) => a + b.following.inc, 0), - dec: logs.reduce((a, b) => a + b.following.dec, 0), - }, - followers: { - total: logs[0].followers.total, - inc: logs.reduce((a, b) => a + b.followers.inc, 0), - dec: logs.reduce((a, b) => a + b.followers.dec, 0), - }, - drive: { - totalFiles: logs[0].drive.totalFiles, - totalUsage: logs[0].drive.totalUsage, - incFiles: logs.reduce((a, b) => a + b.drive.incFiles, 0), - incUsage: logs.reduce((a, b) => a + b.drive.incUsage, 0), - decFiles: logs.reduce((a, b) => a + b.drive.decFiles, 0), - decUsage: logs.reduce((a, b) => a + b.drive.decUsage, 0), - }, - }; - } - - @autobind - protected async fetchActual(group: string): Promise> { + protected async tickMajor(group: string): Promise>> { const [ notesCount, usersCount, followingCount, followersCount, driveFiles, - driveUsage, + //driveUsage, ] = await Promise.all([ Notes.count({ userHost: group }), Users.count({ host: group }), Followings.count({ followerHost: group }), Followings.count({ followeeHost: group }), DriveFiles.count({ userHost: group }), - DriveFiles.calcDriveUsageOfHost(group), + //DriveFiles.calcDriveUsageOfHost(group), ]); return { - notes: { - total: notesCount, - }, - users: { - total: usersCount, - }, - following: { - total: followingCount, - }, - followers: { - total: followersCount, - }, - drive: { - totalFiles: driveFiles, - totalUsage: driveUsage, - }, + 'notes.total': notesCount, + 'users.total': usersCount, + 'following.total': followingCount, + 'followers.total': followersCount, + 'drive.totalFiles': driveFiles, }; } - @autobind + protected async tickMinor(): Promise>> { + return {}; + } + public async requestReceived(host: string): Promise { - await this.inc({ - requests: { - received: 1, - }, + await this.commit({ + 'requests.received': 1, }, toPuny(host)); } - @autobind public async requestSent(host: string, isSucceeded: boolean): Promise { - const update: Obj = {}; - - if (isSucceeded) { - update.succeeded = 1; - } else { - update.failed = 1; - } - - await this.inc({ - requests: update, + await this.commit({ + 'requests.succeeded': isSucceeded ? 1 : 0, + 'requests.failed': isSucceeded ? 0 : 1, }, toPuny(host)); } - @autobind public async newUser(host: string): Promise { - await this.inc({ - users: { - total: 1, - inc: 1, - }, + await this.commit({ + 'users.total': 1, + 'users.inc': 1, }, toPuny(host)); } - @autobind public async updateNote(host: string, note: Note, isAdditional: boolean): Promise { - const diffs = {} as Record; - - if (note.replyId != null) { - diffs.reply = isAdditional ? 1 : -1; - } else if (note.renoteId != null) { - diffs.renote = isAdditional ? 1 : -1; - } else { - diffs.normal = isAdditional ? 1 : -1; - } - - await this.inc({ - notes: { - total: isAdditional ? 1 : -1, - inc: isAdditional ? 1 : 0, - dec: isAdditional ? 0 : 1, - diffs: diffs, - }, + await this.commit({ + 'notes.total': isAdditional ? 1 : -1, + 'notes.inc': isAdditional ? 1 : 0, + 'notes.dec': isAdditional ? 0 : 1, + 'notes.diffs.normal': note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0, + 'notes.diffs.renote': note.renoteId != null ? (isAdditional ? 1 : -1) : 0, + 'notes.diffs.reply': note.replyId != null ? (isAdditional ? 1 : -1) : 0, + 'notes.diffs.withFile': note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, }, toPuny(host)); } - @autobind public async updateFollowing(host: string, isAdditional: boolean): Promise { - await this.inc({ - following: { - total: isAdditional ? 1 : -1, - inc: isAdditional ? 1 : 0, - dec: isAdditional ? 0 : 1, - }, + await this.commit({ + 'following.total': isAdditional ? 1 : -1, + 'following.inc': isAdditional ? 1 : 0, + 'following.dec': isAdditional ? 0 : 1, }, toPuny(host)); } - @autobind public async updateFollowers(host: string, isAdditional: boolean): Promise { - await this.inc({ - followers: { - total: isAdditional ? 1 : -1, - inc: isAdditional ? 1 : 0, - dec: isAdditional ? 0 : 1, - }, + await this.commit({ + 'followers.total': isAdditional ? 1 : -1, + 'followers.inc': isAdditional ? 1 : 0, + 'followers.dec': isAdditional ? 0 : 1, }, toPuny(host)); } - @autobind public async updateDrive(file: DriveFile, isAdditional: boolean): Promise { - const update: Obj = {}; - - update.totalFiles = isAdditional ? 1 : -1; - update.totalUsage = isAdditional ? file.size : -file.size; - if (isAdditional) { - update.incFiles = 1; - update.incUsage = file.size; - } else { - update.decFiles = 1; - update.decUsage = file.size; - } - - await this.inc({ - drive: update, + const fileSizeKb = file.size / 1000; + await this.commit({ + 'drive.totalFiles': isAdditional ? 1 : -1, + 'drive.incFiles': isAdditional ? 1 : 0, + 'drive.incUsage': isAdditional ? fileSizeKb : 0, + 'drive.decFiles': isAdditional ? 1 : 0, + 'drive.decUsage': isAdditional ? fileSizeKb : 0, }, file.userHost); } } diff --git a/packages/backend/src/services/chart/charts/network.ts b/packages/backend/src/services/chart/charts/network.ts deleted file mode 100644 index 73ea2f7e1..000000000 --- a/packages/backend/src/services/chart/charts/network.ts +++ /dev/null @@ -1,49 +0,0 @@ -import autobind from 'autobind-decorator'; -import Chart, { DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { name, schema } from './entities/network'; - -type NetworkLog = SchemaType; - -/** - * ネットワãƒŧクãĢé–ĸするチãƒŖãƒŧト - */ -// eslint-disable-next-line import/no-default-export -export default class NetworkChart extends Chart { - constructor() { - super(name, schema); - } - - @autobind - protected genNewLog(latest: NetworkLog): DeepPartial { - return {}; - } - - @autobind - protected aggregate(logs: NetworkLog[]): NetworkLog { - return { - incomingRequests: logs.reduce((a, b) => a + b.incomingRequests, 0), - outgoingRequests: logs.reduce((a, b) => a + b.outgoingRequests, 0), - totalTime: logs.reduce((a, b) => a + b.totalTime, 0), - incomingBytes: logs.reduce((a, b) => a + b.incomingBytes, 0), - outgoingBytes: logs.reduce((a, b) => a + b.outgoingBytes, 0), - }; - } - - @autobind - protected async fetchActual(): Promise> { - return {}; - } - - @autobind - public async update(incomingRequests: number, time: number, incomingBytes: number, outgoingBytes: number): Promise { - const inc: DeepPartial = { - incomingRequests: incomingRequests, - totalTime: time, - incomingBytes: incomingBytes, - outgoingBytes: outgoingBytes, - }; - - await this.inc(inc); - } -} diff --git a/packages/backend/src/services/chart/charts/notes.ts b/packages/backend/src/services/chart/charts/notes.ts index 86cda1722..ab6a37e3c 100644 --- a/packages/backend/src/services/chart/charts/notes.ts +++ b/packages/backend/src/services/chart/charts/notes.ts @@ -1,101 +1,45 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { Notes } from '@/models/index'; +import Chart, { KVs } from '../core.js'; +import { Notes } from '@/models/index.js'; import { Not, IsNull } from 'typeorm'; -import { Note } from '@/models/entities/note'; -import { name, schema } from './entities/notes'; - -type NotesLog = SchemaType; +import { Note } from '@/models/entities/note.js'; +import { name, schema } from './entities/notes.js'; /** * ノãƒŧトãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class NotesChart extends Chart { +export default class NotesChart extends Chart { constructor() { super(name, schema); } - @autobind - protected genNewLog(latest: NotesLog): DeepPartial { - return { - local: { - total: latest.local.total, - }, - remote: { - total: latest.remote.total, - }, - }; - } - - @autobind - protected aggregate(logs: NotesLog[]): NotesLog { - return { - local: { - total: logs[0].local.total, - inc: logs.reduce((a, b) => a + b.local.inc, 0), - dec: logs.reduce((a, b) => a + b.local.dec, 0), - diffs: { - reply: logs.reduce((a, b) => a + b.local.diffs.reply, 0), - renote: logs.reduce((a, b) => a + b.local.diffs.renote, 0), - normal: logs.reduce((a, b) => a + b.local.diffs.normal, 0), - }, - }, - remote: { - total: logs[0].remote.total, - inc: logs.reduce((a, b) => a + b.remote.inc, 0), - dec: logs.reduce((a, b) => a + b.remote.dec, 0), - diffs: { - reply: logs.reduce((a, b) => a + b.remote.diffs.reply, 0), - renote: logs.reduce((a, b) => a + b.remote.diffs.renote, 0), - normal: logs.reduce((a, b) => a + b.remote.diffs.normal, 0), - }, - }, - }; - } - - @autobind - protected async fetchActual(): Promise> { + protected async tickMajor(): Promise>> { const [localCount, remoteCount] = await Promise.all([ Notes.count({ userHost: null }), Notes.count({ userHost: Not(IsNull()) }), ]); return { - local: { - total: localCount, - }, - remote: { - total: remoteCount, - }, + 'local.total': localCount, + 'remote.total': remoteCount, }; } - @autobind + protected async tickMinor(): Promise>> { + return {}; + } + public async update(note: Note, isAdditional: boolean): Promise { - const update: Obj = { - diffs: {}, - }; + const prefix = note.userHost === null ? 'local' : 'remote'; - update.total = isAdditional ? 1 : -1; - - if (isAdditional) { - update.inc = 1; - } else { - update.dec = 1; - } - - if (note.replyId != null) { - update.diffs.reply = isAdditional ? 1 : -1; - } else if (note.renoteId != null) { - update.diffs.renote = isAdditional ? 1 : -1; - } else { - update.diffs.normal = isAdditional ? 1 : -1; - } - - await this.inc({ - [note.userHost === null ? 'local' : 'remote']: update, + await this.commit({ + [`${prefix}.total`]: isAdditional ? 1 : -1, + [`${prefix}.inc`]: isAdditional ? 1 : 0, + [`${prefix}.dec`]: isAdditional ? 0 : 1, + [`${prefix}.diffs.normal`]: note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0, + [`${prefix}.diffs.renote`]: note.renoteId != null ? (isAdditional ? 1 : -1) : 0, + [`${prefix}.diffs.reply`]: note.replyId != null ? (isAdditional ? 1 : -1) : 0, + [`${prefix}.diffs.withFile`]: note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, }); } } diff --git a/packages/backend/src/services/chart/charts/per-user-drive.ts b/packages/backend/src/services/chart/charts/per-user-drive.ts index fff790367..131befa39 100644 --- a/packages/backend/src/services/chart/charts/per-user-drive.ts +++ b/packages/backend/src/services/chart/charts/per-user-drive.ts @@ -1,68 +1,42 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { DriveFiles } from '@/models/index'; -import { DriveFile } from '@/models/entities/drive-file'; -import { name, schema } from './entities/per-user-drive'; - -type PerUserDriveLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { DriveFiles } from '@/models/index.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { name, schema } from './entities/per-user-drive.js'; /** * ãƒĻãƒŧã‚ļãƒŧごとぎドナイブãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class PerUserDriveChart extends Chart { +export default class PerUserDriveChart extends Chart { constructor() { super(name, schema, true); } - @autobind - protected genNewLog(latest: PerUserDriveLog): DeepPartial { - return { - totalCount: latest.totalCount, - totalSize: latest.totalSize, - }; - } - - @autobind - protected aggregate(logs: PerUserDriveLog[]): PerUserDriveLog { - return { - totalCount: logs[0].totalCount, - totalSize: logs[0].totalSize, - incCount: logs.reduce((a, b) => a + b.incCount, 0), - incSize: logs.reduce((a, b) => a + b.incSize, 0), - decCount: logs.reduce((a, b) => a + b.decCount, 0), - decSize: logs.reduce((a, b) => a + b.decSize, 0), - }; - } - - @autobind - protected async fetchActual(group: string): Promise> { + protected async tickMajor(group: string): Promise>> { const [count, size] = await Promise.all([ DriveFiles.count({ userId: group }), DriveFiles.calcDriveUsageOf(group), ]); return { - totalCount: count, - totalSize: size, + 'totalCount': count, + 'totalSize': size, }; } - @autobind + protected async tickMinor(): Promise>> { + return {}; + } + public async update(file: DriveFile, isAdditional: boolean): Promise { - const update: Obj = {}; - - update.totalCount = isAdditional ? 1 : -1; - update.totalSize = isAdditional ? file.size : -file.size; - if (isAdditional) { - update.incCount = 1; - update.incSize = file.size; - } else { - update.decCount = 1; - update.decSize = file.size; - } - - await this.inc(update, file.userId); + const fileSizeKb = file.size / 1000; + await this.commit({ + 'totalCount': isAdditional ? 1 : -1, + 'totalSize': isAdditional ? fileSizeKb : -fileSizeKb, + 'incCount': isAdditional ? 1 : 0, + 'incSize': isAdditional ? fileSizeKb : 0, + 'decCount': isAdditional ? 0 : 1, + 'decSize': isAdditional ? 0 : fileSizeKb, + }, file.userId); } } diff --git a/packages/backend/src/services/chart/charts/per-user-following.ts b/packages/backend/src/services/chart/charts/per-user-following.ts index d0a80abda..5d5dd1fa1 100644 --- a/packages/backend/src/services/chart/charts/per-user-following.ts +++ b/packages/backend/src/services/chart/charts/per-user-following.ts @@ -1,76 +1,19 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { Followings, Users } from '@/models/index'; +import Chart, { KVs } from '../core.js'; +import { Followings, Users } from '@/models/index.js'; import { Not, IsNull } from 'typeorm'; -import { User } from '@/models/entities/user'; -import { name, schema } from './entities/per-user-following'; - -type PerUserFollowingLog = SchemaType; +import { User } from '@/models/entities/user.js'; +import { name, schema } from './entities/per-user-following.js'; /** * ãƒĻãƒŧã‚ļãƒŧごとぎフりロãƒŧãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class PerUserFollowingChart extends Chart { +export default class PerUserFollowingChart extends Chart { constructor() { super(name, schema, true); } - @autobind - protected genNewLog(latest: PerUserFollowingLog): DeepPartial { - return { - local: { - followings: { - total: latest.local.followings.total, - }, - followers: { - total: latest.local.followers.total, - }, - }, - remote: { - followings: { - total: latest.remote.followings.total, - }, - followers: { - total: latest.remote.followers.total, - }, - }, - }; - } - - @autobind - protected aggregate(logs: PerUserFollowingLog[]): PerUserFollowingLog { - return { - local: { - followings: { - total: logs[0].local.followings.total, - inc: logs.reduce((a, b) => a + b.local.followings.inc, 0), - dec: logs.reduce((a, b) => a + b.local.followings.dec, 0), - }, - followers: { - total: logs[0].local.followers.total, - inc: logs.reduce((a, b) => a + b.local.followers.inc, 0), - dec: logs.reduce((a, b) => a + b.local.followers.dec, 0), - }, - }, - remote: { - followings: { - total: logs[0].remote.followings.total, - inc: logs.reduce((a, b) => a + b.remote.followings.inc, 0), - dec: logs.reduce((a, b) => a + b.remote.followings.dec, 0), - }, - followers: { - total: logs[0].remote.followers.total, - inc: logs.reduce((a, b) => a + b.remote.followers.inc, 0), - dec: logs.reduce((a, b) => a + b.remote.followers.dec, 0), - }, - }, - }; - } - - @autobind - protected async fetchActual(group: string): Promise> { + protected async tickMajor(group: string): Promise>> { const [ localFollowingsCount, localFollowersCount, @@ -84,42 +27,30 @@ export default class PerUserFollowingChart extends Chart { ]); return { - local: { - followings: { - total: localFollowingsCount, - }, - followers: { - total: localFollowersCount, - }, - }, - remote: { - followings: { - total: remoteFollowingsCount, - }, - followers: { - total: remoteFollowersCount, - }, - }, + 'local.followings.total': localFollowingsCount, + 'local.followers.total': localFollowersCount, + 'remote.followings.total': remoteFollowingsCount, + 'remote.followers.total': remoteFollowersCount, }; } - @autobind + protected async tickMinor(): Promise>> { + return {}; + } + public async update(follower: { id: User['id']; host: User['host']; }, followee: { id: User['id']; host: User['host']; }, isFollow: boolean): Promise { - const update: Obj = {}; + const prefixFollower = Users.isLocalUser(follower) ? 'local' : 'remote'; + const prefixFollowee = Users.isLocalUser(followee) ? 'local' : 'remote'; - update.total = isFollow ? 1 : -1; - - if (isFollow) { - update.inc = 1; - } else { - update.dec = 1; - } - - this.inc({ - [Users.isLocalUser(follower) ? 'local' : 'remote']: { followings: update }, + this.commit({ + [`${prefixFollower}.followings.total`]: isFollow ? 1 : -1, + [`${prefixFollower}.followings.inc`]: isFollow ? 1 : 0, + [`${prefixFollower}.followings.dec`]: isFollow ? 0 : 1, }, follower.id); - this.inc({ - [Users.isLocalUser(followee) ? 'local' : 'remote']: { followers: update }, + this.commit({ + [`${prefixFollowee}.followers.total`]: isFollow ? 1 : -1, + [`${prefixFollowee}.followers.inc`]: isFollow ? 1 : 0, + [`${prefixFollowee}.followers.dec`]: isFollow ? 0 : 1, }, followee.id); } } diff --git a/packages/backend/src/services/chart/charts/per-user-notes.ts b/packages/backend/src/services/chart/charts/per-user-notes.ts index d048c8888..9c5dea1aa 100644 --- a/packages/backend/src/services/chart/charts/per-user-notes.ts +++ b/packages/backend/src/services/chart/charts/per-user-notes.ts @@ -1,45 +1,19 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { User } from '@/models/entities/user'; -import { SchemaType } from '@/misc/schema'; -import { Notes } from '@/models/index'; -import { Note } from '@/models/entities/note'; -import { name, schema } from './entities/per-user-notes'; - -type PerUserNotesLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { User } from '@/models/entities/user.js'; +import { Notes } from '@/models/index.js'; +import { Note } from '@/models/entities/note.js'; +import { name, schema } from './entities/per-user-notes.js'; /** * ãƒĻãƒŧã‚ļãƒŧごとぎノãƒŧトãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class PerUserNotesChart extends Chart { +export default class PerUserNotesChart extends Chart { constructor() { super(name, schema, true); } - @autobind - protected genNewLog(latest: PerUserNotesLog): DeepPartial { - return { - total: latest.total, - }; - } - - @autobind - protected aggregate(logs: PerUserNotesLog[]): PerUserNotesLog { - return { - total: logs[0].total, - inc: logs.reduce((a, b) => a + b.inc, 0), - dec: logs.reduce((a, b) => a + b.dec, 0), - diffs: { - reply: logs.reduce((a, b) => a + b.diffs.reply, 0), - renote: logs.reduce((a, b) => a + b.diffs.renote, 0), - normal: logs.reduce((a, b) => a + b.diffs.normal, 0), - }, - }; - } - - @autobind - protected async fetchActual(group: string): Promise> { + protected async tickMajor(group: string): Promise>> { const [count] = await Promise.all([ Notes.count({ userId: group }), ]); @@ -49,28 +23,19 @@ export default class PerUserNotesChart extends Chart { }; } - @autobind + protected async tickMinor(): Promise>> { + return {}; + } + public async update(user: { id: User['id'] }, note: Note, isAdditional: boolean): Promise { - const update: Obj = { - diffs: {}, - }; - - update.total = isAdditional ? 1 : -1; - - if (isAdditional) { - update.inc = 1; - } else { - update.dec = 1; - } - - if (note.replyId != null) { - update.diffs.reply = isAdditional ? 1 : -1; - } else if (note.renoteId != null) { - update.diffs.renote = isAdditional ? 1 : -1; - } else { - update.diffs.normal = isAdditional ? 1 : -1; - } - - await this.inc(update, user.id); + await this.commit({ + 'total': isAdditional ? 1 : -1, + 'inc': isAdditional ? 1 : 0, + 'dec': isAdditional ? 0 : 1, + 'diffs.normal': note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0, + 'diffs.renote': note.renoteId != null ? (isAdditional ? 1 : -1) : 0, + 'diffs.reply': note.replyId != null ? (isAdditional ? 1 : -1) : 0, + 'diffs.withFile': note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, + }, user.id); } } diff --git a/packages/backend/src/services/chart/charts/per-user-reactions.ts b/packages/backend/src/services/chart/charts/per-user-reactions.ts index 2f5353340..3a830e118 100644 --- a/packages/backend/src/services/chart/charts/per-user-reactions.ts +++ b/packages/backend/src/services/chart/charts/per-user-reactions.ts @@ -1,48 +1,30 @@ -import autobind from 'autobind-decorator'; -import Chart, { DeepPartial } from '../core'; -import { User } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { SchemaType } from '@/misc/schema'; -import { Users } from '@/models/index'; -import { name, schema } from './entities/per-user-reactions'; - -type PerUserReactionsLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { User } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { Users } from '@/models/index.js'; +import { name, schema } from './entities/per-user-reactions.js'; /** * ãƒĻãƒŧã‚ļãƒŧごとぎãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class PerUserReactionsChart extends Chart { +export default class PerUserReactionsChart extends Chart { constructor() { super(name, schema, true); } - @autobind - protected genNewLog(latest: PerUserReactionsLog): DeepPartial { + protected async tickMajor(group: string): Promise>> { return {}; } - @autobind - protected aggregate(logs: PerUserReactionsLog[]): PerUserReactionsLog { - return { - local: { - count: logs.reduce((a, b) => a + b.local.count, 0), - }, - remote: { - count: logs.reduce((a, b) => a + b.remote.count, 0), - }, - }; - } - - @autobind - protected async fetchActual(group: string): Promise> { + protected async tickMinor(): Promise>> { return {}; } - @autobind public async update(user: { id: User['id'], host: User['host'] }, note: Note): Promise { - this.inc({ - [Users.isLocalUser(user) ? 'local' : 'remote']: { count: 1 }, + const prefix = Users.isLocalUser(user) ? 'local' : 'remote'; + this.commit({ + [`${prefix}.count`]: 1, }, note.userId); } } diff --git a/packages/backend/src/services/chart/charts/test-grouped.ts b/packages/backend/src/services/chart/charts/test-grouped.ts index c851d2df0..d01c9fcbd 100644 --- a/packages/backend/src/services/chart/charts/test-grouped.ts +++ b/packages/backend/src/services/chart/charts/test-grouped.ts @@ -1,62 +1,35 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { name, schema } from './entities/test-grouped'; - -type TestGroupedLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { name, schema } from './entities/test-grouped.js'; /** * For testing */ // eslint-disable-next-line import/no-default-export -export default class TestGroupedChart extends Chart { +export default class TestGroupedChart extends Chart { private total = {} as Record; constructor() { super(name, schema, true); } - @autobind - protected genNewLog(latest: TestGroupedLog): DeepPartial { + protected async tickMajor(group: string): Promise>> { return { - foo: { - total: latest.foo.total, - }, + 'foo.total': this.total[group], }; } - @autobind - protected aggregate(logs: TestGroupedLog[]): TestGroupedLog { - return { - foo: { - total: logs[0].foo.total, - inc: logs.reduce((a, b) => a + b.foo.inc, 0), - dec: logs.reduce((a, b) => a + b.foo.dec, 0), - }, - }; + protected async tickMinor(): Promise>> { + return {}; } - @autobind - protected async fetchActual(group: string): Promise> { - return { - foo: { - total: this.total[group], - }, - }; - } - - @autobind public async increment(group: string): Promise { if (this.total[group] == null) this.total[group] = 0; - const update: Obj = {}; - - update.total = 1; - update.inc = 1; this.total[group]++; - await this.inc({ - foo: update, + await this.commit({ + 'foo.total': 1, + 'foo.inc': 1, }, group); } } diff --git a/packages/backend/src/services/chart/charts/test-intersection.ts b/packages/backend/src/services/chart/charts/test-intersection.ts new file mode 100644 index 000000000..88b5a715c --- /dev/null +++ b/packages/backend/src/services/chart/charts/test-intersection.ts @@ -0,0 +1,32 @@ +import Chart, { KVs } from '../core.js'; +import { name, schema } from './entities/test-intersection.js'; + +/** + * For testing + */ +// eslint-disable-next-line import/no-default-export +export default class TestIntersectionChart extends Chart { + constructor() { + super(name, schema); + } + + protected async tickMajor(): Promise>> { + return {}; + } + + protected async tickMinor(): Promise>> { + return {}; + } + + public async addA(key: string): Promise { + await this.commit({ + a: [key], + }); + } + + public async addB(key: string): Promise { + await this.commit({ + b: [key], + }); + } +} diff --git a/packages/backend/src/services/chart/charts/test-unique.ts b/packages/backend/src/services/chart/charts/test-unique.ts index 3564f675a..d714f1d40 100644 --- a/packages/backend/src/services/chart/charts/test-unique.ts +++ b/packages/backend/src/services/chart/charts/test-unique.ts @@ -1,39 +1,25 @@ -import autobind from 'autobind-decorator'; -import Chart, { DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { name, schema } from './entities/test-unique'; - -type TestUniqueLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { name, schema } from './entities/test-unique.js'; /** * For testing */ // eslint-disable-next-line import/no-default-export -export default class TestUniqueChart extends Chart { +export default class TestUniqueChart extends Chart { constructor() { super(name, schema); } - @autobind - protected genNewLog(latest: TestUniqueLog): DeepPartial { + protected async tickMajor(): Promise>> { return {}; } - @autobind - protected aggregate(logs: TestUniqueLog[]): TestUniqueLog { - return { - foo: logs.reduce((a, b) => a.concat(b.foo), [] as TestUniqueLog['foo']), - }; - } - - @autobind - protected async fetchActual(): Promise> { + protected async tickMinor(): Promise>> { return {}; } - @autobind public async uniqueIncrement(key: string): Promise { - await this.inc({ + await this.commit({ foo: [key], }); } diff --git a/packages/backend/src/services/chart/charts/test.ts b/packages/backend/src/services/chart/charts/test.ts index 06add7ede..adb2b18c8 100644 --- a/packages/backend/src/services/chart/charts/test.ts +++ b/packages/backend/src/services/chart/charts/test.ts @@ -1,73 +1,42 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { name, schema } from './entities/test'; - -type TestLog = SchemaType; +import Chart, { KVs } from '../core.js'; +import { name, schema } from './entities/test.js'; /** * For testing */ // eslint-disable-next-line import/no-default-export -export default class TestChart extends Chart { +export default class TestChart extends Chart { public total = 0; // publicãĢするぎはテ゚トぎため constructor() { super(name, schema); } - @autobind - protected genNewLog(latest: TestLog): DeepPartial { + protected async tickMajor(): Promise>> { return { - foo: { - total: latest.foo.total, - }, + 'foo.total': this.total, }; } - @autobind - protected aggregate(logs: TestLog[]): TestLog { - return { - foo: { - total: logs[0].foo.total, - inc: logs.reduce((a, b) => a + b.foo.inc, 0), - dec: logs.reduce((a, b) => a + b.foo.dec, 0), - }, - }; + protected async tickMinor(): Promise>> { + return {}; } - @autobind - protected async fetchActual(): Promise> { - return { - foo: { - total: this.total, - }, - }; - } - - @autobind public async increment(): Promise { - const update: Obj = {}; - - update.total = 1; - update.inc = 1; this.total++; - await this.inc({ - foo: update, + await this.commit({ + 'foo.total': 1, + 'foo.inc': 1, }); } - @autobind public async decrement(): Promise { - const update: Obj = {}; - - update.total = -1; - update.dec = 1; this.total--; - await this.inc({ - foo: update, + await this.commit({ + 'foo.total': -1, + 'foo.dec': 1, }); } } diff --git a/packages/backend/src/services/chart/charts/users.ts b/packages/backend/src/services/chart/charts/users.ts index c36c6cd97..fb9d5e15f 100644 --- a/packages/backend/src/services/chart/charts/users.ts +++ b/packages/backend/src/services/chart/charts/users.ts @@ -1,80 +1,41 @@ -import autobind from 'autobind-decorator'; -import Chart, { Obj, DeepPartial } from '../core'; -import { SchemaType } from '@/misc/schema'; -import { Users } from '@/models/index'; +import Chart, { KVs } from '../core.js'; +import { Users } from '@/models/index.js'; import { Not, IsNull } from 'typeorm'; -import { User } from '@/models/entities/user'; -import { name, schema } from './entities/users'; - -type UsersLog = SchemaType; +import { User } from '@/models/entities/user.js'; +import { name, schema } from './entities/users.js'; /** * ãƒĻãƒŧã‚ļãƒŧ数ãĢé–ĸするチãƒŖãƒŧト */ // eslint-disable-next-line import/no-default-export -export default class UsersChart extends Chart { +export default class UsersChart extends Chart { constructor() { super(name, schema); } - @autobind - protected genNewLog(latest: UsersLog): DeepPartial { - return { - local: { - total: latest.local.total, - }, - remote: { - total: latest.remote.total, - }, - }; - } - - @autobind - protected aggregate(logs: UsersLog[]): UsersLog { - return { - local: { - total: logs[0].local.total, - inc: logs.reduce((a, b) => a + b.local.inc, 0), - dec: logs.reduce((a, b) => a + b.local.dec, 0), - }, - remote: { - total: logs[0].remote.total, - inc: logs.reduce((a, b) => a + b.remote.inc, 0), - dec: logs.reduce((a, b) => a + b.remote.dec, 0), - }, - }; - } - - @autobind - protected async fetchActual(): Promise> { + protected async tickMajor(): Promise>> { const [localCount, remoteCount] = await Promise.all([ Users.count({ host: null }), Users.count({ host: Not(IsNull()) }), ]); return { - local: { - total: localCount, - }, - remote: { - total: remoteCount, - }, + 'local.total': localCount, + 'remote.total': remoteCount, }; } - @autobind + protected async tickMinor(): Promise>> { + return {}; + } + public async update(user: { id: User['id'], host: User['host'] }, isAdditional: boolean): Promise { - const update: Obj = {}; + const prefix = Users.isLocalUser(user) ? 'local' : 'remote'; - update.total = isAdditional ? 1 : -1; - if (isAdditional) { - update.inc = 1; - } else { - update.dec = 1; - } - - await this.inc({ - [Users.isLocalUser(user) ? 'local' : 'remote']: update, + await this.commit({ + [`${prefix}.total`]: isAdditional ? 1 : -1, + [`${prefix}.inc`]: isAdditional ? 1 : 0, + [`${prefix}.dec`]: isAdditional ? 0 : 1, }); } } diff --git a/packages/backend/src/services/chart/core.ts b/packages/backend/src/services/chart/core.ts index e406449f4..39fad71dd 100644 --- a/packages/backend/src/services/chart/core.ts +++ b/packages/backend/src/services/chart/core.ts @@ -5,26 +5,39 @@ */ import * as nestedProperty from 'nested-property'; -import autobind from 'autobind-decorator'; -import Logger from '../logger'; -import { Schema } from '@/misc/schema'; +import Logger from '../logger.js'; import { EntitySchema, getRepository, Repository, LessThan, Between } from 'typeorm'; -import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/prelude/time'; -import { getChartInsertLock } from '@/misc/app-lock'; +import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/prelude/time.js'; +import { getChartInsertLock } from '@/misc/app-lock.js'; const logger = new Logger('chart', 'white', process.env.NODE_ENV !== 'test'); -export type Obj = { [key: string]: any }; +const columnPrefix = '___' as const; +const uniqueTempColumnPrefix = 'unique_temp___' as const; +const columnDot = '_' as const; -export type DeepPartial = { - [P in keyof T]?: DeepPartial; +type Schema = Record; + + range?: 'big' | 'small' | 'medium'; + + // previousãĒ値をåŧ•ãįļ™ãã‹ãŠã†ã‹ + accumulate?: boolean; +}>; + +type KeyToColumnName = T extends `${infer R1}.${infer R2}` ? `${R1}${typeof columnDot}${KeyToColumnName}` : T; + +type Columns = { + [K in keyof S as `${typeof columnPrefix}${KeyToColumnName}`]: number; }; -type ArrayValue = { - [P in keyof T]: T[P] extends number ? T[P][] : ArrayValue; +type TempColumnsForUnique = { + [K in keyof S as `${typeof uniqueTempColumnPrefix}${KeyToColumnName}`]: S[K]['uniqueIncrement'] extends true ? string[] : never; }; -type Log = { +type RawRecord = { id: number; /** @@ -36,7 +49,7 @@ type Log = { * 集計æ—Ĩ時ぎUnixã‚ŋイム゚ã‚ŋãƒŗプ(į§’) */ date: number; -}; +} & TempColumnsForUnique & Columns; const camelToSnake = (str: string): string => { return str.replace(/([A-Z])/g, s => '_' + s.charAt(0).toLowerCase()); @@ -44,127 +57,119 @@ const camelToSnake = (str: string): string => { const removeDuplicates = (array: any[]) => Array.from(new Set(array)); +type Commit = { + [K in keyof S]?: S[K]['uniqueIncrement'] extends true ? string[] : number; +}; + +export type KVs = { + [K in keyof S]: number; +}; + +type ChartResult = { + [P in keyof T]: number[]; +}; + +type UnionToIntersection = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never; + +type UnflattenSingleton = K extends `${infer A}.${infer B}` + ? { [_ in A]: UnflattenSingleton; } + : { [_ in K]: V; }; + +type Unflatten> = UnionToIntersection< + { + [K in Extract]: UnflattenSingleton; + }[Extract] +>; + +type ToJsonSchema = { + type: 'object'; + properties: { + [K in keyof S]: S[K] extends number[] ? { type: 'array'; items: { type: 'number'; }; } : ToJsonSchema; + }, + required: (keyof S)[]; +}; + +export function getJsonSchema(schema: S): ToJsonSchema>> { + const object = {}; + for (const [k, v] of Object.entries(schema)) { + nestedProperty.set(object, k, null); + } + + function f(obj: Record>) { + const jsonSchema = { + type: 'object', + properties: {} as Record, + required: [], + }; + for (const [k, v] of Object.entries(obj)) { + jsonSchema.properties[k] = v === null ? { + type: 'array', + items: { type: 'number' }, + } : f(v as Record>); + } + return jsonSchema; + } + + return f(object) as ToJsonSchema>>; +} + /** * 様々ãĒチãƒŖãƒŧトぎįŽĄį†ã‚’司るクナ゚ */ // eslint-disable-next-line import/no-default-export -export default abstract class Chart> { - private static readonly columnPrefix = '___'; - private static readonly columnDot = '_'; +export default abstract class Chart { + public schema: T; private name: string; private buffer: { - diff: DeepPartial; + diff: Commit; group: string | null; }[] = []; - public schema: Schema; - protected repositoryForHour: Repository; - protected repositoryForDay: Repository; - - protected abstract genNewLog(latest: T): DeepPartial; + // ↓ãĢしたいけおfindOneとかで型エナãƒŧãĢãĒる + //private repositoryForHour: Repository>; + //private repositoryForDay: Repository>; + private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }>; + private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }>; /** - * @param logs æ—Ĩ時が新しい斚が先頭 + * 1æ—ĨãĢ一回į¨‹åēĻåŽŸčĄŒã•ã‚Œã‚Œã°č‰¯ã„ã‚ˆã†ãĒ計įŽ—å‡Ļį†ã‚’å…Ĩれる(ä¸ģãĢCASCADE削除ãĒおã‚ĸプãƒĒã‚ąãƒŧã‚ˇãƒ§ãƒŗ側で感įŸĨできãĒい変動ãĢよるã‚ēãƒŦぎäŋŽæ­Ŗį”¨) */ - protected abstract aggregate(logs: T[]): T; + protected abstract tickMajor(group: string | null): Promise>>; - protected abstract fetchActual(group: string | null): Promise>; + /** + * 少ãĒくとも最小゚パãƒŗ内ãĢ1å›žã¯åŽŸčĄŒã•ã‚ŒãĻæŦ˛ã—ã„č¨ˆįŽ—å‡Ļį†ã‚’å…Ĩれる + */ + protected abstract tickMinor(group: string | null): Promise>>; - @autobind - private static convertSchemaToFlatColumnDefinitions(schema: Schema) { - const columns = {} as Record; - const flatColumns = (x: Obj, path?: string) => { - for (const [k, v] of Object.entries(x)) { - const p = path ? `${path}${this.columnDot}${k}` : k; - if (v.type === 'object') { - flatColumns(v.properties, p); - } else if (v.type === 'number') { - columns[this.columnPrefix + p] = { - type: 'bigint', - }; - } else if (v.type === 'array' && v.items.type === 'string') { - columns[this.columnPrefix + p] = { - type: 'varchar', - array: true, - }; - } + private static convertSchemaToColumnDefinitions(schema: Schema): Record { + const columns = {} as Record; + for (const [k, v] of Object.entries(schema)) { + const name = k.replaceAll('.', columnDot); + const type = v.range === 'big' ? 'bigint' : v.range === 'small' ? 'smallint' : 'integer'; + if (v.uniqueIncrement) { + columns[uniqueTempColumnPrefix + name] = { + type: 'varchar', + array: true, + default: '{}', + }; + columns[columnPrefix + name] = { + type, + default: 0, + }; + } else { + columns[columnPrefix + name] = { + type, + default: 0, + }; } - }; - flatColumns(schema.properties!); + } return columns; } - @autobind - private static convertFlattenColumnsToObject(x: Record): Record { - const obj = {} as Record; - for (const k of Object.keys(x).filter(k => k.startsWith(Chart.columnPrefix))) { - // now k is ___x_y_z - const path = k.substr(Chart.columnPrefix.length).split(Chart.columnDot).join('.'); - nestedProperty.set(obj, path, x[k]); - } - return obj; - } - - @autobind - private static convertObjectToFlattenColumns(x: Record) { - const columns = {} as Record; - const flatten = (x: Obj, path?: string) => { - for (const [k, v] of Object.entries(x)) { - const p = path ? `${path}${this.columnDot}${k}` : k; - if (typeof v === 'object' && !Array.isArray(v)) { - flatten(v, p); - } else { - columns[this.columnPrefix + p] = v; - } - } - }; - flatten(x); - return columns; - } - - @autobind - private static countUniqueFields(x: Record) { - const exec = (x: Obj) => { - const res = {} as Record; - for (const [k, v] of Object.entries(x)) { - if (typeof v === 'object' && !Array.isArray(v)) { - res[k] = exec(v); - } else if (Array.isArray(v)) { - res[k] = Array.from(new Set(v)).length; - } else { - res[k] = v; - } - } - return res; - }; - return exec(x); - } - - @autobind - private static convertQuery(diff: Record) { - const query: Record string> = {}; - - for (const [k, v] of Object.entries(diff)) { - if (typeof v === 'number') { - if (v > 0) query[k] = () => `"${k}" + ${v}`; - if (v < 0) query[k] = () => `"${k}" - ${Math.abs(v)}`; - } else if (Array.isArray(v)) { - // TODO: item が文字列äģĨ外ぎ場合も寞åŋœ - // TODO: item をSQLã‚¨ã‚šã‚ąãƒŧプ - const items = v.map(item => `"${item}"`).join(','); - query[k] = () => `array_cat("${k}", '{${items}}'::varchar[])`; - } - } - - return query; - } - - @autobind - private static dateToTimestamp(x: Date): Log['date'] { + private static dateToTimestamp(x: Date): number { return Math.floor(x.getTime() / 1000); } - @autobind private static parseDate(date: Date): [number, number, number, number, number, number, number] { const y = date.getUTCFullYear(); const m = date.getUTCMonth(); @@ -177,12 +182,10 @@ export default abstract class Chart> { return [y, m, d, h, _m, _s, _ms]; } - @autobind private static getCurrentDate() { return Chart.parseDate(new Date()); } - @autobind public static schemaToEntity(name: string, schema: Schema, grouped = false): { hour: EntitySchema, day: EntitySchema, @@ -207,7 +210,7 @@ export default abstract class Chart> { length: 128, }, } : {}), - ...Chart.convertSchemaToFlatColumnDefinitions(schema), + ...Chart.convertSchemaToColumnDefinitions(schema), }, indices: [{ columns: grouped ? ['date', 'group'] : ['date'], @@ -233,37 +236,36 @@ export default abstract class Chart> { }; } - constructor(name: string, schema: Schema, grouped = false) { + constructor(name: string, schema: T, grouped = false) { this.name = name; this.schema = schema; const { hour, day } = Chart.schemaToEntity(name, schema, grouped); - this.repositoryForHour = getRepository(hour); - this.repositoryForDay = getRepository(day); + this.repositoryForHour = getRepository<{ id: number; group?: string | null; date: number; }>(hour); + this.repositoryForDay = getRepository<{ id: number; group?: string | null; date: number; }>(day); } - @autobind - private getNewLog(latest: T | null): T { - const log = latest ? this.genNewLog(latest) : {}; - const flatColumns = (x: Obj, path?: string) => { - for (const [k, v] of Object.entries(x)) { - const p = path ? `${path}.${k}` : k; - if (v.type === 'object') { - flatColumns(v.properties, p); - } else { - if (nestedProperty.get(log, p) == null) { - const emptyValue = v.type === 'number' ? 0 : []; - nestedProperty.set(log, p, emptyValue); - } - } + private convertRawRecord(x: RawRecord): KVs { + const kvs = {} as Record; + for (const k of Object.keys(x).filter((k) => k.startsWith(columnPrefix)) as (keyof Columns)[]) { + kvs[(k as string).substr(columnPrefix.length).split(columnDot).join('.')] = x[k]; + } + return kvs as KVs; + } + + private getNewLog(latest: KVs | null): KVs { + const log = {} as Record; + for (const [k, v] of Object.entries(this.schema) as ([keyof typeof this['schema'], this['schema'][string]])[]) { + if (v.accumulate && latest) { + log[k] = latest[k]; + } else { + log[k] = 0; } - }; - flatColumns(this.schema.properties!); - return log as T; + } + return log as KVs; } - @autobind - private getLatestLog(group: string | null, span: 'hour' | 'day'): Promise { + private getLatestLog(group: string | null, span: 'hour' | 'day'): Promise | null> { const repository = span === 'hour' ? this.repositoryForHour : span === 'day' ? this.repositoryForDay : @@ -275,14 +277,13 @@ export default abstract class Chart> { order: { date: -1, }, - }).then(x => x || null); + }).then(x => x ?? null) as Promise | null>; } /** * įžåœ¨(=äģŠãŽHour or Day)ぎログをデãƒŧã‚ŋベãƒŧ゚からæŽĸしãĻ、あればそれをčŋ”し、ãĒければäŊœæˆã—ãĻčŋ”しぞす。 */ - @autobind - private async claimCurrentLog(group: string | null, span: 'hour' | 'day'): Promise { + private async claimCurrentLog(group: string | null, span: 'hour' | 'day'): Promise> { const [y, m, d, h] = Chart.getCurrentDate(); const current = dateUTC( @@ -299,15 +300,15 @@ export default abstract class Chart> { const currentLog = await repository.findOne({ date: Chart.dateToTimestamp(current), ...(group ? { group: group } : {}), - }); + }) as RawRecord | undefined; // ログがあればそれをčŋ”しãĻįĩ‚äē† if (currentLog != null) { return currentLog; } - let log: Log; - let data: T; + let log: RawRecord; + let data: KVs; // é›†č¨ˆæœŸé–“ãŒå¤‰ã‚ãŖãĻから、初めãĻぎチãƒŖãƒŧト更新ãĒら // 最も最čŋ‘ぎログを持ãŖãĻくる @@ -318,10 +319,8 @@ export default abstract class Chart> { const latest = await this.getLatestLog(group, span); if (latest != null) { - const obj = Chart.convertFlattenColumnsToObject(latest) as T; - // įŠēログデãƒŧã‚ŋをäŊœæˆ - data = this.getNewLog(obj); + data = this.getNewLog(this.convertRawRecord(latest)); } else { // ログが存在しãĒかãŖたら // (Misskeyイãƒŗã‚šã‚ŋãƒŗã‚šã‚’åģēãĻãĻ初めãĻぎチãƒŖãƒŧト更新時ãĒお) @@ -341,17 +340,23 @@ export default abstract class Chart> { const currentLog = await repository.findOne({ date: date, ...(group ? { group: group } : {}), - }); + }) as RawRecord | undefined; // ログがあればそれをčŋ”しãĻįĩ‚äē† if (currentLog != null) return currentLog; + const columns = {} as Record; + for (const [k, v] of Object.entries(data)) { + const name = k.replaceAll('.', columnDot); + columns[columnPrefix + name] = v; + } + // 新čĻãƒ­ã‚°æŒŋå…Ĩ log = await repository.insert({ date: date, ...(group ? { group: group } : {}), - ...Chart.convertObjectToFlattenColumns(data), - }).then(x => repository.findOneOrFail(x.identifiers[0])); + ...columns, + }).then(x => repository.findOneOrFail(x.identifiers[0])) as RawRecord; logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`); @@ -361,14 +366,15 @@ export default abstract class Chart> { } } - @autobind - protected commit(diff: DeepPartial, group: string | null = null): void { + protected commit(diff: Commit, group: string | null = null): void { + for (const [k, v] of Object.entries(diff)) { + if (v == null || v === 0 || (Array.isArray(v) && v.length === 0)) delete diff[k]; + } this.buffer.push({ diff, group, }); } - @autobind public async save(): Promise { if (this.buffer.length === 0) { logger.info(`${this.name}: Write skipped`); @@ -381,37 +387,91 @@ export default abstract class Chart> { // そぎログはæœŦæĨは 01:00~ ぎログとしãĻDBãĢäŋå­˜ã•ã‚ŒãĻæŦ˛ã—いぎãĢ、02:00~ ãŽãƒ­ã‚°æ‰ąã„ãĢãĒãŖãĻしぞう。 // これを回éŋするためぎ原čŖ…ã¯č¤‡é›‘ãĢãĒりそうãĒため、一æ—Ļäŋį•™ã€‚ - const update = async (logHour: Log, logDay: Log): Promise => { - const finalDiffs = {} as Record; + const update = async (logHour: RawRecord, logDay: RawRecord): Promise => { + const finalDiffs = {} as Record; for (const diff of this.buffer.filter(q => q.group == null || (q.group === logHour.group)).map(q => q.diff)) { - const columns = Chart.convertObjectToFlattenColumns(diff); - - for (const [k, v] of Object.entries(columns)) { + for (const [k, v] of Object.entries(diff)) { if (finalDiffs[k] == null) { finalDiffs[k] = v; } else { if (typeof finalDiffs[k] === 'number') { (finalDiffs[k] as number) += v as number; } else { - (finalDiffs[k] as unknown[]) = (finalDiffs[k] as unknown[]).concat(v); + (finalDiffs[k] as string[]) = (finalDiffs[k] as string[]).concat(v); } } } } - const query = Chart.convertQuery(finalDiffs); + const queryForHour: Record, number | (() => string)> = {} as any; + const queryForDay: Record, number | (() => string)> = {} as any; + for (const [k, v] of Object.entries(finalDiffs)) { + if (typeof v === 'number') { + const name = columnPrefix + k.replaceAll('.', columnDot) as keyof Columns; + if (v > 0) queryForHour[name] = () => `"${name}" + ${v}`; + if (v < 0) queryForHour[name] = () => `"${name}" - ${Math.abs(v)}`; + if (v > 0) queryForDay[name] = () => `"${name}" + ${v}`; + if (v < 0) queryForDay[name] = () => `"${name}" - ${Math.abs(v)}`; + } else if (Array.isArray(v) && v.length > 0) { // ãƒĻニãƒŧクイãƒŗクãƒĒãƒĄãƒŗト + const tempColumnName = uniqueTempColumnPrefix + k.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + // TODO: item をSQLã‚¨ã‚šã‚ąãƒŧプ + const itemsForHour = v.filter(item => !logHour[tempColumnName].includes(item)).map(item => `"${item}"`); + const itemsForDay = v.filter(item => !logDay[tempColumnName].includes(item)).map(item => `"${item}"`); + if (itemsForHour.length > 0) queryForHour[tempColumnName] = () => `array_cat("${tempColumnName}", '{${itemsForHour.join(',')}}'::varchar[])`; + if (itemsForDay.length > 0) queryForDay[tempColumnName] = () => `array_cat("${tempColumnName}", '{${itemsForDay.join(',')}}'::varchar[])`; + } + } + + // bake unique count + for (const [k, v] of Object.entries(finalDiffs)) { + if (this.schema[k].uniqueIncrement) { + const name = columnPrefix + k.replaceAll('.', columnDot) as keyof Columns; + const tempColumnName = uniqueTempColumnPrefix + k.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + queryForHour[name] = new Set([...(v as string[]), ...logHour[tempColumnName]]).size; + queryForDay[name] = new Set([...(v as string[]), ...logDay[tempColumnName]]).size; + } + } + + // compute intersection + // TODO: intersectionãĢ指厚されたã‚ĢナムがintersectionだãŖた場合ぎ寞åŋœ + for (const [k, v] of Object.entries(this.schema)) { + const intersection = v.intersection; + if (intersection) { + const name = columnPrefix + k.replaceAll('.', columnDot) as keyof Columns; + const firstKey = intersection[0]; + const firstTempColumnName = uniqueTempColumnPrefix + firstKey.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + const firstValues = finalDiffs[firstKey] as string[] | undefined; + const currentValuesForHour = new Set([...(firstValues ?? []), ...logHour[firstTempColumnName]]); + const currentValuesForDay = new Set([...(firstValues ?? []), ...logDay[firstTempColumnName]]); + for (let i = 1; i < intersection.length; i++) { + const targetKey = intersection[i]; + const targetTempColumnName = uniqueTempColumnPrefix + targetKey.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + const targetValues = finalDiffs[targetKey] as string[] | undefined; + const targetValuesForHour = new Set([...(targetValues ?? []), ...logHour[targetTempColumnName]]); + const targetValuesForDay = new Set([...(targetValues ?? []), ...logDay[targetTempColumnName]]); + currentValuesForHour.forEach(v => { + if (!targetValuesForHour.has(v)) currentValuesForHour.delete(v); + }); + currentValuesForDay.forEach(v => { + if (!targetValuesForDay.has(v)) currentValuesForDay.delete(v); + }); + } + queryForHour[name] = currentValuesForHour.size; + queryForDay[name] = currentValuesForDay.size; + } + } // ログ更新 await Promise.all([ this.repositoryForHour.createQueryBuilder() .update() - .set(query) + .set(queryForHour as any) .where('id = :id', { id: logHour.id }) .execute(), this.repositoryForDay.createQueryBuilder() .update() - .set(query) + .set(queryForDay as any) .where('id = :id', { id: logDay.id }) .execute(), ]); @@ -433,20 +493,29 @@ export default abstract class Chart> { update(logHour, logDay)))); } - @autobind - public async resync(group: string | null = null): Promise { - const data = await this.fetchActual(group); + public async tick(major: boolean, group: string | null = null): Promise { + const data = major ? await this.tickMajor(group) : await this.tickMinor(group); - const update = async (logHour: Log, logDay: Log): Promise => { + const columns = {} as Record, number>; + for (const [k, v] of Object.entries(data) as ([keyof typeof data, number])[]) { + const name = columnPrefix + (k as string).replaceAll('.', columnDot) as keyof Columns; + columns[name] = v; + } + + if (Object.keys(columns).length === 0) { + return; + } + + const update = async (logHour: RawRecord, logDay: RawRecord): Promise => { await Promise.all([ this.repositoryForHour.createQueryBuilder() .update() - .set(Chart.convertObjectToFlattenColumns(data)) + .set(columns) .where('id = :id', { id: logHour.id }) .execute(), this.repositoryForDay.createQueryBuilder() .update() - .set(Chart.convertObjectToFlattenColumns(data)) + .set(columns) .where('id = :id', { id: logDay.id }) .execute(), ]); @@ -459,13 +528,46 @@ export default abstract class Chart> { update(logHour, logDay)); } - @autobind - protected async inc(inc: DeepPartial, group: string | null = null): Promise { - await this.commit(inc, group); + public resync(group: string | null = null): Promise { + return this.tick(true, group); } - @autobind - public async getChart(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise> { + public async clean(): Promise { + const current = dateUTC(Chart.getCurrentDate()); + + // 一æ—ĨäģĨ上前かつ三æ—ĨäģĨ内 + const gt = Chart.dateToTimestamp(current) - (60 * 60 * 24 * 3); + const lt = Chart.dateToTimestamp(current) - (60 * 60 * 24); + + const columns = {} as Record, []>; + for (const [k, v] of Object.entries(this.schema)) { + if (v.uniqueIncrement) { + const name = uniqueTempColumnPrefix + k.replaceAll('.', columnDot) as keyof TempColumnsForUnique; + columns[name] = []; + } + } + + if (Object.keys(columns).length === 0) { + return; + } + + await Promise.all([ + this.repositoryForHour.createQueryBuilder() + .update() + .set(columns) + .where('date > :gt', { gt }) + .andWhere('date < :lt', { lt }) + .execute(), + this.repositoryForDay.createQueryBuilder() + .update() + .set(columns) + .where('date > :gt', { gt }) + .andWhere('date < :lt', { lt }) + .execute(), + ]); + } + + public async getChartRaw(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise> { const [y, m, d, h, _m, _s, _ms] = cursor ? Chart.parseDate(subtractTime(addTime(cursor, 1, span), 1)) : Chart.getCurrentDate(); const [y2, m2, d2, h2] = cursor ? Chart.parseDate(addTime(cursor, 1, span)) : [] as never; @@ -490,7 +592,7 @@ export default abstract class Chart> { order: { date: -1, }, - }); + }) as RawRecord[]; // čĻæą‚されたį¯„å›˛ãĢãƒ­ã‚°ãŒã˛ã¨ã¤ã‚‚ãĒかãŖたら if (logs.length === 0) { @@ -502,7 +604,7 @@ export default abstract class Chart> { order: { date: -1, }, - }); + }) as RawRecord | undefined; if (recentLog) { logs = [recentLog]; @@ -519,14 +621,14 @@ export default abstract class Chart> { order: { date: -1, }, - }); + }) as RawRecord | undefined; if (outdatedLog) { logs.push(outdatedLog); } } - const chart: T[] = []; + const chart: KVs[] = []; for (let i = (amount - 1); i >= 0; i--) { const current = @@ -537,17 +639,16 @@ export default abstract class Chart> { const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current)); if (log) { - const data = Chart.convertFlattenColumnsToObject(log); - chart.unshift(Chart.countUniqueFields(data) as T); + chart.unshift(this.convertRawRecord(log)); } else { // 隙間埋め const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current)); - const data = latest ? Chart.convertFlattenColumnsToObject(latest) as T : null; - chart.unshift(Chart.countUniqueFields(this.getNewLog(data)) as T); + const data = latest ? this.convertRawRecord(latest) : null; + chart.unshift(this.getNewLog(data)); } } - const res = {} as Record; + const res = {} as ChartResult; /** * [{ foo: 1, bar: 5 }, { foo: 2, bar: 6 }, { foo: 3, bar: 7 }] @@ -555,36 +656,25 @@ export default abstract class Chart> { * { foo: [1, 2, 3], bar: [5, 6, 7] } * ãĢする */ - const compact = (x: Obj, path?: string): void => { - for (const [k, v] of Object.entries(x)) { - const p = path ? `${path}.${k}` : k; - if (typeof v === 'object' && !Array.isArray(v)) { - compact(v, p); + for (const record of chart) { + for (const [k, v] of Object.entries(record) as ([keyof typeof record, number])[]) { + if (res[k]) { + res[k].push(v); } else { - const values = chart.map(s => nestedProperty.get(s, p)); - nestedProperty.set(res, p, values); + res[k] = [v]; } } - }; - - compact(chart[0]); - - return res as ArrayValue; - } -} - -export function convertLog(logSchema: Schema): Schema { - const v: Schema = JSON.parse(JSON.stringify(logSchema)); // copy - if (v.type === 'number') { - v.type = 'array'; - v.items = { - type: 'number' as const, - optional: false as const, nullable: false as const, - }; - } else if (v.type === 'object') { - for (const k of Object.keys(v.properties!)) { - v.properties![k] = convertLog(v.properties![k]); } + + return res; + } + + public async getChart(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise>> { + const result = await this.getChartRaw(span, amount, cursor, group); + const object = {}; + for (const [k, v] of Object.entries(result)) { + nestedProperty.set(object, k, v); + } + return object as Unflatten>; } - return v; } diff --git a/packages/backend/src/services/chart/entities.ts b/packages/backend/src/services/chart/entities.ts index dedbd4708..13e994cb6 100644 --- a/packages/backend/src/services/chart/entities.ts +++ b/packages/backend/src/services/chart/entities.ts @@ -1,21 +1,20 @@ -import { entity as FederationChart } from './charts/entities/federation'; -import { entity as NotesChart } from './charts/entities/notes'; -import { entity as UsersChart } from './charts/entities/users'; -import { entity as NetworkChart } from './charts/entities/network'; -import { entity as ActiveUsersChart } from './charts/entities/active-users'; -import { entity as InstanceChart } from './charts/entities/instance'; -import { entity as PerUserNotesChart } from './charts/entities/per-user-notes'; -import { entity as DriveChart } from './charts/entities/drive'; -import { entity as PerUserReactionsChart } from './charts/entities/per-user-reactions'; -import { entity as HashtagChart } from './charts/entities/hashtag'; -import { entity as PerUserFollowingChart } from './charts/entities/per-user-following'; -import { entity as PerUserDriveChart } from './charts/entities/per-user-drive'; +import { entity as FederationChart } from './charts/entities/federation.js'; +import { entity as NotesChart } from './charts/entities/notes.js'; +import { entity as UsersChart } from './charts/entities/users.js'; +import { entity as ActiveUsersChart } from './charts/entities/active-users.js'; +import { entity as InstanceChart } from './charts/entities/instance.js'; +import { entity as PerUserNotesChart } from './charts/entities/per-user-notes.js'; +import { entity as DriveChart } from './charts/entities/drive.js'; +import { entity as PerUserReactionsChart } from './charts/entities/per-user-reactions.js'; +import { entity as HashtagChart } from './charts/entities/hashtag.js'; +import { entity as PerUserFollowingChart } from './charts/entities/per-user-following.js'; +import { entity as PerUserDriveChart } from './charts/entities/per-user-drive.js'; +import { entity as ApRequestChart } from './charts/entities/ap-request.js'; export const entities = [ FederationChart.hour, FederationChart.day, NotesChart.hour, NotesChart.day, UsersChart.hour, UsersChart.day, - NetworkChart.hour, NetworkChart.day, ActiveUsersChart.hour, ActiveUsersChart.day, InstanceChart.hour, InstanceChart.day, PerUserNotesChart.hour, PerUserNotesChart.day, @@ -24,4 +23,5 @@ export const entities = [ HashtagChart.hour, HashtagChart.day, PerUserFollowingChart.hour, PerUserFollowingChart.day, PerUserDriveChart.hour, PerUserDriveChart.day, + ApRequestChart.hour, ApRequestChart.day, ]; diff --git a/packages/backend/src/services/chart/index.ts b/packages/backend/src/services/chart/index.ts index 0b9887b36..8bf2d8f65 100644 --- a/packages/backend/src/services/chart/index.ts +++ b/packages/backend/src/services/chart/index.ts @@ -1,22 +1,21 @@ -import { beforeShutdown } from '@/misc/before-shutdown'; +import { beforeShutdown } from '@/misc/before-shutdown.js'; -import FederationChart from './charts/federation'; -import NotesChart from './charts/notes'; -import UsersChart from './charts/users'; -import NetworkChart from './charts/network'; -import ActiveUsersChart from './charts/active-users'; -import InstanceChart from './charts/instance'; -import PerUserNotesChart from './charts/per-user-notes'; -import DriveChart from './charts/drive'; -import PerUserReactionsChart from './charts/per-user-reactions'; -import HashtagChart from './charts/hashtag'; -import PerUserFollowingChart from './charts/per-user-following'; -import PerUserDriveChart from './charts/per-user-drive'; +import FederationChart from './charts/federation.js'; +import NotesChart from './charts/notes.js'; +import UsersChart from './charts/users.js'; +import ActiveUsersChart from './charts/active-users.js'; +import InstanceChart from './charts/instance.js'; +import PerUserNotesChart from './charts/per-user-notes.js'; +import DriveChart from './charts/drive.js'; +import PerUserReactionsChart from './charts/per-user-reactions.js'; +import HashtagChart from './charts/hashtag.js'; +import PerUserFollowingChart from './charts/per-user-following.js'; +import PerUserDriveChart from './charts/per-user-drive.js'; +import ApRequestChart from './charts/ap-request.js'; export const federationChart = new FederationChart(); export const notesChart = new NotesChart(); export const usersChart = new UsersChart(); -export const networkChart = new NetworkChart(); export const activeUsersChart = new ActiveUsersChart(); export const instanceChart = new InstanceChart(); export const perUserNotesChart = new PerUserNotesChart(); @@ -25,12 +24,12 @@ export const perUserReactionsChart = new PerUserReactionsChart(); export const hashtagChart = new HashtagChart(); export const perUserFollowingChart = new PerUserFollowingChart(); export const perUserDriveChart = new PerUserDriveChart(); +export const apRequestChart = new ApRequestChart(); const charts = [ federationChart, notesChart, usersChart, - networkChart, activeUsersChart, instanceChart, perUserNotesChart, @@ -39,6 +38,7 @@ const charts = [ hashtagChart, perUserFollowingChart, perUserDriveChart, + apRequestChart, ]; // 20分おきãĢãƒĄãƒĸãƒĒæƒ…å ąã‚’DBãĢ書きčžŧãŋ diff --git a/packages/backend/src/services/create-notification.ts b/packages/backend/src/services/create-notification.ts index 1c1c1fcdf..d78e707ec 100644 --- a/packages/backend/src/services/create-notification.ts +++ b/packages/backend/src/services/create-notification.ts @@ -1,10 +1,10 @@ -import { publishMainStream } from '@/services/stream'; -import pushSw from './push-notification'; -import { Notifications, Mutings, UserProfiles, Users } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { User } from '@/models/entities/user'; -import { Notification } from '@/models/entities/notification'; -import { sendEmailNotification } from './send-email-notification'; +import { publishMainStream } from '@/services/stream.js'; +import pushSw from './push-notification.js'; +import { Notifications, Mutings, UserProfiles, Users } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { User } from '@/models/entities/user.js'; +import { Notification } from '@/models/entities/notification.js'; +import { sendEmailNotification } from './send-email-notification.js'; export async function createNotification( notifieeId: User['id'], diff --git a/packages/backend/src/services/create-system-user.ts b/packages/backend/src/services/create-system-user.ts index 82130dd59..781e0560d 100644 --- a/packages/backend/src/services/create-system-user.ts +++ b/packages/backend/src/services/create-system-user.ts @@ -1,13 +1,13 @@ -import * as bcrypt from 'bcryptjs'; +import bcrypt from 'bcryptjs'; import { v4 as uuid } from 'uuid'; -import generateNativeUserToken from '../server/api/common/generate-native-user-token'; -import { genRsaKeyPair } from '@/misc/gen-key-pair'; -import { User } from '@/models/entities/user'; -import { UserProfile } from '@/models/entities/user-profile'; -import { getConnection } from 'typeorm'; -import { genId } from '@/misc/gen-id'; -import { UserKeypair } from '@/models/entities/user-keypair'; -import { UsedUsername } from '@/models/entities/used-username'; +import generateNativeUserToken from '../server/api/common/generate-native-user-token.js'; +import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; +import { User } from '@/models/entities/user.js'; +import { UserProfile } from '@/models/entities/user-profile.js'; +import { getConnection, ObjectLiteral } from 'typeorm'; +import { genId } from '@/misc/gen-id.js'; +import { UserKeypair } from '@/models/entities/user-keypair.js'; +import { UsedUsername } from '@/models/entities/used-username.js'; export async function createSystemUser(username: string) { const password = uuid(); @@ -21,7 +21,7 @@ export async function createSystemUser(username: string) { const keyPair = await genRsaKeyPair(4096); - let account!: User; + let account!: User | ObjectLiteral; // Start transaction await getConnection().transaction(async transactionalEntityManager => { diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index a89e068f4..9f1980bff 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -1,26 +1,26 @@ -import * as fs from 'fs'; +import * as fs from 'node:fs'; import { v4 as uuid } from 'uuid'; -import { publishMainStream, publishDriveStream } from '@/services/stream'; -import { deleteFile } from './delete-file'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { GenerateVideoThumbnail } from './generate-video-thumbnail'; -import { driveLogger } from './logger'; -import { IImage, convertSharpToJpeg, convertSharpToWebp, convertSharpToPng, convertSharpToPngOrJpeg } from './image-processor'; -import { contentDisposition } from '@/misc/content-disposition'; -import { getFileInfo } from '@/misc/get-file-info'; -import { DriveFiles, DriveFolders, Users, Instances, UserProfiles } from '@/models/index'; -import { InternalStorage } from './internal-storage'; -import { DriveFile } from '@/models/entities/drive-file'; -import { IRemoteUser, User } from '@/models/entities/user'; -import { driveChart, perUserDriveChart, instanceChart } from '@/services/chart/index'; -import { genId } from '@/misc/gen-id'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error'; -import * as S3 from 'aws-sdk/clients/s3'; -import { getS3 } from './s3'; -import * as sharp from 'sharp'; -import { FILE_TYPE_BROWSERSAFE } from '@/const'; +import { publishMainStream, publishDriveStream } from '@/services/stream.js'; +import { deleteFile } from './delete-file.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { GenerateVideoThumbnail } from './generate-video-thumbnail.js'; +import { driveLogger } from './logger.js'; +import { IImage, convertSharpToJpeg, convertSharpToWebp, convertSharpToPng, convertSharpToPngOrJpeg } from './image-processor.js'; +import { contentDisposition } from '@/misc/content-disposition.js'; +import { getFileInfo } from '@/misc/get-file-info.js'; +import { DriveFiles, DriveFolders, Users, Instances, UserProfiles } from '@/models/index.js'; +import { InternalStorage } from './internal-storage.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { IRemoteUser, User } from '@/models/entities/user.js'; +import { driveChart, perUserDriveChart, instanceChart } from '@/services/chart/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; +import S3 from 'aws-sdk/clients/s3.js'; +import { getS3 } from './s3.js'; +import sharp from 'sharp'; +import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; const logger = driveLogger.createSubLogger('register', 'yellow'); @@ -160,8 +160,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool webpublic: null, thumbnail, }; - } catch (e) { - logger.warn(`GenerateVideoThumbnail failed: ${e}`); + } catch (err) { + logger.warn(`GenerateVideoThumbnail failed: ${err}`); return { webpublic: null, thumbnail: null, @@ -191,8 +191,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool thumbnail: null, }; } - } catch (e) { - logger.warn(`sharp failed: ${e}`); + } catch (err) { + logger.warn(`sharp failed: ${err}`); return { webpublic: null, thumbnail: null, @@ -215,8 +215,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool } else { logger.debug(`web image not created (not an required image)`); } - } catch (e) { - logger.warn(`web image not created (an error occured)`, e); + } catch (err) { + logger.warn(`web image not created (an error occured)`, err as Error); } } else { logger.info(`web image not created (from remote)`); @@ -234,8 +234,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool } else { logger.debug(`thumbnail not created (not an required file)`); } - } catch (e) { - logger.warn(`thumbnail not created (an error occured)`, e); + } catch (err) { + logger.warn(`thumbnail not created (an error occured)`, err as Error); } // #endregion thumbnail @@ -451,9 +451,9 @@ export async function addFile({ file.storedInternal = false; file = await DriveFiles.insert(file).then(x => DriveFiles.findOneOrFail(x.identifiers[0])); - } catch (e) { + } catch (err) { // duplicate key error (when already registered) - if (isDuplicateKeyValueError(e)) { + if (isDuplicateKeyValueError(err)) { logger.info(`already registered ${file.uri}`); file = await DriveFiles.findOne({ @@ -461,8 +461,8 @@ export async function addFile({ userId: user ? user.id : null, }) as DriveFile; } else { - logger.error(e); - throw e; + logger.error(err as Error); + throw err; } } } else { diff --git a/packages/backend/src/services/drive/delete-file.ts b/packages/backend/src/services/drive/delete-file.ts index 5cda32c7d..18f1dc970 100644 --- a/packages/backend/src/services/drive/delete-file.ts +++ b/packages/backend/src/services/drive/delete-file.ts @@ -1,10 +1,10 @@ -import { DriveFile } from '@/models/entities/drive-file'; -import { InternalStorage } from './internal-storage'; -import { DriveFiles, Instances } from '@/models/index'; -import { driveChart, perUserDriveChart, instanceChart } from '@/services/chart/index'; -import { createDeleteObjectStorageFileJob } from '@/queue/index'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { getS3 } from './s3'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { InternalStorage } from './internal-storage.js'; +import { DriveFiles, Instances } from '@/models/index.js'; +import { driveChart, perUserDriveChart, instanceChart } from '@/services/chart/index.js'; +import { createDeleteObjectStorageFileJob } from '@/queue/index.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { getS3 } from './s3.js'; import { v4 as uuid } from 'uuid'; export async function deleteFile(file: DriveFile, isExpired = false) { diff --git a/packages/backend/src/services/drive/generate-video-thumbnail.ts b/packages/backend/src/services/drive/generate-video-thumbnail.ts index e8cc952b9..04a7a8334 100644 --- a/packages/backend/src/services/drive/generate-video-thumbnail.ts +++ b/packages/backend/src/services/drive/generate-video-thumbnail.ts @@ -1,6 +1,6 @@ -import * as fs from 'fs'; +import * as fs from 'node:fs'; import * as tmp from 'tmp'; -import { IImage, convertToJpeg } from './image-processor'; +import { IImage, convertToJpeg } from './image-processor.js'; import * as FFmpeg from 'fluent-ffmpeg'; export async function GenerateVideoThumbnail(path: string): Promise { diff --git a/packages/backend/src/services/drive/image-processor.ts b/packages/backend/src/services/drive/image-processor.ts index f3c4a2abd..146dcfb6c 100644 --- a/packages/backend/src/services/drive/image-processor.ts +++ b/packages/backend/src/services/drive/image-processor.ts @@ -1,4 +1,4 @@ -import * as sharp from 'sharp'; +import sharp from 'sharp'; export type IImage = { data: Buffer; diff --git a/packages/backend/src/services/drive/internal-storage.ts b/packages/backend/src/services/drive/internal-storage.ts index fe190a028..8f76c81ca 100644 --- a/packages/backend/src/services/drive/internal-storage.ts +++ b/packages/backend/src/services/drive/internal-storage.ts @@ -1,11 +1,10 @@ -import * as fs from 'fs'; -import * as Path from 'path'; -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; -import config from '@/config/index'; +import * as fs from 'node:fs'; +import * as Path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; +import config from '@/config/index.js'; -//const _filename = fileURLToPath(import.meta.url); -const _filename = __filename; +const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); export class InternalStorage { diff --git a/packages/backend/src/services/drive/logger.ts b/packages/backend/src/services/drive/logger.ts index 655d074d6..917a8317e 100644 --- a/packages/backend/src/services/drive/logger.ts +++ b/packages/backend/src/services/drive/logger.ts @@ -1,3 +1,3 @@ -import Logger from '../logger'; +import Logger from '../logger.js'; export const driveLogger = new Logger('drive', 'blue'); diff --git a/packages/backend/src/services/drive/s3.ts b/packages/backend/src/services/drive/s3.ts index 42bf6e187..80e34be95 100644 --- a/packages/backend/src/services/drive/s3.ts +++ b/packages/backend/src/services/drive/s3.ts @@ -1,7 +1,7 @@ -import { URL } from 'url'; -import * as S3 from 'aws-sdk/clients/s3'; -import { Meta } from '@/models/entities/meta'; -import { getAgentByUrl } from '@/misc/fetch'; +import { URL } from 'node:url'; +import S3 from 'aws-sdk/clients/s3.js'; +import { Meta } from '@/models/entities/meta.js'; +import { getAgentByUrl } from '@/misc/fetch.js'; export function getS3(meta: Meta) { const u = meta.objectStorageEndpoint != null diff --git a/packages/backend/src/services/drive/upload-from-url.ts b/packages/backend/src/services/drive/upload-from-url.ts index 7c5fa5ce3..5007fff6e 100644 --- a/packages/backend/src/services/drive/upload-from-url.ts +++ b/packages/backend/src/services/drive/upload-from-url.ts @@ -1,12 +1,12 @@ -import { URL } from 'url'; -import { addFile } from './add-file'; -import { User } from '@/models/entities/user'; -import { driveLogger } from './logger'; -import { createTemp } from '@/misc/create-temp'; -import { downloadUrl } from '@/misc/download-url'; -import { DriveFolder } from '@/models/entities/drive-folder'; -import { DriveFile } from '@/models/entities/drive-file'; -import { DriveFiles } from '@/models/index'; +import { URL } from 'node:url'; +import { addFile } from './add-file.js'; +import { User } from '@/models/entities/user.js'; +import { driveLogger } from './logger.js'; +import { createTemp } from '@/misc/create-temp.js'; +import { downloadUrl } from '@/misc/download-url.js'; +import { DriveFolder } from '@/models/entities/drive-folder.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { DriveFiles } from '@/models/index.js'; const logger = driveLogger.createSubLogger('downloader'); diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index 2c401508a..f3a0424ab 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -1,11 +1,11 @@ import { DOMWindow, JSDOM } from 'jsdom'; import fetch from 'node-fetch'; -import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch'; -import { Instance } from '@/models/entities/instance'; -import { Instances } from '@/models/index'; -import { getFetchInstanceMetadataLock } from '@/misc/app-lock'; -import Logger from './logger'; -import { URL } from 'url'; +import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js'; +import { Instance } from '@/models/entities/instance.js'; +import { Instances } from '@/models/index.js'; +import { getFetchInstanceMetadataLock } from '@/misc/app-lock.js'; +import Logger from './logger.js'; +import { URL } from 'node:url'; const logger = new Logger('metadata', 'cyan'); @@ -156,7 +156,8 @@ async function fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | const url = 'https://' + instance.host; if (doc) { - const href = doc.querySelector('link[rel="icon"]')?.getAttribute('href'); + // https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043 + const href = Array.from(doc.getElementsByTagName('link')).reverse().find(link => link.relList.contains('icon'))?.href; if (href) { return (new URL(href, url)).href; @@ -186,11 +187,16 @@ async function fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | nul if (doc) { const url = 'https://' + instance.host; - const hrefAppleTouchIconPrecomposed = doc.querySelector('link[rel="apple-touch-icon-precomposed"]')?.getAttribute('href'); - const hrefAppleTouchIcon = doc.querySelector('link[rel="apple-touch-icon"]')?.getAttribute('href'); - const hrefIcon = doc.querySelector('link[rel="icon"]')?.getAttribute('href'); - - const href = hrefAppleTouchIconPrecomposed || hrefAppleTouchIcon || hrefIcon; + // https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043 + const links = Array.from(doc.getElementsByTagName('link')).reverse(); + // https://github.com/misskey-dev/misskey/pull/8220/files/0ec4eba22a914e31b86874f12448f88b3e58dd5a#r796487559 + const href = + [ + links.find(link => link.relList.contains('apple-touch-icon-precomposed'))?.href, + links.find(link => link.relList.contains('apple-touch-icon'))?.href, + links.find(link => link.relList.contains('icon'))?.href, + ] + .find(href => href); if (href) { return (new URL(href, url)).href; diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts index bc5ac275b..a41641213 100644 --- a/packages/backend/src/services/following/create.ts +++ b/packages/backend/src/services/following/create.ts @@ -1,20 +1,20 @@ -import { publishMainStream, publishUserEvent } from '@/services/stream'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderFollow from '@/remote/activitypub/renderer/follow'; -import renderAccept from '@/remote/activitypub/renderer/accept'; -import renderReject from '@/remote/activitypub/renderer/reject'; -import { deliver } from '@/queue/index'; -import createFollowRequest from './requests/create'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; -import Logger from '../logger'; -import { IdentifiableError } from '@/misc/identifiable-error'; -import { User } from '@/models/entities/user'; -import { Followings, Users, FollowRequests, Blockings, Instances, UserProfiles } from '@/models/index'; -import { instanceChart, perUserFollowingChart } from '@/services/chart/index'; -import { genId } from '@/misc/gen-id'; -import { createNotification } from '../create-notification'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error'; -import { Packed } from '@/misc/schema'; +import { publishMainStream, publishUserEvent } from '@/services/stream.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import renderAccept from '@/remote/activitypub/renderer/accept.js'; +import renderReject from '@/remote/activitypub/renderer/reject.js'; +import { deliver } from '@/queue/index.js'; +import createFollowRequest from './requests/create.js'; +import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; +import Logger from '../logger.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { User } from '@/models/entities/user.js'; +import { Followings, Users, FollowRequests, Blockings, Instances, UserProfiles } from '@/models/index.js'; +import { instanceChart, perUserFollowingChart } from '@/services/chart/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { createNotification } from '../create-notification.js'; +import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; +import { Packed } from '@/misc/schema.js'; const logger = new Logger('following/create'); diff --git a/packages/backend/src/services/following/delete.ts b/packages/backend/src/services/following/delete.ts index 9b7d72e86..d82c0be52 100644 --- a/packages/backend/src/services/following/delete.ts +++ b/packages/backend/src/services/following/delete.ts @@ -1,14 +1,14 @@ -import { publishMainStream, publishUserEvent } from '@/services/stream'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderFollow from '@/remote/activitypub/renderer/follow'; -import renderUndo from '@/remote/activitypub/renderer/undo'; -import renderReject from '@/remote/activitypub/renderer/reject'; -import { deliver } from '@/queue/index'; -import Logger from '../logger'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; -import { User } from '@/models/entities/user'; -import { Followings, Users, Instances } from '@/models/index'; -import { instanceChart, perUserFollowingChart } from '@/services/chart/index'; +import { publishMainStream, publishUserEvent } from '@/services/stream.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import renderUndo from '@/remote/activitypub/renderer/undo.js'; +import renderReject from '@/remote/activitypub/renderer/reject.js'; +import { deliver } from '@/queue/index.js'; +import Logger from '../logger.js'; +import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; +import { User } from '@/models/entities/user.js'; +import { Followings, Users, Instances } from '@/models/index.js'; +import { instanceChart, perUserFollowingChart } from '@/services/chart/index.js'; const logger = new Logger('following/delete'); diff --git a/packages/backend/src/services/following/reject.ts b/packages/backend/src/services/following/reject.ts index 1deabea4f..3b0cb2ba8 100644 --- a/packages/backend/src/services/following/reject.ts +++ b/packages/backend/src/services/following/reject.ts @@ -1,11 +1,11 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderFollow from '@/remote/activitypub/renderer/follow'; -import renderReject from '@/remote/activitypub/renderer/reject'; -import { deliver } from '@/queue/index'; -import { publishMainStream, publishUserEvent } from '@/services/stream'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user'; -import { Users, FollowRequests, Followings } from '@/models/index'; -import { decrementFollowing } from './delete'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import renderReject from '@/remote/activitypub/renderer/reject.js'; +import { deliver } from '@/queue/index.js'; +import { publishMainStream, publishUserEvent } from '@/services/stream.js'; +import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; +import { Users, FollowRequests, Followings } from '@/models/index.js'; +import { decrementFollowing } from './delete.js'; type Local = ILocalUser | { id: User['id']; host: User['host']; uri: User['host'] }; type Remote = IRemoteUser; diff --git a/packages/backend/src/services/following/requests/accept-all.ts b/packages/backend/src/services/following/requests/accept-all.ts index 06ff835c0..a240bec8f 100644 --- a/packages/backend/src/services/following/requests/accept-all.ts +++ b/packages/backend/src/services/following/requests/accept-all.ts @@ -1,6 +1,6 @@ -import accept from './accept'; -import { User } from '@/models/entities/user'; -import { FollowRequests, Users } from '@/models/index'; +import accept from './accept.js'; +import { User } from '@/models/entities/user.js'; +import { FollowRequests, Users } from '@/models/index.js'; /** * 指厚したãƒĻãƒŧã‚ļãƒŧ厛ãĻぎフりロãƒŧãƒĒクエ゚トをすずãĻæ‰ŋčĒ diff --git a/packages/backend/src/services/following/requests/accept.ts b/packages/backend/src/services/following/requests/accept.ts index fcda49758..b8113cd1b 100644 --- a/packages/backend/src/services/following/requests/accept.ts +++ b/packages/backend/src/services/following/requests/accept.ts @@ -1,12 +1,12 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderFollow from '@/remote/activitypub/renderer/follow'; -import renderAccept from '@/remote/activitypub/renderer/accept'; -import { deliver } from '@/queue/index'; -import { publishMainStream } from '@/services/stream'; -import { insertFollowingDoc } from '../create'; -import { User, ILocalUser } from '@/models/entities/user'; -import { FollowRequests, Users } from '@/models/index'; -import { IdentifiableError } from '@/misc/identifiable-error'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import renderAccept from '@/remote/activitypub/renderer/accept.js'; +import { deliver } from '@/queue/index.js'; +import { publishMainStream } from '@/services/stream.js'; +import { insertFollowingDoc } from '../create.js'; +import { User, ILocalUser } from '@/models/entities/user.js'; +import { FollowRequests, Users } from '@/models/index.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; export default async function(followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, follower: User) { const request = await FollowRequests.findOne({ diff --git a/packages/backend/src/services/following/requests/cancel.ts b/packages/backend/src/services/following/requests/cancel.ts index 53e54f2a1..ca9777d38 100644 --- a/packages/backend/src/services/following/requests/cancel.ts +++ b/packages/backend/src/services/following/requests/cancel.ts @@ -1,11 +1,11 @@ -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderFollow from '@/remote/activitypub/renderer/follow'; -import renderUndo from '@/remote/activitypub/renderer/undo'; -import { deliver } from '@/queue/index'; -import { publishMainStream } from '@/services/stream'; -import { IdentifiableError } from '@/misc/identifiable-error'; -import { User, ILocalUser } from '@/models/entities/user'; -import { Users, FollowRequests } from '@/models/index'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import renderUndo from '@/remote/activitypub/renderer/undo.js'; +import { deliver } from '@/queue/index.js'; +import { publishMainStream } from '@/services/stream.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { User, ILocalUser } from '@/models/entities/user.js'; +import { Users, FollowRequests } from '@/models/index.js'; export default async function(followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox'] }, follower: { id: User['id']; host: User['host']; uri: User['host'] }) { if (Users.isRemoteUser(followee)) { diff --git a/packages/backend/src/services/following/requests/create.ts b/packages/backend/src/services/following/requests/create.ts index e45023015..bca607d7e 100644 --- a/packages/backend/src/services/following/requests/create.ts +++ b/packages/backend/src/services/following/requests/create.ts @@ -1,11 +1,11 @@ -import { publishMainStream } from '@/services/stream'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderFollow from '@/remote/activitypub/renderer/follow'; -import { deliver } from '@/queue/index'; -import { User } from '@/models/entities/user'; -import { Blockings, FollowRequests, Users } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { createNotification } from '../../create-notification'; +import { publishMainStream } from '@/services/stream.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderFollow from '@/remote/activitypub/renderer/follow.js'; +import { deliver } from '@/queue/index.js'; +import { User } from '@/models/entities/user.js'; +import { Blockings, FollowRequests, Users } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { createNotification } from '../../create-notification.js'; export default async function(follower: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, requestId?: string) { if (follower.id === followee.id) return; diff --git a/packages/backend/src/services/i/pin.ts b/packages/backend/src/services/i/pin.ts index 167dfc10c..06d7e79e8 100644 --- a/packages/backend/src/services/i/pin.ts +++ b/packages/backend/src/services/i/pin.ts @@ -1,15 +1,15 @@ -import config from '@/config/index'; -import renderAdd from '@/remote/activitypub/renderer/add'; -import renderRemove from '@/remote/activitypub/renderer/remove'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { IdentifiableError } from '@/misc/identifiable-error'; -import { User } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { Notes, UserNotePinings, Users } from '@/models/index'; -import { UserNotePining } from '@/models/entities/user-note-pining'; -import { genId } from '@/misc/gen-id'; -import { deliverToFollowers } from '@/remote/activitypub/deliver-manager'; -import { deliverToRelays } from '../relay'; +import config from '@/config/index.js'; +import renderAdd from '@/remote/activitypub/renderer/add.js'; +import renderRemove from '@/remote/activitypub/renderer/remove.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { User } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { Notes, UserNotePinings, Users } from '@/models/index.js'; +import { UserNotePining } from '@/models/entities/user-note-pining.js'; +import { genId } from '@/misc/gen-id.js'; +import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js'; +import { deliverToRelays } from '../relay.js'; /** * 指厚した投į¨ŋをピãƒŗį•™ã‚ã—ぞす diff --git a/packages/backend/src/services/i/update.ts b/packages/backend/src/services/i/update.ts index f700d9b48..1fbaf40df 100644 --- a/packages/backend/src/services/i/update.ts +++ b/packages/backend/src/services/i/update.ts @@ -1,10 +1,10 @@ -import renderUpdate from '@/remote/activitypub/renderer/update'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { Users } from '@/models/index'; -import { User } from '@/models/entities/user'; -import { renderPerson } from '@/remote/activitypub/renderer/person'; -import { deliverToFollowers } from '@/remote/activitypub/deliver-manager'; -import { deliverToRelays } from '../relay'; +import renderUpdate from '@/remote/activitypub/renderer/update.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { Users } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; +import { renderPerson } from '@/remote/activitypub/renderer/person.js'; +import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js'; +import { deliverToRelays } from '../relay.js'; export async function publishToFollowers(userId: User['id']) { const user = await Users.findOne(userId); diff --git a/packages/backend/src/services/insert-moderation-log.ts b/packages/backend/src/services/insert-moderation-log.ts index affed4095..0a7c472d8 100644 --- a/packages/backend/src/services/insert-moderation-log.ts +++ b/packages/backend/src/services/insert-moderation-log.ts @@ -1,6 +1,6 @@ -import { ModerationLogs } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { User } from '@/models/entities/user'; +import { ModerationLogs } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { User } from '@/models/entities/user.js'; export async function insertModerationLog(moderator: { id: User['id'] }, type: string, info?: Record) { await ModerationLogs.insert({ diff --git a/packages/backend/src/services/instance-actor.ts b/packages/backend/src/services/instance-actor.ts index 6f2e32667..e27171048 100644 --- a/packages/backend/src/services/instance-actor.ts +++ b/packages/backend/src/services/instance-actor.ts @@ -1,7 +1,7 @@ -import { createSystemUser } from './create-system-user'; -import { ILocalUser } from '@/models/entities/user'; -import { Users } from '@/models/index'; -import { Cache } from '@/misc/cache'; +import { createSystemUser } from './create-system-user.js'; +import { ILocalUser } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; +import { Cache } from '@/misc/cache.js'; const ACTOR_USERNAME = 'instance.actor' as const; diff --git a/packages/backend/src/services/logger.ts b/packages/backend/src/services/logger.ts index 626cc6b44..89d6d5720 100644 --- a/packages/backend/src/services/logger.ts +++ b/packages/backend/src/services/logger.ts @@ -1,8 +1,9 @@ -import * as cluster from 'cluster'; -import * as chalk from 'chalk'; -import * as dateformat from 'dateformat'; -import { envOption } from '../env'; -import config from '@/config/index'; +import cluster from 'node:cluster'; +import chalk from 'chalk'; +import { default as convertColor } from 'color-convert'; +import { format as dateFormat } from 'date-fns'; +import { envOption } from '../env.js'; +import config from '@/config/index.js'; import * as SyslogPro from 'syslog-pro'; @@ -57,7 +58,7 @@ export default class Logger { return; } - const time = dateformat(new Date(), 'HH:MM:ss'); + const time = dateFormat(new Date(), 'HH:mm:ss'); const worker = cluster.isPrimary ? '*' : cluster.worker.id; const l = level === 'error' ? important ? chalk.bgRed.white('ERR ') : chalk.red('ERR ') : @@ -66,7 +67,7 @@ export default class Logger { level === 'debug' ? chalk.gray('VERB') : level === 'info' ? chalk.blue('INFO') : null; - const domains = [this.domain].concat(subDomains).map(d => d.color ? chalk.keyword(d.color)(d.name) : chalk.white(d.name)); + const domains = [this.domain].concat(subDomains).map(d => d.color ? chalk.rgb(...convertColor.keyword.rgb(d.color))(d.name) : chalk.white(d.name)); const m = level === 'error' ? chalk.red(message) : level === 'warning' ? chalk.yellow(message) : @@ -116,7 +117,7 @@ export default class Logger { } public debug(message: string, data?: Record | null, important = false): void { // デバッグį”¨ãĢäŊŋう(開į™ē者ãĢåŋ…čĻã ãŒåˆŠį”¨č€…ãĢ不čĻãĒæƒ…å ą) - if (process.env.NODE_ENV != 'production' || envOption.verbose) { + if (process.env.NODE_ENV !== 'production' || envOption.verbose) { this.log('debug', message, data, important); } } diff --git a/packages/backend/src/services/messages/create.ts b/packages/backend/src/services/messages/create.ts index e1bef09a7..c3908b255 100644 --- a/packages/backend/src/services/messages/create.ts +++ b/packages/backend/src/services/messages/create.ts @@ -1,19 +1,19 @@ -import { User } from '@/models/entities/user'; -import { UserGroup } from '@/models/entities/user-group'; -import { DriveFile } from '@/models/entities/drive-file'; -import { MessagingMessages, UserGroupJoinings, Mutings, Users } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { publishMessagingStream, publishMessagingIndexStream, publishMainStream, publishGroupMessagingStream } from '@/services/stream'; -import pushNotification from '../push-notification'; +import { User } from '@/models/entities/user.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { MessagingMessages, UserGroupJoinings, Mutings, Users } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import { publishMessagingStream, publishMessagingIndexStream, publishMainStream, publishGroupMessagingStream } from '@/services/stream.js'; +import pushNotification from '../push-notification.js'; import { Not } from 'typeorm'; -import { Note } from '@/models/entities/note'; -import renderNote from '@/remote/activitypub/renderer/note'; -import renderCreate from '@/remote/activitypub/renderer/create'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { deliver } from '@/queue/index'; +import { Note } from '@/models/entities/note.js'; +import renderNote from '@/remote/activitypub/renderer/note.js'; +import renderCreate from '@/remote/activitypub/renderer/create.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { deliver } from '@/queue/index.js'; -export async function createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: User | undefined, recipientGroup: UserGroup | undefined, text: string | undefined, file: DriveFile | null, uri?: string) { +export async function createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: User | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) { const message = { id: genId(), createdAt: new Date(), diff --git a/packages/backend/src/services/messages/delete.ts b/packages/backend/src/services/messages/delete.ts index 5c299c9a5..82eb6cb21 100644 --- a/packages/backend/src/services/messages/delete.ts +++ b/packages/backend/src/services/messages/delete.ts @@ -1,11 +1,11 @@ -import config from '@/config/index'; -import { MessagingMessages, Users } from '@/models/index'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { publishGroupMessagingStream, publishMessagingStream } from '@/services/stream'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderDelete from '@/remote/activitypub/renderer/delete'; -import renderTombstone from '@/remote/activitypub/renderer/tombstone'; -import { deliver } from '@/queue/index'; +import config from '@/config/index.js'; +import { MessagingMessages, Users } from '@/models/index.js'; +import { MessagingMessage } from '@/models/entities/messaging-message.js'; +import { publishGroupMessagingStream, publishMessagingStream } from '@/services/stream.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderDelete from '@/remote/activitypub/renderer/delete.js'; +import renderTombstone from '@/remote/activitypub/renderer/tombstone.js'; +import { deliver } from '@/queue/index.js'; export async function deleteMessage(message: MessagingMessage) { await MessagingMessages.delete(message.id); diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index fb22bd659..ed242a0b5 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -1,39 +1,39 @@ import * as mfm from 'mfm-js'; -import es from '../../db/elasticsearch'; -import { publishMainStream, publishNotesStream } from '@/services/stream'; -import DeliverManager from '@/remote/activitypub/deliver-manager'; -import renderNote from '@/remote/activitypub/renderer/note'; -import renderCreate from '@/remote/activitypub/renderer/create'; -import renderAnnounce from '@/remote/activitypub/renderer/announce'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { resolveUser } from '@/remote/resolve-user'; -import config from '@/config/index'; -import { updateHashtags } from '../update-hashtag'; -import { concat } from '@/prelude/array'; -import { insertNoteUnread } from '@/services/note/unread'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; -import { extractMentions } from '@/misc/extract-mentions'; -import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm'; -import { extractHashtags } from '@/misc/extract-hashtags'; -import { Note, IMentionedRemoteUsers } from '@/models/entities/note'; -import { Mutings, Users, NoteWatchings, Notes, Instances, UserProfiles, Antennas, Followings, MutedNotes, Channels, ChannelFollowings, Blockings, NoteThreadMutings } from '@/models/index'; -import { DriveFile } from '@/models/entities/drive-file'; -import { App } from '@/models/entities/app'; +import es from '../../db/elasticsearch.js'; +import { publishMainStream, publishNotesStream } from '@/services/stream.js'; +import DeliverManager from '@/remote/activitypub/deliver-manager.js'; +import renderNote from '@/remote/activitypub/renderer/note.js'; +import renderCreate from '@/remote/activitypub/renderer/create.js'; +import renderAnnounce from '@/remote/activitypub/renderer/announce.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { resolveUser } from '@/remote/resolve-user.js'; +import config from '@/config/index.js'; +import { updateHashtags } from '../update-hashtag.js'; +import { concat } from '@/prelude/array.js'; +import { insertNoteUnread } from '@/services/note/unread.js'; +import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; +import { extractMentions } from '@/misc/extract-mentions.js'; +import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js'; +import { extractHashtags } from '@/misc/extract-hashtags.js'; +import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; +import { Mutings, Users, NoteWatchings, Notes, Instances, UserProfiles, Antennas, Followings, MutedNotes, Channels, ChannelFollowings, Blockings, NoteThreadMutings } from '@/models/index.js'; +import { DriveFile } from '@/models/entities/drive-file.js'; +import { App } from '@/models/entities/app.js'; import { Not, getConnection, In } from 'typeorm'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user'; -import { genId } from '@/misc/gen-id'; -import { notesChart, perUserNotesChart, activeUsersChart, instanceChart } from '@/services/chart/index'; -import { Poll, IPoll } from '@/models/entities/poll'; -import { createNotification } from '../create-notification'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error'; -import { checkHitAntenna } from '@/misc/check-hit-antenna'; -import { checkWordMute } from '@/misc/check-word-mute'; -import { addNoteToAntenna } from '../add-note-to-antenna'; -import { countSameRenotes } from '@/misc/count-same-renotes'; -import { deliverToRelays } from '../relay'; -import { Channel } from '@/models/entities/channel'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; -import { getAntennas } from '@/misc/antenna-cache'; +import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; +import { genId } from '@/misc/gen-id.js'; +import { notesChart, perUserNotesChart, activeUsersChart, instanceChart } from '@/services/chart/index.js'; +import { Poll, IPoll } from '@/models/entities/poll.js'; +import { createNotification } from '../create-notification.js'; +import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; +import { checkHitAntenna } from '@/misc/check-hit-antenna.js'; +import { checkWordMute } from '@/misc/check-word-mute.js'; +import { addNoteToAntenna } from '../add-note-to-antenna.js'; +import { countSameRenotes } from '@/misc/count-same-renotes.js'; +import { deliverToRelays } from '../relay.js'; +import { Channel } from '@/models/entities/channel.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import { getAntennas } from '@/misc/antenna-cache.js'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; @@ -59,7 +59,7 @@ class NotificationManager { if (exist) { // ã€ŒãƒĄãƒŗã‚ˇãƒ§ãƒŗされãĻいるかつčŋ”äŋĄã•ã‚ŒãĻã„ã‚‹ã€å ´åˆã¯ã€ãƒĄãƒŗã‚ˇãƒ§ãƒŗとしãĻぎ通įŸĨではãĒくčŋ”äŋĄã¨ã—ãĻぎ通įŸĨãĢする - if (reason != 'mention') { + if (reason !== 'mention') { exist.reason = reason; } } else { @@ -111,7 +111,7 @@ type Option = { app?: App | null; }; -export default async (user: { id: User['id']; username: User['username']; host: User['host']; isSilenced: User['isSilenced']; }, data: Option, silent = false) => new Promise(async (res, rej) => { +export default async (user: { id: User['id']; username: User['username']; host: User['host']; isSilenced: User['isSilenced']; createdAt: User['createdAt']; }, data: Option, silent = false) => new Promise(async (res, rej) => { // チãƒŖãƒŗネãƒĢ外ãĢãƒĒãƒ—ãƒŠã‚¤ã—ãŸã‚‰å¯žčąĄãŽã‚šã‚ŗãƒŧプãĢ合わせる // (クナイã‚ĸãƒŗトã‚ĩイドでやãŖãĻã‚‚č‰¯ã„å‡Ļį†ã ã¨æ€ã†ã‘おとりあえずã‚ĩãƒŧバãƒŧã‚ĩイドで) if (data.reply && data.channel && data.reply.channelId !== data.channel.id) { @@ -201,7 +201,7 @@ export default async (user: { id: User['id']; username: User['username']; host: mentionedUsers.push(await Users.findOneOrFail(data.reply.userId)); } - if (data.visibility == 'specified') { + if (data.visibility === 'specified') { if (data.visibleUsers == null) throw new Error('invalid param'); for (const u of data.visibleUsers) { @@ -297,11 +297,10 @@ export default async (user: { id: User['id']; username: User['username']; host: } if (!silent) { - // ロãƒŧã‚ĢãƒĢãƒĻãƒŧã‚ļãƒŧぎチãƒŖãƒŧトはã‚ŋイムナイãƒŗ取垗時ãĢ更新しãĻいるぎでãƒĒãƒĸãƒŧトãƒĻãƒŧã‚ļãƒŧぎ場合だけでよい - if (Users.isRemoteUser(user)) activeUsersChart.update(user); + if (Users.isLocalUser(user)) activeUsersChart.write(user); // æœĒčĒ­é€šįŸĨをäŊœæˆ - if (data.visibility == 'specified') { + if (data.visibility === 'specified') { if (data.visibleUsers == null) throw new Error('invalid param'); for (const u of data.visibleUsers) { @@ -439,7 +438,7 @@ export default async (user: { id: User['id']; username: User['username']; host: async function renderNoteOrRenoteActivity(data: Option, note: Note) { if (data.localOnly) return null; - const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length == 0) + const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0) ? renderAnnounce(data.renote.uri ? data.renote.uri : `${config.url}/notes/${data.renote.id}`, note) : renderCreate(await renderNote(note, false), note); @@ -478,7 +477,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O userId: user.id, localOnly: data.localOnly!, visibility: data.visibility as any, - visibleUserIds: data.visibility == 'specified' + visibleUserIds: data.visibility === 'specified' ? data.visibleUsers ? data.visibleUsers.map(u => u.id) : [] @@ -502,7 +501,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O insert.mentions = mentionedUsers.map(u => u.id); const profiles = await UserProfiles.find({ userId: In(insert.mentions) }); insert.mentionedRemoteUsers = JSON.stringify(mentionedUsers.filter(u => Users.isRemoteUser(u)).map(u => { - const profile = profiles.find(p => p.userId == u.id); + const profile = profiles.find(p => p.userId === u.id); const url = profile != null ? profile.url : null; return { uri: u.uri, diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index 64383ee92..cf23656f8 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -1,18 +1,18 @@ -import { publishNoteStream } from '@/services/stream'; -import renderDelete from '@/remote/activitypub/renderer/delete'; -import renderAnnounce from '@/remote/activitypub/renderer/announce'; -import renderUndo from '@/remote/activitypub/renderer/undo'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderTombstone from '@/remote/activitypub/renderer/tombstone'; -import config from '@/config/index'; -import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; -import { User, ILocalUser, IRemoteUser } from '@/models/entities/user'; -import { Note, IMentionedRemoteUsers } from '@/models/entities/note'; -import { Notes, Users, Instances } from '@/models/index'; -import { notesChart, perUserNotesChart, instanceChart } from '@/services/chart/index'; -import { deliverToFollowers, deliverToUser } from '@/remote/activitypub/deliver-manager'; -import { countSameRenotes } from '@/misc/count-same-renotes'; -import { deliverToRelays } from '../relay'; +import { publishNoteStream } from '@/services/stream.js'; +import renderDelete from '@/remote/activitypub/renderer/delete.js'; +import renderAnnounce from '@/remote/activitypub/renderer/announce.js'; +import renderUndo from '@/remote/activitypub/renderer/undo.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderTombstone from '@/remote/activitypub/renderer/tombstone.js'; +import config from '@/config/index.js'; +import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; +import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; +import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; +import { Notes, Users, Instances } from '@/models/index.js'; +import { notesChart, perUserNotesChart, instanceChart } from '@/services/chart/index.js'; +import { deliverToFollowers, deliverToUser } from '@/remote/activitypub/deliver-manager.js'; +import { countSameRenotes } from '@/misc/count-same-renotes.js'; +import { deliverToRelays } from '../relay.js'; import { Brackets, In } from 'typeorm'; /** @@ -39,7 +39,7 @@ export default async function(user: User, note: Note, quiet = false) { let renote: Note | undefined; // if deletd note is renote - if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length == 0)) { + if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { renote = await Notes.findOne({ id: note.renoteId, }); diff --git a/packages/backend/src/services/note/polls/update.ts b/packages/backend/src/services/note/polls/update.ts index a22ce8e37..88baf16b6 100644 --- a/packages/backend/src/services/note/polls/update.ts +++ b/packages/backend/src/services/note/polls/update.ts @@ -1,10 +1,10 @@ -import renderUpdate from '@/remote/activitypub/renderer/update'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import renderNote from '@/remote/activitypub/renderer/note'; -import { Users, Notes } from '@/models/index'; -import { Note } from '@/models/entities/note'; -import { deliverToFollowers } from '@/remote/activitypub/deliver-manager'; -import { deliverToRelays } from '../../relay'; +import renderUpdate from '@/remote/activitypub/renderer/update.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderNote from '@/remote/activitypub/renderer/note.js'; +import { Users, Notes } from '@/models/index.js'; +import { Note } from '@/models/entities/note.js'; +import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js'; +import { deliverToRelays } from '../../relay.js'; export async function deliverQuestionUpdate(noteId: Note['id']) { const note = await Notes.findOne(noteId); diff --git a/packages/backend/src/services/note/polls/vote.ts b/packages/backend/src/services/note/polls/vote.ts index 25c62f3e3..9b83b1953 100644 --- a/packages/backend/src/services/note/polls/vote.ts +++ b/packages/backend/src/services/note/polls/vote.ts @@ -1,10 +1,10 @@ -import { publishNoteStream } from '@/services/stream'; -import { User } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { PollVotes, NoteWatchings, Polls, Blockings } from '@/models/index'; +import { publishNoteStream } from '@/services/stream.js'; +import { User } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { PollVotes, NoteWatchings, Polls, Blockings } from '@/models/index.js'; import { Not } from 'typeorm'; -import { genId } from '@/misc/gen-id'; -import { createNotification } from '../../create-notification'; +import { genId } from '@/misc/gen-id.js'; +import { createNotification } from '../../create-notification.js'; export default async function(user: User, note: Note, choice: number) { const poll = await Polls.findOne(note.id); diff --git a/packages/backend/src/services/note/reaction/create.ts b/packages/backend/src/services/note/reaction/create.ts index 47f46419d..236aa7993 100644 --- a/packages/backend/src/services/note/reaction/create.ts +++ b/packages/backend/src/services/note/reaction/create.ts @@ -1,19 +1,19 @@ -import { publishNoteStream } from '@/services/stream'; -import { renderLike } from '@/remote/activitypub/renderer/like'; -import DeliverManager from '@/remote/activitypub/deliver-manager'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { toDbReaction, decodeReaction } from '@/misc/reaction-lib'; -import { User, IRemoteUser } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { NoteReactions, Users, NoteWatchings, Notes, Emojis, Blockings } from '@/models/index'; +import { publishNoteStream } from '@/services/stream.js'; +import { renderLike } from '@/remote/activitypub/renderer/like.js'; +import DeliverManager from '@/remote/activitypub/deliver-manager.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { toDbReaction, decodeReaction } from '@/misc/reaction-lib.js'; +import { User, IRemoteUser } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { NoteReactions, Users, NoteWatchings, Notes, Emojis, Blockings } from '@/models/index.js'; import { Not } from 'typeorm'; -import { perUserReactionsChart } from '@/services/chart/index'; -import { genId } from '@/misc/gen-id'; -import { createNotification } from '../../create-notification'; -import deleteReaction from './delete'; -import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error'; -import { NoteReaction } from '@/models/entities/note-reaction'; -import { IdentifiableError } from '@/misc/identifiable-error'; +import { perUserReactionsChart } from '@/services/chart/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { createNotification } from '../../create-notification.js'; +import deleteReaction from './delete.js'; +import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; +import { NoteReaction } from '@/models/entities/note-reaction.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; export default async (user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string) => { // Check blocking @@ -76,7 +76,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, // ã‚Ģã‚šã‚ŋムįĩĩ文字ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗだãŖたらįĩĩæ–‡å­—æƒ…å ąã‚‚é€ã‚‹ const decodedReaction = decodeReaction(reaction); - let emoji = await Emojis.findOne({ + const emoji = await Emojis.findOne({ where: { name: decodedReaction.name, host: decodedReaction.host, diff --git a/packages/backend/src/services/note/reaction/delete.ts b/packages/backend/src/services/note/reaction/delete.ts index 21af81953..62b00f56f 100644 --- a/packages/backend/src/services/note/reaction/delete.ts +++ b/packages/backend/src/services/note/reaction/delete.ts @@ -1,13 +1,13 @@ -import { publishNoteStream } from '@/services/stream'; -import { renderLike } from '@/remote/activitypub/renderer/like'; -import renderUndo from '@/remote/activitypub/renderer/undo'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import DeliverManager from '@/remote/activitypub/deliver-manager'; -import { IdentifiableError } from '@/misc/identifiable-error'; -import { User, IRemoteUser } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { NoteReactions, Users, Notes } from '@/models/index'; -import { decodeReaction } from '@/misc/reaction-lib'; +import { publishNoteStream } from '@/services/stream.js'; +import { renderLike } from '@/remote/activitypub/renderer/like.js'; +import renderUndo from '@/remote/activitypub/renderer/undo.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import DeliverManager from '@/remote/activitypub/deliver-manager.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { User, IRemoteUser } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { NoteReactions, Users, Notes } from '@/models/index.js'; +import { decodeReaction } from '@/misc/reaction-lib.js'; export default async (user: { id: User['id']; host: User['host']; }, note: Note) => { // if already unreacted diff --git a/packages/backend/src/services/note/read.ts b/packages/backend/src/services/note/read.ts index aaf1c5ed7..28827c596 100644 --- a/packages/backend/src/services/note/read.ts +++ b/packages/backend/src/services/note/read.ts @@ -1,13 +1,13 @@ -import { publishMainStream } from '@/services/stream'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; -import { NoteUnreads, AntennaNotes, Users, Followings, ChannelFollowings } from '@/models/index'; +import { publishMainStream } from '@/services/stream.js'; +import { Note } from '@/models/entities/note.js'; +import { User } from '@/models/entities/user.js'; +import { NoteUnreads, AntennaNotes, Users, Followings, ChannelFollowings } from '@/models/index.js'; import { Not, IsNull, In } from 'typeorm'; -import { Channel } from '@/models/entities/channel'; -import { checkHitAntenna } from '@/misc/check-hit-antenna'; -import { getAntennas } from '@/misc/antenna-cache'; -import { readNotificationByQuery } from '@/server/api/common/read-notification'; -import { Packed } from '@/misc/schema'; +import { Channel } from '@/models/entities/channel.js'; +import { checkHitAntenna } from '@/misc/check-hit-antenna.js'; +import { getAntennas } from '@/misc/antenna-cache.js'; +import { readNotificationByQuery } from '@/server/api/common/read-notification.js'; +import { Packed } from '@/misc/schema.js'; /** * Mark notes as read @@ -52,7 +52,7 @@ export default async function( if (note.user != null) { // たãļんnullãĢãĒることはį„Ąã„はずだけお一åŋœ for (const antenna of myAntennas) { - if (await checkHitAntenna(antenna, note, note.user as any, undefined, Array.from(following))) { + if (await checkHitAntenna(antenna, note, note.user, undefined, Array.from(following))) { readAntennaNotes.push(note); } } diff --git a/packages/backend/src/services/note/unread.ts b/packages/backend/src/services/note/unread.ts index 0b2b5b8d7..ef95dc7e8 100644 --- a/packages/backend/src/services/note/unread.ts +++ b/packages/backend/src/services/note/unread.ts @@ -1,8 +1,8 @@ -import { Note } from '@/models/entities/note'; -import { publishMainStream } from '@/services/stream'; -import { User } from '@/models/entities/user'; -import { Mutings, NoteThreadMutings, NoteUnreads } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import { Note } from '@/models/entities/note.js'; +import { publishMainStream } from '@/services/stream.js'; +import { User } from '@/models/entities/user.js'; +import { Mutings, NoteThreadMutings, NoteUnreads } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export async function insertNoteUnread(userId: User['id'], note: Note, params: { // NOTE: isSpecifiedがtrueãĒらisMentionedはåŋ…ずfalse diff --git a/packages/backend/src/services/note/unwatch.ts b/packages/backend/src/services/note/unwatch.ts index befdb2aa7..3964b2ba5 100644 --- a/packages/backend/src/services/note/unwatch.ts +++ b/packages/backend/src/services/note/unwatch.ts @@ -1,6 +1,6 @@ -import { User } from '@/models/entities/user'; -import { NoteWatchings } from '@/models/index'; -import { Note } from '@/models/entities/note'; +import { User } from '@/models/entities/user.js'; +import { NoteWatchings } from '@/models/index.js'; +import { Note } from '@/models/entities/note.js'; export default async (me: User['id'], note: Note) => { await NoteWatchings.delete({ diff --git a/packages/backend/src/services/note/watch.ts b/packages/backend/src/services/note/watch.ts index ebaaf3593..2210c44a7 100644 --- a/packages/backend/src/services/note/watch.ts +++ b/packages/backend/src/services/note/watch.ts @@ -1,8 +1,8 @@ -import { User } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { NoteWatchings } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { NoteWatching } from '@/models/entities/note-watching'; +import { User } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { NoteWatchings } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { NoteWatching } from '@/models/entities/note-watching.js'; export default async (me: User['id'], note: Note) => { // č‡Ē分ぎ投į¨ŋはwatchできãĒい diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index 2133768a9..8d5c09e6a 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -1,9 +1,9 @@ -import * as push from 'web-push'; -import config from '@/config/index'; -import { SwSubscriptions } from '@/models/index'; -import { fetchMeta } from '@/misc/fetch-meta'; -import { Packed } from '@/misc/schema'; -import { getNoteSummary } from '@/misc/get-note-summary'; +import push from 'web-push'; +import config from '@/config/index.js'; +import { SwSubscriptions } from '@/models/index.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Packed } from '@/misc/schema.js'; +import { getNoteSummary } from '@/misc/get-note-summary.js'; type notificationType = 'notification' | 'unreadMessagingMessage'; type notificationBody = Packed<'Notification'> | Packed<'MessagingMessage'>; diff --git a/packages/backend/src/services/register-or-fetch-instance-doc.ts b/packages/backend/src/services/register-or-fetch-instance-doc.ts index 18b42ed15..152930dbd 100644 --- a/packages/backend/src/services/register-or-fetch-instance-doc.ts +++ b/packages/backend/src/services/register-or-fetch-instance-doc.ts @@ -1,9 +1,8 @@ -import { Instance } from '@/models/entities/instance'; -import { Instances } from '@/models/index'; -import { federationChart } from '@/services/chart/index'; -import { genId } from '@/misc/gen-id'; -import { toPuny } from '@/misc/convert-host'; -import { Cache } from '@/misc/cache'; +import { Instance } from '@/models/entities/instance.js'; +import { Instances } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { toPuny } from '@/misc/convert-host.js'; +import { Cache } from '@/misc/cache.js'; const cache = new Cache(1000 * 60 * 60); @@ -23,8 +22,6 @@ export async function registerOrFetchInstanceDoc(host: string): Promise Instances.findOneOrFail(x.identifiers[0])); - federationChart.update(true); - cache.set(host, i); return i; } else { diff --git a/packages/backend/src/services/relay.ts b/packages/backend/src/services/relay.ts index 33a5ef7f9..6f0da503f 100644 --- a/packages/backend/src/services/relay.ts +++ b/packages/backend/src/services/relay.ts @@ -1,11 +1,11 @@ -import { createSystemUser } from './create-system-user'; -import { renderFollowRelay } from '@/remote/activitypub/renderer/follow-relay'; -import { renderActivity, attachLdSignature } from '@/remote/activitypub/renderer/index'; -import renderUndo from '@/remote/activitypub/renderer/undo'; -import { deliver } from '@/queue/index'; -import { ILocalUser, User } from '@/models/entities/user'; -import { Users, Relays } from '@/models/index'; -import { genId } from '@/misc/gen-id'; +import { createSystemUser } from './create-system-user.js'; +import { renderFollowRelay } from '@/remote/activitypub/renderer/follow-relay.js'; +import { renderActivity, attachLdSignature } from '@/remote/activitypub/renderer/index.js'; +import renderUndo from '@/remote/activitypub/renderer/undo.js'; +import { deliver } from '@/queue/index.js'; +import { ILocalUser, User } from '@/models/entities/user.js'; +import { Users, Relays } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; const ACTOR_USERNAME = 'relay.actor' as const; diff --git a/packages/backend/src/services/send-email-notification.ts b/packages/backend/src/services/send-email-notification.ts index 157bacb46..debaf3476 100644 --- a/packages/backend/src/services/send-email-notification.ts +++ b/packages/backend/src/services/send-email-notification.ts @@ -1,28 +1,33 @@ -import { UserProfiles } from '@/models/index'; -import { User } from '@/models/entities/user'; -import { sendEmail } from './send-email'; -import { I18n } from '@/misc/i18n'; -import * as Acct from 'misskey-js/built/acct'; -const locales = require('../../../../locales/index.js'); +import { UserProfiles } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; +import { sendEmail } from './send-email.js'; +import { I18n } from '@/misc/i18n.js'; +import * as Acct from '@/misc/acct.js'; +// TODO +//const locales = await import('../../../../locales/index.js'); // TODO: locale ãƒ•ã‚Ąã‚¤ãƒĢをクナイã‚ĸãƒŗトį”¨ã¨ã‚ĩãƒŧバãƒŧį”¨ã§åˆ†ã‘たい async function follow(userId: User['id'], follower: User) { + /* const userProfile = await UserProfiles.findOneOrFail({ userId: userId }); if (!userProfile.email || !userProfile.emailNotificationTypes.includes('follow')) return; const locale = locales[userProfile.lang || 'ja-JP']; const i18n = new I18n(locale); // TODO: render user information html sendEmail(userProfile.email, i18n.t('_email._follow.title'), `${follower.name} (@${Acct.toString(follower)})`, `${follower.name} (@${Acct.toString(follower)})`); + */ } async function receiveFollowRequest(userId: User['id'], follower: User) { + /* const userProfile = await UserProfiles.findOneOrFail({ userId: userId }); if (!userProfile.email || !userProfile.emailNotificationTypes.includes('receiveFollowRequest')) return; const locale = locales[userProfile.lang || 'ja-JP']; const i18n = new I18n(locale); // TODO: render user information html sendEmail(userProfile.email, i18n.t('_email._receiveFollowRequest.title'), `${follower.name} (@${Acct.toString(follower)})`, `${follower.name} (@${Acct.toString(follower)})`); + */ } export const sendEmailNotification = { diff --git a/packages/backend/src/services/send-email.ts b/packages/backend/src/services/send-email.ts index f5f36148f..b35d22548 100644 --- a/packages/backend/src/services/send-email.ts +++ b/packages/backend/src/services/send-email.ts @@ -1,7 +1,7 @@ import * as nodemailer from 'nodemailer'; -import { fetchMeta } from '@/misc/fetch-meta'; -import Logger from './logger'; -import config from '@/config/index'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import Logger from './logger.js'; +import config from '@/config/index.js'; export const logger = new Logger('email'); @@ -114,9 +114,9 @@ export async function sendEmail(to: string, subject: string, html: string, text: `, }); - logger.info('Message sent: %s', info.messageId); - } catch (e) { - logger.error(e); - throw e; + logger.info(`Message sent: ${info.messageId}`); + } catch (err) { + logger.error(err as Error); + throw err; } } diff --git a/packages/backend/src/services/stream.ts b/packages/backend/src/services/stream.ts index c0cefe9af..9fa2b9713 100644 --- a/packages/backend/src/services/stream.ts +++ b/packages/backend/src/services/stream.ts @@ -1,11 +1,11 @@ -import { redisClient } from '../db/redis'; -import { User } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { UserList } from '@/models/entities/user-list'; -import { UserGroup } from '@/models/entities/user-group'; -import config from '@/config/index'; -import { Antenna } from '@/models/entities/antenna'; -import { Channel } from '@/models/entities/channel'; +import { redisClient } from '../db/redis.js'; +import { User } from '@/models/entities/user.js'; +import { Note } from '@/models/entities/note.js'; +import { UserList } from '@/models/entities/user-list.js'; +import { UserGroup } from '@/models/entities/user-group.js'; +import config from '@/config/index.js'; +import { Antenna } from '@/models/entities/antenna.js'; +import { Channel } from '@/models/entities/channel.js'; import { StreamChannels, AdminStreamTypes, @@ -21,8 +21,8 @@ import { NoteStreamTypes, UserListStreamTypes, UserStreamTypes, -} from '@/server/api/stream/types'; -import { Packed } from '@/misc/schema'; +} from '@/server/api/stream/types.js'; +import { Packed } from '@/misc/schema.js'; class Publisher { private publish = (channel: StreamChannels, type: string | null, value?: any): void => { diff --git a/packages/backend/src/services/suspend-user.ts b/packages/backend/src/services/suspend-user.ts index 262c8df5b..033311a3c 100644 --- a/packages/backend/src/services/suspend-user.ts +++ b/packages/backend/src/services/suspend-user.ts @@ -1,9 +1,9 @@ -import renderDelete from '@/remote/activitypub/renderer/delete'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { deliver } from '@/queue/index'; -import config from '@/config/index'; -import { User } from '@/models/entities/user'; -import { Users, Followings } from '@/models/index'; +import renderDelete from '@/remote/activitypub/renderer/delete.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { deliver } from '@/queue/index.js'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; +import { Users, Followings } from '@/models/index.js'; import { Not, IsNull } from 'typeorm'; export async function doPostSuspend(user: { id: User['id']; host: User['host'] }) { diff --git a/packages/backend/src/services/unsuspend-user.ts b/packages/backend/src/services/unsuspend-user.ts index 04ad65a36..3be081d0e 100644 --- a/packages/backend/src/services/unsuspend-user.ts +++ b/packages/backend/src/services/unsuspend-user.ts @@ -1,10 +1,10 @@ -import renderDelete from '@/remote/activitypub/renderer/delete'; -import renderUndo from '@/remote/activitypub/renderer/undo'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { deliver } from '@/queue/index'; -import config from '@/config/index'; -import { User } from '@/models/entities/user'; -import { Users, Followings } from '@/models/index'; +import renderDelete from '@/remote/activitypub/renderer/delete.js'; +import renderUndo from '@/remote/activitypub/renderer/undo.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import { deliver } from '@/queue/index.js'; +import config from '@/config/index.js'; +import { User } from '@/models/entities/user.js'; +import { Users, Followings } from '@/models/index.js'; import { Not, IsNull } from 'typeorm'; export async function doPostUnsuspend(user: User) { diff --git a/packages/backend/src/services/update-hashtag.ts b/packages/backend/src/services/update-hashtag.ts index e8504f6ff..b6fb38bc5 100644 --- a/packages/backend/src/services/update-hashtag.ts +++ b/packages/backend/src/services/update-hashtag.ts @@ -1,9 +1,9 @@ -import { User } from '@/models/entities/user'; -import { Hashtags, Users } from '@/models/index'; -import { hashtagChart } from '@/services/chart/index'; -import { genId } from '@/misc/gen-id'; -import { Hashtag } from '@/models/entities/hashtag'; -import { normalizeForSearch } from '@/misc/normalize-for-search'; +import { User } from '@/models/entities/user.js'; +import { Hashtags, Users } from '@/models/index.js'; +import { hashtagChart } from '@/services/chart/index.js'; +import { genId } from '@/misc/gen-id.js'; +import { Hashtag } from '@/models/entities/hashtag.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; export async function updateHashtags(user: { id: User['id']; host: User['host']; }, tags: string[]) { for (const tag of tags) { diff --git a/packages/backend/src/services/user-list/push.ts b/packages/backend/src/services/user-list/push.ts index 2b862ca9c..d073afcd3 100644 --- a/packages/backend/src/services/user-list/push.ts +++ b/packages/backend/src/services/user-list/push.ts @@ -1,11 +1,11 @@ -import { publishUserListStream } from '@/services/stream'; -import { User } from '@/models/entities/user'; -import { UserList } from '@/models/entities/user-list'; -import { UserListJoinings, Users } from '@/models/index'; -import { UserListJoining } from '@/models/entities/user-list-joining'; -import { genId } from '@/misc/gen-id'; -import { fetchProxyAccount } from '@/misc/fetch-proxy-account'; -import createFollowing from '../following/create'; +import { publishUserListStream } from '@/services/stream.js'; +import { User } from '@/models/entities/user.js'; +import { UserList } from '@/models/entities/user-list.js'; +import { UserListJoinings, Users } from '@/models/index.js'; +import { UserListJoining } from '@/models/entities/user-list-joining.js'; +import { genId } from '@/misc/gen-id.js'; +import { fetchProxyAccount } from '@/misc/fetch-proxy-account.js'; +import createFollowing from '../following/create.js'; export async function pushUserToUserList(target: User, list: UserList) { await UserListJoinings.insert({ diff --git a/packages/backend/src/services/validate-email-for-account.ts b/packages/backend/src/services/validate-email-for-account.ts index 1d039fb26..3c49d37ee 100644 --- a/packages/backend/src/services/validate-email-for-account.ts +++ b/packages/backend/src/services/validate-email-for-account.ts @@ -1,5 +1,5 @@ import validateEmail from 'deep-email-validator'; -import { UserProfiles } from '@/models'; +import { UserProfiles } from '@/models/index.js'; export async function validateEmailForAccount(emailAddress: string): Promise<{ available: boolean; diff --git a/packages/backend/src/tools/accept-migration.ts b/packages/backend/src/tools/accept-migration.ts index 2e54fc129..adbfcdadf 100644 --- a/packages/backend/src/tools/accept-migration.ts +++ b/packages/backend/src/tools/accept-migration.ts @@ -1,7 +1,7 @@ // ex) node built/tools/accept-migration Yo 1000000000001 import { createConnection } from 'typeorm'; -import config from '@/config/index'; +import config from '@/config/index.js'; createConnection({ type: 'postgres', diff --git a/packages/backend/src/tools/demote-admin.ts b/packages/backend/src/tools/demote-admin.ts index 45e32b513..7f6722247 100644 --- a/packages/backend/src/tools/demote-admin.ts +++ b/packages/backend/src/tools/demote-admin.ts @@ -1,4 +1,4 @@ -import { initDb } from '../db/postgre'; +import { initDb } from '../db/postgre.js'; async function main(username: string) { if (!username) throw `username required`; diff --git a/packages/backend/src/tools/mark-admin.ts b/packages/backend/src/tools/mark-admin.ts index 88d59518a..630179e7a 100644 --- a/packages/backend/src/tools/mark-admin.ts +++ b/packages/backend/src/tools/mark-admin.ts @@ -1,4 +1,4 @@ -import { initDb } from '../db/postgre'; +import { initDb } from '../db/postgre.js'; async function main(username: string) { if (!username) throw `username required`; diff --git a/packages/backend/src/tools/refresh-question.ts b/packages/backend/src/tools/refresh-question.ts index 3bbb781ae..0111a2257 100644 --- a/packages/backend/src/tools/refresh-question.ts +++ b/packages/backend/src/tools/refresh-question.ts @@ -1,4 +1,4 @@ -import { initDb } from '@/db/postgre'; +import { initDb } from '@/db/postgre.js'; async function main(uri: string): Promise { await initDb(); diff --git a/packages/backend/src/tools/resync-remote-user.ts b/packages/backend/src/tools/resync-remote-user.ts index 22d2f7c89..8c02ef7ef 100644 --- a/packages/backend/src/tools/resync-remote-user.ts +++ b/packages/backend/src/tools/resync-remote-user.ts @@ -1,5 +1,5 @@ -import { initDb } from '@/db/postgre'; -import * as Acct from 'misskey-js/built/acct'; +import { initDb } from '@/db/postgre.js'; +import * as Acct from '@/misc/acct.js'; async function main(acct: string): Promise { await initDb(); diff --git a/packages/backend/src/tools/show-signin-history.ts b/packages/backend/src/tools/show-signin-history.ts index 7db84ece0..c3388fd1b 100644 --- a/packages/backend/src/tools/show-signin-history.ts +++ b/packages/backend/src/tools/show-signin-history.ts @@ -1,4 +1,4 @@ -import { initDb } from '@/db/postgre'; +import { initDb } from '@/db/postgre.js'; // node built/tools/show-signin-history username // => {Success} {Date} {IPAddrsss} diff --git a/packages/backend/test/activitypub.ts b/packages/backend/test/activitypub.ts index 777e7f355..70f35cafd 100644 --- a/packages/backend/test/activitypub.ts +++ b/packages/backend/test/activitypub.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import rndstr from 'rndstr'; import * as assert from 'assert'; -import { initTestDb } from './utils'; +import { initTestDb } from './utils.js'; describe('ActivityPub', () => { before(async () => { @@ -33,8 +33,8 @@ describe('ActivityPub', () => { }; it('Minimum Actor', async () => { - const { MockResolver } = await import('./misc/mock-resolver'); - const { createPerson } = await import('../src/remote/activitypub/models/person'); + const { MockResolver } = await import('./misc/mock-resolver.js'); + const { createPerson } = await import('../src/remote/activitypub/models/person.js'); const resolver = new MockResolver(); resolver._register(actor.id, actor); @@ -47,8 +47,8 @@ describe('ActivityPub', () => { }); it('Minimum Note', async () => { - const { MockResolver } = await import('./misc/mock-resolver'); - const { createNote } = await import('../src/remote/activitypub/models/note'); + const { MockResolver } = await import('./misc/mock-resolver.js'); + const { createNote } = await import('../src/remote/activitypub/models/note.js'); const resolver = new MockResolver(); resolver._register(actor.id, actor); @@ -80,8 +80,8 @@ describe('ActivityPub', () => { }; it('Actor', async () => { - const { MockResolver } = await import('./misc/mock-resolver'); - const { createPerson } = await import('../src/remote/activitypub/models/person'); + const { MockResolver } = await import('./misc/mock-resolver.js'); + const { createPerson } = await import('../src/remote/activitypub/models/person.js'); const resolver = new MockResolver(); resolver._register(actor.id, actor); diff --git a/packages/backend/test/ap-request.ts b/packages/backend/test/ap-request.ts index 4a9799eb9..48f4fceb5 100644 --- a/packages/backend/test/ap-request.ts +++ b/packages/backend/test/ap-request.ts @@ -1,7 +1,7 @@ import * as assert from 'assert'; -import { genRsaKeyPair } from '../src/misc/gen-key-pair'; -import { createSignedPost, createSignedGet } from '../src/remote/activitypub/ap-request'; -const httpSignature = require('http-signature'); +import { genRsaKeyPair } from '../src/misc/gen-key-pair.js'; +import { createSignedPost, createSignedGet } from '../src/remote/activitypub/ap-request.js'; +import httpSignature from 'http-signature'; export const buildParsedSignature = (signingString: string, signature: string, algorithm: string) => { return { diff --git a/packages/backend/test/api-visibility.ts b/packages/backend/test/api-visibility.ts index ade7b730b..d946191be 100644 --- a/packages/backend/test/api-visibility.ts +++ b/packages/backend/test/api-visibility.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, signup, request, post, startServer, shutdownServer } from './utils'; +import { async, signup, request, post, startServer, shutdownServer } from './utils.js'; describe('API visibility', () => { let p: childProcess.ChildProcess; diff --git a/packages/backend/test/api.ts b/packages/backend/test/api.ts index 99fb196dc..b1b2ecafc 100644 --- a/packages/backend/test/api.ts +++ b/packages/backend/test/api.ts @@ -1,970 +1,83 @@ -/* process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, signup, request, post, react, uploadFile } from './utils'; +import { async, signup, request, post, react, uploadFile, startServer, shutdownServer } from './utils.js'; describe('API', () => { let p: childProcess.ChildProcess; + let alice: any; + let bob: any; + let carol: any; - beforeEach(done => { - p = childProcess.spawn('node', [__dirname + '/../index.js'], { - stdio: ['inherit', 'inherit', 'ipc'], - env: { NODE_ENV: 'test' } - }); - p.on('message', message => { - if (message === 'ok') { - done(); - } - }); + before(async () => { + p = await startServer(); + alice = await signup({ username: 'alice' }); + bob = await signup({ username: 'bob' }); + carol = await signup({ username: 'carol' }); }); - afterEach(() => { - p.kill(); + after(async () => { + await shutdownServer(p); }); - describe('signup', () => { - it('不æ­ŖãĒãƒĻãƒŧã‚ļãƒŧ名でã‚ĸã‚Ģã‚ĻãƒŗトがäŊœæˆã§ããĒい', async(async () => { - const res = await request('/signup', { - username: 'test.', - password: 'test' + describe('General validation', () => { + it('wrong type', async(async () => { + const res = await request('/test', { + required: true, + string: 42, }); assert.strictEqual(res.status, 400); })); - it('įŠēぎパ゚ワãƒŧドでã‚ĸã‚Ģã‚ĻãƒŗトがäŊœæˆã§ããĒい', async(async () => { - const res = await request('/signup', { - username: 'test', - password: '' + it('missing require param', async(async () => { + const res = await request('/test', { + string: 'a', }); assert.strictEqual(res.status, 400); })); - it('æ­Ŗしくã‚ĸã‚Ģã‚ĻãƒŗトがäŊœæˆã§ãã‚‹', async(async () => { - const me = { - username: 'test', - password: 'test' - }; - - const res = await request('/signup', me); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.username, me.username); - })); - - it('同じãƒĻãƒŧã‚ļãƒŧ名ぎã‚ĸã‚Ģã‚ĻãƒŗトはäŊœæˆã§ããĒい', async(async () => { - await signup({ - username: 'test' - }); - - const res = await request('/signup', { - username: 'test', - password: 'test' - }); - - assert.strictEqual(res.status, 400); - })); - }); - - describe('signin', () => { - it('間違ãŖたパ゚ワãƒŧドでã‚ĩイãƒŗイãƒŗできãĒい', async(async () => { - await signup({ - username: 'test', - password: 'foo' - }); - - const res = await request('/signin', { - username: 'test', - password: 'bar' - }); - - assert.strictEqual(res.status, 403); - })); - - it('クエãƒĒをイãƒŗã‚¸ã‚§ã‚¯ã‚ˇãƒ§ãƒŗできãĒい', async(async () => { - await signup({ - username: 'test' - }); - - const res = await request('/signin', { - username: 'test', - password: { - $gt: '' - } - }); - - assert.strictEqual(res.status, 400); - })); - - it('æ­Ŗã—ã„æƒ…å ąã§ã‚ĩイãƒŗイãƒŗできる', async(async () => { - await signup({ - username: 'test', - password: 'foo' - }); - - const res = await request('/signin', { - username: 'test', - password: 'foo' - }); - - assert.strictEqual(res.status, 200); - })); - }); - - describe('i/update', () => { - it('ã‚ĸã‚Ģã‚Ļãƒŗãƒˆč¨­åŽšã‚’æ›´æ–°ã§ãã‚‹', async(async () => { - const me = await signup(); - - const myName = '大厤æĢģ子'; - const myLocation = '七æŖŽä¸­'; - const myBirthday = '2000-09-07'; - - const res = await request('/i/update', { - name: myName, - location: myLocation, - birthday: myBirthday - }, me); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, myName); - assert.strictEqual(res.body.location, myLocation); - assert.strictEqual(res.body.birthday, myBirthday); - })); - - it('名前をįŠēį™ŊãĢできãĒい', async(async () => { - const me = await signup(); - const res = await request('/i/update', { - name: ' ' - }, me); - assert.strictEqual(res.status, 400); - })); - - it('čĒ•į”Ÿæ—ĨãŽč¨­åŽšã‚’å‰Šé™¤ã§ãã‚‹', async(async () => { - const me = await signup(); - await request('/i/update', { - birthday: '2000-09-07' - }, me); - - const res = await request('/i/update', { - birthday: null - }, me); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.birthday, null); - })); - - it('不æ­ŖãĒčĒ•į”Ÿæ—ĨぎåŊĸåŧã§æ€’られる', async(async () => { - const me = await signup(); - const res = await request('/i/update', { - birthday: '2000/09/07' - }, me); - assert.strictEqual(res.status, 400); - })); - }); - - describe('users/show', () => { - it('ãƒĻãƒŧã‚ļãƒŧが取垗できる', async(async () => { - const me = await signup(); - - const res = await request('/users/show', { - userId: me.id - }, me); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.id, me.id); - })); - - it('ãƒĻãƒŧã‚ļãƒŧが存在しãĒかãŖたら怒る', async(async () => { - const res = await request('/users/show', { - userId: '000000000000000000000000' + it('invalid misskey:id (empty string)', async(async () => { + const res = await request('/test', { + required: true, + id: '', }); assert.strictEqual(res.status, 400); })); - it('間違ãŖたIDで怒られる', async(async () => { - const res = await request('/users/show', { - userId: 'kyoppie' + it('valid misskey:id', async(async () => { + const res = await request('/test', { + required: true, + id: '8wvhjghbxu', }); - assert.strictEqual(res.status, 400); + assert.strictEqual(res.status, 200); })); - }); - describe('notes/show', () => { - it('投į¨ŋが取垗できる', async(async () => { - const me = await signup(); - const myPost = await post(me, { - text: 'test' + it('default value', async(async () => { + const res = await request('/test', { + required: true, + string: 'a', }); - - const res = await request('/notes/show', { - noteId: myPost.id - }, me); - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.id, myPost.id); - assert.strictEqual(res.body.text, myPost.text); + assert.strictEqual(res.body.default, 'hello'); })); - it('投į¨ŋが存在しãĒかãŖたら怒る', async(async () => { - const res = await request('/notes/show', { - noteId: '000000000000000000000000' + it('can set null even if it has default value', async(async () => { + const res = await request('/test', { + required: true, + nullableDefault: null, }); - assert.strictEqual(res.status, 400); + assert.strictEqual(res.status, 200); + assert.strictEqual(res.body.nullableDefault, null); })); - it('間違ãŖたIDで怒られる', async(async () => { - const res = await request('/notes/show', { - noteId: 'kyoppie' + it('cannot set undefined if it has default value', async(async () => { + const res = await request('/test', { + required: true, + nullableDefault: undefined, }); - assert.strictEqual(res.status, 400); - })); - }); - - describe('notes/reactions/create', () => { - it('ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗできる', async(async () => { - const bob = await signup({ username: 'bob' }); - const bobPost = await post(bob); - - const alice = await signup({ username: 'alice' }); - const res = await request('/notes/reactions/create', { - noteId: bobPost.id, - reaction: 'like' - }, alice); - - assert.strictEqual(res.status, 204); - })); - - it('č‡Ē分ぎ投į¨ŋãĢはãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗできãĒい', async(async () => { - const me = await signup(); - const myPost = await post(me); - - const res = await request('/notes/reactions/create', { - noteId: myPost.id, - reaction: 'like' - }, me); - - assert.strictEqual(res.status, 400); - })); - - it('äēŒé‡ãĢãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗできãĒい', async(async () => { - const bob = await signup({ username: 'bob' }); - const bobPost = await post(bob); - - const alice = await signup({ username: 'alice' }); - await react(alice, bobPost, 'like'); - - const res = await request('/notes/reactions/create', { - noteId: bobPost.id, - reaction: 'like' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('存在しãĒい投į¨ŋãĢはãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗできãĒい', async(async () => { - const me = await signup(); - - const res = await request('/notes/reactions/create', { - noteId: '000000000000000000000000', - reaction: 'like' - }, me); - - assert.strictEqual(res.status, 400); - })); - - it('įŠēãŽãƒ‘ãƒŠãƒĄãƒŧã‚ŋで怒られる', async(async () => { - const me = await signup(); - - const res = await request('/notes/reactions/create', {}, me); - - assert.strictEqual(res.status, 400); - })); - - it('間違ãŖたIDで怒られる', async(async () => { - const me = await signup(); - - const res = await request('/notes/reactions/create', { - noteId: 'kyoppie', - reaction: 'like' - }, me); - - assert.strictEqual(res.status, 400); - })); - }); - - describe('following/create', () => { - it('フりロãƒŧできる', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - - const res = await request('/following/create', { - userId: alice.id - }, bob); - assert.strictEqual(res.status, 200); - })); - - it('æ—ĸãĢフりロãƒŧしãĻいる場合は怒る', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - await request('/following/create', { - userId: alice.id - }, bob); - - const res = await request('/following/create', { - userId: alice.id - }, bob); - - assert.strictEqual(res.status, 400); - })); - - it('存在しãĒいãƒĻãƒŧã‚ļãƒŧはフりロãƒŧできãĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/following/create', { - userId: '000000000000000000000000' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('č‡Ē分č‡ĒčēĢはフりロãƒŧできãĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/following/create', { - userId: alice.id - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('įŠēãŽãƒ‘ãƒŠãƒĄãƒŧã‚ŋで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/following/create', {}, alice); - - assert.strictEqual(res.status, 400); - })); - - it('間違ãŖたIDで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/following/create', { - userId: 'foo' - }, alice); - - assert.strictEqual(res.status, 400); - })); - }); - - describe('following/delete', () => { - it('フりロãƒŧč§Ŗ除できる', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - await request('/following/create', { - userId: alice.id - }, bob); - - const res = await request('/following/delete', { - userId: alice.id - }, bob); - - assert.strictEqual(res.status, 200); - })); - - it('フりロãƒŧしãĻいãĒい場合は怒る', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - - const res = await request('/following/delete', { - userId: alice.id - }, bob); - - assert.strictEqual(res.status, 400); - })); - - it('存在しãĒいãƒĻãƒŧã‚ļãƒŧはフりロãƒŧč§Ŗ除できãĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/following/delete', { - userId: '000000000000000000000000' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('č‡Ē分č‡ĒčēĢはフりロãƒŧč§Ŗ除できãĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/following/delete', { - userId: alice.id - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('įŠēãŽãƒ‘ãƒŠãƒĄãƒŧã‚ŋで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/following/delete', {}, alice); - - assert.strictEqual(res.status, 400); - })); - - it('間違ãŖたIDで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/following/delete', { - userId: 'kyoppie' - }, alice); - - assert.strictEqual(res.status, 400); - })); - }); - - describe('drive', () => { - it('ãƒ‰ãƒŠã‚¤ãƒ–æƒ…å ąã‚’å–åž—ã§ãã‚‹', async(async () => { - const bob = await signup({ username: 'bob' }); - await uploadFile({ - userId: me.id, - size: 256 - }); - await uploadFile({ - userId: me.id, - size: 512 - }); - await uploadFile({ - userId: me.id, - size: 1024 - }); - const res = await request('/drive', {}, me); - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - expect(res.body).have.property('usage').eql(1792); - })); - }); - - describe('drive/files/create', () => { - it('ãƒ•ã‚Ąã‚¤ãƒĢをäŊœæˆã§ãã‚‹', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await uploadFile(alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, 'Lenna.png'); - })); - - it('ãƒ•ã‚Ąã‚¤ãƒĢãĢ名前をäģ˜ã‘られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await assert.request(server) - .post('/drive/files/create') - .field('i', alice.token) - .field('name', 'Belmond.png') - .attach('file', fs.readFileSync(__dirname + '/resources/Lenna.png'), 'Lenna.png'); - - expect(res).have.status(200); - expect(res.body).be.a('object'); - expect(res.body).have.property('name').eql('Belmond.png'); - })); - - it('ãƒ•ã‚Ąã‚¤ãƒĢį„Ąã—で怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/drive/files/create', {}, alice); - - assert.strictEqual(res.status, 400); - })); - - it('SVGãƒ•ã‚Ąã‚¤ãƒĢをäŊœæˆã§ãã‚‹', async(async () => { - const izumi = await signup({ username: 'izumi' }); - - const res = await uploadFile(izumi, __dirname + '/resources/image.svg'); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, 'image.svg'); - assert.strictEqual(res.body.type, 'image/svg+xml'); - })); - }); - - describe('drive/files/update', () => { - it('名前を更新できる', async(async () => { - const alice = await signup({ username: 'alice' }); - const file = await uploadFile(alice); - const newName = 'ã„ãĄã”ãƒ‘ã‚šã‚ŋ.png'; - - const res = await request('/drive/files/update', { - fileId: file.id, - name: newName - }, alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, newName); - })); - - it('äģ–äēēãŽãƒ•ã‚Ąã‚¤ãƒĢは更新できãĒい', async(async () => { - const bob = await signup({ username: 'bob' }); - const alice = await signup({ username: 'alice' }); - const file = await uploadFile(bob); - - const res = await request('/drive/files/update', { - fileId: file.id, - name: 'ã„ãĄã”ãƒ‘ã‚šã‚ŋ.png' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('čĻĒフりãƒĢダを更新できる', async(async () => { - const alice = await signup({ username: 'alice' }); - const file = await uploadFile(alice); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - - const res = await request('/drive/files/update', { - fileId: file.id, - folderId: folder.id - }, alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.folderId, folder.id); - })); - - it('čĻĒフりãƒĢダをį„Ąã—ãĢできる', async(async () => { - const alice = await signup({ username: 'alice' }); - const file = await uploadFile(alice); - - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - - await request('/drive/files/update', { - fileId: file.id, - folderId: folder.id - }, alice); - - const res = await request('/drive/files/update', { - fileId: file.id, - folderId: null - }, alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.folderId, null); - })); - - it('äģ–äēēぎフりãƒĢダãĢはå…ĨれられãĒい', async(async () => { - const bob = await signup({ username: 'bob' }); - const alice = await signup({ username: 'alice' }); - const file = await uploadFile(alice); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, bob)).body; - - const res = await request('/drive/files/update', { - fileId: file.id, - folderId: folder.id - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('存在しãĒいフりãƒĢダで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - const file = await uploadFile(alice); - - const res = await request('/drive/files/update', { - fileId: file.id, - folderId: '000000000000000000000000' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('不æ­ŖãĒフりãƒĢダIDで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - const file = await uploadFile(alice); - - const res = await request('/drive/files/update', { - fileId: file.id, - folderId: 'foo' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('ãƒ•ã‚Ąã‚¤ãƒĢが存在しãĒかãŖたら怒る', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/drive/files/update', { - fileId: '000000000000000000000000', - name: 'ã„ãĄã”ãƒ‘ã‚šã‚ŋ.png' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('間違ãŖたIDで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/drive/files/update', { - fileId: 'kyoppie', - name: 'ã„ãĄã”ãƒ‘ã‚šã‚ŋ.png' - }, alice); - - assert.strictEqual(res.status, 400); - })); - }); - - describe('drive/folders/create', () => { - it('フりãƒĢダをäŊœæˆã§ãã‚‹', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/drive/folders/create', { - name: 'test' - }, alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, 'test'); - })); - }); - - describe('drive/folders/update', () => { - it('名前を更新できる', async(async () => { - const alice = await signup({ username: 'alice' }); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - - const res = await request('/drive/folders/update', { - folderId: folder.id, - name: 'new name' - }, alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, 'new name'); - })); - - it('äģ–äēēぎフりãƒĢダを更新できãĒい', async(async () => { - const bob = await signup({ username: 'bob' }); - const alice = await signup({ username: 'alice' }); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, bob)).body; - - const res = await request('/drive/folders/update', { - folderId: folder.id, - name: 'new name' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('čĻĒフりãƒĢダを更新できる', async(async () => { - const alice = await signup({ username: 'alice' }); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - const parentFolder = (await request('/drive/folders/create', { - name: 'parent' - }, alice)).body; - - const res = await request('/drive/folders/update', { - folderId: folder.id, - parentId: parentFolder.id - }, alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.parentId, parentFolder.id); - })); - - it('čĻĒフりãƒĢダをį„Ąã—ãĢ更新できる', async(async () => { - const alice = await signup({ username: 'alice' }); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - const parentFolder = (await request('/drive/folders/create', { - name: 'parent' - }, alice)).body; - await request('/drive/folders/update', { - folderId: folder.id, - parentId: parentFolder.id - }, alice); - - const res = await request('/drive/folders/update', { - folderId: folder.id, - parentId: null - }, alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.parentId, null); - })); - - it('äģ–äēēぎフりãƒĢダをčĻĒフりãƒĢダãĢč¨­åŽšã§ããĒい', async(async () => { - const bob = await signup({ username: 'bob' }); - const alice = await signup({ username: 'alice' }); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - const parentFolder = (await request('/drive/folders/create', { - name: 'parent' - }, bob)).body; - - const res = await request('/drive/folders/update', { - folderId: folder.id, - parentId: parentFolder.id - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('フりãƒĢダがåžĒį’°ã™ã‚‹ã‚ˆã†ãĒ構造ãĢできãĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - const parentFolder = (await request('/drive/folders/create', { - name: 'parent' - }, alice)).body; - await request('/drive/folders/update', { - folderId: parentFolder.id, - parentId: folder.id - }, alice); - - const res = await request('/drive/folders/update', { - folderId: folder.id, - parentId: parentFolder.id - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('フりãƒĢダがåžĒį’°ã™ã‚‹ã‚ˆã†ãĒ構造ãĢできãĒい(再帰įš„)', async(async () => { - const alice = await signup({ username: 'alice' }); - const folderA = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - const folderB = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - const folderC = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - await request('/drive/folders/update', { - folderId: folderB.id, - parentId: folderA.id - }, alice); - await request('/drive/folders/update', { - folderId: folderC.id, - parentId: folderB.id - }, alice); - - const res = await request('/drive/folders/update', { - folderId: folderA.id, - parentId: folderC.id - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('フりãƒĢダがåžĒį’°ã™ã‚‹ã‚ˆã†ãĒ構造ãĢできãĒい(č‡ĒčēĢ)', async(async () => { - const arisugawa = await signup({ username: 'arisugawa' }); - const folderA = (await request('/drive/folders/create', { - name: 'test' - }, arisugawa)).body; - - const res = await request('/drive/folders/update', { - folderId: folderA.id, - parentId: folderA.id - }, arisugawa); - - assert.strictEqual(res.status, 400); - })); - - it('存在しãĒいčĻĒフりãƒĢãƒ€ã‚’č¨­åŽšã§ããĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - - const res = await request('/drive/folders/update', { - folderId: folder.id, - parentId: '000000000000000000000000' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('不æ­ŖãĒčĻĒフりãƒĢダIDで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - const folder = (await request('/drive/folders/create', { - name: 'test' - }, alice)).body; - - const res = await request('/drive/folders/update', { - folderId: folder.id, - parentId: 'foo' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('存在しãĒいフりãƒĢダを更新できãĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/drive/folders/update', { - folderId: '000000000000000000000000' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('不æ­ŖãĒフりãƒĢダIDで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/drive/folders/update', { - folderId: 'foo' - }, alice); - - assert.strictEqual(res.status, 400); - })); - }); - - describe('messaging/messages/create', () => { - it('ãƒĄãƒƒã‚ģãƒŧジを送äŋĄã§ãã‚‹', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - - const res = await request('/messaging/messages/create', { - userId: bob.id, - text: 'test' - }, alice); - - assert.strictEqual(res.status, 200); - assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.text, 'test'); - })); - - it('č‡Ē分č‡ĒčēĢãĢã¯ãƒĄãƒƒã‚ģãƒŧジを送äŋĄã§ããĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/messaging/messages/create', { - userId: alice.id, - text: 'Yo' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('存在しãĒいãƒĻãƒŧã‚ļãƒŧãĢã¯ãƒĄãƒƒã‚ģãƒŧジを送äŋĄã§ããĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/messaging/messages/create', { - userId: '000000000000000000000000', - text: 'test' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('不æ­ŖãĒãƒĻãƒŧã‚ļãƒŧIDで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - - const res = await request('/messaging/messages/create', { - userId: 'foo', - text: 'test' - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('テキ゚トがį„ĄããĻ怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - - const res = await request('/messaging/messages/create', { - userId: bob.id - }, alice); - - assert.strictEqual(res.status, 400); - })); - - it('文字数ã‚Ēãƒŧバãƒŧで怒られる', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - - const res = await request('/messaging/messages/create', { - userId: bob.id, - text: '!'.repeat(1001) - }, alice); - - assert.strictEqual(res.status, 400); - })); - }); - - describe('notes/replies', () => { - it('č‡Ē分ãĢ閲čĻ§æ¨Šé™ãŽãĒい投į¨ŋはåĢぞれãĒい', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - const carol = await signup({ username: 'carol' }); - - const alicePost = await post(alice, { - text: 'foo' - }); - - await post(bob, { - replyId: alicePost.id, - text: 'bar', - visibility: 'specified', - visibleUserIds: [alice.id] - }); - - const res = await request('/notes/replies', { - noteId: alicePost.id - }, carol); - - assert.strictEqual(res.status, 200); - assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.length, 0); - })); - }); - - describe('notes/timeline', () => { - it('フりロワãƒŧ限厚投į¨ŋがåĢぞれる', async(async () => { - const alice = await signup({ username: 'alice' }); - const bob = await signup({ username: 'bob' }); - - await request('/following/create', { - userId: alice.id - }, bob); - - const alicePost = await post(alice, { - text: 'foo', - visibility: 'followers' - }); - - const res = await request('/notes/timeline', {}, bob); - - assert.strictEqual(res.status, 200); - assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.length, 1); - assert.strictEqual(res.body[0].id, alicePost.id); + assert.strictEqual(res.body.nullableDefault, 'hello'); })); }); }); -*/ diff --git a/packages/backend/test/block.ts b/packages/backend/test/block.ts index 6d9efb77b..103eec991 100644 --- a/packages/backend/test/block.ts +++ b/packages/backend/test/block.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, signup, request, post, startServer, shutdownServer } from './utils'; +import { async, signup, request, post, startServer, shutdownServer } from './utils.js'; describe('Block', () => { let p: childProcess.ChildProcess; diff --git a/packages/backend/test/chart.ts b/packages/backend/test/chart.ts index 66000bc92..c8cea874f 100644 --- a/packages/backend/test/chart.ts +++ b/packages/backend/test/chart.ts @@ -2,18 +2,21 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as lolex from '@sinonjs/fake-timers'; -import { async, initTestDb } from './utils'; -import TestChart from '../src/services/chart/charts/test'; -import TestGroupedChart from '../src/services/chart/charts/test-grouped'; -import TestUniqueChart from '../src/services/chart/charts/test-unique'; -import * as _TestChart from '../src/services/chart/charts/entities/test'; -import * as _TestGroupedChart from '../src/services/chart/charts/entities/test-grouped'; -import * as _TestUniqueChart from '../src/services/chart/charts/entities/test-unique'; +import { async, initTestDb } from './utils.js'; +import TestChart from '../src/services/chart/charts/test.js'; +import TestGroupedChart from '../src/services/chart/charts/test-grouped.js'; +import TestUniqueChart from '../src/services/chart/charts/test-unique.js'; +import TestIntersectionChart from '../src/services/chart/charts/test-intersection.js'; +import * as _TestChart from '../src/services/chart/charts/entities/test.js'; +import * as _TestGroupedChart from '../src/services/chart/charts/entities/test-grouped.js'; +import * as _TestUniqueChart from '../src/services/chart/charts/entities/test-unique.js'; +import * as _TestIntersectionChart from '../src/services/chart/charts/entities/test-intersection.js'; describe('Chart', () => { let testChart: TestChart; let testGroupedChart: TestGroupedChart; let testUniqueChart: TestUniqueChart; + let testIntersectionChart: TestIntersectionChart; let clock: lolex.Clock; beforeEach(async(async () => { @@ -21,11 +24,13 @@ describe('Chart', () => { _TestChart.entity.hour, _TestChart.entity.day, _TestGroupedChart.entity.hour, _TestGroupedChart.entity.day, _TestUniqueChart.entity.hour, _TestUniqueChart.entity.day, + _TestIntersectionChart.entity.hour, _TestIntersectionChart.entity.day, ]); testChart = new TestChart(); testGroupedChart = new TestGroupedChart(); testUniqueChart = new TestUniqueChart(); + testIntersectionChart = new TestIntersectionChart(); clock = lolex.install({ now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0)) @@ -426,6 +431,53 @@ describe('Chart', () => { foo: [2, 0, 0], }); })); + + describe('Intersection', () => { + it('æĄäģļがæē€ãŸã•ã‚ŒãĻいãĒい場合はã‚Ģã‚ĻãƒŗトされãĒい', async(async () => { + await testIntersectionChart.addA('alice'); + await testIntersectionChart.addA('bob'); + await testIntersectionChart.addB('carol'); + await testIntersectionChart.save(); + + const chartHours = await testIntersectionChart.getChart('hour', 3, null); + const chartDays = await testIntersectionChart.getChart('day', 3, null); + + assert.deepStrictEqual(chartHours, { + a: [2, 0, 0], + b: [1, 0, 0], + aAndB: [0, 0, 0], + }); + + assert.deepStrictEqual(chartDays, { + a: [2, 0, 0], + b: [1, 0, 0], + aAndB: [0, 0, 0], + }); + })); + + it('æĄäģļがæē€ãŸã•ã‚ŒãĻいる場合ãĢã‚Ģã‚Ļãƒŗトされる', async(async () => { + await testIntersectionChart.addA('alice'); + await testIntersectionChart.addA('bob'); + await testIntersectionChart.addB('carol'); + await testIntersectionChart.addB('alice'); + await testIntersectionChart.save(); + + const chartHours = await testIntersectionChart.getChart('hour', 3, null); + const chartDays = await testIntersectionChart.getChart('day', 3, null); + + assert.deepStrictEqual(chartHours, { + a: [2, 0, 0], + b: [2, 0, 0], + aAndB: [1, 0, 0], + }); + + assert.deepStrictEqual(chartDays, { + a: [2, 0, 0], + b: [2, 0, 0], + aAndB: [1, 0, 0], + }); + })); + }); }); describe('Resync', () => { diff --git a/packages/backend/test/endpoints.ts b/packages/backend/test/endpoints.ts new file mode 100644 index 000000000..2aedc25f2 --- /dev/null +++ b/packages/backend/test/endpoints.ts @@ -0,0 +1,865 @@ +/* +process.env.NODE_ENV = 'test'; + +import * as assert from 'assert'; +import * as childProcess from 'child_process'; +import { async, signup, request, post, react, uploadFile, startServer, shutdownServer } from './utils.js'; + +describe('API: Endpoints', () => { + let p: childProcess.ChildProcess; + let alice: any; + let bob: any; + let carol: any; + + before(async () => { + p = await startServer(); + alice = await signup({ username: 'alice' }); + bob = await signup({ username: 'bob' }); + carol = await signup({ username: 'carol' }); + }); + + after(async () => { + await shutdownServer(p); + }); + + describe('signup', () => { + it('不æ­ŖãĒãƒĻãƒŧã‚ļãƒŧ名でã‚ĸã‚Ģã‚ĻãƒŗトがäŊœæˆã§ããĒい', async(async () => { + const res = await request('/signup', { + username: 'test.', + password: 'test' + }); + assert.strictEqual(res.status, 400); + })); + + it('įŠēぎパ゚ワãƒŧドでã‚ĸã‚Ģã‚ĻãƒŗトがäŊœæˆã§ããĒい', async(async () => { + const res = await request('/signup', { + username: 'test', + password: '' + }); + assert.strictEqual(res.status, 400); + })); + + it('æ­Ŗしくã‚ĸã‚Ģã‚ĻãƒŗトがäŊœæˆã§ãã‚‹', async(async () => { + const me = { + username: 'test1', + password: 'test1' + }; + + const res = await request('/signup', me); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.username, me.username); + })); + + it('同じãƒĻãƒŧã‚ļãƒŧ名ぎã‚ĸã‚Ģã‚ĻãƒŗトはäŊœæˆã§ããĒい', async(async () => { + await signup({ + username: 'test2' + }); + + const res = await request('/signup', { + username: 'test2', + password: 'test2' + }); + + assert.strictEqual(res.status, 400); + })); + }); + + describe('signin', () => { + it('間違ãŖたパ゚ワãƒŧドでã‚ĩイãƒŗイãƒŗできãĒい', async(async () => { + await signup({ + username: 'test3', + password: 'foo' + }); + + const res = await request('/signin', { + username: 'test3', + password: 'bar' + }); + + assert.strictEqual(res.status, 403); + })); + + it('クエãƒĒをイãƒŗã‚¸ã‚§ã‚¯ã‚ˇãƒ§ãƒŗできãĒい', async(async () => { + await signup({ + username: 'test4' + }); + + const res = await request('/signin', { + username: 'test4', + password: { + $gt: '' + } + }); + + assert.strictEqual(res.status, 400); + })); + + it('æ­Ŗã—ã„æƒ…å ąã§ã‚ĩイãƒŗイãƒŗできる', async(async () => { + await signup({ + username: 'test5', + password: 'foo' + }); + + const res = await request('/signin', { + username: 'test5', + password: 'foo' + }); + + assert.strictEqual(res.status, 200); + })); + }); + + describe('i/update', () => { + it('ã‚ĸã‚Ģã‚Ļãƒŗãƒˆč¨­åŽšã‚’æ›´æ–°ã§ãã‚‹', async(async () => { + const myName = '大厤æĢģ子'; + const myLocation = '七æŖŽä¸­'; + const myBirthday = '2000-09-07'; + + const res = await request('/i/update', { + name: myName, + location: myLocation, + birthday: myBirthday + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.name, myName); + assert.strictEqual(res.body.location, myLocation); + assert.strictEqual(res.body.birthday, myBirthday); + })); + + it('名前をįŠēį™ŊãĢできãĒい', async(async () => { + const res = await request('/i/update', { + name: ' ' + }, alice); + assert.strictEqual(res.status, 400); + })); + + it('čĒ•į”Ÿæ—ĨãŽč¨­åŽšã‚’å‰Šé™¤ã§ãã‚‹', async(async () => { + await request('/i/update', { + birthday: '2000-09-07' + }, alice); + + const res = await request('/i/update', { + birthday: null + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.birthday, null); + })); + + it('不æ­ŖãĒčĒ•į”Ÿæ—ĨぎåŊĸåŧã§æ€’られる', async(async () => { + const res = await request('/i/update', { + birthday: '2000/09/07' + }, alice); + assert.strictEqual(res.status, 400); + })); + }); + + describe('users/show', () => { + it('ãƒĻãƒŧã‚ļãƒŧが取垗できる', async(async () => { + const res = await request('/users/show', { + userId: alice.id + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.id, alice.id); + })); + + it('ãƒĻãƒŧã‚ļãƒŧが存在しãĒかãŖたら怒る', async(async () => { + const res = await request('/users/show', { + userId: '000000000000000000000000' + }); + assert.strictEqual(res.status, 400); + })); + + it('間違ãŖたIDで怒られる', async(async () => { + const res = await request('/users/show', { + userId: 'kyoppie' + }); + assert.strictEqual(res.status, 400); + })); + }); + + describe('notes/show', () => { + it('投į¨ŋが取垗できる', async(async () => { + const myPost = await post(alice, { + text: 'test' + }); + + const res = await request('/notes/show', { + noteId: myPost.id + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.id, myPost.id); + assert.strictEqual(res.body.text, myPost.text); + })); + + it('投į¨ŋが存在しãĒかãŖたら怒る', async(async () => { + const res = await request('/notes/show', { + noteId: '000000000000000000000000' + }); + assert.strictEqual(res.status, 400); + })); + + it('間違ãŖたIDで怒られる', async(async () => { + const res = await request('/notes/show', { + noteId: 'kyoppie' + }); + assert.strictEqual(res.status, 400); + })); + }); + + describe('notes/reactions/create', () => { + it('ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗできる', async(async () => { + const bobPost = await post(bob); + + const alice = await signup({ username: 'alice' }); + const res = await request('/notes/reactions/create', { + noteId: bobPost.id, + reaction: '🚀', + }, alice); + + assert.strictEqual(res.status, 204); + + const resNote = await request('/notes/show', { + noteId: bobPost.id, + }, alice); + + assert.strictEqual(resNote.status, 200); + assert.strictEqual(resNote.body.reactions['🚀'], [alice.id]); + })); + + it('č‡Ē分ぎ投į¨ŋãĢもãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗできる', async(async () => { + const myPost = await post(alice); + + const res = await request('/notes/reactions/create', { + noteId: myPost.id, + reaction: '🚀', + }, alice); + + assert.strictEqual(res.status, 204); + })); + + it('äēŒé‡ãĢãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗできãĒい', async(async () => { + const bobPost = await post(bob); + + await react(alice, bobPost, 'like'); + + const res = await request('/notes/reactions/create', { + noteId: bobPost.id, + reaction: '🚀', + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('存在しãĒい投į¨ŋãĢはãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗできãĒい', async(async () => { + const res = await request('/notes/reactions/create', { + noteId: '000000000000000000000000', + reaction: '🚀', + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('įŠēãŽãƒ‘ãƒŠãƒĄãƒŧã‚ŋで怒られる', async(async () => { + const res = await request('/notes/reactions/create', {}, alice); + + assert.strictEqual(res.status, 400); + })); + + it('間違ãŖたIDで怒られる', async(async () => { + const res = await request('/notes/reactions/create', { + noteId: 'kyoppie', + reaction: '🚀', + }, alice); + + assert.strictEqual(res.status, 400); + })); + }); + + describe('following/create', () => { + it('フりロãƒŧできる', async(async () => { + const res = await request('/following/create', { + userId: alice.id + }, bob); + + assert.strictEqual(res.status, 200); + })); + + it('æ—ĸãĢフりロãƒŧしãĻいる場合は怒る', async(async () => { + const res = await request('/following/create', { + userId: alice.id + }, bob); + + assert.strictEqual(res.status, 400); + })); + + it('存在しãĒいãƒĻãƒŧã‚ļãƒŧはフりロãƒŧできãĒい', async(async () => { + const res = await request('/following/create', { + userId: '000000000000000000000000' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('č‡Ē分č‡ĒčēĢはフりロãƒŧできãĒい', async(async () => { + const res = await request('/following/create', { + userId: alice.id + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('įŠēãŽãƒ‘ãƒŠãƒĄãƒŧã‚ŋで怒られる', async(async () => { + const res = await request('/following/create', {}, alice); + + assert.strictEqual(res.status, 400); + })); + + it('間違ãŖたIDで怒られる', async(async () => { + const res = await request('/following/create', { + userId: 'foo' + }, alice); + + assert.strictEqual(res.status, 400); + })); + }); + + describe('following/delete', () => { + it('フりロãƒŧč§Ŗ除できる', async(async () => { + await request('/following/create', { + userId: alice.id + }, bob); + + const res = await request('/following/delete', { + userId: alice.id + }, bob); + + assert.strictEqual(res.status, 200); + })); + + it('フりロãƒŧしãĻいãĒい場合は怒る', async(async () => { + const res = await request('/following/delete', { + userId: alice.id + }, bob); + + assert.strictEqual(res.status, 400); + })); + + it('存在しãĒいãƒĻãƒŧã‚ļãƒŧはフりロãƒŧč§Ŗ除できãĒい', async(async () => { + const res = await request('/following/delete', { + userId: '000000000000000000000000' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('č‡Ē分č‡ĒčēĢはフりロãƒŧč§Ŗ除できãĒい', async(async () => { + const res = await request('/following/delete', { + userId: alice.id + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('įŠēãŽãƒ‘ãƒŠãƒĄãƒŧã‚ŋで怒られる', async(async () => { + const res = await request('/following/delete', {}, alice); + + assert.strictEqual(res.status, 400); + })); + + it('間違ãŖたIDで怒られる', async(async () => { + const res = await request('/following/delete', { + userId: 'kyoppie' + }, alice); + + assert.strictEqual(res.status, 400); + })); + }); + + describe('drive', () => { + it('ãƒ‰ãƒŠã‚¤ãƒ–æƒ…å ąã‚’å–åž—ã§ãã‚‹', async(async () => { + await uploadFile({ + userId: alice.id, + size: 256 + }); + await uploadFile({ + userId: alice.id, + size: 512 + }); + await uploadFile({ + userId: alice.id, + size: 1024 + }); + const res = await request('/drive', {}, alice); + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + expect(res.body).have.property('usage').eql(1792); + })); + }); + + describe('drive/files/create', () => { + it('ãƒ•ã‚Ąã‚¤ãƒĢをäŊœæˆã§ãã‚‹', async(async () => { + const res = await uploadFile(alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.name, 'Lenna.png'); + })); + + it('ãƒ•ã‚Ąã‚¤ãƒĢãĢ名前をäģ˜ã‘られる', async(async () => { + const res = await assert.request(server) + .post('/drive/files/create') + .field('i', alice.token) + .field('name', 'Belmond.png') + .attach('file', fs.readFileSync(__dirname + '/resources/Lenna.png'), 'Lenna.png'); + + expect(res).have.status(200); + expect(res.body).be.a('object'); + expect(res.body).have.property('name').eql('Belmond.png'); + })); + + it('ãƒ•ã‚Ąã‚¤ãƒĢį„Ąã—で怒られる', async(async () => { + const res = await request('/drive/files/create', {}, alice); + + assert.strictEqual(res.status, 400); + })); + + it('SVGãƒ•ã‚Ąã‚¤ãƒĢをäŊœæˆã§ãã‚‹', async(async () => { + const res = await uploadFile(alice, __dirname + '/resources/image.svg'); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.name, 'image.svg'); + assert.strictEqual(res.body.type, 'image/svg+xml'); + })); + }); + + describe('drive/files/update', () => { + it('名前を更新できる', async(async () => { + const file = await uploadFile(alice); + const newName = 'ã„ãĄã”ãƒ‘ã‚šã‚ŋ.png'; + + const res = await request('/drive/files/update', { + fileId: file.id, + name: newName + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.name, newName); + })); + + it('äģ–äēēãŽãƒ•ã‚Ąã‚¤ãƒĢは更新できãĒい', async(async () => { + const file = await uploadFile(bob); + + const res = await request('/drive/files/update', { + fileId: file.id, + name: 'ã„ãĄã”ãƒ‘ã‚šã‚ŋ.png' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('čĻĒフりãƒĢダを更新できる', async(async () => { + const file = await uploadFile(alice); + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + + const res = await request('/drive/files/update', { + fileId: file.id, + folderId: folder.id + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.folderId, folder.id); + })); + + it('čĻĒフりãƒĢダをį„Ąã—ãĢできる', async(async () => { + const file = await uploadFile(alice); + + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + + await request('/drive/files/update', { + fileId: file.id, + folderId: folder.id + }, alice); + + const res = await request('/drive/files/update', { + fileId: file.id, + folderId: null + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.folderId, null); + })); + + it('äģ–äēēぎフりãƒĢダãĢはå…ĨれられãĒい', async(async () => { + const file = await uploadFile(alice); + const folder = (await request('/drive/folders/create', { + name: 'test' + }, bob)).body; + + const res = await request('/drive/files/update', { + fileId: file.id, + folderId: folder.id + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('存在しãĒいフりãƒĢダで怒られる', async(async () => { + const file = await uploadFile(alice); + + const res = await request('/drive/files/update', { + fileId: file.id, + folderId: '000000000000000000000000' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('不æ­ŖãĒフりãƒĢダIDで怒られる', async(async () => { + const file = await uploadFile(alice); + + const res = await request('/drive/files/update', { + fileId: file.id, + folderId: 'foo' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('ãƒ•ã‚Ąã‚¤ãƒĢが存在しãĒかãŖたら怒る', async(async () => { + const res = await request('/drive/files/update', { + fileId: '000000000000000000000000', + name: 'ã„ãĄã”ãƒ‘ã‚šã‚ŋ.png' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('間違ãŖたIDで怒られる', async(async () => { + const res = await request('/drive/files/update', { + fileId: 'kyoppie', + name: 'ã„ãĄã”ãƒ‘ã‚šã‚ŋ.png' + }, alice); + + assert.strictEqual(res.status, 400); + })); + }); + + describe('drive/folders/create', () => { + it('フりãƒĢダをäŊœæˆã§ãã‚‹', async(async () => { + const res = await request('/drive/folders/create', { + name: 'test' + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.name, 'test'); + })); + }); + + describe('drive/folders/update', () => { + it('名前を更新できる', async(async () => { + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + + const res = await request('/drive/folders/update', { + folderId: folder.id, + name: 'new name' + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.name, 'new name'); + })); + + it('äģ–äēēぎフりãƒĢダを更新できãĒい', async(async () => { + const folder = (await request('/drive/folders/create', { + name: 'test' + }, bob)).body; + + const res = await request('/drive/folders/update', { + folderId: folder.id, + name: 'new name' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('čĻĒフりãƒĢダを更新できる', async(async () => { + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + const parentFolder = (await request('/drive/folders/create', { + name: 'parent' + }, alice)).body; + + const res = await request('/drive/folders/update', { + folderId: folder.id, + parentId: parentFolder.id + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.parentId, parentFolder.id); + })); + + it('čĻĒフりãƒĢダをį„Ąã—ãĢ更新できる', async(async () => { + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + const parentFolder = (await request('/drive/folders/create', { + name: 'parent' + }, alice)).body; + await request('/drive/folders/update', { + folderId: folder.id, + parentId: parentFolder.id + }, alice); + + const res = await request('/drive/folders/update', { + folderId: folder.id, + parentId: null + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.parentId, null); + })); + + it('äģ–äēēぎフりãƒĢダをčĻĒフりãƒĢダãĢč¨­åŽšã§ããĒい', async(async () => { + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + const parentFolder = (await request('/drive/folders/create', { + name: 'parent' + }, bob)).body; + + const res = await request('/drive/folders/update', { + folderId: folder.id, + parentId: parentFolder.id + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('フりãƒĢダがåžĒį’°ã™ã‚‹ã‚ˆã†ãĒ構造ãĢできãĒい', async(async () => { + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + const parentFolder = (await request('/drive/folders/create', { + name: 'parent' + }, alice)).body; + await request('/drive/folders/update', { + folderId: parentFolder.id, + parentId: folder.id + }, alice); + + const res = await request('/drive/folders/update', { + folderId: folder.id, + parentId: parentFolder.id + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('フりãƒĢダがåžĒį’°ã™ã‚‹ã‚ˆã†ãĒ構造ãĢできãĒい(再帰įš„)', async(async () => { + const folderA = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + const folderB = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + const folderC = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + await request('/drive/folders/update', { + folderId: folderB.id, + parentId: folderA.id + }, alice); + await request('/drive/folders/update', { + folderId: folderC.id, + parentId: folderB.id + }, alice); + + const res = await request('/drive/folders/update', { + folderId: folderA.id, + parentId: folderC.id + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('フりãƒĢダがåžĒį’°ã™ã‚‹ã‚ˆã†ãĒ構造ãĢできãĒい(č‡ĒčēĢ)', async(async () => { + const folderA = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + + const res = await request('/drive/folders/update', { + folderId: folderA.id, + parentId: folderA.id + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('存在しãĒいčĻĒフりãƒĢãƒ€ã‚’č¨­åŽšã§ããĒい', async(async () => { + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + + const res = await request('/drive/folders/update', { + folderId: folder.id, + parentId: '000000000000000000000000' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('不æ­ŖãĒčĻĒフりãƒĢダIDで怒られる', async(async () => { + const folder = (await request('/drive/folders/create', { + name: 'test' + }, alice)).body; + + const res = await request('/drive/folders/update', { + folderId: folder.id, + parentId: 'foo' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('存在しãĒいフりãƒĢダを更新できãĒい', async(async () => { + const res = await request('/drive/folders/update', { + folderId: '000000000000000000000000' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('不æ­ŖãĒフりãƒĢダIDで怒られる', async(async () => { + const res = await request('/drive/folders/update', { + folderId: 'foo' + }, alice); + + assert.strictEqual(res.status, 400); + })); + }); + + describe('messaging/messages/create', () => { + it('ãƒĄãƒƒã‚ģãƒŧジを送äŋĄã§ãã‚‹', async(async () => { + const res = await request('/messaging/messages/create', { + userId: bob.id, + text: 'test' + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.strictEqual(res.body.text, 'test'); + })); + + it('č‡Ē分č‡ĒčēĢãĢã¯ãƒĄãƒƒã‚ģãƒŧジを送äŋĄã§ããĒい', async(async () => { + const res = await request('/messaging/messages/create', { + userId: alice.id, + text: 'Yo' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('存在しãĒいãƒĻãƒŧã‚ļãƒŧãĢã¯ãƒĄãƒƒã‚ģãƒŧジを送äŋĄã§ããĒい', async(async () => { + const res = await request('/messaging/messages/create', { + userId: '000000000000000000000000', + text: 'test' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('不æ­ŖãĒãƒĻãƒŧã‚ļãƒŧIDで怒られる', async(async () => { + const res = await request('/messaging/messages/create', { + userId: 'foo', + text: 'test' + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('テキ゚トがį„ĄããĻ怒られる', async(async () => { + const res = await request('/messaging/messages/create', { + userId: bob.id + }, alice); + + assert.strictEqual(res.status, 400); + })); + + it('文字数ã‚Ēãƒŧバãƒŧで怒られる', async(async () => { + const res = await request('/messaging/messages/create', { + userId: bob.id, + text: '!'.repeat(1001) + }, alice); + + assert.strictEqual(res.status, 400); + })); + }); + + describe('notes/replies', () => { + it('č‡Ē分ãĢ閲čĻ§æ¨Šé™ãŽãĒい投į¨ŋはåĢぞれãĒい', async(async () => { + const alicePost = await post(alice, { + text: 'foo' + }); + + await post(bob, { + replyId: alicePost.id, + text: 'bar', + visibility: 'specified', + visibleUserIds: [alice.id] + }); + + const res = await request('/notes/replies', { + noteId: alicePost.id + }, carol); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + assert.strictEqual(res.body.length, 0); + })); + }); + + describe('notes/timeline', () => { + it('フりロワãƒŧ限厚投į¨ŋがåĢぞれる', async(async () => { + await request('/following/create', { + userId: alice.id + }, bob); + + const alicePost = await post(alice, { + text: 'foo', + visibility: 'followers' + }); + + const res = await request('/notes/timeline', {}, bob); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + assert.strictEqual(res.body.length, 1); + assert.strictEqual(res.body[0].id, alicePost.id); + })); + }); +}); +*/ diff --git a/packages/backend/test/extract-mentions.ts b/packages/backend/test/extract-mentions.ts index 9e6d04190..9bfbc4192 100644 --- a/packages/backend/test/extract-mentions.ts +++ b/packages/backend/test/extract-mentions.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; -import { extractMentions } from '../src/misc/extract-mentions'; +import { extractMentions } from '../src/misc/extract-mentions.js'; import { parse } from 'mfm-js'; describe('Extract mentions', () => { diff --git a/packages/backend/test/fetch-resource.ts b/packages/backend/test/fetch-resource.ts index c403f4d39..4cb4b4256 100644 --- a/packages/backend/test/fetch-resource.ts +++ b/packages/backend/test/fetch-resource.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, startServer, signup, post, request, simpleGet, port, shutdownServer } from './utils'; +import { async, startServer, signup, post, request, simpleGet, port, shutdownServer } from './utils.js'; import * as openapi from '@redocly/openapi-core'; // Request Accept diff --git a/packages/backend/test/ff-visibility.ts b/packages/backend/test/ff-visibility.ts index 295ab1933..4f6847be6 100644 --- a/packages/backend/test/ff-visibility.ts +++ b/packages/backend/test/ff-visibility.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, signup, request, post, react, connectStream, startServer, shutdownServer, simpleGet } from './utils'; +import { async, signup, request, post, react, connectStream, startServer, shutdownServer, simpleGet } from './utils.js'; describe('FF visibility', () => { let p: childProcess.ChildProcess; diff --git a/packages/backend/test/get-file-info.ts b/packages/backend/test/get-file-info.ts index a0146bd81..20061b870 100644 --- a/packages/backend/test/get-file-info.ts +++ b/packages/backend/test/get-file-info.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; -import { async } from './utils'; -import { getFileInfo } from '../src/misc/get-file-info'; +import { async } from './utils.js'; +import { getFileInfo } from '../src/misc/get-file-info.js'; describe('Get file info', () => { it('Empty file', async (async () => { diff --git a/packages/backend/test/loader.js b/packages/backend/test/loader.js new file mode 100644 index 000000000..016f32f1a --- /dev/null +++ b/packages/backend/test/loader.js @@ -0,0 +1,37 @@ +import path from 'path' +import typescript from 'typescript' +import { createMatchPath } from 'tsconfig-paths' +import { resolve as BaseResolve, getFormat, transformSource } from 'ts-node/esm' + +const { readConfigFile, parseJsonConfigFileContent, sys } = typescript + +const __dirname = path.dirname(new URL(import.meta.url).pathname) + +const configFile = readConfigFile('./test/tsconfig.json', sys.readFile) +if (typeof configFile.error !== 'undefined') { + throw new Error(`Failed to load tsconfig: ${configFile.error}`) +} + +const { options } = parseJsonConfigFileContent( + configFile.config, + { + fileExists: sys.fileExists, + readFile: sys.readFile, + readDirectory: sys.readDirectory, + useCaseSensitiveFileNames: true, + }, + __dirname +) + +export { getFormat, transformSource } // こいつらはそぎぞぞäŊŋãŖãĻãģしいぎで re-export する + +const matchPath = createMatchPath(options.baseUrl, options.paths) + +export async function resolve(specifier, context, defaultResolve) { + const matchedSpecifier = matchPath(specifier.replace('.js', '.ts')) + return BaseResolve( // ts-node/esm ぎ resolve ãĢ tsconfig-paths でč§Ŗæąēã—ãŸãƒ‘ã‚šã‚’æ¸Ąã™ + matchedSpecifier ? `${matchedSpecifier}.ts` : specifier, + context, + defaultResolve + ) +} diff --git a/packages/backend/test/mfm.ts b/packages/backend/test/mfm.ts index ecf886ad6..5218942a5 100644 --- a/packages/backend/test/mfm.ts +++ b/packages/backend/test/mfm.ts @@ -1,8 +1,8 @@ import * as assert from 'assert'; import * as mfm from 'mfm-js'; -import { toHtml } from '../src/mfm/to-html'; -import { fromHtml } from '../src/mfm/from-html'; +import { toHtml } from '../src/mfm/to-html.js'; +import { fromHtml } from '../src/mfm/from-html.js'; describe('toHtml', () => { it('br', () => { diff --git a/packages/backend/test/misc/mock-resolver.ts b/packages/backend/test/misc/mock-resolver.ts index c245c83ba..5a46daf49 100644 --- a/packages/backend/test/misc/mock-resolver.ts +++ b/packages/backend/test/misc/mock-resolver.ts @@ -1,5 +1,5 @@ -import Resolver from '../../src/remote/activitypub/resolver'; -import { IObject } from '../../src/remote/activitypub/type'; +import Resolver from '../../src/remote/activitypub/resolver.js'; +import { IObject } from '../../src/remote/activitypub/type.js'; type MockResponse = { type: string; diff --git a/packages/backend/test/mute.ts b/packages/backend/test/mute.ts index ecac31075..288e8a805 100644 --- a/packages/backend/test/mute.ts +++ b/packages/backend/test/mute.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, signup, request, post, react, connectStream, startServer, shutdownServer } from './utils'; +import { async, signup, request, post, react, connectStream, startServer, shutdownServer } from './utils.js'; describe('Mute', () => { let p: childProcess.ChildProcess; diff --git a/packages/backend/test/note.ts b/packages/backend/test/note.ts index ab8b6b190..62cea5208 100644 --- a/packages/backend/test/note.ts +++ b/packages/backend/test/note.ts @@ -2,8 +2,8 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, signup, request, post, uploadFile, startServer, shutdownServer, initTestDb } from './utils'; -import { Note } from '../src/models/entities/note'; +import { async, signup, request, post, uploadFile, startServer, shutdownServer, initTestDb } from './utils.js'; +import { Note } from '../src/models/entities/note.js'; describe('Note', () => { let p: childProcess.ChildProcess; diff --git a/packages/backend/test/prelude/maybe.ts b/packages/backend/test/prelude/maybe.ts index 2687a739a..0f4b00065 100644 --- a/packages/backend/test/prelude/maybe.ts +++ b/packages/backend/test/prelude/maybe.ts @@ -1,5 +1,5 @@ import * as assert from 'assert'; -import { just, nothing } from '../../src/prelude/maybe'; +import { just, nothing } from '../../src/prelude/maybe.js'; describe('just', () => { it('has a value', () => { diff --git a/packages/backend/test/prelude/url.ts b/packages/backend/test/prelude/url.ts index 1f814968a..84e43d26c 100644 --- a/packages/backend/test/prelude/url.ts +++ b/packages/backend/test/prelude/url.ts @@ -1,5 +1,5 @@ import * as assert from 'assert'; -import { query } from '../../src/prelude/url'; +import { query } from '../../src/prelude/url.js'; describe('url', () => { it('query', () => { diff --git a/packages/backend/test/reaction-lib.ts b/packages/backend/test/reaction-lib.ts index 59c07de00..7c61dc76c 100644 --- a/packages/backend/test/reaction-lib.ts +++ b/packages/backend/test/reaction-lib.ts @@ -1,7 +1,7 @@ /* import * as assert from 'assert'; -import { toDbReaction } from '../src/misc/reaction-lib'; +import { toDbReaction } from '../src/misc/reaction-lib.js'; describe('toDbReaction', async () => { it('æ—ĸ存ぎ文字列ãƒĒã‚ĸã‚¯ã‚ˇãƒ§ãƒŗはそぎぞぞ', async () => { diff --git a/packages/backend/test/streaming.ts b/packages/backend/test/streaming.ts index e4b651aa9..8d22b6d3d 100644 --- a/packages/backend/test/streaming.ts +++ b/packages/backend/test/streaming.ts @@ -2,8 +2,8 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { connectStream, signup, request, post, startServer, shutdownServer, initTestDb } from './utils'; -import { Following } from '../src/models/entities/following'; +import { connectStream, signup, request, post, startServer, shutdownServer, initTestDb } from './utils.js'; +import { Following } from '../src/models/entities/following.js'; describe('Streaming', () => { let p: childProcess.ChildProcess; diff --git a/packages/backend/test/thread-mute.ts b/packages/backend/test/thread-mute.ts index 95601cd90..cd3e51939 100644 --- a/packages/backend/test/thread-mute.ts +++ b/packages/backend/test/thread-mute.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, signup, request, post, react, connectStream, startServer, shutdownServer } from './utils'; +import { async, signup, request, post, react, connectStream, startServer, shutdownServer } from './utils.js'; describe('Note thread mute', () => { let p: childProcess.ChildProcess; diff --git a/packages/backend/test/tsconfig.json b/packages/backend/test/tsconfig.json index 9f9e724ea..3f9020d46 100644 --- a/packages/backend/test/tsconfig.json +++ b/packages/backend/test/tsconfig.json @@ -10,7 +10,7 @@ "declaration": false, "sourceMap": true, "target": "es2017", - "module": "commonjs", + "module": "es2020", "moduleResolution": "node", "allowSyntheticDefaultImports": true, "removeComments": false, diff --git a/packages/backend/test/user-notes.ts b/packages/backend/test/user-notes.ts index c90c07d75..25ffe0475 100644 --- a/packages/backend/test/user-notes.ts +++ b/packages/backend/test/user-notes.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as childProcess from 'child_process'; -import { async, signup, request, post, uploadFile, startServer, shutdownServer } from './utils'; +import { async, signup, request, post, uploadFile, startServer, shutdownServer } from './utils.js'; describe('users/notes', () => { let p: childProcess.ChildProcess; diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index b7f6cfbda..994c098b7 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -1,14 +1,14 @@ -import * as fs from 'fs'; +import * as fs from 'node:fs'; import * as WebSocket from 'ws'; import * as misskey from 'misskey-js'; import fetch from 'node-fetch'; -const FormData = require('form-data'); +import FormData from 'form-data'; import * as childProcess from 'child_process'; import * as http from 'http'; -import loadConfig from '../src/config/load'; +import loadConfig from '../src/config/load.js'; import { SIGKILL } from 'constants'; import { createConnection, getConnection } from 'typeorm'; -import { entities } from '../src/db/postgre'; +import { entities } from '../src/db/postgre.js'; const config = loadConfig(); export const port = config.port; diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json index 3311e117d..3120851aa 100644 --- a/packages/backend/tsconfig.json +++ b/packages/backend/tsconfig.json @@ -10,7 +10,7 @@ "declaration": false, "sourceMap": false, "target": "es2017", - "module": "commonjs", + "module": "es2020", "moduleResolution": "node", "allowSyntheticDefaultImports": true, "removeComments": false, @@ -30,7 +30,7 @@ "outDir": "./built", "typeRoots": [ "./node_modules/@types", - "./@types" + "./src/@types" ], "lib": [ "esnext" diff --git a/packages/backend/yarn.lock b/packages/backend/yarn.lock index 99e2e2306..fea3b2e01 100644 --- a/packages/backend/yarn.lock +++ b/packages/backend/yarn.lock @@ -82,14 +82,14 @@ pump "^3.0.0" secure-json-parse "^2.1.0" -"@eslint/eslintrc@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318" - integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ== +"@eslint/eslintrc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.1.0.tgz#583d12dbec5d4f22f333f9669f7d0b7c7815b4d3" + integrity sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.2.0" + espree "^9.3.1" globals "^13.9.0" ignore "^4.0.6" import-fresh "^3.2.1" @@ -128,10 +128,10 @@ resolved "https://registry.yarnpkg.com/@koa/multer/-/multer-3.0.0.tgz#439777949f28097d7b329c0b4ce3048074c862f8" integrity sha512-y+OQBmex5D1jIl723gAEUYcAWPEicIXppaAKw/zCMfpllQ08ZNweDPwoCLxEoatqd5pCu2XG6V8dl67JRq3RJw== -"@koa/router@9.0.1": - version "9.0.1" - resolved "https://registry.yarnpkg.com/@koa/router/-/router-9.0.1.tgz#4090a14223ea7e78aa13b632761209cba69acd95" - integrity sha512-OI+OU49CJV4px0WkIMmayBeqVXB/JS1ZMq7UoGlTZt6Y7ijK7kdeQ18+SEHHJPytmtI1y6Hf8XLrpxva3mhv5Q== +"@koa/router@10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@koa/router/-/router-10.1.1.tgz#8e5a85c9b243e0bc776802c0de564561e57a5f78" + integrity sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw== dependencies: debug "^4.1.1" http-errors "^1.7.3" @@ -216,10 +216,10 @@ require-from-string "^2.0.2" uri-js "^4.2.2" -"@redocly/openapi-core@1.0.0-beta.79": - version "1.0.0-beta.79" - resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.79.tgz#7512b3507ab99dc78226f9069669c5302abb0969" - integrity sha512-do79vGt3iiHsaVG9LKY8dH+d1E7TLHr+3T+CQ1lqagtWVjYOxqGaoxAT8tRD7R1W0z8BmS4e2poNON6c1sxP5g== +"@redocly/openapi-core@1.0.0-beta.83": + version "1.0.0-beta.83" + resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.83.tgz#df1324cc6f1874ecf3046e503192cf872f134a2f" + integrity sha512-XwlxMAmNEQeyBfODXVg2iBpSUqzCwT2zI+7o5iKxjUwJ+5ZugNOYjZGGM3Q9rJGqzFVwLKdElM5a1MlhPvlu4Q== dependencies: "@redocly/ajv" "^8.6.4" "@types/node" "^14.11.8" @@ -238,9 +238,9 @@ integrity sha512-JiX9vxoKMmu8Y3Zr2RVathBL1Cdu4Nt4MuNWemt1Nc06A0RAin9c5FArkhGsyMBWfCu4zj+9b+GxtjAnE4qqLQ== "@sindresorhus/is@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.0.tgz#2ff674e9611b45b528896d820d3d7a812de2f0e4" - integrity sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ== + version "4.4.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.4.0.tgz#e277e5bdbdf7cb1e20d320f02f5e2ed113cd3185" + integrity sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ== "@sinonjs/commons@^1.7.0": version "1.7.2" @@ -249,10 +249,10 @@ dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz#2524eae70c4910edccf99b2f4e6efc5894aff7b5" - integrity sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg== +"@sinonjs/fake-timers@9.1.0": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.0.tgz#8c92c56f195e0bed4c893ba59c8e3d55831ca0df" + integrity sha512-M8vapsv9qQupMdzrVzkn5rb9jG7aUTEPAZdMtME2PuBaefksFZVE2C1g4LBRTkF/k3nRDNbDc5tp5NFC1PEYxA== dependencies: "@sinonjs/commons" "^1.7.0" @@ -289,6 +289,11 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + "@tsconfig/node10@^1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.7.tgz#1eb1de36c73478a2479cc661ef5af1c16d86d606" @@ -316,11 +321,6 @@ dependencies: "@types/node" "*" -"@types/anymatch@*": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" - integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== - "@types/bcryptjs@2.4.2": version "2.4.2" resolved "https://registry.yarnpkg.com/@types/bcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae" @@ -334,10 +334,10 @@ "@types/connect" "*" "@types/node" "*" -"@types/bull@3.15.7": - version "3.15.7" - resolved "https://registry.yarnpkg.com/@types/bull/-/bull-3.15.7.tgz#a9d7fb332cc02dc021d0eb234b9604b356e9e6de" - integrity sha512-7NC7XN5NoS0A+leJ/dR69ZfKaegOlCZaii/xGgKnCyh1UYisRncibImb7VMwrc3OdJcbDJt6+4om70TeNl3J7g== +"@types/bull@3.15.8": + version "3.15.8" + resolved "https://registry.yarnpkg.com/@types/bull/-/bull-3.15.8.tgz#ae2139f94490d740b37c8da5d828ce75dd82ce7c" + integrity sha512-8DbSPMSsZH5PWPnGEkAZLYgJEH4ghHJNKF7LB6Wr5R0/v6g+Vs+JoaA7kcvLtHE936xg2WpFPkaoaJgExOmKDw== dependencies: "@types/ioredis" "*" "@types/redis" "^2.8.0" @@ -386,11 +386,6 @@ "@types/keygrip" "*" "@types/node" "*" -"@types/dateformat@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/dateformat/-/dateformat-3.0.1.tgz#98d747a2e5e9a56070c6bf14e27bff56204e34cc" - integrity sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g== - "@types/disposable-email-domains@^1.0.1": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/disposable-email-domains/-/disposable-email-domains-1.0.2.tgz#0280f6b38fa7f14e54b056a434135ecd254483b1" @@ -401,27 +396,6 @@ resolved "https://registry.yarnpkg.com/@types/escape-regexp/-/escape-regexp-0.0.1.tgz#f1a977ccdf2ef059e9862bd3af5e92cbbe723e0e" integrity sha512-ogj/ZTIdeFkiuxDwawYuZSIgC6suFGgBeZPr6Xs5lHEcvIXTjXGtH+/n8f1XhZhespaUwJ5LIGRICPji972FLw== -"@types/eslint-scope@^3.7.0": - version "3.7.0" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.0.tgz#4792816e31119ebd506902a482caec4951fabd86" - integrity sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.0.tgz#eb5c5b575237334df24c53195e37b53d66478d7b" - integrity sha512-LpUXkr7fnmPXWGxB0ZuLEzNeTURuHPavkC5zuU4sg62/TgL5ZEjamr5Y8b6AftwHtx2bPJasI+CL0TT2JwQ7aA== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@^0.0.46": - version "0.0.46" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe" - integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== - "@types/express-serve-static-core@*": version "4.17.5" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.5.tgz#a00ac7dadd746ae82477443e4d480a6a93ea083c" @@ -447,14 +421,6 @@ dependencies: "@types/node" "*" -"@types/glob@7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" - integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - "@types/http-assert@*": version "1.5.1" resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.1.tgz#d775e93630c2469c2f980fc27e3143240335db3b" @@ -496,11 +462,6 @@ "@types/parse5" "*" "@types/tough-cookie" "*" -"@types/json-schema@*": - version "7.0.5" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" - integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== - "@types/json-schema@^7.0.6": version "7.0.6" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" @@ -643,15 +604,10 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== -"@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/mocha@8.2.3": - version "8.2.3" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.3.tgz#bbeb55fbc73f28ea6de601fbfa4613f58d785323" - integrity sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw== +"@types/mocha@9.1.0": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.0.tgz#baf17ab2cca3fcce2d322ebc30454bff487efad5" + integrity sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg== "@types/node-fetch@3.0.3": version "3.0.3" @@ -665,10 +621,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50" integrity sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA== -"@types/node@17.0.10": - version "17.0.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.10.tgz#616f16e9d3a2a3d618136b1be244315d95bd7cab" - integrity sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog== +"@types/node@17.0.19": + version "17.0.19" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.19.tgz#726171367f404bfbe8512ba608a09ebad810c7e6" + integrity sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA== "@types/node@^14.11.8": version "14.17.9" @@ -770,13 +726,6 @@ resolved "https://registry.yarnpkg.com/@types/rename/-/rename-1.0.4.tgz#30c6f0306042591a560361ea02639e89647dd173" integrity sha512-eV81+6bVv2mdCBahkMefjEUwAjKDAP3AuyhqWCWRxcRaeVdUeHUBaoq2zSz+5HNHF2jzTajMcfLvJsy4K3cbwA== -"@types/request-stats@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/request-stats/-/request-stats-3.0.0.tgz#d3909a9f778b8ae0b42fb8c1ed20cb936ed95f99" - integrity sha512-POsDF7nETH8up49iBNvbZuO0pEk9F+TG0rXCkvjxCClcOS99xfF+mKmJteYlwKYpuRKkixzysKlL8rwN1hU2lw== - dependencies: - "@types/node" "*" - "@types/responselike@*", "@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" @@ -791,10 +740,10 @@ dependencies: htmlparser2 "^6.0.0" -"@types/seedrandom@2.4.28": - version "2.4.28" - resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.28.tgz#9ce8fa048c1e8c85cb71d7fe4d704e000226036f" - integrity sha512-SMA+fUwULwK7sd/ZJicUztiPs8F1yCPwF3O23Z9uQ32ME5Ha0NmDK9+QTsYE4O2tHXChzXomSWWeIhCnoN1LqA== +"@types/seedrandom@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-3.0.1.tgz#1254750a4fec4aff2ebec088ccd0bb02e91fedb4" + integrity sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw== "@types/serve-static@*": version "1.13.3" @@ -811,15 +760,10 @@ dependencies: "@types/node" "*" -"@types/sinonjs__fake-timers@6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.4.tgz#0ecc1b9259b76598ef01942f547904ce61a6a77d" - integrity sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A== - -"@types/source-list-map@*": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" - integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== +"@types/sinonjs__fake-timers@8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" + integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== "@types/speakeasy@2.0.7": version "2.0.7" @@ -828,11 +772,6 @@ dependencies: "@types/node" "*" -"@types/tapable@^1": - version "1.0.7" - resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.7.tgz#545158342f949e8fd3bfd813224971ecddc3fac4" - integrity sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ== - "@types/throttle-debounce@2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@types/throttle-debounce/-/throttle-debounce-2.1.0.tgz#1c3df624bfc4b62f992d3012b84c56d41eab3776" @@ -853,13 +792,6 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d" integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A== -"@types/uglify-js@*": - version "3.9.0" - resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.9.0.tgz#4490a140ca82aa855ad68093829e7fd6ae94ea87" - integrity sha512-3ZcoyPYHVOCcLpnfZwD47KFLr8W/mpUcgjpf1M4Q78TMJIw7KMAHSjiCLJp1z3ZrBR9pTLbe191O0TldFK5zcw== - dependencies: - source-map "^0.6.1" - "@types/uuid@8.3.4": version "8.3.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" @@ -872,55 +804,17 @@ dependencies: "@types/node" "*" -"@types/webpack-sources@*": - version "0.1.7" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.7.tgz#0a330a9456113410c74a5d64180af0cbca007141" - integrity sha512-XyaHrJILjK1VHVC4aVlKsdNN5KBTwufMb43cQs+flGxtPAf/1Qwl8+Q0tp5BwEGaI8D6XT1L+9bSWXckgkjTLw== - dependencies: - "@types/node" "*" - "@types/source-list-map" "*" - source-map "^0.6.1" - -"@types/webpack-stream@3.2.12": - version "3.2.12" - resolved "https://registry.yarnpkg.com/@types/webpack-stream/-/webpack-stream-3.2.12.tgz#cf13e64067a662a7acd8cd0524b3f64c86b0ecb6" - integrity sha512-znMUl4kKT0V0SwkUgRgwUNSAO7J5I/jdTCBNy3utkCsgMJ3IHp4FBTDwsQC+tfQ73TWeKIH05QNmbUYmeGThGw== - dependencies: - "@types/node" "*" - "@types/webpack" "^4" - -"@types/webpack@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-5.28.0.tgz#78dde06212f038d77e54116cfe69e88ae9ed2c03" - integrity sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w== - dependencies: - "@types/node" "*" - tapable "^2.2.0" - webpack "^5" - -"@types/webpack@^4": - version "4.41.27" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.27.tgz#f47da488c8037e7f1b2dbf2714fbbacb61ec0ffc" - integrity sha512-wK/oi5gcHi72VMTbOaQ70VcDxSQ1uX8S2tukBK9ARuGXrYM/+u4ou73roc7trXDNmCxCoerE8zruQqX/wuHszA== - dependencies: - "@types/anymatch" "*" - "@types/node" "*" - "@types/tapable" "^1" - "@types/uglify-js" "*" - "@types/webpack-sources" "*" - source-map "^0.6.0" - -"@types/websocket@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.4.tgz#1dc497280d8049a5450854dd698ee7e6ea9e60b8" - integrity sha512-qn1LkcFEKK8RPp459jkjzsfpbsx36BBt3oC3pITYtkoBw/aVX+EZFa5j3ThCRTNpLFvIMr5dSTD4RaMdilIOpA== +"@types/websocket@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.5.tgz#3fb80ed8e07f88e51961211cd3682a3a4a81569c" + integrity sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ== dependencies: "@types/node" "*" -"@types/ws@8.2.2": - version "8.2.2" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.2.tgz#7c5be4decb19500ae6b3d563043cd407bf366c21" - integrity sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg== +"@types/ws@8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.3.tgz#0bca6b03ba2f41e0fab782d4a573fe284aa907ae" + integrity sha512-ahRJZquUYCdOZf/rCsWg88S0/+cb9wazUBHv6HZEe3XdYaBe2zr/slM8J28X07Hn88Pnm4ezo7N8/ofnOgrPVQ== dependencies: "@types/node" "*" @@ -929,14 +823,14 @@ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71" integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg== -"@typescript-eslint/eslint-plugin@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.0.tgz#e90afea96dff8620892ad216b0e4ccdf8ee32d3a" - integrity sha512-XXVKnMsq2fuu9K2KsIxPUGqb6xAImz8MEChClbXmE3VbveFtBUU5bzM6IPVWqzyADIgdkS2Ws/6Xo7W2TeZWjQ== +"@typescript-eslint/eslint-plugin@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz#b2cd3e288f250ce8332d5035a2ff65aba3374ac4" + integrity sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw== dependencies: - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/type-utils" "5.10.0" - "@typescript-eslint/utils" "5.10.0" + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/type-utils" "5.12.1" + "@typescript-eslint/utils" "5.12.1" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -944,69 +838,69 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/parser@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.10.0.tgz#8f59e036f5f1cffc178cacbd5ccdd02aeb96c91c" - integrity sha512-pJB2CCeHWtwOAeIxv8CHVGJhI5FNyJAIpx5Pt72YkK3QfEzt6qAlXZuyaBmyfOdM62qU0rbxJzNToPTVeJGrQw== +"@typescript-eslint/parser@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.12.1.tgz#b090289b553b8aa0899740d799d0f96e6f49771b" + integrity sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw== dependencies: - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/typescript-estree" "5.10.0" + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/typescript-estree" "5.12.1" debug "^4.3.2" -"@typescript-eslint/scope-manager@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.10.0.tgz#bb5d872e8b9e36203908595507fbc4d3105329cb" - integrity sha512-tgNgUgb4MhqK6DoKn3RBhyZ9aJga7EQrw+2/OiDk5hKf3pTVZWyqBi7ukP+Z0iEEDMF5FDa64LqODzlfE4O/Dg== +"@typescript-eslint/scope-manager@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz#58734fd45d2d1dec49641aacc075fba5f0968817" + integrity sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ== dependencies: - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/visitor-keys" "5.10.0" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/visitor-keys" "5.12.1" -"@typescript-eslint/type-utils@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.10.0.tgz#8524b9479c19c478347a7df216827e749e4a51e5" - integrity sha512-TzlyTmufJO5V886N+hTJBGIfnjQDQ32rJYxPaeiyWKdjsv2Ld5l8cbS7pxim4DeNs62fKzRSt8Q14Evs4JnZyQ== +"@typescript-eslint/type-utils@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz#8d58c6a0bb176b5e9a91581cda1a7f91a114d3f0" + integrity sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg== dependencies: - "@typescript-eslint/utils" "5.10.0" + "@typescript-eslint/utils" "5.12.1" debug "^4.3.2" tsutils "^3.21.0" -"@typescript-eslint/types@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.0.tgz#beb3cb345076f5b088afe996d57bcd1dfddaa75c" - integrity sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ== +"@typescript-eslint/types@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.12.1.tgz#46a36a28ff4d946821b58fe5a73c81dc2e12aa89" + integrity sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA== -"@typescript-eslint/typescript-estree@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz#4be24a3dea0f930bb1397c46187d0efdd955a224" - integrity sha512-x+7e5IqfwLwsxTdliHRtlIYkgdtYXzE0CkFeV6ytAqq431ZyxCFzNMNR5sr3WOlIG/ihVZr9K/y71VHTF/DUQA== +"@typescript-eslint/typescript-estree@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz#6a9425b9c305bcbc38e2d1d9a24c08e15e02b722" + integrity sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw== dependencies: - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/visitor-keys" "5.10.0" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/visitor-keys" "5.12.1" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.10.0.tgz#c3d152a85da77c400e37281355561c72fb1b5a65" - integrity sha512-IGYwlt1CVcFoE2ueW4/ioEwybR60RAdGeiJX/iDAw0t5w0wK3S7QncDwpmsM70nKgGTuVchEWB8lwZwHqPAWRg== +"@typescript-eslint/utils@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.12.1.tgz#447c24a05d9c33f9c6c64cb48f251f2371eef920" + integrity sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/typescript-estree" "5.10.0" + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/typescript-estree" "5.12.1" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz#770215497ad67cd15a572b52089991d5dfe06281" - integrity sha512-GMxj0K1uyrFLPKASLmZzCuSddmjZVbVj3Ouy5QVuIGKZopxvOr24JsS7gruz6C3GExE01mublZ3mIBOaon9zuQ== +"@typescript-eslint/visitor-keys@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz#f722da106c8f9695ae5640574225e45af3e52ec3" + integrity sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A== dependencies: - "@typescript-eslint/types" "5.10.0" + "@typescript-eslint/types" "5.12.1" eslint-visitor-keys "^3.0.0" "@ungap/promise-all-settled@1.1.2": @@ -1014,137 +908,6 @@ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== -"@webassemblyjs/ast@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f" - integrity sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - -"@webassemblyjs/floating-point-hex-parser@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz#34d62052f453cd43101d72eab4966a022587947c" - integrity sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA== - -"@webassemblyjs/helper-api-error@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz#aaea8fb3b923f4aaa9b512ff541b013ffb68d2d4" - integrity sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w== - -"@webassemblyjs/helper-buffer@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz#d026c25d175e388a7dbda9694e91e743cbe9b642" - integrity sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA== - -"@webassemblyjs/helper-numbers@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz#7ab04172d54e312cc6ea4286d7d9fa27c88cd4f9" - integrity sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.0" - "@webassemblyjs/helper-api-error" "1.11.0" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/helper-wasm-bytecode@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz#85fdcda4129902fe86f81abf7e7236953ec5a4e1" - integrity sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA== - -"@webassemblyjs/helper-wasm-section@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz#9ce2cc89300262509c801b4af113d1ca25c1a75b" - integrity sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew== - dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-buffer" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - "@webassemblyjs/wasm-gen" "1.11.0" - -"@webassemblyjs/ieee754@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz#46975d583f9828f5d094ac210e219441c4e6f5cf" - integrity sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.0.tgz#f7353de1df38aa201cba9fb88b43f41f75ff403b" - integrity sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.0.tgz#86e48f959cf49e0e5091f069a709b862f5a2cadf" - integrity sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw== - -"@webassemblyjs/wasm-edit@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz#ee4a5c9f677046a210542ae63897094c2027cb78" - integrity sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ== - dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-buffer" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - "@webassemblyjs/helper-wasm-section" "1.11.0" - "@webassemblyjs/wasm-gen" "1.11.0" - "@webassemblyjs/wasm-opt" "1.11.0" - "@webassemblyjs/wasm-parser" "1.11.0" - "@webassemblyjs/wast-printer" "1.11.0" - -"@webassemblyjs/wasm-gen@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz#3cdb35e70082d42a35166988dda64f24ceb97abe" - integrity sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ== - dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - "@webassemblyjs/ieee754" "1.11.0" - "@webassemblyjs/leb128" "1.11.0" - "@webassemblyjs/utf8" "1.11.0" - -"@webassemblyjs/wasm-opt@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz#1638ae188137f4bb031f568a413cd24d32f92978" - integrity sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg== - dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-buffer" "1.11.0" - "@webassemblyjs/wasm-gen" "1.11.0" - "@webassemblyjs/wasm-parser" "1.11.0" - -"@webassemblyjs/wasm-parser@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz#3e680b8830d5b13d1ec86cc42f38f3d4a7700754" - integrity sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw== - dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-api-error" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - "@webassemblyjs/ieee754" "1.11.0" - "@webassemblyjs/leb128" "1.11.0" - "@webassemblyjs/utf8" "1.11.0" - -"@webassemblyjs/wast-printer@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz#680d1f6a5365d6d401974a8e949e05474e1fab7e" - integrity sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ== - dependencies: - "@webassemblyjs/ast" "1.11.0" - "@xtuc/long" "4.2.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - abab@^2.0.3, abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" @@ -1198,22 +961,12 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4: - version "8.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.1.0.tgz#52311fd7037ae119cbb134309e901aa46295b3fe" - integrity sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA== - -acorn@^8.2.4: - version "8.2.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.4.tgz#caba24b08185c3b56e3168e97d15ed17f4d31fd0" - integrity sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg== - acorn@^8.4.1: version "8.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== -acorn@^8.7.0: +acorn@^8.5.0, acorn@^8.7.0: version "8.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== @@ -1247,6 +1000,16 @@ ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== +ajv@8.10.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" + integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: version "6.12.5" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" @@ -1476,10 +1239,10 @@ autwh@0.1.0: dependencies: oauth "0.9.15" -aws-sdk@2.1061.0: - version "2.1061.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1061.0.tgz#79c75e6856e5a59e0857d0d066a8ff5ff5e0d752" - integrity sha512-T29yV+EPo4Fis9hAArxAXS/u6utKnlBq3DEu85LTSIA8i6e6Xg7e9u7Rveo8DmrlVrf7EGCNThaeF9WERHnwLg== +aws-sdk@2.1079.0: + version "2.1079.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1079.0.tgz#41ede54aa4ba5ce77d4ffe202f9a1ee7869da2a8" + integrity sha512-WHYWiye9f2XYQ33Rj/uVw4VF/Qq/xrB9NDnGlRhgK8Ga7T20+8/iZD5/Z8wICVNZTsfUZ3g6LfkeZ1l+LZhHKw== dependencies: buffer "4.9.2" events "1.1.1" @@ -1584,10 +1347,10 @@ bluebird@~3.4.1: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" integrity sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM= -blurhash@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-1.1.4.tgz#a7010ceb3019cd2c9809b17c910ebf6175d29244" - integrity sha512-MXIPz6zwYUKayju+Uidf83KhH0vodZfeRl6Ich8Gu+KGl0JgKiFq9LsfqV7cVU5fKD/AotmduZqvOfrGKOfTaA== +blurhash@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-1.1.5.tgz#3034104cd5dce5a3e5caa871ae2f0f1f2d0ab566" + integrity sha512-a+LO3A2DfxTaTztsmkbLYmUzUeApi0LZuKalwbNmqAHR6HhJGMt1qSV/R3wc+w4DL28holjqO3Bg74aUGavGjg== bn.js@^4.0.0: version "4.11.8" @@ -1614,10 +1377,10 @@ braces@^3.0.1, braces@~3.0.2: dependencies: fill-range "^7.0.1" -broadcast-channel@4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.9.0.tgz#8af337d4ea19aeb6b819ec2eb3dda942b28c724c" - integrity sha512-xWzFb3wrOZGJF2kOSs2D3KvHXdLDMVb+WypEIoNvwblcHgUBydVy65pDJ9RS4WN9Kyvs0UVQuCCzfKme0G6Qjw== +broadcast-channel@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.10.0.tgz#d19fb902df227df40b1b580351713d30c302d198" + integrity sha512-hOUh312XyHk6JTVyX9cyXaH1UYs+2gHVtnW16oQAu9FL7ALcXGXc/YoJWqlkV8vUn14URQPMmRi4A9q4UrwVEQ== dependencies: "@babel/runtime" "^7.16.0" detect-node "^2.1.0" @@ -1638,17 +1401,6 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserslist@^4.14.5: - version "4.16.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717" - integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw== - dependencies: - caniuse-lite "^1.0.30001181" - colorette "^1.2.1" - electron-to-chromium "^1.3.649" - escalade "^3.1.1" - node-releases "^1.1.70" - buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -1711,16 +1463,17 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "~3.7.0" -bull@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/bull/-/bull-4.2.1.tgz#c5a7e1496c7903274ce90192e4e5cb18f6c866c0" - integrity sha512-YkCQZMOub++siHw3SbYYXZ5xGEn6Tt3BPoCVq/irPNCxUqUYzta8yDlXyyAsfMKMVj0M7PcnynUabfMf9PFpOA== +bull@4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/bull/-/bull-4.6.2.tgz#fdde3b13245cff79571d85c4702884dfbf419b27" + integrity sha512-RA6wnL+rZ2GRHMhz+UxFEn7hlLBpxPEiW4A0UY3YwWnheRA55AT4MC0PknxqO1K55pGFKSh/GpHQaj8flJMm+w== dependencies: - cron-parser "^2.13.0" + cron-parser "^4.2.1" debuglog "^1.0.0" get-port "^5.1.1" - ioredis "^4.27.0" + ioredis "^4.28.5" lodash "^4.17.21" + msgpackr "^1.5.2" p-timeout "^3.2.0" semver "^7.3.2" uuid "^8.3.0" @@ -1821,11 +1574,6 @@ camelcase@^6.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -caniuse-lite@^1.0.30001181: - version "1.0.30001191" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001191.tgz#bacb432b6701f690c8c5f7c680166b9a9f0843d9" - integrity sha512-xJJqzyd+7GCJXkcoBiQ1GuxEiOBCLQ0aVW9HMekifZsAVGdj5eJ4mFB9fEhSHipq9IOk/QXFJUiIr9lZT+EsGw== - canonicalize@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/canonicalize/-/canonicalize-1.0.1.tgz#657b4f3fa38a6ecb97a9e5b7b26d7a19cc6e0da9" @@ -1853,6 +1601,13 @@ chainsaw@~0.1.0: dependencies: traverse ">=0.3.0 <0.4" +chalk-template@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.3.1.tgz#9511cd31ec3c4911448410d49645526c1c7a3a22" + integrity sha512-sbWkBbb9Tfo81aTtQrfP9eBSVCTL8biVvZ0tA1rH9xqVrKoV2T9Y6Bp94wB+DRXtSGl/UXsgV83Np5hLhNRXww== + dependencies: + chalk "^4.1.2" + chalk@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.0.0.tgz#6e98081ed2d17faab615eb52ac66ec1fe6209e72" @@ -1861,13 +1616,10 @@ chalk@4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" +chalk@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.0.tgz#bd96c6bb8e02b96e08c0c3ee2a9d90e050c7b832" + integrity sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ== chalk@^2.4.2: version "2.4.2" @@ -1886,6 +1638,14 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -1920,7 +1680,7 @@ cheerio@0.22.0: lodash.reject "^4.4.0" lodash.some "^4.4.0" -chokidar@3.5.1, chokidar@^3.3.1, chokidar@^3.5.2: +chokidar@3.5.3, chokidar@^3.3.1, chokidar@^3.5.2: version "3.3.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== @@ -1945,13 +1705,6 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -chrome-trace-event@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" - integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== - dependencies: - tslib "^1.9.0" - clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -2029,6 +1782,13 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= +color-convert@2.0.1, color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -2036,13 +1796,6 @@ color-convert@^1.9.0: dependencies: color-name "1.1.3" -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" @@ -2053,10 +1806,10 @@ color-name@^1.0.0, color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312" - integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA== +color-string@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa" + integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ== dependencies: color-name "^1.0.0" simple-swizzle "^0.2.2" @@ -2066,15 +1819,15 @@ color-support@^1.1.2: resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -color@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/color/-/color-4.0.1.tgz#21df44cd10245a91b1ccf5ba031609b0e10e7d67" - integrity sha512-rpZjOKN5O7naJxkH2Rx1sZzzBgaiWECc6BYXjeCE6kF0kcASJYbUq02u7JqIHwCb/j3NhV+QhRL2683aICeGZA== +color@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.0.tgz#0c782459a3e98838ea01e4bc0fb43310ca35af78" + integrity sha512-hHTcrbvEnGjC7WBMk6ibQWFVDgEFTVmjrz2Q5HlU6ltwxv0JJN2Z8I7uRbWeQLF04dikxs8zgyZkazRJvSMtyQ== dependencies: color-convert "^2.0.1" - color-string "^1.6.0" + color-string "^1.9.0" -colorette@^1.2.0, colorette@^1.2.1: +colorette@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== @@ -2086,7 +1839,7 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@^2.19.0, commander@^2.20.0: +commander@^2.19.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2195,7 +1948,7 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -crc-32@1.2.0, crc-32@^1.2.0: +crc-32@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== @@ -2216,13 +1969,12 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cron-parser@^2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.13.0.tgz#6f930bb6f2931790d2a9eec83b3ec276e27a6725" - integrity sha512-UWeIpnRb0eyoWPVk+pD3TDpNx3KCFQeezO224oJIkktBrcW6RoAPOx5zIKprZGfk6vcYSmA8yQXItejSaDBhbQ== +cron-parser@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.2.1.tgz#b43205d05ccd5c93b097dae64f3bd811f5993af3" + integrity sha512-5sJBwDYyCp+0vU5b7POl8zLWfgV5fOHxlc45FWoWdHecGC7MQHCjx0CHivCMRnGFovghKhhyYM+Zm9DcY5qcHg== dependencies: - is-nan "^1.2.1" - moment-timezone "^0.5.25" + luxon "^1.28.0" cross-env@7.0.3: version "7.0.3" @@ -2255,10 +2007,10 @@ css-what@2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== cssom@~0.3.6: version "0.3.8" @@ -2297,19 +2049,19 @@ data-uri-to-buffer@^4.0.0: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b" integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA== -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== +data-urls@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.1.tgz#597fc2ae30f8bc4dbcf731fcd1b1954353afc6f8" + integrity sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw== dependencies: abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^10.0.0" -dateformat@4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.5.1.tgz#c20e7a9ca77d147906b6dc2261a8be0a5bd2173c" - integrity sha512-OD0TZ+B7yP7ZgpJf5K2DIbj3FZvFvxgFUuaqA/V5zTjAtAAXZ1E8bktHxmAGs4x5b7PflqA9LeQ84Og7wYtF7Q== +date-fns@2.28.0: + version "2.28.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" + integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== debug@2, debug@^2.2.0, debug@^2.5.2, debug@^2.6.9: version "2.6.9" @@ -2318,7 +2070,7 @@ debug@2, debug@^2.2.0, debug@^2.5.2, debug@^2.6.9: dependencies: ms "2.0.0" -debug@4, debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== @@ -2368,10 +2120,10 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -decimal.js@^10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" - integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== +decimal.js@^10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== decompress-response@^6.0.0: version "6.0.0" @@ -2462,10 +2214,10 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-libc@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detect-libc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.0.tgz#c528bc09bc6d1aa30149228240917c225448f204" + integrity sha512-S55LzUl8HUav8l9E2PBTlC5PAJrHK7tkM+XXFGD+fbsbkTzhCpG6K05LxJcUOEWzMa4v6ptcMZ9s3fOdJDu0Zw== detect-node@2.1.0, detect-node@^2.1.0: version "2.1.0" @@ -2566,12 +2318,12 @@ domelementtype@^2.2.0: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== dependencies: - webidl-conversions "^5.0.0" + webidl-conversions "^7.0.0" domhandler@^2.3.0: version "2.4.2" @@ -2661,11 +2413,6 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.649: - version "1.3.672" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.672.tgz#3a6e335016dab4bc584d5292adc4f98f54541f6a" - integrity sha512-gFQe7HBb0lbOMqK2GAS5/1F+B0IMdYiAgB9OT/w1F4M7lgJK2aNOMNOM622aEax+nS1cTMytkiT0uMOkbtFmHw== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -2708,14 +2455,6 @@ enhanced-resolve@^5.0.0: graceful-fs "^4.2.4" tapable "^2.2.0" -enhanced-resolve@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz#525c5d856680fbd5052de453ac83e32049958b5c" - integrity sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - entities@^1.1.1, entities@~1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" @@ -2762,11 +2501,6 @@ es-abstract@^1.19.0, es-abstract@^1.19.1: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" -es-module-lexer@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.4.0.tgz#21f4181cc8b7eee06855f1c59e6087c7bc4f77b0" - integrity sha512-iuEGihqqhKWFgh72Q/Jtch7V2t/ft8w8IPP2aEN8ArYKO+IWyo6hsi96hCdgyeEDQIV3InhYQ9BlwUFPGXrbEQ== - es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -2882,10 +2616,10 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153" - integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -2907,17 +2641,17 @@ eslint-visitor-keys@^3.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186" integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q== -eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1" - integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.7.0.tgz#22e036842ee5b7cf87b03fe237731675b4d3633c" - integrity sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w== +eslint@8.9.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.9.0.tgz#a2a8227a99599adc4342fd9b854cb8d8d6412fdb" + integrity sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q== dependencies: - "@eslint/eslintrc" "^1.0.5" + "@eslint/eslintrc" "^1.1.0" "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" @@ -2925,10 +2659,10 @@ eslint@8.7.0: debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.0" + eslint-scope "^7.1.1" eslint-utils "^3.0.0" - eslint-visitor-keys "^3.2.0" - espree "^9.3.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -2958,14 +2692,14 @@ esm@^3.2.22: resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== -espree@^9.2.0, espree@^9.3.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.0.tgz#c1240d79183b72aaee6ccfa5a90bc9111df085a8" - integrity sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ== +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== dependencies: acorn "^8.7.0" acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.1.0" + eslint-visitor-keys "^3.3.0" esprima@^4.0.1: version "4.0.1" @@ -3021,24 +2755,19 @@ events@1.1.1: resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= -events@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" - integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== - -execa@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-6.0.0.tgz#598b46f09ae44f5d8097a30cfb1681d0f0371503" - integrity sha512-m4wU9j4Z9nXXoqT8RSfl28JSwmMNLFF69OON8H/lL3NeU0tNpGz313bcOfYoBBHokB0dC2tMl3VUcKgHELhL2Q== +execa@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" + integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA== dependencies: cross-spawn "^7.0.3" get-stream "^6.0.1" human-signals "^3.0.1" is-stream "^3.0.0" merge-stream "^2.0.0" - npm-run-path "^5.0.1" + npm-run-path "^5.1.0" onetime "^6.0.0" - signal-exit "^3.0.5" + signal-exit "^3.0.7" strip-final-newline "^3.0.0" exit-on-epipe@~1.0.1: @@ -3241,10 +2970,10 @@ follow-redirects@^1.14.4: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -3406,9 +3135,9 @@ github-from-package@0.0.0: integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= glob-parent@^5.1.0, glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" @@ -3419,15 +3148,10 @@ glob-parent@^6.0.1: dependencies: is-glob "^4.0.3" -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - -glob@7.1.6, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3436,10 +3160,10 @@ glob@7.1.6, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== +glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3619,12 +3343,12 @@ hpagent@^0.1.1: resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-0.1.1.tgz#66f67f16e5c7a8b59a068e40c2658c2c749ad5e2" integrity sha512-IxJWQiY0vmEjetHdoE9HZjD4Cx+mYTr25tR7JCxXaiI3QxW0YqYyM11KyZbHufoa/piWhMb2+D3FGpMgmA2cFQ== -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== dependencies: - whatwg-encoding "^1.0.5" + whatwg-encoding "^2.0.0" html-entities@2.3.2: version "2.3.2" @@ -3687,13 +3411,6 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" -http-headers@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/http-headers/-/http-headers-3.0.2.tgz#5147771292f0b39d6778d930a3a59a76fc7ef44d" - integrity sha512-87E1I+2Wg4dxxz4rcxElo3dxO/w1ZtgL1yA0Sb6vH3qU16vRKq1NjWQv9SCY3ly2OQROcoxHZOUpmelS+k6wOw== - dependencies: - next-line "^1.1.0" - http-proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" @@ -3703,6 +3420,15 @@ http-proxy-agent@^4.0.1: agent-base "6" debug "4" +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + http-signature@1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" @@ -3712,7 +3438,7 @@ http-signature@1.3.6: jsprim "^2.0.2" sshpk "^1.14.1" -http2-wrapper@^1.0.0-beta.5.0: +http2-wrapper@^1.0.0-beta.5.0, http2-wrapper@^1.0.0-beta.5.2: version "1.0.3" resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== @@ -3720,14 +3446,6 @@ http2-wrapper@^1.0.0-beta.5.0: quick-lru "^5.1.1" resolve-alpn "^1.0.0" -http2-wrapper@^1.0.0-beta.5.2: - version "1.0.0-beta.5.2" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz#8b923deb90144aea65cf834b016a340fc98556f3" - integrity sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ== - dependencies: - quick-lru "^5.1.1" - resolve-alpn "^1.0.0" - http_ece@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/http_ece/-/http_ece-1.1.0.tgz#74780c6eb32d8ddfe9e36a83abcd81fe0cd4fb75" @@ -3767,6 +3485,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + iconv-lite@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" @@ -3869,16 +3594,17 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" -ioredis@^4.27.0: - version "4.27.6" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.6.tgz#a53d427d3fe75fbd10ed7ad150ce00559df8dcf8" - integrity sha512-6W3ZHMbpCa8ByMyC1LJGOi7P2WiOKP9B3resoZOVLDhi+6dDBOW+KNsRq3yI36Hmnb2sifCxHX+YSarTeXh48A== +ioredis@^4.28.5: + version "4.28.5" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" + integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== dependencies: cluster-key-slot "^1.1.0" debug "^4.3.1" denque "^1.1.0" lodash.defaults "^4.2.0" lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" p-map "^2.1.0" redis-commands "1.7.0" redis-errors "^1.2.0" @@ -4017,14 +3743,7 @@ is-generator-function@^1.0.7: resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -4043,13 +3762,6 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= -is-nan@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.0.tgz#85d1f5482f7051c2019f5673ccebdb06f3b0db03" - integrity sha512-z7bbREymOqt2CCaZVly8aC4ML3Xhfi0ekuOnjO2L8vKdl+CttdVoGZQhd4adMFAsxQ5VeRVwORs4tU8RH+HFtQ== - dependencies: - define-properties "^1.1.3" - is-negative-zero@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" @@ -4152,6 +3864,11 @@ is-typedarray@^1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + is-weakref@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" @@ -4184,15 +3901,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - jmespath@0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" @@ -4224,13 +3932,6 @@ js-stringify@^1.0.2: resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= -js-yaml@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f" - integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q== - dependencies: - argparse "^2.0.1" - js-yaml@4.1.0, js-yaml@^4.0.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -4253,23 +3954,23 @@ jschardet@3.0.0: resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882" integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ== -jsdom@16.7.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== +jsdom@19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-19.0.0.tgz#93e67c149fe26816d38a849ea30ac93677e16b6a" + integrity sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A== dependencies: abab "^2.0.5" - acorn "^8.2.4" + acorn "^8.5.0" acorn-globals "^6.0.0" - cssom "^0.4.4" + cssom "^0.5.0" cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" + data-urls "^3.0.1" + decimal.js "^10.3.1" + domexception "^4.0.0" escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" https-proxy-agent "^5.0.0" is-potential-custom-element-name "^1.0.1" nwsapi "^2.2.0" @@ -4278,24 +3979,19 @@ jsdom@16.7.0: symbol-tree "^3.2.4" tough-cookie "^4.0.0" w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" + w3c-xmlserializer "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^2.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^10.0.0" + ws "^8.2.3" + xml-name-validator "^4.0.0" json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -4577,11 +4273,6 @@ ky@^0.25.1: resolved "https://registry.yarnpkg.com/ky/-/ky-0.25.1.tgz#0df0bd872a9cc57e31acd5dbc1443547c881bfbc" integrity sha512-PjpCEWlIU7VpiMVrTwssahkYXX1by6NCT0fhTUX34F3DTinARlgMpriuroolugFPcMgpPWrOW4mTb984Qm1RXA== -langmap@0.0.16: - version "0.0.16" - resolved "https://registry.yarnpkg.com/langmap/-/langmap-0.0.16.tgz#2fe3e98a531fec0fec546624ebe168c2855bab56" - integrity sha512-AtYvBK7BsDvWwnSfmO7CfgeUy7GUT1wK3QX8eKH/Ey/eXodqoHuAtvdQ82hmWD9QVFVKnuiNjym9fGY4qSJeLA== - lazystream@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" @@ -4610,11 +4301,6 @@ listenercount@~1.0.1: resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc= -loader-runner@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" - integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== - loader-utils@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" @@ -4681,6 +4367,11 @@ lodash.foreach@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -4731,27 +4422,23 @@ lodash.some@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - lodash.union@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= -lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" - integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: - chalk "^4.0.0" + chalk "^4.1.0" + is-unicode-supported "^0.1.0" lowercase-keys@^2.0.0: version "2.0.0" @@ -4773,6 +4460,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +luxon@^1.28.0: + version "1.28.0" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.28.0.tgz#e7f96daad3938c06a62de0fb027115d251251fbf" + integrity sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ== + mailcheck@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/mailcheck/-/mailcheck-1.1.1.tgz#d87cf6ba0b64ba512199dbf93f1489f479591e34" @@ -4867,7 +4559,7 @@ mime-types@2.1.34: dependencies: mime-db "1.51.0" -mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@~2.1.24: +mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.24: version "2.1.27" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== @@ -4945,17 +4637,10 @@ minipass-sized@^1.0.3: dependencies: minipass "^3.0.0" -minipass@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" - integrity sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w== - dependencies: - yallist "^4.0.0" - -minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" - integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" + integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== dependencies: yallist "^4.0.0" @@ -4967,10 +4652,10 @@ minizlib@^2.0.0, minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" -misskey-js@0.0.13: - version "0.0.13" - resolved "https://registry.yarnpkg.com/misskey-js/-/misskey-js-0.0.13.tgz#03a4e469186e28752d599dc4093519eb64647970" - integrity sha512-kBdJdfe281gtykzzsrN3IAxWUQIimzPiJGyKWf863ggWJlWYVPmP9hTFlX2z8oPOaypgVBPEPHyw/jNUdc2DbQ== +misskey-js@0.0.14: + version "0.0.14" + resolved "https://registry.yarnpkg.com/misskey-js/-/misskey-js-0.0.14.tgz#1a616bdfbe81c6ee6900219eaf425bb5c714dd4d" + integrity sha512-bvLx6U3OwQwqHfp/WKwIVwdvNYAAPk0+YblXyxmSG3dwlzCgBRRLcB8o6bNruUDyJgh3t73pLDcOz3myxcUmww== dependencies: autobind-decorator "^2.4.0" eventemitter3 "^4.0.7" @@ -4998,45 +4683,37 @@ mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mocha@8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.4.0.tgz#677be88bf15980a3cae03a73e10a0fc3997f0cff" - integrity sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ== +mocha@9.2.1: + version "9.2.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.1.tgz#a1abb675aa9a8490798503af57e8782a78f1338e" + integrity sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ== dependencies: "@ungap/promise-all-settled" "1.1.2" ansi-colors "4.1.1" browser-stdout "1.3.1" - chokidar "3.5.1" - debug "4.3.1" + chokidar "3.5.3" + debug "4.3.3" diff "5.0.0" escape-string-regexp "4.0.0" find-up "5.0.0" - glob "7.1.6" + glob "7.2.0" growl "1.10.5" he "1.2.0" - js-yaml "4.0.0" - log-symbols "4.0.0" + js-yaml "4.1.0" + log-symbols "4.1.0" minimatch "3.0.4" ms "2.1.3" - nanoid "3.1.20" - serialize-javascript "5.0.1" + nanoid "3.2.0" + serialize-javascript "6.0.0" strip-json-comments "3.1.1" supports-color "8.1.1" which "2.0.2" - wide-align "1.1.3" - workerpool "6.1.0" + workerpool "6.2.0" yargs "16.2.0" yargs-parser "20.2.4" yargs-unparser "2.0.0" -moment-timezone@^0.5.25: - version "0.5.28" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.28.tgz#f093d789d091ed7b055d82aa81a82467f72e4338" - integrity sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw== - dependencies: - moment ">= 2.9.0" - -"moment@>= 2.9.0", moment@^2.22.2: +moment@^2.22.2: version "2.24.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== @@ -5061,6 +4738,21 @@ ms@3.0.0-canary.1: resolved "https://registry.yarnpkg.com/ms/-/ms-3.0.0-canary.1.tgz#c7b34fbce381492fd0b345d1cf56e14d67b77b80" integrity sha512-kh8ARjh8rMN7Du2igDRO9QJnqCb2xYTJxyQYK7vJJS4TvLLmsbyhiKpSW+t+y26gyOyMd0riphX0GeWKU3ky5g== +msgpackr-extract@^1.0.14: + version "1.0.16" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-1.0.16.tgz#701c4f6e6f25c100ae84557092274e8fffeefe45" + integrity sha512-fxdRfQUxPrL/TizyfYfMn09dK58e+d65bRD/fcaVH4052vj30QOzzqxcQIS7B0NsqlypEQ/6Du3QmP2DhWFfCA== + dependencies: + nan "^2.14.2" + node-gyp-build "^4.2.3" + +msgpackr@^1.5.2: + version "1.5.4" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.5.4.tgz#2b6ea6cb7d79c0ad98fc76c68163c48eda50cf0d" + integrity sha512-Z7w5Jg+2Q9z9gJxeM68d7tSuWZZGnFIRhZnyqcZCa/1dKkhOCNvR1TUV3zzJ3+vj78vlwKRzUgVDlW4jiSOeDA== + optionalDependencies: + msgpackr-extract "^1.0.14" + multer@1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4.tgz#e2bc6cac0df57a8832b858d7418ccaa8ebaf7d8c" @@ -5089,7 +4781,7 @@ mz@^2.4.0, mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nan@^2.15.0: +nan@^2.14.2, nan@^2.15.0: version "2.15.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== @@ -5101,10 +4793,10 @@ nano-time@1.0.0: dependencies: big-integer "^1.6.16" -nanoid@3.1.20: - version "3.1.20" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" - integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== +nanoid@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" + integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== nanoid@^3.1.30: version "3.1.30" @@ -5135,11 +4827,6 @@ negotiator@0.6.2, negotiator@^0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - nested-property@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/nested-property/-/nested-property-4.0.0.tgz#a67b5a31991e701e03cdbaa6453bc5b1011bb88d" @@ -5150,11 +4837,6 @@ netmask@^2.0.2: resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== -next-line@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/next-line/-/next-line-1.1.0.tgz#fcae57853052b6a9bae8208e40dd7d3c2d304603" - integrity sha1-/K5XhTBStqm66CCOQN19PC0wRgM= - next-tick@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" @@ -5167,10 +4849,10 @@ node-abi@^3.3.0: dependencies: semver "^7.3.5" -node-addon-api@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.2.0.tgz#117cbb5a959dff0992e1c586ae0393573e4d2a87" - integrity sha512-eazsqzwG2lskuzBqCGPi7Ac2UgOoMz8JVOXVhTvvPDYhthvNpefx8jWD8Np7Gv+2Sz0FlPWZk0nJV0z598Wn8Q== +node-addon-api@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" + integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== node-domexception@^1.0.0: version "1.0.0" @@ -5186,10 +4868,12 @@ node-fetch@*: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-fetch@2.6.1, node-fetch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-fetch@2.6.7, node-fetch@^2.6.1: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" node-fetch@3.0.0-beta.9: version "3.0.0-beta.9" @@ -5199,6 +4883,11 @@ node-fetch@3.0.0-beta.9: data-uri-to-buffer "^3.0.1" fetch-blob "^2.1.1" +node-gyp-build@^4.2.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" + integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + node-gyp-build@~3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" @@ -5220,11 +4909,6 @@ node-gyp@^8.4.1: tar "^6.1.2" which "^2.0.2" -node-releases@^1.1.70: - version "1.1.71" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" - integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== - nodemailer@6.7.2: version "6.7.2" resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0" @@ -5263,14 +4947,14 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-url@^4.1.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" - integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== -npm-run-path@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.0.1.tgz#748dd68ed7de377bb1f7132c7dafe657be5ab400" - integrity sha512-ybBJQUSyFwEEhqO2lXmyKOl9ucHtyZBWVM0h0FiMfT/+WKxCUZFa95qAR2X3w/w6oigN3B0b2UNHZbD+kdfD5w== +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== dependencies: path-key "^4.0.0" @@ -5464,13 +5148,6 @@ p-limit@^3.0.2: dependencies: p-try "^2.0.0" -p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -5604,9 +5281,9 @@ path-key@^4.0.0: integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-to-regexp@^6.1.0: version "6.1.0" @@ -5633,10 +5310,10 @@ pg-int8@1.0.1: resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== -pg-pool@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.4.1.tgz#0e71ce2c67b442a5e862a9c182172c37eda71e9c" - integrity sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ== +pg-pool@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.5.1.tgz#f499ce76f9bf5097488b3b83b19861f28e4ed905" + integrity sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ== pg-protocol@^1.5.0: version "1.5.0" @@ -5654,15 +5331,15 @@ pg-types@^2.1.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" -pg@8.7.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" - integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== +pg@8.7.3: + version "8.7.3" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.3.tgz#8a5bdd664ca4fda4db7997ec634c6e5455b27c44" + integrity sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw== dependencies: buffer-writer "2.0.0" packet-reader "1.0.0" pg-connection-string "^2.5.0" - pg-pool "^3.4.1" + pg-pool "^3.5.1" pg-protocol "^1.5.0" pg-types "^2.1.0" pgpass "1.x" @@ -5743,12 +5420,12 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" -prebuild-install@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.0.0.tgz#3c5ce3902f1cb9d6de5ae94ca53575e4af0c1574" - integrity sha512-IvSenf33K7JcgddNz2D5w521EgO+4aMMjFt73Uk9FRzQ7P+QZPKrp7qPsDydsSwjGt3T5xRNnM1bj1zMTD5fTA== +prebuild-install@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.0.1.tgz#c10075727c318efe72412f333e0ef625beaf3870" + integrity sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg== dependencies: - detect-libc "^1.0.3" + detect-libc "^2.0.0" expand-template "^2.0.3" github-from-package "0.0.0" minimist "^1.2.3" @@ -5796,10 +5473,10 @@ private-ip@2.3.3: is-ip "^3.1.0" netmask "^2.0.2" -probe-image-size@7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/probe-image-size/-/probe-image-size-7.2.2.tgz#e5851b9be7864f21e3bac5e6e4fac9da9055b412" - integrity sha512-QUm+w1S9WTsT5GZB830u0BHExrUmF0J4fyRm5kbLUMEP3fl9UVYXc3xOBVqZNnH9tnvVEJO8vDk3PMtsLqjxug== +probe-image-size@7.2.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/probe-image-size/-/probe-image-size-7.2.3.tgz#d49c64be540ec8edea538f6f585f65a9b3ab4309" + integrity sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w== dependencies: lodash.merge "^4.6.2" needle "^2.5.2" @@ -6061,10 +5738,10 @@ rdf-canonize@^3.0.0: dependencies: setimmediate "^1.0.5" -re2@1.17.3: - version "1.17.3" - resolved "https://registry.yarnpkg.com/re2/-/re2-1.17.3.tgz#8cceb48f52c45b860b1f67cee8a44726f7d05e9a" - integrity sha512-Dp5iWVR8W3C7Nm9DziMY4BleMPRb/pe6kvfbzLv80dVYaXRc9jRnwwNqU0oE/taRm0qYR1+Qrtzk9rPjS9ecaQ== +re2@1.17.4: + version "1.17.4" + resolved "https://registry.yarnpkg.com/re2/-/re2-1.17.4.tgz#7bf29290bdde963014e77bd2c2e799a6d788386e" + integrity sha512-xyZ4h5PqE8I9tAxTh3G0UttcK5ufrcUxReFjGzfX61vtanNbS1XZHjnwRSyPcLgChI4KLxVgOT/ioZXnUAdoTA== dependencies: install-artifact-from-github "^1.3.0" nan "^2.15.0" @@ -6194,14 +5871,6 @@ rename@1.0.4: dependencies: debug "^2.5.2" -request-stats@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/request-stats/-/request-stats-3.0.0.tgz#769155dc8974d78d4a1cb87bbf14eaab985afe25" - integrity sha1-dpFV3Il0141KHLh7vxTqq5ha/iU= - dependencies: - http-headers "^3.0.1" - once "^1.4.0" - require-all@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/require-all/-/require-all-3.0.0.tgz#473d49704be310115ce124f77383b1ebd8671312" @@ -6325,10 +5994,10 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sanitize-html@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.6.1.tgz#5d37c08e189c61c0631560a889b10d9d155d000e" - integrity sha512-DzjSz3H5qDntD7s1TcWCSoRPmNR8UmA+y+xZQOvWgjATe2Br9ZW73+vD3Pj6Snrg0RuEuJdXgrKvnYuiuixRkA== +sanitize-html@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.7.0.tgz#e106205b468aca932e2f9baf241f24660d34e279" + integrity sha512-jfQelabOn5voO7FAfnQF7v+jsA6z9zC/O4ec0z3E35XPEtHYJT/OdUziVWlKW4irCr2kXaQAyXTXDHWAibg1tA== dependencies: deepmerge "^4.2.2" escape-string-regexp "^4.0.0" @@ -6397,10 +6066,10 @@ semver@^7.3.5: dependencies: lru-cache "^6.0.0" -serialize-javascript@5.0.1, serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== dependencies: randombytes "^2.1.0" @@ -6432,17 +6101,17 @@ sha.js@^2.4.11: inherits "^2.0.1" safe-buffer "^5.0.1" -sharp@0.29.3: - version "0.29.3" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.29.3.tgz#0da183d626094c974516a48fab9b3e4ba92eb5c2" - integrity sha512-fKWUuOw77E4nhpyzCCJR1ayrttHoFHBT2U/kR/qEMRhvPEcluG4BKj324+SCO1e84+knXHwhJ1HHJGnUt4ElGA== +sharp@0.30.1: + version "0.30.1" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.30.1.tgz#203efaf9acfc5c15c8a343800254621e56011c12" + integrity sha512-ycpz81q8AeVjz1pGvvirQBeJcYE2sXAjcLXR/69LWOe/oxavBLOrenZcTzvTXn83jqAGqY+OuwF+2kFXzbKtDA== dependencies: - color "^4.0.1" - detect-libc "^1.0.3" - node-addon-api "^4.2.0" - prebuild-install "^7.0.0" + color "^4.2.0" + detect-libc "^2.0.0" + node-addon-api "^4.3.0" + prebuild-install "^7.0.1" semver "^7.3.5" - simple-get "^4.0.0" + simple-get "^4.0.1" tar-fs "^2.1.1" tunnel-agent "^0.6.0" @@ -6477,20 +6146,20 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -signal-exit@^3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" - integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== +signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== simple-concat@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" - integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== -simple-get@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.0.tgz#73fa628278d21de83dadd5512d2cc1f4872bd675" - integrity sha512-ZalZGexYr3TA0SwySsr5HlgOOinS4Jsa8YB2GJ6lUNAazyAu4KG/VmzMTwAt2YVXzzVj8QmefmAonZIK2BSGcQ== +simple-get@^4.0.0, simple-get@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== dependencies: decompress-response "^6.0.0" once "^1.3.1" @@ -6530,34 +6199,16 @@ socks@^2.6.1: ip "^1.1.5" smart-buffer "^4.1.0" -source-list-map@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - source-map-js@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== -source-map-support@~0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - speakeasy@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/speakeasy/-/speakeasy-2.0.0.tgz#85c91a071b09a5cb8642590d983566165f57613a" @@ -6794,7 +6445,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -6813,12 +6464,12 @@ syslog-pro@1.0.0: dependencies: moment "^2.22.2" -systeminformation@5.9.9: - version "5.9.9" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.9.9.tgz#aa8234a138363bd988f438fed3273370f79d7e30" - integrity sha512-xciy6NKCLfs4dqMD1Tdlo7v1/g0NfdA1EKsIptUQjlcVvpwHyjifAbNOF7ppFezGSMXxYE8me+l2+RlFF4lyTg== +systeminformation@5.11.4: + version "5.11.4" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.11.4.tgz#3ed99533c67d0b4bd357871687e014f1c2a37194" + integrity sha512-rh7bjpjP5whUaTknim5CiGdAiKZcgWhmbmxjzBRXDWqUc/k67bz2OP+03DdcX6/SN/CDSAi/NeUwM5o2gjHJoA== -tapable@^2.1.1, tapable@^2.2.0: +tapable@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== @@ -6865,19 +6516,7 @@ tar-stream@^2.1.4, tar-stream@^2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^6.0.2: - version "6.0.5" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" - integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -tar@^6.1.2: +tar@^6.0.2, tar@^6.1.2: version "6.1.11" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== @@ -6889,27 +6528,6 @@ tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" -terser-webpack-plugin@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz#7effadee06f7ecfa093dbbd3e9ab23f5f3ed8673" - integrity sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q== - dependencies: - jest-worker "^26.6.2" - p-limit "^3.1.0" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - source-map "^0.6.1" - terser "^5.5.1" - -terser@^5.5.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" - integrity sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6990,13 +6608,18 @@ tough-cookie@^4.0.0: punycode "^2.1.1" universalify "^0.1.2" -tr46@^2.0.0, tr46@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" - integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + trace-redirect@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/trace-redirect/-/trace-redirect-1.0.6.tgz#ac629b5bf8247d30dde5a35fe9811b811075b504" @@ -7017,10 +6640,10 @@ ts-loader@9.2.6: micromatch "^4.0.0" semver "^7.3.4" -ts-node@10.4.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" - integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A== +ts-node@10.5.0: + version "10.5.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.5.0.tgz#618bef5854c1fbbedf5e31465cbb224a1d524ef9" + integrity sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw== dependencies: "@cspotcode/source-map-support" "0.7.0" "@tsconfig/node10" "^1.0.7" @@ -7033,6 +6656,7 @@ ts-node@10.4.0: create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" + v8-compile-cache-lib "^3.0.0" yn "3.1.1" tsc-alias@1.4.1: @@ -7057,7 +6681,7 @@ tsconfig-paths@3.12.0, tsconfig-paths@^3.12.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1: version "1.11.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== @@ -7150,10 +6774,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typeorm@0.2.41: - version "0.2.41" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.41.tgz#88758101ac158dc0a0a903d70eaacea2974281cc" - integrity sha512-/d8CLJJxKPgsnrZWiMyPI0rz2MFZnBQrnQ5XP3Vu3mswv2WPexb58QM6BEtmRmlTMYN5KFWUz8SKluze+wS9xw== +typeorm@0.2.44: + version "0.2.44" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.44.tgz#4cc07eb1eb7a0e7f3ec9e65ded9eb3c3aedbb3e1" + integrity sha512-yFyb9Ts73vGaS/O06TvLpzvT5U/ngO31GeciNc0eoH7P1QcG8kVZdOy9FHJqkTeDmIljMRgWjbYUoMw53ZY7Xw== dependencies: "@sqltools/formatter" "^1.2.2" app-root-path "^3.0.0" @@ -7168,6 +6792,7 @@ typeorm@0.2.41: reflect-metadata "^0.1.13" sha.js "^2.4.11" tslib "^2.1.0" + uuid "^8.3.2" xml2js "^0.4.23" yargs "^17.0.1" zen-observable-ts "^1.0.0" @@ -7282,11 +6907,16 @@ uuid@7.0.3: resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== -uuid@8.3.2, uuid@^8.3.0: +uuid@8.3.2, uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-compile-cache-lib@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" + integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== + v8-compile-cache@^2.0.3: version "2.2.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" @@ -7318,20 +6948,12 @@ w3c-hr-time@^1.0.2: dependencies: browser-process-hrtime "^1.0.0" -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== +w3c-xmlserializer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz#06cdc3eefb7e4d0b20a560a5a3aeb0d2d9a65923" + integrity sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg== dependencies: - xml-name-validator "^3.0.0" - -watchpack@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.0.0.tgz#b12248f32f0fd4799b7be0802ad1f6573a45955c" - integrity sha512-xSdCxxYZWNk3VK13bZRYhsQpfa8Vg63zXG+3pyU8ouqSLRCv4IGXIp9Kr226q6GBkGRlZrST2wwKtjfKz2m7Cg== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" + xml-name-validator "^4.0.0" web-push@3.4.5: version "3.4.5" @@ -7350,52 +6972,15 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965" integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA== -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - -webpack-sources@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac" - integrity sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w== - dependencies: - source-list-map "^2.0.1" - source-map "^0.6.1" - -webpack@^5: - version "5.33.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.33.2.tgz#c049717c9b038febf5a72fd2f53319ad59a8c1fc" - integrity sha512-X4b7F1sYBmJx8mlh2B7mV5szEkE0jYNJ2y3akgAP0ERi0vLCG1VvdsIxt8lFd4st6SUy0lf7W0CCQS566MBpJg== - dependencies: - "@types/eslint-scope" "^3.7.0" - "@types/estree" "^0.0.46" - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/wasm-edit" "1.11.0" - "@webassemblyjs/wasm-parser" "1.11.0" - acorn "^8.0.4" - browserslist "^4.14.5" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.7.0" - es-module-lexer "^0.4.0" - eslint-scope "^5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.4" - json-parse-better-errors "^1.0.2" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.0.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.1.1" - watchpack "^2.0.0" - webpack-sources "^2.1.1" +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== websocket@1.0.34: version "1.0.34" @@ -7409,35 +6994,33 @@ websocket@1.0.34: utf-8-validate "^5.0.2" yaeti "^0.0.6" -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== +whatwg-encoding@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== dependencies: - iconv-lite "0.4.24" + iconv-lite "0.6.3" -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== -whatwg-url@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.0.0.tgz#37f256cb746398e19b107bd6ef820b4ae2d15871" - integrity sha512-41ou2Dugpij8/LPO5Pq64K5q++MnRCBpEHvQr26/mArEKTkCV5aoXIqyhuYtE0pkqScXwhf2JP57rkRTYM29lQ== +whatwg-url@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-10.0.0.tgz#37264f720b575b4a311bd4094ed8c760caaa05da" + integrity sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w== dependencies: - lodash.sortby "^4.7.0" - tr46 "^2.0.0" - webidl-conversions "^5.0.0" + tr46 "^3.0.0" + webidl-conversions "^7.0.0" -whatwg-url@^8.5.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.5.0.tgz#7752b8464fc0903fec89aa9846fc9efe07351fd3" - integrity sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= dependencies: - lodash "^4.7.0" - tr46 "^2.0.2" - webidl-conversions "^6.1.0" + tr46 "~0.0.3" + webidl-conversions "^3.0.0" which-boxed-primitive@^1.0.2: version "1.0.2" @@ -7469,7 +7052,7 @@ which@^1.1.1, which@^1.2.14: dependencies: isexe "^2.0.0" -wide-align@1.1.3, wide-align@^1.1.0: +wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== @@ -7498,10 +7081,10 @@ word-wrap@^1.2.3, word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -workerpool@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b" - integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg== +workerpool@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" + integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== wrap-ansi@^6.2.0: version "6.2.0" @@ -7526,16 +7109,16 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@8.4.2: +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + +ws@^8.2.3: version "8.4.2" resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b" integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA== -ws@^7.4.6: - version "7.5.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" - integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== - xev@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xev/-/xev-2.0.1.tgz#24484173a22115bc8a990ef5d4d5129695b827a7" @@ -7548,10 +7131,10 @@ xml-js@^1.6.11: dependencies: sax "^1.2.4" -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== xml2js@0.4.19: version "0.4.19" @@ -7695,11 +7278,6 @@ yn@3.1.1: resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - zen-observable-ts@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.0.0.tgz#30d1202b81d8ba4c489e3781e8ca09abf0075e70" diff --git a/packages/client/.eslintrc.js b/packages/client/.eslintrc.js index d414f86ed..a6e23e517 100644 --- a/packages/client/.eslintrc.js +++ b/packages/client/.eslintrc.js @@ -18,6 +18,8 @@ module.exports = { // data ぎįĻæ­ĸį†į”ą: æŠŊ蹥įš„すぎるため // e ぎįĻæ­ĸį†į”ą: error や event ãĒãŠã€č¤‡æ•°ãŽã‚­ãƒŧワãƒŧドぎ頭文字であり分かりãĢくいため "id-denylist": ["error", "window", "data", "e"], + 'eqeqeq': ['error', 'always', { 'null': 'ignore' }], + "no-shadow": ["warn"], "vue/attributes-order": ["error", { "alphabetical": false }], diff --git a/packages/client/package.json b/packages/client/package.json index c5b91148a..a781f43c5 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -11,53 +11,50 @@ }, "dependencies": { "@discordapp/twemoji": "13.1.0", + "@fortawesome/fontawesome-free": "6.0.0", "@syuilo/aiscript": "0.11.1", - "@types/dateformat": "3.0.1", "@types/escape-regexp": "0.0.1", "@types/glob": "7.2.0", "@types/gulp": "4.0.9", "@types/gulp-rename": "2.0.1", "@types/is-url": "1.2.30", "@types/katex": "0.11.1", - "@types/matter-js": "0.17.6", - "@types/mocha": "8.2.3", + "@types/matter-js": "0.17.7", + "@types/mocha": "9.1.0", "@types/oauth": "0.9.1", "@types/parse5": "6.0.3", "@types/punycode": "2.1.0", "@types/qrcode": "1.4.2", "@types/random-seed": "0.3.3", - "@types/request-stats": "3.0.0", "@types/seedrandom": "2.4.28", "@types/throttle-debounce": "2.1.0", "@types/tinycolor2": "1.4.3", - "@types/tmp": "0.2.3", "@types/uuid": "8.3.4", - "@types/web-push": "3.3.2", "@types/webpack": "5.28.0", "@types/webpack-stream": "3.2.12", - "@types/websocket": "1.0.4", - "@types/ws": "8.2.2", - "@typescript-eslint/parser": "5.10.0", - "@vue/compiler-sfc": "3.2.29", + "@types/websocket": "1.0.5", + "@types/ws": "8.2.3", + "@typescript-eslint/parser": "5.12.1", + "@vue/compiler-sfc": "3.2.31", "abort-controller": "3.0.0", "autobind-decorator": "2.4.0", "autosize": "5.0.1", "autwh": "0.1.0", - "blurhash": "1.1.4", - "broadcast-channel": "4.9.0", - "chart.js": "3.7.0", + "blurhash": "1.1.5", + "broadcast-channel": "4.10.0", + "chart.js": "3.7.1", "chartjs-adapter-date-fns": "2.0.0", + "chartjs-plugin-gradient": "0.2.1", "chartjs-plugin-zoom": "1.2.0", "compare-versions": "4.1.3", "content-disposition": "0.5.4", - "crc-32": "1.2.0", - "css-loader": "6.5.1", - "cssnano": "5.0.15", + "css-loader": "6.6.0", + "cssnano": "5.0.17", "date-fns": "2.28.0", "deepcopy": "2.1.0", "escape-regexp": "0.0.1", - "eslint": "8.7.0", - "eslint-plugin-vue": "8.3.0", + "eslint": "8.9.0", + "eslint-plugin-vue": "8.5.0", "eventemitter3": "4.0.7", "feed": "4.2.2", "glob": "7.2.0", @@ -67,19 +64,18 @@ "json5": "2.2.0", "json5-loader": "4.0.1", "katex": "0.15.2", - "langmap": "0.0.16", "matter-js": "0.18.0", "mfm-js": "0.21.0", - "misskey-js": "0.0.13", - "mocha": "8.4.0", + "misskey-js": "0.0.14", + "mocha": "9.2.1", "ms": "2.1.3", "nested-property": "4.0.0", "parse5": "6.0.1", "photoswipe": "git+https://github.com/dimsemenov/photoswipe#v5-beta", "portscanner": "2.2.0", - "postcss": "8.4.5", + "postcss": "8.4.6", "postcss-loader": "6.2.1", - "prismjs": "1.26.0", + "prismjs": "1.27.0", "private-ip": "2.3.3", "promise-limit": "2.7.0", "pug": "3.0.2", @@ -88,11 +84,10 @@ "querystring": "0.2.1", "random-seed": "0.3.0", "reflect-metadata": "0.1.13", - "request-stats": "3.0.0", "rndstr": "1.0.0", "s-age": "1.1.2", - "sass": "1.49.0", - "sass-loader": "12.4.0", + "sass": "1.49.8", + "sass-loader": "12.6.0", "seedrandom": "3.0.5", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", @@ -102,9 +97,7 @@ "three": "0.136.0", "throttle-debounce": "3.0.1", "tinycolor2": "1.4.2", - "tmp": "0.2.1", "ts-loader": "9.2.6", - "ts-node": "10.4.0", "tsc-alias": "1.5.0", "tsconfig-paths": "3.12.0", "twemoji-parser": "13.1.0", @@ -112,25 +105,22 @@ "uuid": "8.3.2", "v-debounce": "0.1.2", "vanilla-tilt": "1.7.2", - "vue": "3.2.29", + "vue": "3.2.31", "vue-loader": "17.0.0", "vue-prism-editor": "2.0.0-alpha.2", - "vue-router": "4.0.5", + "vue-router": "4.0.12", "vue-style-loader": "4.1.3", "vue-svg-loader": "0.17.0-beta.2", "vuedraggable": "4.0.1", - "web-push": "3.4.5", - "webpack": "5.66.0", - "webpack-cli": "4.9.1", + "webpack": "5.69.1", + "webpack-cli": "4.9.2", "websocket": "1.0.34", - "ws": "8.4.2" + "ws": "8.5.0" }, "devDependencies": { - "@redocly/openapi-core": "1.0.0-beta.79", - "@types/fluent-ffmpeg": "2.1.20", - "@typescript-eslint/eslint-plugin": "5.10.0", + "@typescript-eslint/eslint-plugin": "5.12.1", "cross-env": "7.0.3", - "cypress": "9.3.1", + "cypress": "9.5.0", "eslint-plugin-import": "2.25.4", "start-server-and-test": "1.14.0" } diff --git a/packages/client/src/components/autocomplete.vue b/packages/client/src/components/autocomplete.vue index 91a50ffa5..adeac4e05 100644 --- a/packages/client/src/components/autocomplete.vue +++ b/packages/client/src/components/autocomplete.vue @@ -57,7 +57,7 @@ const lib = emojilist.filter(x => x.category !== 'flags'); const char2file = (char: string) => { let codes = Array.from(char).map(x => x.codePointAt(0)?.toString(16)); - if (!codes.includes('200d')) codes = codes.filter(x => x != 'fe0f'); + if (!codes.includes('200d')) codes = codes.filter(x => x !== 'fe0f'); return codes.filter(x => x && x.length).join('-'); }; @@ -192,8 +192,7 @@ function exec() { const cache = sessionStorage.getItem(cacheKey); if (cache) { - const users = JSON.parse(cache); - users.value = users; + users.value = JSON.parse(cache); fetching.value = false; } else { os.api('users/search-by-username-and-host', { @@ -208,7 +207,7 @@ function exec() { }); } } else if (props.type === 'hashtag') { - if (!props.q || props.q == '') { + if (!props.q || props.q === '') { hashtags.value = JSON.parse(localStorage.getItem('hashtags') || '[]'); fetching.value = false; } else { @@ -231,9 +230,9 @@ function exec() { } } } else if (props.type === 'emoji') { - if (!props.q || props.q == '') { + if (!props.q || props.q === '') { // 最čŋ‘äŊŋãŖたįĩĩ文字をã‚ĩジェ゚ト - emojis.value = defaultStore.state.recentlyUsedEmojis.map(emoji => emojiDb.find(e => e.emoji == emoji)).filter(x => x) as EmojiDef[]; + emojis.value = defaultStore.state.recentlyUsedEmojis.map(emoji => emojiDb.find(e => e.emoji === emoji)).filter(x => x) as EmojiDef[]; return; } @@ -241,37 +240,37 @@ function exec() { const max = 30; emojiDb.some(x => { - if (x.name.startsWith(props.q || '') && !x.aliasOf && !matched.some(y => y.emoji == x.emoji)) matched.push(x); - return matched.length == max; + if (x.name.startsWith(props.q ?? '') && !x.aliasOf && !matched.some(y => y.emoji === x.emoji)) matched.push(x); + return matched.length === max; }); if (matched.length < max) { emojiDb.some(x => { - if (x.name.startsWith(props.q || '') && !matched.some(y => y.emoji == x.emoji)) matched.push(x); - return matched.length == max; + if (x.name.startsWith(props.q ?? '') && !matched.some(y => y.emoji === x.emoji)) matched.push(x); + return matched.length === max; }); } if (matched.length < max) { emojiDb.some(x => { - if (x.name.includes(props.q || '') && !matched.some(y => y.emoji == x.emoji)) matched.push(x); - return matched.length == max; + if (x.name.includes(props.q ?? '') && !matched.some(y => y.emoji === x.emoji)) matched.push(x); + return matched.length === max; }); } emojis.value = matched; } else if (props.type === 'mfmTag') { - if (!props.q || props.q == '') { + if (!props.q || props.q === '') { mfmTags.value = MFM_TAGS; return; } - mfmTags.value = MFM_TAGS.filter(tag => tag.startsWith(props.q || '')); + mfmTags.value = MFM_TAGS.filter(tag => tag.startsWith(props.q ?? '')); } } function onMousedown(e: Event) { - if (!contains(rootEl.value, e.target) && (rootEl.value != e.target)) props.close(); + if (!contains(rootEl.value, e.target) && (rootEl.value !== e.target)) props.close(); } function onKeydown(e: KeyboardEvent) { @@ -348,7 +347,7 @@ function chooseUser() { onUpdated(() => { setPosition(); - items.value = suggests.value?.children || []; + items.value = suggests.value?.children ?? []; }); onMounted(() => { diff --git a/packages/client/src/components/captcha.vue b/packages/client/src/components/captcha.vue index 963ae25f8..ccd8880df 100644 --- a/packages/client/src/components/captcha.vue +++ b/packages/client/src/components/captcha.vue @@ -93,7 +93,7 @@ function requestRender() { } function callback(response?: string) { - emit('update:modelValue', typeof response == 'string' ? response : null); + emit('update:modelValue', typeof response === 'string' ? response : null); } onMounted(() => { diff --git a/packages/client/src/components/chart-tooltip.vue b/packages/client/src/components/chart-tooltip.vue new file mode 100644 index 000000000..20e094a5a --- /dev/null +++ b/packages/client/src/components/chart-tooltip.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/packages/client/src/components/chart.vue b/packages/client/src/components/chart.vue index d17c0c9f3..3787c5f06 100644 --- a/packages/client/src/components/chart.vue +++ b/packages/client/src/components/chart.vue @@ -8,7 +8,7 @@ diff --git a/packages/client/src/components/url-preview.vue b/packages/client/src/components/url-preview.vue index 6c5795761..c7bbd1fbd 100644 --- a/packages/client/src/components/url-preview.vue +++ b/packages/client/src/components/url-preview.vue @@ -67,7 +67,7 @@ let tweetHeight = $ref(150); const requestUrl = new URL(props.url); -if (requestUrl.hostname == 'twitter.com') { +if (requestUrl.hostname === 'twitter.com') { const m = requestUrl.pathname.match(/^\/.+\/status(?:es)?\/(\d+)/); if (m) tweetId = m[1]; } diff --git a/packages/client/src/components/widgets.vue b/packages/client/src/components/widgets.vue index ccde5fbe5..da9d93528 100644 --- a/packages/client/src/components/widgets.vue +++ b/packages/client/src/components/widgets.vue @@ -12,13 +12,14 @@ @@ -121,10 +122,6 @@ export default defineComponent({ position: relative; cursor: move; - > *:not(.remove):not(.config) { - pointer-events: none; - } - > .config, > .remove { position: absolute; diff --git a/packages/client/src/directives/get-size.ts b/packages/client/src/directives/get-size.ts index e3b5dea0f..1fcd0718d 100644 --- a/packages/client/src/directives/get-size.ts +++ b/packages/client/src/directives/get-size.ts @@ -1,34 +1,55 @@ import { Directive } from 'vue'; +const mountings = new Map void; +}>(); + +function calc(src: Element) { + const info = mountings.get(src); + const height = src.clientHeight; + const width = src.clientWidth; + + if (!info) return; + + // ã‚ĸクテã‚Ŗベãƒŧト前ãĒおでsrcが描į”ģされãĻいãĒい場合 + if (!height) { + // IntersectionObserverã§čĄ¨į¤ē検å‡ēする + if (!info.intersection) { + info.intersection = new IntersectionObserver(entries => { + if (entries.some(entry => entry.isIntersecting)) calc(src); + }); + } + info.intersection.observe(src); + return; + } + if (info.intersection) { + info.intersection.disconnect() + delete info.intersection; + }; + + info.fn(width, height); +}; + export default { mounted(src, binding, vn) { - const calc = () => { - const height = src.clientHeight; - const width = src.clientWidth; - // čĻį´ ãŒ(一時įš„ãĢ)DOMãĢ存在しãĒã„ã¨ãã¯č¨ˆįŽ—゚キップ - if (height === 0) return; - - binding.value(width, height); - }; - - calc(); - - // Vue3ではäŊŋえãĒくãĒãŖた - // į„ĄããĻも大丈å¤Ģか...īŧŸ - // TODO: ↑大丈å¤ĢじゃãĒかãŖたぎでč§Ŗæąēį­–ã‚’æŽĸす - //vn.context.$on('hook:activated', calc); - - const ro = new ResizeObserver((entries, observer) => { - calc(); + const resize = new ResizeObserver((entries, observer) => { + calc(src); }); - ro.observe(src); + resize.observe(src); - src._get_size_ro_ = ro; + mountings.set(src, { resize, fn: binding.value, }); + calc(src); }, unmounted(src, binding, vn) { binding.value(0, 0); - src._get_size_ro_.unobserve(src); + const info = mountings.get(src); + if (!info) return; + info.resize.disconnect(); + if (info.intersection) info.intersection.disconnect(); + mountings.delete(src); } -} as Directive; +} as Directive void>; diff --git a/packages/client/src/directives/size.ts b/packages/client/src/directives/size.ts index a72a97abc..36f649f18 100644 --- a/packages/client/src/directives/size.ts +++ b/packages/client/src/directives/size.ts @@ -1,68 +1,107 @@ import { Directive } from 'vue'; +type Value = { max?: number[]; min?: number[]; }; + //const observers = new Map(); +const mountings = new Map(); + +type ClassOrder = { + add: string[]; + remove: string[]; +}; + +const cache = new Map(); + +function getClassOrder(width: number, queue: Value): ClassOrder { + const getMaxClass = (v: number) => `max-width_${v}px`; + const getMinClass = (v: number) => `min-width_${v}px`; + + return { + add: [ + ...(queue.max ? queue.max.filter(v => width <= v).map(getMaxClass) : []), + ...(queue.min ? queue.min.filter(v => width >= v).map(getMinClass) : []), + ], + remove: [ + ...(queue.max ? queue.max.filter(v => width > v).map(getMaxClass) : []), + ...(queue.min ? queue.min.filter(v => width < v).map(getMinClass) : []), + ] + }; +} + +function applyClassOrder(el: Element, order: ClassOrder) { + el.classList.add(...order.add); + el.classList.remove(...order.remove); +} + +function getOrderName(width: number, queue: Value): string { + return `${width}|${queue.max ? queue.max.join(',') : ''}|${queue.min ? queue.min.join(',') : ''}`; +} + +function calc(el: Element) { + const info = mountings.get(el); + const width = el.clientWidth; + + if (!info || info.previousWidth === width) return; + + // ã‚ĸクテã‚Ŗベãƒŧト前ãĒおでsrcが描į”ģされãĻいãĒい場合 + if (!width) { + // IntersectionObserverã§čĄ¨į¤ē検å‡ēする + if (!info.intersection) { + info.intersection = new IntersectionObserver(entries => { + if (entries.some(entry => entry.isIntersecting)) calc(el); + }); + } + info.intersection.observe(el); + return; + } + if (info.intersection) { + info.intersection.disconnect() + delete info.intersection; + }; + + mountings.set(el, Object.assign(info, { previousWidth: width })); + + const cached = cache.get(getOrderName(width, info.value)); + if (cached) { + applyClassOrder(el, cached); + } else { + const order = getClassOrder(width, info.value); + cache.set(getOrderName(width, info.value), order); + applyClassOrder(el, order); + } +} export default { mounted(src, binding, vn) { - const query = binding.value; + const resize = new ResizeObserver((entries, observer) => { + calc(src); + }); - const addClass = (el: Element, cls: string) => { - el.classList.add(cls); - }; + mountings.set(src, { + value: binding.value, + resize, + previousWidth: 0, + }); - const removeClass = (el: Element, cls: string) => { - el.classList.remove(cls); - }; + calc(src); + resize.observe(src); + }, - const calc = () => { - const width = src.clientWidth; - - // čĻį´ ãŒ(一時įš„ãĢ)DOMãĢ存在しãĒã„ã¨ãã¯č¨ˆįŽ—゚キップ - if (width === 0) return; - - if (query.max) { - for (const v of query.max) { - if (width <= v) { - addClass(src, 'max-width_' + v + 'px'); - } else { - removeClass(src, 'max-width_' + v + 'px'); - } - } - } - if (query.min) { - for (const v of query.min) { - if (width >= v) { - addClass(src, 'min-width_' + v + 'px'); - } else { - removeClass(src, 'min-width_' + v + 'px'); - } - } - } - }; - - calc(); - - window.addEventListener('resize', calc); - - // Vue3ではäŊŋえãĒくãĒãŖた - // į„ĄããĻも大丈å¤Ģか...īŧŸ - // TODO: ↑大丈å¤ĢじゃãĒかãŖたぎでč§Ŗæąēį­–ã‚’æŽĸす - //vn.context.$on('hook:activated', calc); - - //const ro = new ResizeObserver((entries, observer) => { - // calc(); - //}); - - //ro.observe(el); - - // TODO: 新たãĢプロパテã‚ŖをäŊœã‚‹ãŽã‚’やめMapをäŊŋう - // ãŸã ãƒĄãƒĸãƒĒįš„ãĢは↓ぎ斚がįœãƒĄãƒĸãƒĒかもしれãĒã„ãŽã§æ¤œč¨Žä¸­ - //el._ro_ = ro; - src._calc_ = calc; + updated(src, binding, vn) { + mountings.set(src, Object.assign({}, mountings.get(src), { value: binding.value })); + calc(src); }, unmounted(src, binding, vn) { - //el._ro_.unobserve(el); - window.removeEventListener('resize', src._calc_); + const info = mountings.get(src); + if (!info) return; + info.resize.disconnect(); + if (info.intersection) info.intersection.disconnect(); + mountings.delete(src); } -} as Directive; +} as Directive; diff --git a/packages/client/src/directives/tooltip.ts b/packages/client/src/directives/tooltip.ts index fffde1487..dd715227a 100644 --- a/packages/client/src/directives/tooltip.ts +++ b/packages/client/src/directives/tooltip.ts @@ -48,7 +48,7 @@ export default { popup(import('@/components/ui/tooltip.vue'), { showing, text: self.text, - source: el + targetElement: el, }, {}, 'closed'); self._close = () => { @@ -56,8 +56,8 @@ export default { }; }; - el.addEventListener('selectstart', e => { - e.preventDefault(); + el.addEventListener('selectstart', ev => { + ev.preventDefault(); }); el.addEventListener(start, () => { diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts index 9b670b430..5809f2568 100644 --- a/packages/client/src/init.ts +++ b/packages/client/src/init.ts @@ -14,7 +14,8 @@ if (localStorage.getItem('accounts') != null) { //#endregion import { computed, createApp, watch, markRaw, version as vueVersion } from 'vue'; -import * as compareVersions from 'compare-versions'; +import compareVersions from 'compare-versions'; +import * as JSON5 from 'json5'; import widgets from '@/widgets'; import directives from '@/directives'; @@ -32,7 +33,7 @@ import { defaultStore, ColdDeviceStorage } from '@/store'; import { fetchInstance, instance } from '@/instance'; import { makeHotkey } from '@/scripts/hotkey'; import { search } from '@/scripts/search'; -import { isMobile } from '@/scripts/is-mobile'; +import { deviceKind } from '@/scripts/device-kind'; import { initializeSw } from '@/scripts/initialize-sw'; import { reloadChannel } from '@/scripts/unison-reload'; import { reactionPicker } from '@/scripts/reaction-picker'; @@ -95,11 +96,10 @@ window.addEventListener('resize', () => { //#endregion // If mobile, insert the viewport meta tag -if (isMobile || window.innerWidth <= 1024) { +if (['smartphone', 'tablet'].includes(deviceKind)) { const viewport = document.getElementsByName('viewport').item(0); viewport.setAttribute('content', - `${viewport.getAttribute('content')},minimum-scale=1,maximum-scale=1,user-scalable=no`); - document.head.appendChild(viewport); + `${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`); } //#region Set lang attr @@ -163,7 +163,9 @@ if ($i && $i.token) { } //#endregion -fetchInstance().then(() => { +const fetchInstanceMetaPromise = fetchInstance(); + +fetchInstanceMetaPromise.then(() => { localStorage.setItem('v', instance.version); // Init service worker @@ -274,6 +276,14 @@ window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => { }); //#endregion +fetchInstanceMetaPromise.then(() => { + if (defaultStore.state.themeInitial) { + if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON5.parse(instance.defaultLightTheme)); + if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON5.parse(instance.defaultDarkTheme)); + defaultStore.set('themeInitial', false); + } +}); + // shortcut document.addEventListener('keydown', makeHotkey({ 'd': () => { diff --git a/packages/client/src/os.ts b/packages/client/src/os.ts index f3be5c68f..5f1fb1ef9 100644 --- a/packages/client/src/os.ts +++ b/packages/client/src/os.ts @@ -7,8 +7,10 @@ import * as Misskey from 'misskey-js'; import { apiUrl, url } from '@/config'; import MkPostFormDialog from '@/components/post-form-dialog.vue'; import MkWaitingDialog from '@/components/waiting-dialog.vue'; +import { MenuItem } from '@/types/menu'; import { resolve } from '@/router'; import { $i } from '@/account'; +import { defaultStore } from '@/store'; export const pendingApiRequestsCount = ref(0); @@ -470,7 +472,7 @@ export async function openEmojiPicker(src?: HTMLElement, opts, initialTextarea: }); } -export function popupMenu(items: any[] | Ref, src?: HTMLElement, options?: { +export function popupMenu(items: MenuItem[] | Ref, src?: HTMLElement, options?: { align?: string; width?: number; viaKeyboard?: boolean; @@ -494,7 +496,7 @@ export function popupMenu(items: any[] | Ref, src?: HTMLElement, options? }); } -export function contextMenu(items: any[], ev: MouseEvent) { +export function contextMenu(items: MenuItem[] | Ref, ev: MouseEvent) { ev.preventDefault(); return new Promise((resolve, reject) => { let dispose; @@ -541,8 +543,8 @@ export const uploads = ref<{ img: string; }[]>([]); -export function upload(file: File, folder?: any, name?: string): Promise { - if (folder && typeof folder == 'object') folder = folder.id; +export function upload(file: File, folder?: any, name?: string, keepOriginal: boolean = defaultStore.state.keepOriginalUploading): Promise { + if (folder && typeof folder === 'object') folder = folder.id; return new Promise((resolve, reject) => { const id = Math.random().toString(); @@ -559,6 +561,8 @@ export function upload(file: File, folder?: any, name?: string): Promise - +

@@ -65,35 +65,50 @@
+ + + diff --git a/packages/client/src/pages/admin/files.vue b/packages/client/src/pages/admin/files.vue index 87dd12f48..c62f05309 100644 --- a/packages/client/src/pages/admin/files.vue +++ b/packages/client/src/pages/admin/files.vue @@ -28,7 +28,7 @@
- +
- + -