summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-03-22 15:27:08 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-03-22 15:27:08 +0900
commit52d577c7dd7bf87b3fae34f539bb6e656c7c0ed2 (patch)
tree9805c625a7fba9d8631db8a92772b2772d8632ec
parentMerge branch 'develop' (diff)
parent12.75.0 (diff)
downloadmisskey-52d577c7dd7bf87b3fae34f539bb6e656c7c0ed2.tar.gz
misskey-52d577c7dd7bf87b3fae34f539bb6e656c7c0ed2.tar.bz2
misskey-52d577c7dd7bf87b3fae34f539bb6e656c7c0ed2.zip
Merge branch 'develop'
-rw-r--r--.autogen/check_pr.jq3
-rw-r--r--.autogen/next_url.jq2
-rw-r--r--.autogen/patreon.jq39
-rwxr-xr-x.autogen/update_readme_patreon.sh87
-rw-r--r--.eslintrc20
-rw-r--r--CHANGELOG.md1
-rw-r--r--assets/favicon.icobin0 -> 90022 bytes
-rw-r--r--assets/redoc.html2
-rw-r--r--gulpfile.ts18
-rw-r--r--locales/fr-FR.yml69
-rw-r--r--locales/it-IT.yml595
-rw-r--r--locales/ja-JP.yml2
-rw-r--r--locales/ja-KS.yml6
-rw-r--r--locales/ru-RU.yml36
-rw-r--r--locales/zh-CN.yml2
-rw-r--r--locales/zh-TW.yml6
-rw-r--r--migration/1615965918224-chart-v2.ts218
-rw-r--r--migration/1615966519402-chart-v2-2.ts22
-rw-r--r--package.json112
-rw-r--r--src/.eslintrc6
-rw-r--r--src/client/.eslintrc20
-rw-r--r--src/client/components/note-detailed.vue3
-rw-r--r--src/client/components/note.vue3
-rw-r--r--src/client/components/ui/modal.vue2
-rw-r--r--src/client/init.ts34
-rw-r--r--src/client/pages/doc.vue2
-rw-r--r--src/client/pages/page-editor/page-editor.vue22
-rw-r--r--src/client/store.ts1
-rw-r--r--src/client/theme-store.ts27
-rw-r--r--src/client/ui/chat/note.vue3
-rw-r--r--src/daemons/janitor.ts2
-rw-r--r--src/daemons/queue-stats.ts2
-rw-r--r--src/daemons/server-stats.ts2
-rw-r--r--src/db/postgre.ts4
-rw-r--r--src/docs/fr-FR/api.md80
-rw-r--r--src/docs/fr-FR/create-plugin.md2
-rw-r--r--src/docs/fr-FR/follow.md2
-rw-r--r--src/docs/fr-FR/pages.md4
-rw-r--r--src/docs/fr-FR/stream.md2
-rw-r--r--src/docs/fr-FR/theme.md4
-rw-r--r--src/docs/it-IT/custom-emoji.md4
-rw-r--r--src/docs/it-IT/follow.md4
-rw-r--r--src/docs/it-IT/keyboard-shortcut.md34
-rw-r--r--src/docs/it-IT/mute.md16
-rw-r--r--src/docs/it-IT/pages.md2
-rw-r--r--src/docs/it-IT/reaction.md16
-rw-r--r--src/docs/it-IT/theme.md18
-rw-r--r--src/docs/it-IT/timelines.md12
-rw-r--r--src/global.d.ts1
-rw-r--r--src/misc/before-shutdown.ts90
-rw-r--r--src/misc/cache.ts43
-rw-r--r--src/misc/fetch-meta.ts2
-rw-r--r--src/misc/keypair-store.ts10
-rw-r--r--src/misc/populate-emojis.ts119
-rw-r--r--src/models/entities/drive-file.ts2
-rw-r--r--src/models/entities/note-reaction.ts4
-rw-r--r--src/models/repositories/antenna.ts18
-rw-r--r--src/models/repositories/drive-file.ts36
-rw-r--r--src/models/repositories/note.ts120
-rw-r--r--src/models/repositories/notification.ts72
-rw-r--r--src/models/repositories/user.ts24
-rw-r--r--src/queue/index.ts23
-rw-r--r--src/queue/initialize.ts18
-rw-r--r--src/queue/processors/deliver.ts19
-rw-r--r--src/queue/processors/inbox.ts1
-rw-r--r--src/queue/queues.ts7
-rw-r--r--src/remote/activitypub/deliver-manager.ts6
-rw-r--r--src/remote/activitypub/renderer/index.ts6
-rw-r--r--src/remote/activitypub/renderer/person.ts5
-rw-r--r--src/remote/activitypub/request.ts10
-rw-r--r--src/server/activitypub.ts5
-rw-r--r--src/server/api/authenticate.ts13
-rw-r--r--src/server/api/common/inject-featured.ts2
-rw-r--r--src/server/api/define.ts1
-rw-r--r--src/server/api/endpoints/admin/invite.ts2
-rw-r--r--src/server/api/endpoints/admin/promo/create.ts2
-rw-r--r--src/server/api/endpoints/antennas/notes.ts6
-rw-r--r--src/server/api/endpoints/auth/accept.ts2
-rw-r--r--src/server/api/endpoints/channels/follow.ts5
-rw-r--r--src/server/api/endpoints/channels/timeline.ts6
-rw-r--r--src/server/api/endpoints/channels/unfollow.ts3
-rw-r--r--src/server/api/endpoints/clips/add-note.ts2
-rw-r--r--src/server/api/endpoints/clips/notes.ts6
-rw-r--r--src/server/api/endpoints/i.ts27
-rw-r--r--src/server/api/endpoints/i/notifications.ts10
-rw-r--r--src/server/api/endpoints/i/read-announcement.ts2
-rw-r--r--src/server/api/endpoints/i/update.ts3
-rw-r--r--src/server/api/endpoints/miauth/gen-token.ts2
-rw-r--r--src/server/api/endpoints/mute/create.ts3
-rw-r--r--src/server/api/endpoints/mute/delete.ts3
-rw-r--r--src/server/api/endpoints/notes.ts6
-rw-r--r--src/server/api/endpoints/notes/children.ts6
-rw-r--r--src/server/api/endpoints/notes/favorites/create.ts2
-rw-r--r--src/server/api/endpoints/notes/featured.ts6
-rw-r--r--src/server/api/endpoints/notes/global-timeline.ts11
-rw-r--r--src/server/api/endpoints/notes/hybrid-timeline.ts11
-rw-r--r--src/server/api/endpoints/notes/local-timeline.ts11
-rw-r--r--src/server/api/endpoints/notes/mentions.ts10
-rw-r--r--src/server/api/endpoints/notes/renotes.ts6
-rw-r--r--src/server/api/endpoints/notes/replies.ts6
-rw-r--r--src/server/api/endpoints/notes/search-by-tag.ts6
-rw-r--r--src/server/api/endpoints/notes/search.ts6
-rw-r--r--src/server/api/endpoints/notes/timeline.ts11
-rw-r--r--src/server/api/endpoints/notes/user-list-timeline.ts6
-rw-r--r--src/server/api/endpoints/pages/like.ts2
-rw-r--r--src/server/api/endpoints/promo/read.ts2
-rw-r--r--src/server/api/endpoints/sw/register.ts2
-rw-r--r--src/server/api/endpoints/users/followers.ts3
-rw-r--r--src/server/api/endpoints/users/following.ts3
-rw-r--r--src/server/api/endpoints/users/groups/create.ts2
-rw-r--r--src/server/api/endpoints/users/groups/invitations/accept.ts2
-rw-r--r--src/server/api/endpoints/users/notes.ts6
-rw-r--r--src/server/api/private/signin.ts4
-rw-r--r--src/server/api/stream/channels/antenna.ts2
-rw-r--r--src/server/api/stream/channels/channel.ts2
-rw-r--r--src/server/api/stream/channels/global-timeline.ts2
-rw-r--r--src/server/api/stream/channels/hashtag.ts2
-rw-r--r--src/server/api/stream/channels/home-timeline.ts2
-rw-r--r--src/server/api/stream/channels/hybrid-timeline.ts2
-rw-r--r--src/server/api/stream/channels/local-timeline.ts2
-rw-r--r--src/server/api/stream/channels/main.ts8
-rw-r--r--src/server/api/stream/index.ts112
-rw-r--r--src/server/web/index.ts12
-rw-r--r--src/server/web/views/flush.pug59
-rw-r--r--src/services/add-note-to-antenna.ts2
-rw-r--r--src/services/blocking/create.ts14
-rw-r--r--src/services/chart/charts/classes/active-users.ts18
-rw-r--r--src/services/chart/charts/classes/drive.ts22
-rw-r--r--src/services/chart/charts/classes/federation.ts11
-rw-r--r--src/services/chart/charts/classes/hashtag.ts18
-rw-r--r--src/services/chart/charts/classes/instance.ts44
-rw-r--r--src/services/chart/charts/classes/network.ts11
-rw-r--r--src/services/chart/charts/classes/notes.ts26
-rw-r--r--src/services/chart/charts/classes/per-user-drive.ts12
-rw-r--r--src/services/chart/charts/classes/per-user-following.ts30
-rw-r--r--src/services/chart/charts/classes/per-user-notes.ts14
-rw-r--r--src/services/chart/charts/classes/per-user-reactions.ts12
-rw-r--r--src/services/chart/charts/classes/test-grouped.ts11
-rw-r--r--src/services/chart/charts/classes/test-unique.ts13
-rw-r--r--src/services/chart/charts/classes/test.ts11
-rw-r--r--src/services/chart/charts/classes/users.ts16
-rw-r--r--src/services/chart/charts/schemas/active-users.ts12
-rw-r--r--src/services/chart/charts/schemas/hashtag.ts12
-rw-r--r--src/services/chart/charts/schemas/test-unique.ts7
-rw-r--r--src/services/chart/core.ts276
-rw-r--r--src/services/chart/index.ts25
-rw-r--r--src/services/create-notification.ts2
-rw-r--r--src/services/following/create.ts11
-rw-r--r--src/services/following/delete.ts7
-rw-r--r--src/services/following/requests/reject.ts7
-rw-r--r--src/services/i/pin.ts2
-rw-r--r--src/services/insert-moderation-log.ts2
-rw-r--r--src/services/messages/create.ts6
-rw-r--r--src/services/note/create.ts50
-rw-r--r--src/services/note/polls/vote.ts2
-rw-r--r--src/services/note/reaction/create.ts48
-rw-r--r--src/services/note/read.ts80
-rw-r--r--src/services/note/unread.ts6
-rw-r--r--src/services/note/watch.ts2
-rw-r--r--src/services/register-or-fetch-instance-doc.ts8
-rw-r--r--src/services/stream.ts5
-rw-r--r--src/services/update-hashtag.ts4
-rw-r--r--src/services/user-list/push.ts2
-rw-r--r--src/tsconfig.json (renamed from tsconfig.json)8
-rw-r--r--test/.eslintrc7
-rw-r--r--test/chart.ts54
-rw-r--r--test/fetch-resource.ts187
-rw-r--r--test/get-file-info.ts4
-rw-r--r--test/tsconfig.json36
-rw-r--r--test/utils.ts61
-rw-r--r--yarn.lock1252
171 files changed, 3354 insertions, 1765 deletions
diff --git a/.autogen/check_pr.jq b/.autogen/check_pr.jq
deleted file mode 100644
index 0adb0b503d..0000000000
--- a/.autogen/check_pr.jq
+++ /dev/null
@@ -1,3 +0,0 @@
-.[]
-.head
-.label
diff --git a/.autogen/next_url.jq b/.autogen/next_url.jq
deleted file mode 100644
index b4c3b819a5..0000000000
--- a/.autogen/next_url.jq
+++ /dev/null
@@ -1,2 +0,0 @@
-.links
-.next
diff --git a/.autogen/patreon.jq b/.autogen/patreon.jq
deleted file mode 100644
index c761d587b8..0000000000
--- a/.autogen/patreon.jq
+++ /dev/null
@@ -1,39 +0,0 @@
-(
- .data |
- map(
- select(
- .relationships
- .currently_entitled_tiers
- .data[]
- )
- ) |
- map(
- .relationships
- .user
- .data
- .id
- )
-) as $data |
-.included |
-map(
- select(
- .id as $id |
- $data |
- contains(
- [
- $id
- ]
- )
- )
-) |
-map(
- .attributes |
- [
- .full_name,
- .thumb_url,
- .url
- ] |
- @tsv
-) |
-.[] |
-@text
diff --git a/.autogen/update_readme_patreon.sh b/.autogen/update_readme_patreon.sh
deleted file mode 100755
index 7a108c2b67..0000000000
--- a/.autogen/update_readme_patreon.sh
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/env bash
-# __MISSKEY_BEARER_TOKEN=
-# __MISSKEY_CAMPAIGN_ID=
-# __MISSKEY_GITHUB_TOKEN=
-# __MISSKEY_HEAD=syuilo:patch-autogen
-# __MISSKEY_REPO=syuilo/misskey
-# __MISSKEY_BRANCH=develop
-test "$(curl -LSs -w '\n' -- "https://api.github.com/repos/$REPO/pulls?access_token=$__MISSKEY_GITHUB_TOKEN" | jq -r -f check_pr.jq | grep $__MISSKEY_HEAD)" && exit 1
-cd "$(dirname $0)/.." && \
-touch null.cache && \
-rm *.cache && \
-git checkout $__MISSKEY_BRANCH && \
-git pull origin $__MISSKEY_BRANCH && \
-git pull upstream $__MISSKEY_BRANCH && \
-git stash && \
-git rebase -f upstream/$__MISSKEY_BRANCH && \
-git branch patch-autogen && \
-git checkout patch-autogen && \
-git reset --hard HEAD || \
-exit 1
-touch patreon.md.cache && \
-rm patreon.md.cache && \
-echo '<!-- PATREON_START -->' > patreon.md.cache && \
-url="https://www.patreon.com/api/oauth2/v2/campaigns/$__MISSKEY_CAMPAIGN_ID/members?include=currently_entitled_tiers,user&fields%5Btier%5D=title&fields%5Buser%5D=full_name,thumb_url,url,hide_pledges"
-while :
- do
- touch patreon.raw.cache && \
- rm patreon.raw.cache && \
- curl -LSs -w '\n' -H "Authorization: Bearer $__MISSKEY_BEARER_TOKEN" -- $url > patreon.raw.cache && \
- touch patreon.cache && \
- rm patreon.cache && \
- cat patreon.raw.cache | \
- jq -r -f patreon.jq >> patreon.cache && \
- echo '<table><tr>' >> patreon.md.cache && \
- cat patreon.cache | \
- awk -F'\t' '{print $2,$1}' | \
- sed -e 's/ /\\" alt=\\"/' | \
- xargs -I% echo '<td><img src="%" width="100"></td>' >> patreon.md.cache && \
- echo '</tr><tr>' >> patreon.md.cache && \
- cat patreon.cache | \
- awk -F'\t' '{print $3,$1}' | \
- sed -e 's/ /\\">/' | \
- xargs -I% echo '<td><a href="%</a></td>' >> patreon.md.cache && \
- echo '</tr></table>' >> patreon.md.cache || \
- exit 1
- new_url="$(cat patreon.raw.cache | jq -r -f next_url.jq)"
- test "$new_url" = 'null' && \
- break || \
- URL="$url"
-done
-ignore= && \
-echo -e "\n**Last updated:** $(date -uR | sed 's/\+0000/UTC/')\n<!-- PATREON_END -->" >> patreon.md.cache && \
-touch README.md && \
-touch .autogen/README.md && \
-rm .autogen/README.md && \
-mv README.md .autogen/README.md && \
-cat .autogen/README.md | while IFS= read line;
- do
- if [[ -z "$ignore" ]]
- then
- if [[ "$line" = '<!-- PATREON_START -->' ]]
- then
- ignore='PATREON_INSIDE'
- else
- echo "$line" >> README.md
- fi
- else
- if [[ "$LINE" = '<!-- PATREON_END -->' ]]
- then
- ignore=
- cat patreon.md.cache >> README.md
- fi
- fi
-done
-cat patreon.md.cache
-touch null.cache && \
-rm *.cache && \
-diff .autogen/README.md README.md > diff.cache
-cat diff.cache && \
-test 4 -lt $(cat diff.cache | wc -l) && \
-git add README.md && \
-git commit -m 'Update README.md [AUTOGEN]' && \
-git push -f origin patch-autogen && \
-curl -LSs -w '\n' -X POST -d '{"title":"[AUTOMATED] Update README.md","body":"*This pull request was created by a tool.*","head":"'$__MISSKEY_HEAD'","base":"'$__MISSKEY_BRANCH'"}' -- "https://api.github.com/repos/$__MISSKEY_REPO/pulls?access_token=$__MISSKEY_GITHUB_TOKEN"
-git stash
-git checkout $__MISSKEY_BRANCH
-git branch -D patch-autogen
diff --git a/.eslintrc b/.eslintrc
index 3a220319e5..3e5b59cb04 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -3,29 +3,11 @@
"parser": "@typescript-eslint/parser"
},
"extends": [
- "eslint:recommended",
- "plugin:vue/recommended"
+ "eslint:recommended"
],
"rules": {
- "vue/require-v-for-key": 0,
- "vue/max-attributes-per-line": 0,
- "vue/html-indent": 0,
- "vue/html-self-closing": 0,
- "vue/no-unused-vars": 0,
- "vue/attributes-order": 0,
- "vue/require-prop-types": 0,
- "vue/require-default-prop": 0,
- "vue/html-closing-bracket-spacing": 0,
- "vue/singleline-html-element-content-newline": 0,
- "vue/no-v-html": 0,
"no-console": 0,
"no-unused-vars": 0,
"no-empty": 0
- },
- "globals": {
- "ENV": true,
- "VERSION": true,
- "API": true,
- "LANGS": true
}
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000..1fd048e8ea
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1 @@
+see [releases](https://github.com/syuilo/misskey/releases)
diff --git a/assets/favicon.ico b/assets/favicon.ico
new file mode 100644
index 0000000000..9be1ff6295
--- /dev/null
+++ b/assets/favicon.ico
Binary files differ
diff --git a/assets/redoc.html b/assets/redoc.html
index 4d2360fb20..9ee5a95c05 100644
--- a/assets/redoc.html
+++ b/assets/redoc.html
@@ -19,6 +19,6 @@
</head>
<body>
<redoc spec-url="/api.json" expand-responses="200" expand-single-schema-field="true"></redoc>
- <script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
+ <script src="https://cdn.jsdelivr.net/npm/redoc@2.0.0-rc.50/bundles/redoc.standalone.js" integrity="sha256-WJbngBWN9vp6vkEuzeoSj5tE5saW9Hfj6/SinkzhL2s=" crossorigin="anonymous"></script>
</body>
</html>
diff --git a/gulpfile.ts b/gulpfile.ts
index 95b2394887..771a5c0e32 100644
--- a/gulpfile.ts
+++ b/gulpfile.ts
@@ -14,7 +14,7 @@ const locales: { [x: string]: any } = require('./locales');
const meta = require('./package.json');
gulp.task('build:ts', () => {
- const tsProject = ts.createProject('./tsconfig.json');
+ const tsProject = ts.createProject('./src/tsconfig.json');
return tsProject
.src()
@@ -64,7 +64,6 @@ gulp.task('build:client:style', () => {
gulp.task('build:copy', gulp.parallel('build:copy:locales', 'build:copy:views', 'build:client:script', 'build:client:style', 'build:copy:fonts', () =>
gulp.src([
'./src/emojilist.json',
- './src/server/web/views/**/*',
'./src/**/assets/**/*',
'!./src/client/assets/**/*'
]).pipe(gulp.dest('./built/'))
@@ -78,17 +77,16 @@ gulp.task('cleanall', gulp.parallel('clean', cb =>
rimraf('./node_modules', cb)
));
-gulp.task('copy:docs', () =>
- gulp.src([
- './src/docs/**/*',
- ])
- .pipe(gulp.dest('./built/assets/docs/'))
-);
-
gulp.task('build', gulp.parallel(
'build:ts',
'build:copy',
- 'copy:docs',
));
gulp.task('default', gulp.task('build'));
+
+gulp.task('watch', () => {
+ gulp.watch([
+ './src/**/*',
+ '!./src/client/**/*'
+ ], { ignoreInitial: false }, gulp.task('build'));
+});
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index 16815ab25d..1b3ccbbb0c 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -110,7 +110,7 @@ attachCancel: "Supprimer le fichier attaché"
markAsSensitive: "Marquer comme sensible"
unmarkAsSensitive: "Supprimer le marquage comme sensible"
enterFileName: "Entrer le nom du fichier"
-mute: "Mettre en sourdine"
+mute: "Masquer"
unmute: "Ne plus masquer"
block: "Bloquer"
unblock: "Débloquer"
@@ -206,7 +206,7 @@ all: "Tous"
subscribing: "Abonné"
publishing: "Publié"
notResponding: "Ne répond pas"
-instanceFollowing: "Suivre une instance"
+instanceFollowing: "Abonnements de l'instance"
instanceFollowers: "Abonné·e·s de l’instance"
instanceUsers: "Utilisateur·rice·s de cette l’instance"
changePassword: "Modifier votre mot de passe"
@@ -317,12 +317,12 @@ disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateurÂ
registration: "S’inscrire"
enableRegistration: "Autoriser les nouvelles inscriptions"
invite: "Inviter"
-proxyRemoteFiles: "Proxy fichiers distants"
+proxyRemoteFiles: "Utiliser les fichiers distants comme proxy"
proxyRemoteFilesDescription: "Si vous activez ce paramètre, les fichiers distants non stockés ou supprimés en raison d'une capacité excédentaire seront affichés via un proxy local et généreront une miniature. Cela n'affectera pas le stockage du serveur."
driveCapacityPerLocalAccount: "Volume du Drive par utilisateur local"
driveCapacityPerRemoteAccount: "Volume du Drive par utilisateur distant"
inMb: "en mégaoctets"
-iconUrl: "URL de l’image de l’avatar"
+iconUrl: "URL de l'icône"
bannerUrl: "URL de l’image de la bannière"
basicInfo: "Informations basiques"
pinnedUsers: "Utilisateur·rice épinglé·e"
@@ -491,7 +491,7 @@ objectStorageUseProxyDesc: "Désactivez cette option si vous n'utilisez pas Prox
objectStorageSetPublicRead: "Régler sur « public » lors de l'envoi"
serverLogs: "Journal du serveur"
deleteAll: "Supprimer tout"
-showFixedPostForm: "Afficher le formulaire en haut du fil d'actualité"
+showFixedPostForm: "Afficher le formulaire de publication en haut du fil d'actualité"
newNoteRecived: "Vous avez reçu une nouvelle note"
sounds: "Sons"
listen: "Écouter"
@@ -616,12 +616,14 @@ openInNewTab: "Ouvrir dans un nouvel onglet"
openInSideView: "Ouvrir en vue latérale"
defaultNavigationBehaviour: "Navigation par défaut"
editTheseSettingsMayBreakAccount: "La modification de ces paramètres peut endommager votre compte."
+instanceTicker: "Nom de l'instance d'origine des notes"
waitingFor: "En attente de {x}"
random: "Aléatoire"
system: "Système"
switchUi: "Modifier l'interface utilisateur"
desktop: "Bureau"
clip: "Clip"
+createNew: "Créer nouveau"
optional: "Facultatif"
createNewClip: "Créer un nouveau clip"
public: "Public"
@@ -806,6 +808,7 @@ _reversi:
canPutEverywhere: "Les pions peuvent être placés partout "
_instanceTicker:
none: "Cacher "
+ remote: "Montrer pour les utilisateur·ice·s distant·e·s"
always: "Toujours afficher"
_serverDisconnectedBehavior:
reload: "Rechargement automatique"
@@ -823,11 +826,12 @@ _channel:
notesCount: "{n} Notes"
_sidebar:
full: "Complet"
- icon: "Avatar"
+ icon: "Icônes"
hide: "Masquer"
_wordMute:
muteWords: "Mots à filtrer"
muteWordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec un saut de ligne pour une condition OR."
+ muteWordsDescription2: "Pour utiliser des expressions régulières (regex), mettez les mots-clés entre barres obliques."
softDescription: "Masquez les notes de votre fil selon les paramètres que vous définissez."
hardDescription: "Empêchez votre fil de charger les notes selon les paramètres que vous définissez. Cette action est irréversible : si vous modifiez ces paramètres plus tard, les notes précédemment filtrées ne seront pas récupérées."
soft: "Doux"
@@ -902,6 +906,8 @@ _sfx:
chatBg: "Discuter (De fond)"
antenna: "Réception de l’antenne"
channel: "Notifications de canal"
+ reversiPutBlack: "Reversi : les pions noirs ont joué"
+ reversiPutWhite: "Reversi : les pions blancs ont joué"
_ago:
unknown: "Inconnu"
future: "Futur"
@@ -953,12 +959,12 @@ _2fa:
_permissions:
"read:account": "Afficher les informations du compte"
"write:account": "Mettre à jour les informations de votre compte"
- "read:blocks": "Voir les blocs"
- "write:blocks": "Écrire des blocs"
+ "read:blocks": "Voir les comptes bloqués"
+ "write:blocks": "Gérer les comptes bloqués"
"read:drive": "Parcourir le Drive"
"write:drive": "Écrire sur le Drive"
"read:favorites": "Afficher les favoris"
- "write:favorites": "Écrire des favoris"
+ "write:favorites": "Gérer les favoris"
"read:following": "Voir les informations de vos abonnements"
"write:following": "Abonnements/Se désabonner"
"read:messaging": "Cherche à discuter"
@@ -1012,7 +1018,7 @@ _widgets:
photos: "Photos"
digitalClock: "Horloge numérique"
federation: "Fédération"
- postForm: "Formulaire à publier"
+ postForm: "Formulaire de publication"
slideshow: "Diaporama"
button: "Bouton"
onlineUsers: "Utilisateurs en ligne"
@@ -1083,8 +1089,8 @@ _profile:
_exportOrImport:
allNotes: "Toutes les notes"
followingList: "Abonnements"
- muteList: "Liste des comptes maqués"
- blockingList: "Bloquer"
+ muteList: "Comptes masqués"
+ blockingList: "Comptes bloqués"
userLists: "Listes"
_charts:
federationInstancesIncDec: "Variation du nombre des instances fédérées"
@@ -1228,17 +1234,17 @@ _pages:
if: "Si"
_if:
variable: "Variables"
- post: "Formulaire à publier"
+ post: "Formulaire de publication"
_post:
text: "Contenu"
attachCanvasImage: "Publier avec Toile comme image"
canvasId: "Toile ID"
- textInput: "Entrée de textuelle"
+ textInput: "Entrée textuelle"
_textInput:
name: "Nom de la variable"
text: "Titre"
default: "Valeur par défaut"
- textareaInput: "Entrée de textuelle multiligne"
+ textareaInput: "Entrée textuelle multi-ligne"
_textareaInput:
name: "Nom de la variable"
text: "Titre"
@@ -1253,10 +1259,12 @@ _pages:
id: "Toile ID"
width: "Largeur"
height: "Hauteur"
+ note: "Note intégrée"
_note:
id: "Identifiant de la note"
+ idDescription: "Pour configurer la note, vous pouvez aussi coller ici l'URL correspondante."
detailed: "Afficher les détails"
- switch: "Basculer"
+ switch: "Interrupteur"
_switch:
name: "Nom de la variable"
text: "Titre"
@@ -1265,16 +1273,16 @@ _pages:
_counter:
name: "Nom de la variable"
text: "Titre"
- inc: "Augmenter le chiffre"
+ inc: "Augmenter de"
_button:
text: "Titre"
colored: "Coloré"
- action: "L'opération lorsque le bouton sera pressé"
+ action: "Opération à effectuer lorsque le bouton est pressé"
_action:
dialog: "Afficher une fenêtre de dialogue"
_dialog:
content: "Contenu"
- resetRandom: "Réinitialiser le nombre aléatoire"
+ resetRandom: "Réinitialiser un nombre aléatoire"
pushEvent: "Envoyer un évènement"
_pushEvent:
event: "Nom de l’évènement"
@@ -1288,7 +1296,7 @@ _pages:
_radioButton:
name: "Nom de la variable"
title: "Titre"
- values: "Choix séparés par des sauts de ligne"
+ values: "Liste des choix (un par ligne)"
default: "Valeur par défaut"
script:
categories:
@@ -1304,7 +1312,7 @@ _pages:
list: "Listes"
blocks:
text: "Texte"
- multiLineText: "Texte (Multi-lignes)"
+ multiLineText: "Texte (multi-ligne)"
textList: "Liste de texte"
_textList:
info: "Veuillez séparer chaque entrée avec un saut de ligne"
@@ -1347,10 +1355,10 @@ _pages:
_mod:
arg1: "A"
arg2: "B"
- round: "Décimal rond"
+ round: "Arrondir les décimales"
_round:
arg1: "Numérique"
- eq: "A et B sont équivalents"
+ eq: "A et B sont égaux"
_eq:
arg1: "A"
arg2: "B"
@@ -1366,7 +1374,7 @@ _pages:
_or:
arg1: "A"
arg2: "B"
- lt: "A est plus petit que B"
+ lt: "A est inférieur à B"
_lt:
arg1: "A"
arg2: "B"
@@ -1374,7 +1382,7 @@ _pages:
_gt:
arg1: "A"
arg2: "B"
- ltEq: "A est plus petit ou égal à B"
+ ltEq: "A est inférieur ou égal à B"
_ltEq:
arg1: "A"
arg2: "B"
@@ -1440,7 +1448,7 @@ _pages:
numberToString: "Convertir du numérique en texte"
_numberToString:
arg1: "Numérique"
- splitStrByLine: "Séparer le texte par lignes"
+ splitStrByLine: "Séparer le texte par des sauts de lignes"
_splitStrByLine:
arg1: "Texte"
ref: "Variables"
@@ -1448,7 +1456,7 @@ _pages:
fn: "Fonction"
_fn:
slots: "Slots"
- slots-info: "Veuillez délimiter chaque slot par un saut de ligne"
+ slots-info: "Veuillez insérer un seul slot par ligne"
arg1: "Sortie"
for: "Répéter"
_for:
@@ -1482,18 +1490,19 @@ _notification:
youWereFollowed: "Vous suit"
youReceivedFollowRequest: "Vous avez reçu une demande d’abonnement"
yourFollowRequestAccepted: "Votre demande d’abonnement a été accepté"
- youWereInvitedToGroup: "Invité au groupe"
+ youWereInvitedToGroup: "Invité·e au groupe"
_types:
all: "Toutes"
follow: "Abonnements"
- mention: "Mentionner"
+ mention: "Mentions"
reply: "Réponses"
renote: "Partager"
quote: "Citer"
reaction: "Réactions"
+ pollVote: "Votes dans des sondages"
receiveFollowRequest: "Demande d'abonnement reçue"
followRequestAccepted: "Demande d'abonnement acceptée"
- groupInvited: "Invité aux groupes"
+ groupInvited: "Invitation à un groupe"
app: "Notifications provenant des apps"
_deck:
alwaysShowMainColumn: "Toujours afficher la colonne principale"
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index 4e2e4a5353..25ee8c6f6b 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -1,6 +1,7 @@
---
_lang_: "Italiano"
headlineMisskey: "Rete collegata tramite note"
+introMisskey: "Benvenut@! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \nScrivi \"note\" per condividere ciò che sta succedendo adesso o per dire a tutti qualcosa di te. 📡\nGrazie alla funzione \"reazioni\" puoi anche mandare reazioni rapide alle note delle altre persone del Fediverso. ðŸ‘\nEsplora un nuovo mondo! 🚀"
monthAndDay: "{day}/{month}"
search: "Cerca"
notifications: "Notifiche"
@@ -11,7 +12,7 @@ ok: "OK"
gotIt: "Capito!"
cancel: "Annulla"
enterUsername: "Inserisci un nome utente"
-renotedBy: "Condiviso da {user}"
+renotedBy: "Rinotato da {user}"
noNotes: "Nessuna nota!"
noNotifications: "Nessuna notifica"
instance: "Istanza"
@@ -21,6 +22,7 @@ otherSettings: "Altre impostazioni"
openInWindow: "Apri in una finestra"
profile: "Profilo"
timeline: "Timeline"
+noAccountDescription: "L'utente non ha ancora scritto niente nella biografia di profilo."
login: "Accedi"
loggingIn: "Accesso in corso..."
logout: "Esci"
@@ -32,15 +34,16 @@ addUser: "Aggiungi utente"
favorite: "Preferiti"
favorites: "Preferiti"
unfavorite: "Rimuovi nota dai preferiti"
-favorited: "Aggiunta ai preferiti."
-alreadyFavorited: "Già tra i preferiti."
-cantFavorite: "Impossibile aggiungere ai Preferiti."
+favorited: "Aggiunta ai tuoi preferiti."
+alreadyFavorited: "Già tra i tuoi preferiti."
+cantFavorite: "Impossibile aggiungere la nota ai preferiti."
pin: "Fissa sul profilo"
unpin: "Non fissare sul profilo"
copyContent: "Copia il contenuto"
-copyLink: "Copia link"
+copyLink: "Copia il link"
delete: "Elimina"
-deleteAndEdit: "Elimina & Modifica"
+deleteAndEdit: "Elimina e modifica"
+deleteAndEditConfirm: "Vuoi davvero cancellare questa nota e scriverla di nuovo? Verrano eliminate anche tutte le reazioni, Rinote e risposte collegate."
addToList: "Aggiungi alla lista"
sendMessage: "Invia messaggio"
copyUsername: "Copia nome utente"
@@ -49,65 +52,104 @@ reply: "Rispondi"
loadMore: "Mostra di più"
showMore: "Mostra di più"
youGotNewFollower: "Ha iniziato a seguirti"
-receiveFollowRequest: "Nuova richiesta di essere seguito"
+receiveFollowRequest: "Hai ricevuto una richiesta di follow."
+followRequestAccepted: "Richiesta di follow accettata"
mention: "Menzioni"
mentions: "Menzioni"
directNotes: "Note dirette"
-importAndExport: "Importa ed Esporta"
+importAndExport: "Importa ed esporta"
import: "Importa"
export: "Esporta"
-files: "Allegato"
+files: "Allegati"
download: "Scarica"
+driveFileDeleteConfirm: "Vuoi davvero eliminare il file「{name}? Anche gli allegati verranno eliminati."
+unfollowConfirm: "Vuoi davvero smettere di seguire {name}?"
+exportRequested: "Hai richiesto un'esportazione, e potrebbe volerci tempo. Quando sarà compiuta, il file verrà aggiunto direttamente al Drive."
+importRequested: "Hai richiesto un'importazione. Può volerci tempo. "
lists: "Liste"
-noLists: "Qui non c'è ancora niente"
+noLists: "Nessuna lista"
note: "Nota"
notes: "Note"
-following: "Seiguiti"
-followers: "Seguaci"
+following: "Follows"
+followers: "Followers"
followsYou: "Ti segue"
-createList: "Crea una nuova lista"
-manageLists: "Modifica lista"
+createList: "Aggiungi una nuova lista"
+manageLists: "Gestisci liste"
error: "Errore"
-somethingHappened: "Qualcosa è andato storto."
+somethingHappened: "Si è verificato un problema"
retry: "Riprova"
-enterListName: "Inserisci il nome della lista"
+pageLoadError: "Caricamento pagina non riuscito. "
+enterListName: "Nome della lista"
privacy: "Privacy"
+makeFollowManuallyApprove: "Richiedi di approvare i follower manualmente"
+defaultNoteVisibility: "Privacy predefinita delle note"
follow: "Segui"
-followRequest: "Richiesta di seguire"
-followRequests: "Richiesta di seguire"
+followRequest: "Richiesta di follow"
+followRequests: "Richieste di follow"
unfollow: "Smetti di seguire"
-followRequestPending: "In sospeso"
+followRequestPending: "La richiesta di follow deve essere approvata"
enterEmoji: "Inserisci emoji"
renote: "Rinota"
unrenote: "Annulla rinota"
-renoted: "Condiviso!"
-cantReRenote: "È impossibile rinota una condivisione."
+renoted: "Rinotato!"
+cantRenote: "È impossibile rinotare questa nota."
+cantReRenote: "È impossibile rinotare una Rinota."
quote: "Cita"
+pinnedNote: "Nota fissata"
pinned: "Fissa sul profilo"
you: "Tu"
clickToShow: "Clicca per visualizzare"
sensitive: "Contenuto sensibile"
add: "Aggiungi"
reaction: "Reazione"
+reactionSettingDescription: "Scegli le reazioni che preferisci e fissale nel pannello di reazioni."
+reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere."
+rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note"
attachCancel: "Rimuovi allegato"
markAsSensitive: "Segna come sensibile"
unmarkAsSensitive: "Segna come non sensibile"
+enterFileName: "Nome del file"
mute: "Silenzia"
unmute: "Riattiva"
block: "Blocca"
unblock: "Sblocca"
suspend: "Sospendi"
unsuspend: "Annulla la sospensione dell'account"
-blockConfirm: "Vuoi bloccare?"
-unblockConfirm: "Vuoi sbloccare?"
+blockConfirm: "Vuoi davvero bloccare l'account?"
+unblockConfirm: "Vuoi davvero sbloccare l'account?"
+suspendConfirm: "Vuoi davvero sospendere questo account?"
+unsuspendConfirm: "Vuoi annullare la sospensione dell'account?"
+selectList: "Seleziona una lista"
+selectAntenna: "Scegli un'antenna"
+selectWidget: "Seleziona widget"
+editWidgets: "Modifica i widget"
editWidgetsExit: "Modifica fine"
+customEmojis: "Emoji personalizzati"
emoji: "Emoji"
-addAcount: "Aggiungi un account esistente"
+emojiName: "Nome dell'emoji"
+emojiUrl: "URL dell'emoji"
+addEmoji: "Aggiungi un emoji"
+settingGuide: "Configurazione suggerita"
+cacheRemoteFiles: "Memorizzazione nella cache dei file remoti"
+flagAsBot: "Io sono un robot"
+flagAsBotDescription: "Se l'account esegue principalmente operazioni automatiche, attiva quest'opzione. Quando attivata, opera come un segnalatore per gli altri sviluppatori allo scopo di prevenire catene d’interazione senza fine con altri bot, e di adeguare i sistemi interni di Misskey perché trattino questo account come un bot."
+flagAsCat: "Io sono un gatto"
+flagAsCatDescription: "Abilita l'opzione \"Io sono un gatto\" per l'account."
+autoAcceptFollowed: "Accetta automaticamente le richieste di follow da utenti che già segui"
+addAcount: "Aggiungi account"
+loginFailed: "Accesso non riuscito"
+showOnRemote: "Sfoglia sull'istanza remota"
general: "Generali"
wallpaper: "Sfondo"
setWallpaper: "Imposta sfondo"
removeWallpaper: "Elimina lo sfondo"
searchWith: "Cerca: {q}"
+youHaveNoLists: "Non hai ancora creato nessuna lista"
+followConfirm: "Sei sicur@ di voler seguire {name}?"
+proxyAccount: "Account proxy"
+host: "Server remoto"
+selectUser: "Seleziona utente"
+recipient: "Destinatario"
annotation: "Descrizione"
federation: "Federazione"
instances: "Istanza"
@@ -115,36 +157,62 @@ storageUsage: "Volume di dischi"
charts: "Grafici"
perHour: "All'ora"
perDay: "al giorno"
+blockThisInstance: "Blocca l'istanza"
+operations: "Operazioni"
software: "Software"
version: "Versione"
metadata: "Metadato"
+withNFiles: "{n} file in allegato"
+monitor: "Monitorare"
+jobQueue: "Coda di lavoro"
cpuAndMemory: "CPU e Memoria"
network: "Rete"
disk: "Disco"
-instanceInfo: "Informazioni di istanza"
+instanceInfo: "Informazioni sull'istanza"
statistics: "Statistiche"
-clearQueue: "Cancella coda"
-clearQueueConfirmTitle: "Cancella coda?"
-blockedInstances: "Istanza bloccati"
-muteAndBlock: "Silenziamento e blocco"
+clearQueue: "Svuota coda"
+clearQueueConfirmTitle: "Vuoi davvero svuotare la coda?"
+clearCachedFiles: "Svuota cache"
+clearCachedFilesConfirm: "Vuoi davvero svuotare la cache da tutti i file remoti?"
+blockedInstances: "Istanze bloccate"
+blockedInstancesDescription: "Elenca le istanze che vuoi bloccare, una per riga. Esse non potranno più interagire con la tua istanza."
+muteAndBlock: "Silenziati / Bloccati"
mutedUsers: "Account silenziati"
blockedUsers: "Account bloccati"
+noUsers: "Nessun utente trovato"
editProfile: "Modifica profilo"
noteDeleteConfirm: "Eliminare questo Nota?"
+pinLimitExceeded: "Non puoi fissare altre note "
+intro: "L'installazione di Misskey è finita! Si prega di creare un account amministratore."
done: "Fine"
processing: "In elaborazione"
-blocked: "Bloccati"
+preview: "Anteprima"
+default: "Predefinito"
+noCustomEmojis: "Nessun emoji"
+noJobs: "Nessun lavoro"
+federating: "Federando"
+blocked: "Bloccato"
+suspended: "Sospes@"
all: "Tutti"
+subscribing: "Iscrivendo"
+publishing: "Pubblicando"
notResponding: "Nessuna risposta"
+instanceFollowing: "Seguiti dall'istanza"
+instanceFollowers: "Followers dell'istanza"
+instanceUsers: "Utenti dell'istanza"
changePassword: "Aggiorna Password"
security: "Sicurezza"
retypedNotMatch: "Le password non corrispondono."
currentPassword: "Password attuale"
newPassword: "Nuova Password"
-newPasswordRetype: "Conferma nuova password"
+newPasswordRetype: "Conferma password"
+attachFile: "Allega file"
more: "Altri!"
+featured: "Tendenze"
+usernameOrUserId: "Nome utente o ID utente"
+noSuchUser: "Nessun utente trovato"
lookup: "Cercare"
-announcements: "Annuncio"
+announcements: "Annunci"
imageUrl: "URL dell'immagine"
remove: "Elimina"
removed: "Il tuo Tweet è stato eliminato"
@@ -154,31 +222,66 @@ resetAreYouSure: "Reimposta"
saved: "Salvato"
messaging: "Messaggi"
upload: "Carica"
+fromDrive: "Dal Drive"
+fromUrl: "Dall'URL"
uploadFromUrl: "Incolla URL immagine"
+uploadFromUrlDescription: "URL del file che vuoi caricare"
+uploadFromUrlRequested: "Caricamento richiesto"
+uploadFromUrlMayTakeTime: "Il caricamento del file può richiedere tempo."
explore: "Esplora"
games: "Misskey Giochi"
messageRead: "Visualizzato"
+noMoreHistory: "Non c'è più cronologia da visualizzare"
startMessaging: "Nuovo messaggio"
+nUsersRead: "Letto da {n} persone"
+agreeTo: "Sono d'accordo con {0}"
tos: "Termini di servizio"
+start: "Inizia!"
home: "Home"
+remoteUserCaution: "Può darsi che le informazioni siano incomplete perché questo è un utente remoto."
+activity: "Attività"
images: "Immagini"
birthday: "Compleanno"
yearsOld: "{age}Anni"
registeredDate: "Iscrizione a.."
location: "Posizione"
theme: "Tema"
+themeForLightMode: "Tema da utilizzare per il modo chiaro"
+themeForDarkMode: "Tema da utilizzare per il modo scuro"
light: "Chiaro"
dark: "Scuro"
lightThemes: "Tema Chiaro"
darkThemes: "Tema Scuro"
+syncDeviceDarkMode: "Sincronizza il tema scuro con le impostazioni del dispositivo"
drive: "Drive"
fileName: "Nome dell'allegato"
+selectFile: "Scelta allegato"
+selectFiles: "Scelta allegato"
+selectFolder: "Seleziona cartella"
+selectFolders: "Seleziona cartella"
+renameFile: "Rinomina file"
+folderName: "Nome della cartella"
+createFolder: "Nuova cartella"
+renameFolder: "Rinominare cartella"
+deleteFolder: "Elimina cartella"
+addFile: "Allega"
+emptyDrive: "Il Drive è vuoto"
+emptyFolder: "La cartella è vuota"
+unableToDelete: "Eliminazione impossibile"
+inputNewFileName: "Inserisci nome del nuovo file"
+inputNewFolderName: "Inserisci nome della nuova cartella"
+circularReferenceFolder: "La cartella di destinazione è una sottocartella della cartella che vuoi spostare."
+hasChildFilesOrFolders: "Impossibile eliminare la cartella perché non è vuota"
copyUrl: "Copia URL"
rename: "Modifica nome"
avatar: "Foto del profilo"
-banner: "Foto d'intestazione"
+banner: "Intestazione"
nsfw: "Contenuti sensibili"
+whenServerDisconnected: "Quando la connessione col server è persa"
+disconnectedFromServer: "Disconness@ dal server"
reload: "Ricarica"
+doNothing: "Nessun'azione"
+reloadConfirm: "Vuoi ricaricare?"
watch: "Osserva"
unwatch: "Smetti di Osserva"
accept: "Accetta"
@@ -195,21 +298,64 @@ today: "Oggi"
dayX: "{day}"
monthX: "{month}"
yearX: "{year}"
+pages: "Pagine"
integration: "App collegate"
connectSerice: "Connetti"
disconnectSerice: "Disconnetti"
+enableLocalTimeline: "Abilita Timeline locale"
+enableGlobalTimeline: "Abilita Timeline federata"
+disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e i moderatori potranno sempre accederci."
registration: "Iscriviti"
+enableRegistration: "Permettere nuove registrazioni"
invite: "Invita"
-bannerUrl: "indirizzo Foto d'intestazione"
+proxyRemoteFiles: "Usare file remoti come proxy"
+driveCapacityPerLocalAccount: "Volume del Drive per utente locale"
+driveCapacityPerRemoteAccount: "Volume del Drive per utente remoto"
+inMb: "in Megabytes"
+iconUrl: "URL di icona (favicon, ecc.)"
+bannerUrl: "URL dell'immagine d'intestazione"
basicInfo: "Informazioni fondamentali"
+pinnedUsers: "Utenti in evidenza"
+pinnedUsersDescription: "Elenca gli/le utenti che vuoi fissare in cima alla pagina \"Esplora\", un@ per riga."
+pinnedPages: "Pagine in evidenza"
+pinnedPagesDescription: "Specifica il percorso delle pagine che vuoi fissare in cima alla pagina dell'istanza. Una pagina per riga."
+pinnedClipId: "ID della clip in evidenza"
+pinnedNotes: "Nota fissata"
hcaptcha: "hCaptcha"
enableHcaptcha: "Abilita hCaptcha"
+hcaptchaSiteKey: "Chiave del sito"
+hcaptchaSecretKey: "Chiave segreta"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Abilita reCAPTCHA"
+recaptchaSiteKey: "Chiave del sito"
+recaptchaSecretKey: "Chiave segreta"
+antennas: "Antenne"
+manageAntennas: "Gestore delle antenne"
name: "Nome"
+antennaSource: "Fonte dell'antenna"
+antennaKeywords: "Parole chiavi da ricevere"
+antennaExcludeKeywords: "Parole chiavi da escludere"
+antennaKeywordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare con un'interruzzione riga indica la condizione \"O\"."
+notifyAntenna: "Invia notifiche delle nuove note"
+withFileAntenna: "Solo note con file in allegato"
serviceworker: "ServiceWorker"
+enableServiceworker: "Abilita ServiceWorker"
+antennaUsersDescription: "Inserisci solo un nome utente per riga"
+caseSensitive: "Sensibile alla distinzione tra maiuscole e minuscole"
+withReplies: "Includere le risposte"
+connectedTo: "Sei conness@ agli account qui sotto:"
notesAndReplies: "Note e risposte"
-exploreFediverse: "Esplora Fediverse"
+withFiles: "Con file in allegato"
+silence: "Silenzia"
+silenceConfirm: "Vuoi davvero silenziare l'utente?"
+unsilence: "Riattiva"
+unsilenceConfirm: "Vuoi davvero riattivare l'utente?"
+popularUsers: "Utenti popolari"
+recentlyUpdatedUsers: "Utenti attivi di recente"
+recentlyRegisteredUsers: "Utenti registrati di recente"
+recentlyDiscoveredUsers: "Utenti scoperti di recente"
+exploreUsersCount: "Ci sono {count} utenti"
+exploreFediverse: "Esplora il Fediverso"
popularTags: "Tag di tendenza"
userList: "Liste"
about: "Informazioni"
@@ -218,96 +364,243 @@ administrator: "Amministratore"
token: "Token"
twoStepAuthentication: "Autenticazione a due fattori"
moderator: "Moderatore"
+nUsersMentioned: "{n} utenti menzionatÉ™"
+securityKey: "Chiave di sicurezza"
+securityKeyName: "Nome della chiave"
+registerSecurityKey: "Registra una chiave di sicurezza"
lastUsed: "Ultima attività"
-unregister: "Disattiva account"
+unregister: "Annulla l'iscrizione"
+passwordLessLogin: "Accedi senza password"
resetPassword: "Reimposta password"
-share: "Renota"
+newPasswordIs: "La tua nuova password è「{password}ã€"
+reduceUiAnimation: "Ridurre le animazioni dell'interfaccia"
+share: "Condividi"
+notFound: "Non trovato"
+notFoundDescription: "Nessuna pagina corrisponde all'URL indicata."
+uploadFolder: "Destinazione caricamento predefinita"
cacheClear: "Svuota cache"
+markAsReadAllNotifications: "Segna tutte le notifiche come lette"
+markAsReadAllUnreadNotes: "Segna tutte le note come lette"
+markAsReadAllTalkMessages: "Segna tutte le chat come lette"
help: "Guida"
+inputMessageHere: "Scrivi messaggio qui"
close: "Chiudi"
group: "Gruppo"
groups: "Gruppi"
createGroup: "Nuovo gruppo"
-invites: "Invita"
+ownedGroups: "I miei gruppi"
+joinedGroups: "Gruppi a cui mi sono unit@"
+invites: "Inviti"
+groupName: "Nome del gruppo"
+members: "Membri"
transfer: "Trasferisci"
+messagingWithUser: "Iniziare una chat con un altr@ utente"
+messagingWithGroup: "Chattare in gruppo"
title: "Titolo"
+text: "Testo"
+enable: "Abilita"
next: "Avanti"
+retype: "Conferma"
noteOf: "Note di {user}"
+inviteToGroup: "Invitare al gruppo"
+maxNoteTextLength: "Lunghezza massima delle note"
+quoteAttached: "Citazione allegata"
+quoteQuestion: "Vuoi aggiungere una citazione?"
+noMessagesYet: "Ancora nessuna chat"
+newMessageExists: "Hai ricevuto un nuovo messaggio"
+onlyOneFileCanBeAttached: "È possibile allegare al messaggio soltanto uno file"
+signinRequired: "Devi essere registrat@ nel tuo account"
invitations: "Invita"
invitationCode: "Codice di invito"
+checking: "Confermando"
available: "Consigliati"
unavailable: "Il nome utente è già in uso"
usernameInvalidFormat: "Il nome utente può contenere solo lettere, numeri e '_'"
tooShort: "Troppo breve"
tooLong: "Troppo lungo"
+weakPassword: "Password debole"
+normalPassword: "Password buona"
+strongPassword: "Password forte"
+passwordMatched: "Corretta"
passwordNotMatched: "Le password non corrispondono."
+signinWith: "Accedi con {x}"
+signinFailed: "Autenticazione non riuscita. Controlla la tua password e nome utente."
+tapSecurityKey: "Premi la chiave di sicurezza"
+or: "oppure"
+language: "Lingua"
+uiLanguage: "Lingua di visualizzazione dell'interfaccia"
+groupInvited: "Invitat@ al gruppo"
+aboutX: "Informazioni su {x}"
+useOsNativeEmojis: "Usare le emoji native del sistema operativo"
+youHaveNoGroups: "Nessun gruppo"
+joinOrCreateGroup: "Puoi creare il tuo gruppo o essere invitat@ a gruppi che già esistono."
+noHistory: "Nessuna cronologia"
signinHistory: "Cronologia di accesso all'account"
+category: "Categoria"
tags: "Tag"
+docSource: "Sorgente della scheda"
createAccount: "Crea il tuo account"
existingAcount: "Account esistente"
+regenerate: "Generare di nuovo"
+fontSize: "Dimensione carattere"
+noFollowRequests: "Non hai alcuna richiesta di follow"
+openImageInNewTab: "Aprire immagini in una nuova scheda"
+dashboard: "Pannello di controllo"
local: "Locale"
remote: "Remoto"
-accountSettings: "Impostazioni Account"
+total: "Totale"
+weekOverWeekChanges: "Settimanale"
+dayOverDayChanges: "Giornaliero"
+appearance: "Aspetto"
+clientSettings: "Impostazioni client"
+accountSettings: "Impostazioni account"
+promotion: "Promossa"
promote: "Pubblicizza"
+numberOfDays: "Numero di giorni"
+hideThisNote: "Nasconda la nota"
+showFeaturedNotesInTimeline: "Mostrare le note di tendenza nella tua timeline"
+objectStorage: "Stoccaggio oggetti"
+useObjectStorage: "Utilizza stoccaggio oggetti"
objectStorageBaseUrl: "Base URL"
objectStorageBucket: "Bucket"
+objectStoragePrefix: "Prefix"
+objectStoragePrefixDesc: "I file saranno conservati sotto la directory di questo prefisso."
objectStorageEndpoint: "Endpoint"
objectStorageRegion: "Region"
objectStorageUseSSL: "Usare SSL"
serverLogs: "Log del server"
deleteAll: "Cancella cronologia"
-sounds: "Effetti sonori"
+showFixedPostForm: "Visualizzare la finestra di pubblicazione in cima alla timeline"
+newNoteRecived: "Nuova nota ricevuta"
+sounds: "Impostazioni suoni"
listen: "Ascolta"
none: "Niente"
+showInPage: "Visualizza in pagina"
+popout: "Finestra pop-out"
volume: "Volume"
+masterVolume: "Volume principale"
details: "Dettagli"
+chooseEmoji: "Scegli emoji"
+unableToProcess: "Impossibile compiere l'operazione"
+recentUsed: "Usato di recente"
install: "Installa"
uninstall: "Disinstalla"
+installedApps: "Applicazioni installate"
+nothing: "Niente da visualizzare"
installedDate: "Data installazione"
+lastUsedDate: "Data di ultimo uso"
state: "Stato"
sort: "Ordina per"
-visibility: "Privacy dei post"
+ascendingOrder: "Ascendente"
+descendingOrder: "Discendente"
+scratchpad: "ScratchPad"
+output: "Uscita"
+script: "Script"
+disablePagesScript: "Disabilita AiScript nelle pagine"
+updateRemoteUser: "Aggiornare le informazioni di utente remoto"
+deleteAllFiles: "Elimina tutti i file"
+deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?"
+removeAllFollowing: "Cancella tutti i follows"
+removeAllFollowingDescription: "Cancella tutti i follows del server {host}. Per favore, esegui se, ad esempio, l'istanza non esiste più."
+userSuspended: "L'utente è sospes@."
+userSilenced: "L'utente è silenziat@."
+sidebar: "Barra laterale"
+divider: "Linea di separazione"
+addItem: "Aggiungi elemento"
+rooms: "Camera"
+serviceworkerInfo: "Deve essere abilitato per le notifiche push. "
+deletedNote: "Nota eliminata"
+invisibleNote: "Nota invisibile"
+enableInfiniteScroll: "Abilita scorrimento infinito"
+visibility: "Visibilità"
poll: "Sondaggio"
useCw: "Nascondere media"
+expandTweet: "Espandi tweet"
+themeEditor: "Editor di temi"
description: "Descrizione"
author: "Autore"
+leaveConfirm: "Ci sono delle modifiche ancora non salvate. Vuoi cancellarle?"
+manage: "Gestione"
+useFullReactionPicker: "Usa la totalità del pannello di reazioni"
width: "Larghezza"
height: "Altezza"
large: "Grande"
medium: "Predefinito"
small: "Piccolo"
+enableAll: "Abilita tutto"
+disableAll: "Disabilita tutto"
+tokenRequested: "Autorizza accesso all'account"
+notificationType: "Tipo di notifiche"
edit: "Modifica"
+useStarForReactionFallback: "Se è sconosciuto l'emoji di reazione, usare la ★ come alternativa."
+emailConfig: "Impostazioni server email"
email: "Email"
+smtpHost: "Server remoto"
smtpUser: "Nome utente"
smtpPass: "Password"
-wordMute: "Parole silenziate"
+wordMute: "Filtri parole"
+userSaysSomething: "{name} ha detto qualcosa"
display: "Visualizza"
copy: "Copia"
logs: "Log"
database: "Base di dati"
channel: "Canale"
-notificationSetting: "impostazioni delle notifiche"
+create: "Crea"
+notificationSetting: "Impostazioni notifiche"
+notificationSettingDesc: "Seleziona il tipo di notifiche da visualizzare."
other: "Avanzate"
+fileIdOrUrl: "ID o URL del file"
abuseReports: "Segnala"
reportAbuse: "Segnala"
reportAbuseOf: "Segnala {name}"
send: "Inviare"
openInNewTab: "Apri in una nuova scheda"
+editTheseSettingsMayBreakAccount: "Modificare queste impostazioni può danneggiare l'account."
+waitingFor: "Aspettando {x}"
random: "Casuale"
system: "Sistema"
+switchUi: "Cambiare interfaccia utente"
desktop: "Desktop"
+clip: "Clip"
+createNew: "Crea nuov@"
optional: "Opzionale"
-public: "Pubblico"
+createNewClip: "Nuova clip"
+public: "Pubblica"
+i18nInfo: "Misskey è tradotto in diverse lingue da volontari. Anche tu puoi contribuire su {link}."
+notesCount: "Conteggio note"
+repliesCount: "Numero di risposte inviate"
+renotesCount: "Numero di note che hai ricondiviso"
+repliedCount: "Numero di risposte ricevute"
+renotedCount: "Numero delle tue note ricondivise"
+followingCount: "Numero di account seguiti"
+followersCount: "Numero di account che ti seguono"
+sentReactionsCount: "Numero di reazioni inviate"
+receivedReactionsCount: "Numero di reazioni ricevute"
+pollVotesCount: "Numero di voti inviati"
+pollVotedCount: "Numero di voti ricevuti"
yes: "Sì"
no: "No"
+driveFilesCount: "Numero di file nel Drive"
+noteFavoritesCount: "Conteggio note tra i preferiti"
+pageLikesCount: "Numero di pagine che ti piacciono"
+pageLikedCount: "Numero delle tue pagine che hanno ricevuto \"Mi piace\""
+reversiCount: "Numero di partite a Reversi"
contact: "Contatti"
+clips: "Clip"
+experimentalFeatures: "Funzioni sperimentali"
developer: "Sviluppatore"
+showGapBetweenNotesInTimeline: "Mostrare un intervallo tra le note sulla timeline"
duplicate: "Duplica"
left: "Sinistra"
center: "Centro"
wide: "Largo"
+clearCache: "Svuota cache"
+onlineUsersCount: "{n} utenti online"
+nUsers: "{n} utenti"
nNotes: "{n}Note"
+myTheme: "I miei temi"
backgroundColor: "Sfondo"
+textColor: "Testo"
value: "Valore"
saveConfirm: "Vuoi salvare le modifiche?"
deleteConfirm: "Rimuovere?"
@@ -317,45 +610,103 @@ currentVersion: "Versione attuale"
latestVersion: "Ultima versione"
editCode: "Modifica codice"
apply: "Applica"
+emailNotification: "Eventi per notifiche via mail"
+inChannelSearch: "Cerca in canale"
+useReactionPickerForContextMenu: "Cliccare sul tasto destro per aprire il pannello di reazioni"
+typingUsers: "{users} sta(nno) scrivendo"
+showingPastTimeline: "Stai visualizzando una vecchia timeline"
_email:
_follow:
title: "Ha iniziato a seguirti"
+ _receiveFollowRequest:
+ title: "Hai ricevuto una richiesta di follow"
_registry:
key: "Dati"
keys: "Dati"
+ createKey: "Crea chiave"
_aboutMisskey:
+ source: "Codice sorgente"
morePatrons: "Ci sono molti altri che ci sostengono. Grazie 🥰"
_mfm:
mention: "Menzioni"
+ mentionDescription: "Si può menzionare un utente specifico digitando il suo nome utente subito dopo il segno @."
+ hashtag: "Hashtag"
url: "URL"
link: "Link"
bold: "Grassetto"
- blockCode: "Codice(blocco)"
+ blockCode: "Codice (blocco)"
inlineMath: "Espressione matematica(Immersione)"
- blockMath: "Espressione matematica(blocco)"
+ blockMath: "Formula matematica (blocco)"
quote: "Cita il nota"
+ emoji: "Emoji personalizzati"
search: "Cerca"
blur: "Sfocatura"
font: "Tipo di carattere"
_reversi:
+ gameSettings: "Impostazioni di gioco"
+ botSettings: "Opzioni del bot"
black: "Nero"
white: "Bianco"
+ total: "Totale"
ended: "Esci"
+_instanceTicker:
+ none: "Nascondi"
+ remote: "Mostra solo per gli/le utenti remotÉ™"
+ always: "Mostra sempre"
_channel:
+ create: "Nuovo canale"
+ edit: "Gerisci canale"
+ setBanner: "Scegli intestazione"
+ removeBanner: "Rimuovi intestazione"
featured: "Tendenze"
+ owned: "I miei canali"
+ following: "Seguiti"
+ usersCount: "{n} partecipanti"
+ notesCount: "{n} note"
_sidebar:
- icon: "Foto del profilo"
+ icon: "Icone"
hide: "Nascondere"
+_wordMute:
+ muteWords: "Parole da silenziare"
+ muteWordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare con un'interruzzione riga indica la condizione \"O\"."
+ muteWordsDescription2: "Metti le parole chiavi tra slash per usare espressioni regolari (regexp)."
+ mutedNotes: "Note silenziate"
_theme:
+ explore: "Esplora temi"
+ install: "Installa un tema"
+ manage: "Gerisci temi"
+ code: "Codice tema"
+ installed: "{name} è installato"
+ installedThemes: "Temi installati"
+ builtinThemes: "Temi integrati"
+ alreadyInstalled: "Questo tema è già installato"
+ invalid: "Il formato tema non è valido"
+ make: "Crea un tema"
+ base: "Base"
+ addConstant: "Aggiungi costante"
constant: "Costante"
defaultValue: "Valore predefinito"
color: "Colore"
+ key: "Chiave"
func: "Funzione"
+ argument: "Argomento"
darken: "Scuro"
lighten: "Chiaro"
keys:
bg: "Sfondo"
+ fg: "Testo"
+ focus: "Focalizzazione"
+ indicator: "Indicatore"
+ panel: "Pannello"
shadow: "Ombra"
+ header: "Intestazione"
+ navBg: "Sfondo della barra laterale"
+ navFg: "Testo della barra laterale"
+ navHoverFg: "Testo della barra laterale (al passaggio del mouse)"
+ navActive: "Testo della barra laterale (attivo)"
+ navIndicator: "Indicatore di barra laterale"
+ link: "Link"
+ hashtag: "Hashtag"
mention: "Menzioni"
renote: "Rinota"
divider: "Interruzione di linea"
@@ -363,6 +714,8 @@ _sfx:
note: "Nota"
notification: "Notifiche"
chat: "Messaggi"
+ antenna: "Ricezione dell'antenna"
+ channel: "Notifiche di canale"
_ago:
unknown: "Sconosciuto"
future: "Futuro"
@@ -381,14 +734,51 @@ _time:
day: "giorni"
_tutorial:
title: "Come usare Misskey"
- step1_1: "Benvenuto"
+ step1_1: "Benvenuto/a!"
+ step1_2: "Questa pagina si chiama una \" Timeline \". Mostra in ordine cronologico le \" note \" delle persone che segui."
+ step1_3: "Attualmente la tua Timeline è vuota perché non segui alcun account e non hai pubblicato alcuna nota ancora."
+ step2_1: "Prima di scrivere una nota o di seguire un account, imposta il tuo profilo!"
+ step2_2: "Aggiungere qualche informazione su di te aumenterà le tue possibilità di essere seguit@ da altre persone. "
+ step3_1: "Hai finito di impostare il tuo profilo?"
+ step3_2: "Ora, puoi pubblicare una nota. Facciamo una prova! Premi il pulsante a forma di penna in cima allo schermo per aprire una finestra di dialogo. "
+ step3_3: "Scritto il testo della nota, puoi pubblicarla premendo il pulsante nella parte superiore destra della finestra di dialogo."
+ step3_4: "Non ti viene niente in mente? Perché non scrivi semplicemente \"Ho appena cominciato a usare Misskey\"?"
+ step4_1: "Hai pubblicato qualcosa?"
+ step4_2: "Se puoi visualizzare la tua nota sulla timeline, ce l'hai fatta!"
+ step5_1: "Adesso, cerca di seguire altre persone per vivacizzare la tua timeline. "
+ step5_2: "La pagina {featured} mostra le note di tendenza su questa istanza e, sfogliandole, magari toverai degli account che ti piacciono e che vorrai seguire. Oppure, potrai trovare utenti popolari usando {explore}."
+ step5_3: "Per seguire altrÉ™ utenti, clicca sul loro avatar per aprire la pagina di profilo dove puoi premere il pulsante \"Seguire\". "
+ step5_4: "Alcunə utenti scelgono di confermare manualmente le richieste di follow che ricevono, quindi a seconda delle persone potrebbe volerci un pò prima che la tua richiesta sia accolta."
+ step6_1: "Ora, se puoi visualizzare le note di altrÉ™ utenti sulla tua timeline, ce l'hai fatta!"
+ step6_2: "Puoi inviare una risposta rapida alle note di altrÉ™ utenti mandando loro \"reazioni\"."
+ step6_3: "Per inviare una reazione, premi l'icona + della nota e scegli l'emoji che vuoi mandare."
+ step7_1: "Complimenti! Sei arrivat@ alla fine dell'esercitazione di base su come usare Misskey. "
+ step7_2: "Se vuoi saperne di più su Misskey, puoi dare un'occhiata alla sezione {help}."
+ step7_3: "Da ultimo, buon divertimento su Misskey! 🚀"
_permissions:
- "read:blocks": "Visualizza gli account che hai bloccato."
- "write:blocks": "Gestisci gli account che hai bloccato."
- "read:favorites": "Visualizza Preferiti"
- "write:favorites": "Gestisci Preferiti"
+ "read:blocks": "Visualizza gli account bloccati"
+ "write:blocks": "Gestisci gli account bloccati"
+ "read:favorites": "Visualizza i tuoi preferiti"
+ "write:favorites": "Gestisci i tuoi preferiti"
+ "read:following": "Vedi le informazioni di follow"
"write:following": "Seguiti/ Smetti di seguire"
+ "read:mutes": "Vedi account silenziati"
+ "write:mutes": "Gerisci account silenziati"
+ "write:notes": "Creare / Eliminare note"
"read:notifications": "Visualizza notifiche"
+ "write:notifications": "Gerisci notifiche"
+ "read:reactions": "Vedi reazioni"
+ "write:reactions": "Gerisci reazioni"
+ "read:user-groups": "Vedi gruppi di utenti"
+ "write:user-groups": "Gestisci gruppi di utenti"
+ "read:channels": "Visualizza canali"
+ "write:channels": "Gerisci canali"
+_antennaSources:
+ all: "Tutte le note"
+ homeTimeline: "Note dagli utenti che segui"
+ users: "Note dagli utenti selezionati"
+ userList: "Note dagli utenti della lista selezionata"
+ userGroup: "Note dagli utenti del gruppo selezionato"
_weekday:
sunday: "Domenica"
monday: "Lunedì"
@@ -409,6 +799,9 @@ _widgets:
photos: "Foto"
digitalClock: "Orologio digitale"
federation: "Federazione"
+ button: "Pulsante"
+ onlineUsers: "Utenti online"
+ jobQueue: "Coda di lavoro"
_cw:
hide: "Nascondere"
show: "Mostra di più"
@@ -422,14 +815,20 @@ _poll:
voted: "Votato"
closed: "Terminato"
_visibility:
- public: "Pubblico"
+ public: "Pubblica"
+ publicDescription: "Visibile per tutti sul Fediverso"
home: "Home"
- followers: "Seguaci"
- localOnly: "Solo Locale"
- localOnlyDescription: "Solo locale"
+ homeDescription: "Visibile solo sulla timeline \"Home\""
+ followers: "Followers"
+ followersDescription: "Visibile solo per i tuoi followers"
+ specified: "Diretta"
+ specifiedDescription: "Visibile solo per gli/le utenti menzionatÉ™"
+ localOnly: "Soltanto locale"
+ localOnlyDescription: "Nascosta per gli/le utenti remotÉ™"
_postForm:
replyPlaceholder: "Nota la tua risposta.."
quotePlaceholder: "Cita Nota..."
+ channelPlaceholder: "Pubblica in canale"
_profile:
name: "Nome"
username: "Nome utente"
@@ -437,16 +836,29 @@ _profile:
metadata: "Metadati"
metadataLabel: "Etichetta"
metadataContent: "Contenuto"
+ changeBanner: "Cambia intestazione"
_exportOrImport:
- followingList: "Seiguiti"
- muteList: "Silenzia"
- blockingList: "Blocca"
+ allNotes: "Tutte le note"
+ followingList: "Follows"
+ muteList: "Account silenziati"
+ blockingList: "Account bloccati"
userLists: "Liste"
+_charts:
+ usersIncDec: "Variazione del numero di utenti"
+ usersTotal: "Numero totale di utenti"
+ activeUsers: "Numero di utenti attivi"
+ notesTotal: "Conteggio totale di note"
+_instanceCharts:
+ users: "Variazione del numero di utenti"
+ usersTotal: "Totale cumulativo di utenti"
_timelines:
home: "Home"
local: "Locale"
+ social: "Sociale"
_rooms:
+ roomOf: "Camera di {user}"
_roomType:
+ default: "Predefinito"
washitsu: "Washitsu"
_furnitures:
milk: "Cartone del latte"
@@ -477,31 +889,59 @@ _rooms:
photoframe: "Cornice"
cube: "Cubo"
tv: "Televisore"
- pinguin: "Pinguini"
+ pinguin: "Pinguino"
bin: "Cestino"
cup-noodle: "Noodle istantanei"
_pages:
+ created: "Pagina creata!"
+ pageSetting: "Impostazioni pagina"
+ viewSource: "Visualizza sorgente"
like: "Mi piace"
unlike: "Togli Mi piace"
+ featured: "Popolari"
+ content: "Blocco di pagina"
variables: "Variabili"
title: "Titolo"
+ hideTitleWhenPinned: "Nascondere il titolo pagina quando è fissata in cima al profilo."
font: "Tipo di carattere"
+ chooseBlock: "Aggiungi blocco"
blocks:
+ text: "Testo"
+ textarea: "Area di testo"
+ section: "Sezione"
image: "Immagini"
+ button: "Pulsante"
if: "Se"
_if:
variable: "Variabili"
_post:
text: "Contenuto"
_textInput:
+ name: "Nome della variabile"
text: "Titolo"
+ default: "Valore predefinito"
_textareaInput:
+ name: "Nome della variabile"
text: "Titolo"
+ default: "Valore predefinito"
_numberInput:
+ name: "Nome della variabile"
text: "Titolo"
+ default: "Valore predefinito"
+ _canvas:
+ width: "Larghezza"
+ height: "Altezza"
+ note: "Nota integrata"
+ _note:
+ id: "ID nota"
+ idDescription: "Qui puoi anche incollare l'URL della nota che vuoi impostare."
+ detailed: "Visualizzazione dettagliata"
_switch:
+ name: "Nome della variabile"
text: "Titolo"
+ default: "Valore predefinito"
_counter:
+ name: "Nome della variabile"
text: "Titolo"
_button:
text: "Titolo"
@@ -509,7 +949,9 @@ _pages:
_dialog:
content: "Contenuto"
_radioButton:
+ name: "Nome della variabile"
title: "Titolo"
+ default: "Valore predefinito"
script:
categories:
comparison: "Metodo comparativo"
@@ -518,6 +960,15 @@ _pages:
fn: "Funzione"
list: "Liste"
blocks:
+ text: "Testo"
+ _strLen:
+ arg1: "Testo"
+ _strPick:
+ arg1: "Testo"
+ _strReplace:
+ arg1: "Testo"
+ _strReverse:
+ arg1: "Testo"
_join:
arg1: "Liste"
_add:
@@ -575,26 +1026,46 @@ _pages:
arg1: "Liste"
_listLen:
arg1: "Liste"
+ _stringToNumber:
+ arg1: "Testo"
+ _splitStrByLine:
+ arg1: "Testo"
ref: "Variabili"
fn: "Funzione"
types:
+ string: "Testo"
array: "Liste"
_notification:
+ fileUploaded: "File caricato correttamente"
+ youGotMention: "{name} ti ha menzionato"
+ youGotReply: "{name} ti ha risposto"
youGotQuote: "{name} ha citato il tuo Nota e ha detto"
- youRenoted: "{name} ha rinota"
+ youRenoted: "{name} ha rinotato"
youGotPoll: "{name} ha volluto."
+ youGotMessagingMessageFromUser: "{name} ti ha mandato un messaggio"
+ youGotMessagingMessageFromGroup: "{name} ti ha mandato un messaggio nella chat"
youWereFollowed: "Ha iniziato a seguirti"
+ youReceivedFollowRequest: "Hai ricevuto una richiesta di follow"
+ yourFollowRequestAccepted: "La tua richiesta di follow è stata accettata"
+ youWereInvitedToGroup: "Invitat@ al gruppo"
_types:
all: "Tutto"
- follow: "Seiguiti"
+ follow: "Follows"
mention: "Menzioni"
reply: "Rispondi"
renote: "Rinota"
quote: "Cita"
reaction: "Reazione"
+ pollVote: "Voti ricevuti"
+ receiveFollowRequest: "Richiesta di follow ricevuta"
+ followRequestAccepted: "Richiesta di follow accettata"
+ groupInvited: "Invito a un gruppo"
+ app: "Notifiche da applicazioni"
_deck:
_columns:
notifications: "Notifiche"
tl: "Timeline"
+ antenna: "Antenne"
list: "Liste"
mentions: "Menzioni"
+ direct: "Diretta"
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index e5700fe059..5729da8da8 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -322,7 +322,7 @@ proxyRemoteFilesDescription: "ã“ã®è¨­å®šã‚’有効ã«ã™ã‚‹ã¨ã€æœªä¿å­˜ã¾ã
driveCapacityPerLocalAccount: "ローカルユーザーã²ã¨ã‚Šã‚ãŸã‚Šã®ãƒ‰ãƒ©ã‚¤ãƒ–容é‡"
driveCapacityPerRemoteAccount: "リモートユーザーã²ã¨ã‚Šã‚ãŸã‚Šã®ãƒ‰ãƒ©ã‚¤ãƒ–容é‡"
inMb: "メガãƒã‚¤ãƒˆå˜ä½"
-iconUrl: "アイコン画åƒã®URL"
+iconUrl: "アイコン画åƒã®URL (faviconãªã©)"
bannerUrl: "ãƒãƒŠãƒ¼ç”»åƒã®URL"
basicInfo: "基本情報"
pinnedUsers: "ピン留ã‚ユーザー"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index 0015db07b9..1a7001269a 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -81,7 +81,7 @@ pageLoadError: "ページã®èª­ã¿è¾¼ã¿ã«å¤±æ•—ã—ã¦ã—ã‚‚ã†ãŸã§â€¦"
pageLoadErrorDescription: "ã“ã‚Œã¯æ™®é€šã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‹ãƒ–ラウザキャッシュãŒåŽŸå› ã‚„ã‹ã‚‰ã­ã€‚キャッシュをクリアã™ã‚‹ã‹ã€ã‚‚ã†ã¡ã£ã¨ã ã‘å¾…ã£ã¦ãれã¸ã‚“ã‹ï¼Ÿ"
enterListName: "リストåを入れã¦ã‚„"
privacy: "プライãƒã‚·ãƒ¼"
-makeFollowManuallyApprove: "ãˆãˆã£ã¦è¨€ã‚ãªãƒ•ォローã§ãã¸ã‚“よã†ã«ã™ã‚‹"
+makeFollowManuallyApprove: "自分ãŒèªã‚ãŸäººã ã‘ãŒã“ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’フォローã§ãるよã†ã«ã™ã‚‹"
defaultNoteVisibility: "ã‚‚ã¨ã‹ã‚‰ã®å…¬é–‹ç¯„囲"
follow: "フォロー"
followRequest: "フォローを頼む"
@@ -308,7 +308,7 @@ monthX: "{month}月"
yearX: "{year}å¹´"
pages: "ページ"
integration: "連æº"
-connectSerice: "ã¤ãªã’ã‚‹"
+connectSerice: "ã¤ãªã"
disconnectSerice: "切ã£ã¦ã¾ã†"
enableLocalTimeline: "ローカルタイムラインを使ãˆã‚‹ã‚ˆã†ã«ã™ã‚‹"
enableGlobalTimeline: "グローãƒãƒ«ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã‚’使ãˆã‚‹ã‚ˆã†ã«ã™ã‚‹"
@@ -392,7 +392,7 @@ markAsReadAllUnreadNotes: "投稿ã¯å…¨ã¦èª­ã‚“ã ã‚ã£"
markAsReadAllTalkMessages: "ãƒãƒ£ãƒƒãƒˆã¯ã‚‚ã†ãœã‚“ã¶èª­ã‚“ã ã‚ã£"
help: "ヘルプ"
inputMessageHere: "ã“ã“ã«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸æ›¸ã„ã¦ã‚„"
-close: "ã•ã„ãªã‚‰"
+close: "é–‰ã˜ã‚‹"
group: "グループ"
groups: "グループ"
createGroup: "グループを作るã§"
diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml
index eb392a27bb..6893213409 100644
--- a/locales/ru-RU.yml
+++ b/locales/ru-RU.yml
@@ -241,7 +241,7 @@ explore: "Обзор"
games: "Игры Misskey"
messageRead: "Прочитали"
noMoreHistory: "ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð·Ð°ÐºÐ¾Ð½Ñ‡Ð¸Ð»Ð°ÑÑŒ"
-startMessaging: "Отправить Ñообщение"
+startMessaging: "Ðачать общение"
nUsersRead: "Прочитали {n}"
agreeTo: "Я ÑоглашаюÑÑŒ Ñ {0}"
tos: "ПользовательÑкое Ñоглашение"
@@ -329,7 +329,7 @@ pinnedUsers: "Прикреплённый пользователь"
pinnedUsersDescription: "ПеречиÑлите по одному имени Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð² Ñтроке. Пользователи, перечиÑленные здеÑÑŒ, будут привÑзаны к закладке \"Изучение\"."
pinnedPages: "Закрепленные Ñтраницы"
pinnedPagesDescription: "ЕÑли хотите закрепить Ñтраницы на главной Ñайта, Ñюда можно добавить пути к ним, каждый в отдельной Ñтроке."
-pinnedClipId: "Идентификатор закреплённой памÑтки"
+pinnedClipId: "Идентификатор закреплённой подборки"
pinnedNotes: "Ð—Ð°ÐºÑ€ÐµÐ¿Ð»Ñ‘Ð½Ð½Ð°Ñ Ð·Ð°Ð¼ÐµÑ‚ÐºÐ°"
hcaptcha: "hCaptcha"
enableHcaptcha: "Включить hCaptcha"
@@ -405,8 +405,8 @@ invites: "ПриглашениÑ"
groupName: "Ðазвание группы"
members: "УчаÑтники"
transfer: "Отдать"
-messagingWithUser: "Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¹"
-messagingWithGroup: "Чат в группе"
+messagingWithUser: "Общение Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼ пользователем"
+messagingWithGroup: "Общение в группе"
title: "Заголовок"
text: "ТекÑÑ‚"
enable: "Включить"
@@ -471,7 +471,7 @@ promotion: "Продвинуто"
promote: "Продвинуть"
numberOfDays: "КоличеÑтво дней"
hideThisNote: "СпрÑтать Ñту запиÑÑŒ"
-showFeaturedNotesInTimeline: "Показывать в ленте заметки из подборки Ñайта"
+showFeaturedNotesInTimeline: "Показывать в ленте заметки из «ГорÑчего»"
objectStorage: "Хранилище"
useObjectStorage: "ЗанÑто в хранилище"
objectStorageBaseUrl: "Базовый адреÑ"
@@ -524,7 +524,7 @@ deleteAllFiles: "Удалить вÑе файлы"
deleteAllFilesConfirm: "Ð’Ñ‹ хотите удалить вÑе файлы?"
removeAllFollowing: "Удалить вÑех подпиÑчиков"
removeAllFollowingDescription: "Отменить вÑе подпиÑки Ñ Ð´Ð¾Ð¼ÐµÐ½Ð° {host}? ПожалуйÑта, применÑйте Ñто дейÑтвие, еÑли инÑÑ‚Ð°Ð½Ñ Ð±Ð¾Ð»ÑŒÑˆÐµ не ÑущеÑтвует."
-userSuspended: "Этот пользователь был заморожен"
+userSuspended: "Эта ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ заморожена"
userSilenced: "Этот пользователь был заглушен"
sidebar: "Ð‘Ð¾ÐºÐ¾Ð²Ð°Ñ Ð¿Ð°Ð½ÐµÐ»ÑŒ"
divider: "ЛиниÑ-разделитель"
@@ -623,30 +623,30 @@ random: "Случайные"
system: "СиÑтема"
switchUi: "Выбор вида"
desktop: "Стол"
-clip: "Ð’ памÑтку"
+clip: "В подборку"
createNew: "Ðовый документ"
optional: "ÐеобÑзательно"
-createNewClip: "ÐÐ¾Ð²Ð°Ñ Ð¿Ð°Ð¼Ñтка"
+createNewClip: "ÐÐ¾Ð²Ð°Ñ Ð¿Ð¾Ð´Ð±Ð¾Ñ€ÐºÐ°"
public: "ОбщедоÑтупно"
i18nInfo: "Misskey переводÑÑ‚ на разные Ñзыки добровольцы Ñо вÑего Ñвета. Ваша помощь тоже пригодитÑÑ Ð·Ð´ÐµÑÑŒ: {link}."
manageAccessTokens: "Управление токенами доÑтупа"
accountInfo: "Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ð± учётной запиÑи"
notesCount: "КоличеÑтво заметок"
repliesCount: "Сколько раз пользователь кому-то ответил"
-renotesCount: "Сколько раз пользователь передал чужие заметки"
+renotesCount: "Сколько раз пользователь делилÑÑ Ð·Ð°Ð¼ÐµÑ‚ÐºÐ°Ð¼Ð¸"
repliedCount: "Сколько раз ответили пользователю"
-renotedCount: "Сколько раз передавали заметки пользователÑ"
+renotedCount: "Сколько раз делилиÑÑŒ заметками пользователÑ"
followingCount: "КоличеÑтво подпиÑок"
followersCount: "КоличеÑтво подпиÑавшихÑÑ"
-sentReactionsCount: "Сколько раз пользователь отреагировал"
-receivedReactionsCount: "Сколько раз отреагировали на заметки пользователÑ"
-pollVotesCount: "Сколько раз учаÑтвовал в опроÑах"
+sentReactionsCount: "КоличеÑтво реакций пользователÑ"
+receivedReactionsCount: "КоличеÑтво реакций на заметки пользователÑ"
+pollVotesCount: "Сколько раз пользователь учаÑтвовал в опроÑах"
pollVotedCount: "Сколько раз учаÑтвовали в опроÑах пользователÑ"
yes: "Да"
no: "Ðет"
driveFilesCount: "КоличеÑтво файлов на диÑке"
-driveUsage: "Сколько меÑта занÑто на диÑке"
-noCrawle: "Паукам вход воÑпрещён"
+driveUsage: "ЗанÑто меÑта на диÑке"
+noCrawle: "Запретить паукам индекÑировать Ñайт"
noCrawleDescription: "ПроÑьба поиÑковым ÑиÑтемам не ходить по вашему профилю, по заметкам, Ñтраницам и не индекÑировать их."
lockedAccountInfo: "Даже еÑли вы вручную подтверждаете подпиÑки, кто угодно может читать ваши заметки, еÑли вы не отмечаете их Â«Ð´Ð»Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñчиков»."
alwaysMarkSensitive: "Отмечать файлы как «Ñодержимое не Ð´Ð»Ñ Ð²Ñех» по умолчанию"
@@ -661,7 +661,7 @@ pageLikedCount: "КоличеÑтво Ñтраниц, понравившихÑÑ
reversiCount: "КоличеÑтво Ñыгранных игр в реверÑи"
contact: "Как ÑвÑзатьÑÑ"
useSystemFont: "ИÑпользовать шрифт, предлагаемый ÑиÑтемой"
-clips: "ПамÑтки"
+clips: "Подборки"
experimentalFeatures: "ЭкÑпериментальные функции"
developer: "Разработчик"
makeExplorable: "Опубликовать профиль в «Обзоре»."
@@ -983,7 +983,7 @@ _tutorial:
step7_2: "Хотите изучить Misskey глубже — добро пожаловать в раздел «{help}»."
step7_3: "ПриÑтно вам провеÑти Ð²Ñ€ÐµÐ¼Ñ Ñ Misskey🚀"
_2fa:
- alreadyRegistered: "ÐаÑтройка завершена"
+ alreadyRegistered: "Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ ÑƒÐ¶Ðµ наÑтроена."
registerDevice: "ЗарегиÑтрируйте ваше уÑтройÑтво"
registerKey: "ЗарегиÑтрировать ключ"
step1: "Прежде вÑего, уÑтановите на уÑтройÑтво приложение Ð´Ð»Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸, например, {a} или {b}."
@@ -1240,7 +1240,7 @@ _pages:
liked: "ПонравившиеÑÑ Ñтраницы"
featured: "ПопулÑрные"
inspector: "ИнÑпектор"
- contents: "Содержательные"
+ contents: "Содержимое"
content: "Содержимое"
variables: "Переменные"
title: "Заголовок"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index c13cf12220..d6da577982 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -579,7 +579,7 @@ smtpPort: "端å£"
smtpUser: "用户å"
smtpPass: "密ç "
emptyToDisableSmtpAuth: "用户å和密ç ç•™ç©ºå¯ä»¥ç¦ç”¨SMTP验è¯"
-smtpSecure: "在 SMTP 连接中默认使用 SSL / TLS"
+smtpSecure: "在 SMTP 连接中使用éšå¼ SSL / TLS"
smtpSecureInfo: "使用STARTTLS时关闭。"
testEmail: "邮件å‘逿µ‹è¯•"
wordMute: "文字å±è”½"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 9d95c958d1..dfae988f1b 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -438,6 +438,7 @@ signinWith: "以{x}登錄"
signinFailed: "登入失敗。 請檢查用戶å和密碼。"
tapSecurityKey: "點擊安全密鑰"
or: "或者"
+language: "語言"
uiLanguage: "介é¢èªžè¨€"
groupInvited: "您有新的群組邀請"
aboutX: "關於{x}"
@@ -677,9 +678,12 @@ newVersionOfClientAvailable: "新版本的用戶端å¯ç”¨ã€‚"
usageAmount: "使用é‡"
capacity: "容é‡"
inUse: "已使用"
+clear: "清除"
_email:
_follow:
title: "您有新的追隨者"
+_plugin:
+ manage: "ç®¡ç†æ’ä»¶"
_registry:
scope: "範åœ"
key: "機碼"
@@ -702,7 +706,9 @@ _nsfw:
_mfm:
cheatSheet: "MFMä»£ç¢¼å°æŠ„"
intro: "MFM是Misskey專用的標記語言,å¯ä»¥åœ¨Misskey中的å„個ä½ç½®ä½¿ç”¨ã€‚ 您å¯ä»¥é€™è£çœ‹åˆ°MFMå¯ç”¨èªžæ³•列表。"
+ dummy: "通éŽMisskey擴展Fediverse的世界"
mention: "æåŠ"
+ mentionDescription: "é€éŽ @+用戶å 來標示特定使用者。"
hashtag: "#tag"
url: "URL"
link: "éˆæŽ¥"
diff --git a/migration/1615965918224-chart-v2.ts b/migration/1615965918224-chart-v2.ts
new file mode 100644
index 0000000000..cacbd1945b
--- /dev/null
+++ b/migration/1615965918224-chart-v2.ts
@@ -0,0 +1,218 @@
+import {MigrationInterface, QueryRunner} from "typeorm";
+
+export class chartV21615965918224 implements MigrationInterface {
+ name = 'chartV21615965918224'
+
+ public async up(queryRunner: QueryRunner): Promise<void> {
+ await queryRunner.query(`DELETE FROM "__chart__active_users" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__drive" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__federation" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__hashtag" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__instance" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__network" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__notes" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__per_user_drive" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__per_user_following" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__per_user_notes" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__per_user_reaction" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__test" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__test_grouped" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__test_unique" WHERE "span" = 'day'`);
+ await queryRunner.query(`DELETE FROM "__chart__users" WHERE "span" = 'day'`);
+
+ await queryRunner.query(`DROP INDEX "IDX_15e91a03aeeac9dbccdf43fc06"`);
+ await queryRunner.query(`DROP INDEX "IDX_20f57cc8f142c131340ee16742"`);
+ await queryRunner.query(`DROP INDEX "IDX_c26e2c1cbb6e911e0554b27416"`);
+ await queryRunner.query(`DROP INDEX "IDX_3fa0d0f17ca72e3dc80999a032"`);
+ await queryRunner.query(`DROP INDEX "IDX_6e1df243476e20cbf86572ecc0"`);
+ await queryRunner.query(`DROP INDEX "IDX_06690fc959f1c9fdaf21928222"`);
+ await queryRunner.query(`DROP INDEX "IDX_e447064455928cf627590ef527"`);
+ await queryRunner.query(`DROP INDEX "IDX_2d416e6af791a82e338c79d480"`);
+ await queryRunner.query(`DROP INDEX "IDX_e9cd07672b37d8966cf3709283"`);
+ await queryRunner.query(`DROP INDEX "IDX_fcc181fb8283009c61cc4083ef"`);
+ await queryRunner.query(`DROP INDEX "IDX_49975586f50ed7b800fdd88fbd"`);
+ await queryRunner.query(`DROP INDEX "IDX_6d6f156ceefc6bc5f273a0e370"`);
+ await queryRunner.query(`DROP INDEX "IDX_c12f0af4a66cdd30c2287ce8aa"`);
+ await queryRunner.query(`DROP INDEX "IDX_d0a4f79af5a97b08f37b547197"`);
+ await queryRunner.query(`DROP INDEX "IDX_f5448d9633cff74208d850aabe"`);
+ await queryRunner.query(`DROP INDEX "IDX_f8dd01baeded2ffa833e0a610a"`);
+ await queryRunner.query(`DROP INDEX "IDX_08fac0eb3b11f04c200c0b40dd"`);
+ await queryRunner.query(`DROP INDEX "IDX_9ff6944f01acb756fdc92d7563"`);
+ await queryRunner.query(`DROP INDEX "IDX_e69096589f11e3baa98ddd64d0"`);
+ await queryRunner.query(`DROP INDEX "IDX_0c9a159c5082cbeef3ca6706b5"`);
+ await queryRunner.query(`DROP INDEX "IDX_924fc196c80ca24bae01dd37e4"`);
+ await queryRunner.query(`DROP INDEX "IDX_328f259961e60c4fa0bfcf55ca"`);
+ await queryRunner.query(`DROP INDEX "IDX_42ea9381f0fda8dfe0fa1c8b53"`);
+ await queryRunner.query(`DROP INDEX "IDX_f2aeafde2ae6fbad38e857631b"`);
+ await queryRunner.query(`DROP INDEX "IDX_f92dd6d03f8d994f29987f6214"`);
+ await queryRunner.query(`DROP INDEX "IDX_57b5458d0d3d6d1e7f13d4e57f"`);
+ await queryRunner.query(`DROP INDEX "IDX_4db3b84c7be0d3464714f3e0b1"`);
+ await queryRunner.query(`DROP INDEX "IDX_8d2cbbc8114d90d19b44d626b6"`);
+ await queryRunner.query(`DROP INDEX "IDX_046feeb12e9ef5f783f409866a"`);
+ await queryRunner.query(`DROP INDEX "IDX_f68a5ab958f9f5fa17a32ac23b"`);
+ await queryRunner.query(`DROP INDEX "IDX_65633a106bce43fc7c5c30a5c7"`);
+ await queryRunner.query(`DROP INDEX "IDX_edeb73c09c3143a81bcb34d569"`);
+ await queryRunner.query(`DROP INDEX "IDX_e316f01a6d24eb31db27f88262"`);
+ await queryRunner.query(`DROP INDEX "IDX_2be7ec6cebddc14dc11e206686"`);
+ await queryRunner.query(`DROP INDEX "IDX_a5133470f4825902e170328ca5"`);
+ await queryRunner.query(`DROP INDEX "IDX_84e661abb7bd1e51b690d4b017"`);
+ await queryRunner.query(`DROP INDEX "IDX_5c73bf61da4f6e6f15bae88ed1"`);
+ await queryRunner.query(`DROP INDEX "IDX_d70c86baedc68326be11f9c0ce"`);
+ await queryRunner.query(`DROP INDEX "IDX_66e1e1ecd2f29e57778af35b59"`);
+ await queryRunner.query(`DROP INDEX "IDX_92255988735563f0fe4aba1f05"`);
+ await queryRunner.query(`DROP INDEX "IDX_c5870993e25c3d5771f91f5003"`);
+ await queryRunner.query(`DROP INDEX "IDX_f170de677ea75ad4533de2723e"`);
+ await queryRunner.query(`DROP INDEX "IDX_7c184198ecf66a8d3ecb253ab3"`);
+ await queryRunner.query(`DROP INDEX "IDX_f091abb24193d50c653c6b77fc"`);
+ await queryRunner.query(`DROP INDEX "IDX_a770a57c70e668cc61590c9161"`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__active_users_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___local_count"`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" DROP COLUMN "___remote_count"`);
+ await queryRunner.query(`ALTER TABLE "__chart__drive" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__drive_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__drive" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__federation_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__hashtag_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "___local_count"`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "___remote_count"`);
+ await queryRunner.query(`ALTER TABLE "__chart__instance" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__instance_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__instance" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__network" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__network_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__network" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__notes" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__notes_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__notes" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__per_user_drive_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_following" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__per_user_following_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_following" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__per_user_notes_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__per_user_reaction_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_grouped" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__test_grouped_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_grouped" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_unique" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__test_unique_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_unique" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_unique" DROP COLUMN "___foo"`);
+ await queryRunner.query(`ALTER TABLE "__chart__test" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__test_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__test" DROP COLUMN "unique"`);
+ await queryRunner.query(`ALTER TABLE "__chart__users" DROP COLUMN "span"`);
+ await queryRunner.query(`DROP TYPE "public"."__chart__users_span_enum"`);
+ await queryRunner.query(`ALTER TABLE "__chart__users" DROP COLUMN "unique"`);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise<void> {
+ await queryRunner.query(`ALTER TABLE "__chart__users" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__users_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__users" ADD "span" "__chart__users_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__test" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__test_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__test" ADD "span" "__chart__test_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_unique" ADD "___foo" bigint NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_unique" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__test_unique_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_unique" ADD "span" "__chart__test_unique_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_grouped" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__test_grouped_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_grouped" ADD "span" "__chart__test_grouped_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__per_user_reaction_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_reaction" ADD "span" "__chart__per_user_reaction_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__per_user_notes_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ADD "span" "__chart__per_user_notes_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__per_user_following_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_following" ADD "span" "__chart__per_user_following_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__per_user_drive_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__per_user_drive" ADD "span" "__chart__per_user_drive_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__notes" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__notes_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__notes" ADD "span" "__chart__notes_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__network" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__network_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__network" ADD "span" "__chart__network_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__instance" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__instance_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__instance" ADD "span" "__chart__instance_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "___remote_count" bigint NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "___local_count" bigint NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__hashtag_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "span" "__chart__hashtag_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__federation_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "span" "__chart__federation_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__drive" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__drive_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__drive" ADD "span" "__chart__drive_span_enum" NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___remote_count" bigint NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___local_count" bigint NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "unique" jsonb NOT NULL DEFAULT '{}'`);
+ await queryRunner.query(`CREATE TYPE "public"."__chart__active_users_span_enum" AS ENUM('hour', 'day')`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "span" "__chart__active_users_span_enum" NOT NULL`);
+ await queryRunner.query(`CREATE INDEX "IDX_a770a57c70e668cc61590c9161" ON "__chart__users" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_f091abb24193d50c653c6b77fc" ON "__chart__users" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_7c184198ecf66a8d3ecb253ab3" ON "__chart__users" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_f170de677ea75ad4533de2723e" ON "__chart__test" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_c5870993e25c3d5771f91f5003" ON "__chart__test" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_92255988735563f0fe4aba1f05" ON "__chart__test" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_66e1e1ecd2f29e57778af35b59" ON "__chart__test_unique" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_d70c86baedc68326be11f9c0ce" ON "__chart__test_unique" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_5c73bf61da4f6e6f15bae88ed1" ON "__chart__test_unique" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_84e661abb7bd1e51b690d4b017" ON "__chart__test_grouped" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_a5133470f4825902e170328ca5" ON "__chart__test_grouped" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_2be7ec6cebddc14dc11e206686" ON "__chart__test_grouped" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_e316f01a6d24eb31db27f88262" ON "__chart__per_user_reaction" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_edeb73c09c3143a81bcb34d569" ON "__chart__per_user_reaction" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_65633a106bce43fc7c5c30a5c7" ON "__chart__per_user_reaction" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_f68a5ab958f9f5fa17a32ac23b" ON "__chart__per_user_notes" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_046feeb12e9ef5f783f409866a" ON "__chart__per_user_notes" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_8d2cbbc8114d90d19b44d626b6" ON "__chart__per_user_notes" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_4db3b84c7be0d3464714f3e0b1" ON "__chart__per_user_following" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_57b5458d0d3d6d1e7f13d4e57f" ON "__chart__per_user_following" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_f92dd6d03f8d994f29987f6214" ON "__chart__per_user_following" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_f2aeafde2ae6fbad38e857631b" ON "__chart__per_user_drive" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_42ea9381f0fda8dfe0fa1c8b53" ON "__chart__per_user_drive" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_328f259961e60c4fa0bfcf55ca" ON "__chart__per_user_drive" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_924fc196c80ca24bae01dd37e4" ON "__chart__notes" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_0c9a159c5082cbeef3ca6706b5" ON "__chart__notes" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_e69096589f11e3baa98ddd64d0" ON "__chart__notes" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_9ff6944f01acb756fdc92d7563" ON "__chart__network" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_08fac0eb3b11f04c200c0b40dd" ON "__chart__network" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_f8dd01baeded2ffa833e0a610a" ON "__chart__network" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_f5448d9633cff74208d850aabe" ON "__chart__instance" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_d0a4f79af5a97b08f37b547197" ON "__chart__instance" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_c12f0af4a66cdd30c2287ce8aa" ON "__chart__instance" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_6d6f156ceefc6bc5f273a0e370" ON "__chart__hashtag" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_49975586f50ed7b800fdd88fbd" ON "__chart__hashtag" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_fcc181fb8283009c61cc4083ef" ON "__chart__hashtag" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_e9cd07672b37d8966cf3709283" ON "__chart__federation" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_2d416e6af791a82e338c79d480" ON "__chart__federation" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_e447064455928cf627590ef527" ON "__chart__federation" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_06690fc959f1c9fdaf21928222" ON "__chart__drive" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_6e1df243476e20cbf86572ecc0" ON "__chart__drive" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_3fa0d0f17ca72e3dc80999a032" ON "__chart__drive" ("span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_c26e2c1cbb6e911e0554b27416" ON "__chart__active_users" ("date", "group", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_20f57cc8f142c131340ee16742" ON "__chart__active_users" ("date", "span") `);
+ await queryRunner.query(`CREATE INDEX "IDX_15e91a03aeeac9dbccdf43fc06" ON "__chart__active_users" ("span") `);
+ }
+
+}
diff --git a/migration/1615966519402-chart-v2-2.ts b/migration/1615966519402-chart-v2-2.ts
new file mode 100644
index 0000000000..a694f9542a
--- /dev/null
+++ b/migration/1615966519402-chart-v2-2.ts
@@ -0,0 +1,22 @@
+import {MigrationInterface, QueryRunner} from "typeorm";
+
+export class chartV221615966519402 implements MigrationInterface {
+ name = 'chartV221615966519402'
+
+ public async up(queryRunner: QueryRunner): Promise<void> {
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___local_users" character varying array NOT NULL DEFAULT '{}'::varchar[]`);
+ await queryRunner.query(`ALTER TABLE "__chart__active_users" ADD "___remote_users" character varying array NOT NULL DEFAULT '{}'::varchar[]`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "___local_users" character varying array NOT NULL DEFAULT '{}'::varchar[]`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" ADD "___remote_users" character varying array NOT NULL DEFAULT '{}'::varchar[]`);
+ await queryRunner.query(`ALTER TABLE "__chart__test_unique" ADD "___foo" character varying array NOT NULL DEFAULT '{}'::varchar[]`);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise<void> {
+ await queryRunner.query(`ALTER TABLE "__chart__test_unique" DROP COLUMN "___foo"`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" DROP COLUMN "___remote_users"`);
+ await queryRunner.query(`ALTER TABLE "__chart__hashtag" 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 "___local_users"`);
+ }
+
+}
diff --git a/package.json b/package.json
index 2c0525b605..0f40837a6f 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
- "version": "12.74.1",
+ "version": "12.75.0",
"codename": "indigo",
"repository": {
"type": "git",
@@ -11,20 +11,20 @@
"private": true,
"scripts": {
"start": "node ./index.js",
- "start-product": "cross-env NODE_ENV=production node ./index.js",
"init": "npm run migrate",
"ormconfig": "node ./built/ormconfig.js",
"migrate": "ts-node ./node_modules/typeorm/cli.js migration:run",
"migrateandstart": "npm run migrate && npm run start",
- "build": "webpack && gulp build",
- "build-product": "cross-env NODE_ENV=production webpack && gulp build",
- "webpack": "webpack",
- "watch": "webpack --watch",
- "gulp": "gulp build",
+ "build": "npm run build-webpack && npm run build-gulp",
+ "build-webpack": "webpack",
+ "build-gulp": "gulp build",
+ "watch": "concurrently \"npm:watch-*\"",
+ "watch-webpack": "webpack --watch",
+ "watch-gulp": "gulp watch",
"clean": "gulp clean",
"cleanall": "gulp cleanall",
"lint": "tslint 'src/**/*.ts'",
- "test": "cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_COMPILER_OPTIONS=\"{\\\"target\\\":\\\"es2017\\\",\\\"module\\\":\\\"commonjs\\\",\\\"typeRoots\\\":[\\\"node_modules/@types\\\",\\\"src/@types\\\"]}\" mocha",
+ "test": "cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
"format": "gulp format"
},
"resolutions": {
@@ -35,25 +35,24 @@
"lodash": "^4.17.20"
},
"dependencies": {
- "@babel/plugin-transform-runtime": "7.13.9",
+ "@babel/plugin-transform-runtime": "7.13.10",
"@elastic/elasticsearch": "7.11.0",
- "@fortawesome/fontawesome-svg-core": "1.2.34",
- "@fortawesome/free-brands-svg-icons": "5.15.2",
- "@fortawesome/free-regular-svg-icons": "5.15.2",
- "@fortawesome/free-solid-svg-icons": "5.15.2",
+ "@fortawesome/fontawesome-svg-core": "1.2.35",
+ "@fortawesome/free-brands-svg-icons": "5.15.3",
+ "@fortawesome/free-regular-svg-icons": "5.15.3",
+ "@fortawesome/free-solid-svg-icons": "5.15.3",
"@fortawesome/vue-fontawesome": "3.0.0-3",
"@koa/cors": "3.1.0",
"@koa/multer": "3.0.0",
"@koa/router": "9.0.1",
"@sentry/browser": "5.29.2",
"@sentry/tracing": "5.29.2",
- "@sinonjs/fake-timers": "6.0.1",
+ "@sinonjs/fake-timers": "7.0.2",
"@syuilo/aiscript": "0.11.1",
"@types/bcryptjs": "2.4.2",
"@types/bull": "3.15.0",
"@types/cbor": "5.0.1",
"@types/dateformat": "3.0.1",
- "@types/double-ended-queue": "2.1.1",
"@types/escape-regexp": "0.0.0",
"@types/glob": "7.1.3",
"@types/gulp": "4.0.8",
@@ -61,10 +60,10 @@
"@types/gulp-replace": "0.0.31",
"@types/is-url": "1.2.28",
"@types/js-yaml": "4.0.0",
- "@types/jsdom": "16.2.6",
- "@types/jsonld": "1.5.4",
+ "@types/jsdom": "16.2.7",
+ "@types/jsonld": "1.5.5",
"@types/katex": "0.11.0",
- "@types/koa": "2.13.0",
+ "@types/koa": "2.13.1",
"@types/koa-bodyparser": "4.3.0",
"@types/koa-cors": "0.0.0",
"@types/koa-favicon": "2.0.19",
@@ -78,9 +77,9 @@
"@types/markdown-it": "12.0.1",
"@types/matter-js": "0.14.10",
"@types/mocha": "8.2.1",
- "@types/node": "14.14.31",
+ "@types/node": "14.14.35",
"@types/node-fetch": "2.5.8",
- "@types/nodemailer": "6.4.0",
+ "@types/nodemailer": "6.4.1",
"@types/nprogress": "0.2.0",
"@types/oauth": "0.9.1",
"@types/parse5": "6.0.0",
@@ -105,44 +104,44 @@
"@types/web-push": "3.3.0",
"@types/webpack": "4.41.26",
"@types/webpack-stream": "3.2.11",
- "@types/websocket": "1.0.1",
+ "@types/websocket": "1.0.2",
"@types/ws": "7.4.0",
- "@typescript-eslint/parser": "4.16.1",
- "@vue/compiler-sfc": "3.0.5",
+ "@typescript-eslint/parser": "4.18.0",
+ "@vue/compiler-sfc": "3.0.7",
"abort-controller": "3.0.0",
- "apexcharts": "3.25.0",
+ "apexcharts": "3.26.0",
"autobind-decorator": "2.4.0",
"autosize": "4.0.2",
"autwh": "0.1.0",
- "aws-sdk": "2.848.0",
+ "aws-sdk": "2.867.0",
"bcryptjs": "2.4.3",
"blurhash": "1.1.3",
- "broadcast-channel": "3.4.1",
- "bull": "3.20.1",
+ "broadcast-channel": "3.5.3",
+ "bull": "3.21.1",
"cafy": "15.2.1",
- "cbor": "7.0.3",
+ "cbor": "7.0.4",
"chalk": "4.1.0",
"chart.js": "2.9.4",
"cli-highlight": "2.1.10",
"commander": "4.1.1",
+ "concurrently": "6.0.0",
"content-disposition": "0.5.3",
- "core-js": "3.9.0",
+ "core-js": "3.9.1",
"crc-32": "1.2.0",
- "css-loader": "5.0.2",
+ "css-loader": "5.1.3",
"cssnano": "4.1.10",
"dateformat": "4.5.1",
"diskusage": "1.1.3",
- "double-ended-queue": "2.1.0-0",
"escape-regexp": "0.0.1",
- "eslint": "7.21.0",
- "eslint-plugin-vue": "7.6.0",
+ "eslint": "7.22.0",
+ "eslint-plugin-vue": "7.7.0",
"eventemitter3": "4.0.7",
"feed": "4.2.2",
"fibers": "5.0.0",
- "file-type": "16.2.0",
+ "file-type": "16.3.0",
"fluent-ffmpeg": "2.1.2",
"glob": "7.1.6",
- "got": "11.8.1",
+ "got": "11.8.2",
"gulp": "4.0.2",
"gulp-cssnano": "2.1.3",
"gulp-rename": "2.0.0",
@@ -155,17 +154,17 @@
"http-proxy-agent": "4.0.1",
"http-signature": "1.3.5",
"https-proxy-agent": "5.0.0",
- "idb-keyval": "5.0.2",
+ "idb-keyval": "5.0.4",
"insert-text-at-cursor": "0.3.0",
"is-root": "2.1.0",
- "is-svg": "4.2.1",
+ "is-svg": "4.3.1",
"js-yaml": "4.0.0",
- "jsdom": "16.4.0",
+ "jsdom": "16.5.1",
"json5": "2.2.0",
"json5-loader": "4.0.1",
"jsonld": "4.0.1",
"jsrsasign": "8.0.20",
- "katex": "0.12.0",
+ "katex": "0.13.0",
"koa": "2.13.1",
"koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0",
@@ -174,13 +173,13 @@
"koa-mount": "4.0.0",
"koa-send": "5.0.1",
"koa-slow": "2.1.0",
- "koa-views": "6.3.1",
+ "koa-views": "7.0.1",
"langmap": "0.0.16",
"lookup-dns-cache": "2.1.0",
"markdown-it": "12.0.4",
- "markdown-it-anchor": "7.0.2",
+ "markdown-it-anchor": "7.1.0",
"matter-js": "0.16.1",
- "mocha": "8.3.0",
+ "mocha": "8.3.2",
"moji": "0.5.1",
"ms": "2.1.3",
"multer": "1.4.2",
@@ -189,20 +188,19 @@
"nodemailer": "6.5.0",
"object-assign-deep": "0.4.0",
"os-utils": "0.0.14",
- "p-cancelable": "2.0.0",
"parse5": "6.0.1",
"parsimmon": "1.16.0",
"pg": "8.5.1",
"portscanner": "2.2.0",
- "postcss": "8.2.7",
- "postcss-loader": "5.0.0",
+ "postcss": "8.2.8",
+ "postcss-loader": "5.2.0",
"prismjs": "1.23.0",
- "probe-image-size": "6.0.0",
+ "probe-image-size": "7.0.1",
"promise-limit": "2.7.0",
"promise-sequential": "1.1.1",
- "pug": "2.0.4",
+ "pug": "3.0.2",
"punycode": "2.1.1",
- "pureimage": "0.2.5",
+ "pureimage": "0.2.7",
"qrcode": "1.4.4",
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
@@ -221,49 +219,49 @@
"sass": "1.32.8",
"sass-loader": "11.0.1",
"seedrandom": "3.0.5",
- "sharp": "0.27.1",
+ "sharp": "0.27.2",
"speakeasy": "2.0.0",
"stringz": "2.1.0",
"style-loader": "2.0.0",
"summaly": "2.4.0",
"syslog-pro": "1.0.0",
- "systeminformation": "5.6.1",
+ "systeminformation": "5.6.7",
"syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0",
"three": "0.117.1",
"throttle-debounce": "3.0.1",
"tinycolor2": "1.4.2",
"tmp": "0.2.1",
- "ts-loader": "8.0.17",
+ "ts-loader": "8.0.18",
"ts-node": "9.1.1",
"tslint": "6.1.3",
"tslint-sonarts": "1.9.0",
"typeorm": "0.2.31",
- "typescript": "4.1.5",
+ "typescript": "4.2.3",
"ulid": "2.3.0",
"url-loader": "4.1.1",
"uuid": "8.3.2",
"v-debounce": "0.1.2",
"vanilla-tilt": "1.7.0",
- "vue": "3.0.5",
+ "vue": "3.0.7",
"vue-color": "2.8.1",
"vue-json-pretty": "1.7.1",
"vue-loader": "16.1.2",
"vue-prism-editor": "2.0.0-alpha.2",
- "vue-router": "4.0.4",
+ "vue-router": "4.0.5",
"vue-style-loader": "4.1.3",
"vuedraggable": "4.0.1",
"web-push": "3.4.4",
- "webpack": "5.24.2",
+ "webpack": "5.26.3",
"webpack-cli": "4.5.0",
"websocket": "1.0.33",
- "ws": "7.4.3",
+ "ws": "7.4.4",
"xev": "2.0.1"
},
"devDependencies": {
"@types/chai": "4.2.15",
"@types/fluent-ffmpeg": "2.1.16",
- "chai": "4.3.0",
+ "chai": "4.3.4",
"cross-env": "7.0.3"
}
}
diff --git a/src/.eslintrc b/src/.eslintrc
new file mode 100644
index 0000000000..d54e20f6b6
--- /dev/null
+++ b/src/.eslintrc
@@ -0,0 +1,6 @@
+{
+ "env": {
+ "node": true,
+ "commonjs": true
+ }
+}
diff --git a/src/client/.eslintrc b/src/client/.eslintrc
index 8829472b49..fffa28d9e4 100644
--- a/src/client/.eslintrc
+++ b/src/client/.eslintrc
@@ -1,4 +1,24 @@
{
+ "env": {
+ "node": false,
+ },
+ "extends": [
+ "eslint:recommended",
+ "plugin:vue/recommended"
+ ],
+ "rules": {
+ "vue/require-v-for-key": 0,
+ "vue/max-attributes-per-line": 0,
+ "vue/html-indent": 0,
+ "vue/html-self-closing": 0,
+ "vue/no-unused-vars": 0,
+ "vue/attributes-order": 0,
+ "vue/require-prop-types": 0,
+ "vue/require-default-prop": 0,
+ "vue/html-closing-bracket-spacing": 0,
+ "vue/singleline-html-element-content-newline": 0,
+ "vue/no-v-html": 0
+ },
"globals": {
"_DEV_": false,
"_LANGS_": false,
diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue
index 1ef3f43389..ea26d31100 100644
--- a/src/client/components/note-detailed.vue
+++ b/src/client/components/note-detailed.vue
@@ -350,7 +350,8 @@ export default defineComponent({
capture(withHandler = false) {
if (this.$i) {
- this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id });
+ // TODO: ã“ã®ãƒŽãƒ¼ãƒˆãŒã‚¹ãƒˆãƒªãƒ¼ãƒŸãƒ³ã‚°çµŒç”±ã§æµã‚Œã¦ããŸå ´åˆã®ã¿ sr ã™ã‚‹
+ this.connection.send(document.body.contains(this.$el) ? 'sr' : 's', { id: this.appearNote.id });
if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
}
},
diff --git a/src/client/components/note.vue b/src/client/components/note.vue
index 65e09b7802..70f49fef7e 100644
--- a/src/client/components/note.vue
+++ b/src/client/components/note.vue
@@ -325,7 +325,8 @@ export default defineComponent({
capture(withHandler = false) {
if (this.$i) {
- this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id });
+ // TODO: ã“ã®ãƒŽãƒ¼ãƒˆãŒã‚¹ãƒˆãƒªãƒ¼ãƒŸãƒ³ã‚°çµŒç”±ã§æµã‚Œã¦ããŸå ´åˆã®ã¿ sr ã™ã‚‹
+ this.connection.send(document.body.contains(this.$el) ? 'sr' : 's', { id: this.appearNote.id });
if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
}
},
diff --git a/src/client/components/ui/modal.vue b/src/client/components/ui/modal.vue
index ff5b98d39f..db6564bacc 100644
--- a/src/client/components/ui/modal.vue
+++ b/src/client/components/ui/modal.vue
@@ -1,7 +1,7 @@
<template>
<transition :name="$store.state.animation ? popup ? 'modal-popup' : 'modal' : ''" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered">
<div v-show="manualShowing != null ? manualShowing : showing" class="mk-modal" v-hotkey.global="keymap" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
- <div class="bg _modalBg" @click="onBgClick"></div>
+ <div class="bg _modalBg" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
<div class="content" :class="{ popup, fixed, top: position === 'top' }" @click.self="onBgClick" ref="content">
<slot></slot>
</div>
diff --git a/src/client/init.ts b/src/client/init.ts
index 1c44e7f23e..2a2b6a2f86 100644
--- a/src/client/init.ts
+++ b/src/client/init.ts
@@ -4,40 +4,6 @@
import '@/style.scss';
-// TODO: ãã®ã†ã¡æ¶ˆã™
-if (localStorage.getItem('vuex') != null) {
- const vuex = JSON.parse(localStorage.getItem('vuex'));
-
- localStorage.setItem('account', JSON.stringify({
- ...vuex.i,
- token: localStorage.getItem('i')
- }));
- localStorage.setItem('accounts', JSON.stringify(vuex.device.accounts));
- localStorage.setItem('miux:themes', JSON.stringify(vuex.device.themes));
-
- if (vuex.device.userData) {
- for (const [k, v] of Object.entries(vuex.device.userData)) {
- localStorage.setItem('pizzax::base::' + k, JSON.stringify({
- widgets: v.widgets
- }));
-
- if (v.deck) {
- localStorage.setItem('pizzax::deck::' + k, JSON.stringify({
- columns: v.deck.columns,
- layout: v.deck.layout,
- }));
- }
- }
- }
-
- localStorage.setItem('vuex-old', JSON.stringify(vuex));
- localStorage.removeItem('vuex');
- localStorage.removeItem('i');
- localStorage.removeItem('locale');
-
- location.reload();
-}
-
import * as Sentry from '@sentry/browser';
import { Integrations } from '@sentry/tracing';
import { createApp, watch } from 'vue';
diff --git a/src/client/pages/doc.vue b/src/client/pages/doc.vue
index 3379a5fe68..ed4eae4d02 100644
--- a/src/client/pages/doc.vue
+++ b/src/client/pages/doc.vue
@@ -60,7 +60,7 @@ export default defineComponent({
methods: {
fetchDoc() {
- fetch(`${url}/assets/docs/${lang}/${this.doc}.md`).then(res => res.text()).then(md => {
+ fetch(`${url}/doc-assets/${lang}/${this.doc}.md`).then(res => res.text()).then(md => {
this.parse(md);
});
},
diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue
index 45997dfd65..08856ebfe4 100644
--- a/src/client/pages/page-editor/page-editor.vue
+++ b/src/client/pages/page-editor/page-editor.vue
@@ -4,9 +4,9 @@
<MkA class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><Fa :icon="faExternalLinkSquareAlt"/> {{ $ts._pages.viewPage }}</MkA>
<div class="buttons" style="margin: 16px 0;">
- <MkButton inline @click="save" primary class="save"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
+ <MkButton inline @click="save" primary class="save" v-if="!readonly"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
<MkButton inline @click="duplicate" class="duplicate" v-if="pageId"><Fa :icon="faCopy"/> {{ $ts.duplicate }}</MkButton>
- <MkButton inline @click="del" class="delete" v-if="pageId"><Fa :icon="faTrashAlt"/> {{ $ts.delete }}</MkButton>
+ <MkButton inline @click="del" class="delete" v-if="pageId && !readonly"><Fa :icon="faTrashAlt"/> {{ $ts.delete }}</MkButton>
</div>
<MkContainer :body-togglable="true" :expanded="true" class="_vMargin">
@@ -134,12 +134,18 @@ export default defineComponent({
data() {
return {
- INFO: computed(() => this.initPageId ? {
- title: this.$ts._pages.editPage,
- icon: faPencilAlt,
- } : {
- title: this.$ts._pages.newPage,
- icon: faPencilAlt,
+ INFO: computed(() => {
+ let title = this.$ts._pages.newPage;
+ if (this.initPageId) {
+ title = this.$ts._pages.editPage;
+ }
+ else if (this.initPageName && this.initUser) {
+ title = this.$ts._pages.readPage;
+ }
+ return {
+ title: title,
+ icon: faPencilAlt,
+ };
}),
author: this.$i,
readonly: false,
diff --git a/src/client/store.ts b/src/client/store.ts
index 14924dadd0..e6fdd12f1d 100644
--- a/src/client/store.ts
+++ b/src/client/store.ts
@@ -212,7 +212,6 @@ type Plugin = {
*/
export class ColdDeviceStorage {
public static default = {
- themes: [] as Theme[], // TODO: ãã®ã†ã¡æ¶ˆã™
// TODO: テーマをアカウントã«ä¿å­˜ã™ã‚‹ã‚ˆã†ã«ãªã£ãŸã®ã«ã‚‚ã‹ã‹ã‚らãšã€ä»¥ä¸‹ã®ã©ã®ãƒ†ãƒ¼ãƒžã‚’使ã†ã‹ã¨ã„ã†æƒ…å ±ã ã‘ãŒãƒ–ラウザä¿å­˜ã«ãªã£ã¦ã„ã¦ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆåˆ‡ã‚Šæ›¿ãˆãŸã‚Šãƒ­ã‚°ã‚¢ã‚¦ãƒˆã—ãŸã¨ãã«ä¸å…·åˆãŒç™ºç”Ÿã™ã‚‹ã®ã§ãªã‚“ã¨ã‹ã™ã‚‹
// テーマIDã‚’ä¿å­˜ã™ã‚‹ã®ã§ã¯ãªãã€ãƒ†ãƒ¼ãƒžè‡ªä½“ã‚’ä¿å­˜ã™ã‚‹ã‚ˆã†ã«ã™ã‚Œã°è§£æ±ºã™ã‚‹ã‹ã‚‚
darkTheme: '8050783a-7f63-445a-b270-36d0f6ba1677',
diff --git a/src/client/theme-store.ts b/src/client/theme-store.ts
index 5e440efbf9..8e21af70fc 100644
--- a/src/client/theme-store.ts
+++ b/src/client/theme-store.ts
@@ -33,30 +33,3 @@ export async function removeTheme(theme: Theme): Promise<void> {
await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes });
localStorage.setItem(lsCacheKey, JSON.stringify(themes));
}
-
-// TODO: ãã®ã†ã¡æ¶ˆã™
-if (ColdDeviceStorage.get('themes').length > 0) {
- const lsThemes = ColdDeviceStorage.get('themes');
- let registryThemes;
- try {
- registryThemes = await api('i/registry/get', { scope: ['client'], key: 'themes' });
- } catch (e) {
- if (e.code === 'NO_SUCH_KEY') {
- registryThemes = [];
- } else {
- throw e;
- }
- }
- const themes = [] as Theme[];
- for (const theme of lsThemes) {
- if (themes.some(x => x.id === theme.id)) continue;
- themes.push(theme);
- }
- for (const theme of registryThemes) {
- if (themes.some(x => x.id === theme.id)) continue;
- themes.push(theme);
- }
- await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes });
- localStorage.setItem(lsCacheKey, JSON.stringify(themes));
- ColdDeviceStorage.set('themes', []);
-}
diff --git a/src/client/ui/chat/note.vue b/src/client/ui/chat/note.vue
index 5a4a13d889..97275875ca 100644
--- a/src/client/ui/chat/note.vue
+++ b/src/client/ui/chat/note.vue
@@ -325,7 +325,8 @@ export default defineComponent({
capture(withHandler = false) {
if (this.$i) {
- this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id });
+ // TODO: ã“ã®ãƒŽãƒ¼ãƒˆãŒã‚¹ãƒˆãƒªãƒ¼ãƒŸãƒ³ã‚°çµŒç”±ã§æµã‚Œã¦ããŸå ´åˆã®ã¿ sr ã™ã‚‹
+ this.connection.send(document.body.contains(this.$el) ? 'sr' : 's', { id: this.appearNote.id });
if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
}
},
diff --git a/src/daemons/janitor.ts b/src/daemons/janitor.ts
index 462ebf915c..c079086427 100644
--- a/src/daemons/janitor.ts
+++ b/src/daemons/janitor.ts
@@ -1,3 +1,5 @@
+// TODO: 消ã—ãŸã„
+
const interval = 30 * 60 * 1000;
import { AttestationChallenges } from '../models';
import { LessThan } from 'typeorm';
diff --git a/src/daemons/queue-stats.ts b/src/daemons/queue-stats.ts
index 288e855ae9..77f09b18d6 100644
--- a/src/daemons/queue-stats.ts
+++ b/src/daemons/queue-stats.ts
@@ -1,5 +1,5 @@
import Xev from 'xev';
-import { deliverQueue, inboxQueue } from '../queue';
+import { deliverQueue, inboxQueue } from '../queue/queues';
const ev = new Xev();
diff --git a/src/daemons/server-stats.ts b/src/daemons/server-stats.ts
index bc1da5eef6..8dfa946250 100644
--- a/src/daemons/server-stats.ts
+++ b/src/daemons/server-stats.ts
@@ -75,5 +75,5 @@ async function net() {
// FS STAT
async function fs() {
const data = await si.disksIO().catch(() => ({ rIO_sec: 0, wIO_sec: 0 }));
- return data;
+ return data || { rIO_sec: 0, wIO_sec: 0 };
}
diff --git a/src/db/postgre.ts b/src/db/postgre.ts
index 2f3c910163..831e5e0592 100644
--- a/src/db/postgre.ts
+++ b/src/db/postgre.ts
@@ -1,3 +1,7 @@
+// https://github.com/typeorm/typeorm/issues/2400
+const types = require('pg').types;
+types.setTypeParser(20, Number);
+
import { createConnection, Logger, getConnection } from 'typeorm';
import config from '../config';
import { entities as charts } from '../services/chart/entities';
diff --git a/src/docs/fr-FR/api.md b/src/docs/fr-FR/api.md
index 76019b6145..0147f95bac 100644
--- a/src/docs/fr-FR/api.md
+++ b/src/docs/fr-FR/api.md
@@ -1,58 +1,58 @@
-# Misskey API
+# API de Misskey
-MisskeyAPIを使ã£ã¦Misskeyクライアントã€Misskey連æºWebサービスã€Botç­‰(以下「アプリケーションã€ã¨å‘¼ã³ã¾ã™)を開発ã§ãã¾ã™ã€‚ ストリーミングAPIã‚‚ã‚ã‚‹ã®ã§ã€ãƒªã‚¢ãƒ«ã‚¿ã‚¤ãƒ æ€§ã®ã‚るアプリケーションを作るã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚
+Vous pouvez utiliser l'API de Misskey pour développer des clients Misskey, des services web s'intégrant à Misskey, des Bots (que nous appellerons plus loin "Applications"), etc. Comme l'API streaming est aussi implémenté, vous avez la possibilité de créer des applications de temps réel.
-APIを使ã„å§‹ã‚ã‚‹ã«ã¯ã€ã¾ãšã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’å–å¾—ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã§ã¯ã€ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’å–å¾—ã™ã‚‹æ‰‹é †ã‚’説明ã—ãŸå¾Œã€åŸºæœ¬çš„ãªAPIã®ä½¿ã„方を説明ã—ã¾ã™ã€‚
+Pour pouvoir vous servir de l'API, il vous faudra d'abord obtenir un jeton d'accès. Ce guide a été conçu pour vous accompagner dans le processus d'obtention du jeton d'accès, puis donner des instructions de base sur l'utilisation de l'API.
-## アクセストークンã®å–å¾—
-基本的ã«ã€APIã¯ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã¯ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ãŒå¿…è¦ã¨ãªã‚Šã¾ã™ã€‚ APIã«ãƒªã‚¯ã‚¨ã‚¹ãƒˆã™ã‚‹ã®ãŒè‡ªåˆ†è‡ªèº«ãªã®ã‹ã€ä¸ç‰¹å®šã®åˆ©ç”¨è€…ã«ä½¿ã£ã¦ã‚‚らã†ã‚¢ãƒ—リケーションãªã®ã‹ã«ã‚ˆã£ã¦å–得手順ã¯ç•°ãªã‚Šã¾ã™ã€‚
+## Obtenir le jeton d'accès
+Une requête d'API, par essence, nécessite un jeton d'accès. La procédure d'acquisition du jeton diffère selon que vous effectuez la requête vous-même, ou qu'elle est envoyée via une application par un utilisateur final non défini.
-* å‰è€…ã®å ´åˆ: [「自分自身ã®ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’手動発行ã™ã‚‹ã€](#自分自身ã®ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’手動発行ã™ã‚‹)ã«é€²ã‚€
-* 後者ã®å ´åˆ: [「アプリケーション利用者ã«ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã®ç™ºè¡Œã‚’リクエストã™ã‚‹ã€](#アプリケーション利用者ã«ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã®ç™ºè¡Œã‚’リクエストã™ã‚‹)ã«é€²ã‚€
+* Dans le premier cas : allez à [« Générer manuellement un jeton d'accès pour son propre compte »](#自分自身ã®ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’手動発行ã™ã‚‹).
+* Dans le second cas : allez à [« Demander la génération du jeton d'accès via un utilisateur d'application »](#アプリケーション利用者ã«ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã®ç™ºè¡Œã‚’リクエストã™ã‚‹).
-### 自分自身ã®ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’手動発行ã™ã‚‹
-「設定 > APIã€ã§ã€è‡ªåˆ†ã®ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’発行ã§ãã¾ã™ã€‚
+### Générer manuellement un jeton d'accès pour son propre compte
+Vous pouvez générer votre propre jeton d'accès en allant dans { Paramètres > API }.
-[「APIã®ä½¿ã„æ–¹ã€ã¸é€²ã‚€](#APIã®ä½¿ã„æ–¹)
+[Continuer avec « Utiliser l'API ».](#APIã®ä½¿ã„æ–¹)
-### アプリケーション利用者ã«ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã®ç™ºè¡Œã‚’リクエストã™ã‚‹
-アプリケーション利用者ã®ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’å–å¾—ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ‰‹é †ã§ç™ºè¡Œã‚’リクエストã—ã¾ã™ã€‚
+### Demander la génération du jeton d'accès via un utilisateur d'application
+Pour obtenir un jeton d'accès pour le compte utilisateur final de votre application, suivez la procédure de génération ci-dessous.
-#### Step 1
+#### Étape 1
-UUIDを生æˆã™ã‚‹ã€‚以後ã“れをセッションIDã¨å‘¼ã³ã¾ã™ã€‚
+Générez un UUID. Nous l'appellerons « ID de session » dans la suite de ce guide.
-> ã“ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³IDã¯æ¯Žå›žç”Ÿæˆã—ã€ä½¿ã„ã¾ã‚ã•ãªã„よã†ã«ã—ã¦ãã ã•ã„。
+> Un même ID de session ne devrait pas être utilisé plusieurs fois ; veillez à en générer un nouveau pour chaque jeton d'accès.
-#### Step 2
+#### Étape 2
-`{_URL_}/miauth/{session}`をユーザーã®ãƒ–ラウザã§è¡¨ç¤ºã•ã›ã‚‹ã€‚`{session}`ã®éƒ¨åˆ†ã¯ã€ã‚»ãƒƒã‚·ãƒ§ãƒ³IDã«ç½®ãæ›ãˆã¦ãã ã•ã„。
-> 例: `{_URL_}/miauth/c1f6d42b-468b-4fd2-8274-e58abdedef6f`
+Ouvrez l'adresse `{_URL_}/miauth/{session}` dans le navigateur de l'utilisateur. Remplacez alors la partie `{session}` de l'URL par l'ID de session que vous venez de générer.
+> Par ex. : `{_URL_}/miauth/c1f6d42b-468b-4fd2-8274-e58abdedef6f`
-表示ã™ã‚‹éš›ã€URLã«ã‚¯ã‚¨ãƒªãƒ‘ラメータã¨ã—ã¦ã„ãã¤ã‹ã®ã‚ªãƒ—ションを設定ã§ãã¾ã™:
-* `name` ... アプリケーションå
- * > 例: `MissDeck`
-* `icon` ... アプリケーションã®ã‚¢ã‚¤ã‚³ãƒ³ç”»åƒURL
- * > 例: `https://missdeck.example.com/icon.png`
-* `callback` ... èªè¨¼ãŒçµ‚ã‚ã£ãŸå¾Œã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã™ã‚‹URL
- * > 例: `https://missdeck.example.com/callback`
- * リダイレクト時ã«ã¯ã€`session`ã¨ã„ã†ã‚¯ã‚¨ãƒªãƒ‘ラメータã§ã‚»ãƒƒã‚·ãƒ§ãƒ³IDãŒä»˜ãã¾ã™
-* `permission` ... アプリケーションãŒè¦æ±‚ã™ã‚‹æ¨©é™
- * > 例: `write:notes,write:following,read:drive`
- * è¦æ±‚ã™ã‚‹æ¨©é™ã‚’`,`ã§åŒºåˆ‡ã£ã¦åˆ—挙ã—ã¾ã™
- * ã©ã®ã‚ˆã†ãªæ¨©é™ãŒã‚ã‚‹ã‹ã¯[APIリファレンス](/api-doc)ã§ç¢ºèªã§ãã¾ã™
+En ouvrant cette URL, vous pourrez configurer un certain nombre d'options pour les paramètres de requête :
+* `name` : nom de l'application
+ * > Ex. : `MissDeck`
+* `icon` : URL de l'icône de l'application
+ * > Ex. : `https://missdeck.example.com/icon.png`
+* `callback` : URL de redirection après l'authentification
+ * > Ex. : `https://missdeck.example.com/callback`
+ * Lors de la redirection, un paramètre de requête `session` contenant l'ID de session sera joint.
+* `permission` : permissions requises par l'application
+ * > Ex. : `write:notes,write:following,read:drive`
+ * Listez les permissions requises en utilisant une `,` pour les séparer.
+ * Vous pouvez vérifier quelles sont les permissions disponibles sur [les références API de Misskey](/api-doc).
-#### Step 3
-ユーザーãŒç™ºè¡Œã‚’許å¯ã—ãŸå¾Œã€`{_URL_}/api/miauth/{session}/check`ã«POSTリクエストã™ã‚‹ã¨ã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã¨ã—ã¦ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’å«ã‚€JSONãŒè¿”りã¾ã™ã€‚
+#### Étape 3
+Si vous envoyez une requête POST à `{_URL_}/api/miauth/{session}/check` une fois que l'utilisateur a validé le jeton d'accès, la réponse arrivera sous forme de fichier JSON contenant ce jeton.
-レスãƒãƒ³ã‚¹ã«å«ã¾ã‚Œã‚‹ãƒ—ロパティ:
-* `token` ... ユーザーã®ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³
-* `user` ... ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æƒ…å ±
+Propriétés incluses dans la réponse :
+* `token` : jeton d'accès de l'utilisateur
+* `user` : données de l'utilisateur
-[「APIã®ä½¿ã„æ–¹ã€ã¸é€²ã‚€](#APIã®ä½¿ã„æ–¹)
+[Continuer avec « Utiliser l'API ».](#APIã®ä½¿ã„æ–¹)
-## APIã®ä½¿ã„æ–¹
-**APIã¯ã™ã¹ã¦POSTã§ã€ãƒªã‚¯ã‚¨ã‚¹ãƒˆ/レスãƒãƒ³ã‚¹ã¨ã‚‚ã«JSONå½¢å¼ã§ã™ã€‚RESTã§ã¯ã‚りã¾ã›ã‚“。** アクセストークンã¯ã€`i`ã¨ã„ã†ãƒ‘ラメータåã§ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«å«ã‚ã¾ã™ã€‚
+## Utiliser l'API
+**L'API utilise seulement la méthode POST, et toutes les requêtes / réponses sont au format JSON. REST n'est pas pris en charge. ** Le jeton d'accès s'insère dans le paramètre de requête nommé `i`.
-* [APIリファレンス](/api-doc)
-* [ストリーミングAPI](./stream)
+* [Références API de Misskey](/api-doc)
+* [API streaming](./stream)
diff --git a/src/docs/fr-FR/create-plugin.md b/src/docs/fr-FR/create-plugin.md
index 540909de42..c0d5fa9c57 100644
--- a/src/docs/fr-FR/create-plugin.md
+++ b/src/docs/fr-FR/create-plugin.md
@@ -34,7 +34,7 @@ Misskey Webクライアントã®ãƒ—ラグイン機能を使ã†ã¨ã€ã‚¯ãƒ©ã‚¤ã‚¢
#### default
設定ã®ãƒ‡ãƒ•ォルト値
-## APIリファレンス
+## Références API de Misskey
AiScript標準ã§çµ„ã¿è¾¼ã¾ã‚Œã¦ã„ã‚‹APIã¯æŽ²è¼‰ã—ã¾ã›ã‚“。
### Mk:dialog(title text type)
diff --git a/src/docs/fr-FR/follow.md b/src/docs/fr-FR/follow.md
index 5ef74c0903..fde5c5e471 100644
--- a/src/docs/fr-FR/follow.md
+++ b/src/docs/fr-FR/follow.md
@@ -1,2 +1,2 @@
# Abonnements
-Lorsque vous suivez un·e utilisateur·rice, ses publications apparaissent dans votre fil.Cela n'inclut toutefois pas ses réponses aux autres utilisateur·ice·s. Vous pouvez vous désabonner du compte en cliquant une seconde fois.
+Lorsque vous suivez un·e utilisateur·rice, ses publications apparaissent dans votre fil.Cela n'inclut toutefois pas ses réponses aux autres utilisateur·ice·s. Pour suivre un compte, rendez-vous sur sa page et cliquez sur le bouton « s'abonner ». Vous pouvez vous désabonner du compte en cliquant une seconde fois.
diff --git a/src/docs/fr-FR/pages.md b/src/docs/fr-FR/pages.md
index 9021d41b1c..0dbafb806e 100644
--- a/src/docs/fr-FR/pages.md
+++ b/src/docs/fr-FR/pages.md
@@ -3,8 +3,8 @@
## Variables
Vous pouvez créer des pages dynamiques en utilisant des variables.Vous pouvez incorporer la valeur d'une variable en insérant le <b>{ variablename }</b> dans votre texte.Par exemple, si la valeur de la variable "thing" dans le texte <b>Hello { thing } world!</b> est <b>ai</b>, votre trexte devient alors : <b>Hello ai world!</b>.
-Les variables sont évaluées du haut vers le bas, il n'est donc pas possible de référencer une variable située plus bas que celle en cours.Par exemple, si vous définissez, dans l'ordre, 3 variables telles que <b>Aã€Bã€C</b>, vous pourrez référencer en <b>C</b> aussi bien <b>A</b> que <b>B</b> ; par contre, vous ne pourrez référencer en <b>A</b> ni <b>B</b> ni <b>C</b>.
+Les variables sont prises en compte dans l'ordre chronologique, de haut en bas. Il n'est donc pas possible d'appeler une variable située plus bas dans le code. Par exemple, si vous définissez, dans l'ordre, 3 variables telles que <b>A, B, C</b>, vous pourrez appeler en <b>C</b> aussi bien <b>A</b> que <b>B</b> ; par contre, vous ne pourrez appeler en <b>A</b> ni <b>B</b> ni <b>C</b>.
Pour recevoir une entrée utilisateur, ajoutez un bloc "Entrée" sur la page et définissez le nom des variables que vous souhaitez stocker dans le champ "Nom de la variable" (les variables seront créées automatiquement).Vous pourrez alors exécuter les actions en fonction de l'entrée utilisateur de ces variables.
-Utiliser des fonctions vous permettra de mettre en place une façon de calculer des valeurs que vous pourrez réutiliser.Pour créer des fonctions, il faut d'abord définir une variable du type "fonction".Ensuite, vous pouvez configurer des arguments dont la valeur sera utilisable comme une variable à l'intérieur de la fonction. Par ailleurs, il existe ce que l'on appelle des "fonctions d'ordre supérieur" dont les arguments sont aussi des fonctions. En plus de paramétrer des fonctions à l'avance, vous avez également la possibilité de définir des fonctions à l'improviste directement dans les arguments de ces "fonctions d'ordre supérieur".
+Appeler des fonctions vous permet de définir des valeurs que vous pourrez réutiliser. Pour créer des fonctions, il faut d'abord définir une variable du type "fonction". Vous pouvez y configurer des « slots » (arguments), dont la valeur devient alors disponible en tant que variable à l'intérieur de la fonction. Par ailleurs, il existe ce que l'on appelle des "fonctions d'ordre supérieur" dont les arguments sont aussi des fonctions. En plus de paramétrer des fonctions à l'avance, vous avez également la possibilité de définir des fonctions à l'improviste directement dans les « slots » de ces fonctions d'ordre supérieur.
diff --git a/src/docs/fr-FR/stream.md b/src/docs/fr-FR/stream.md
index 04dad66799..55e6bc6806 100644
--- a/src/docs/fr-FR/stream.md
+++ b/src/docs/fr-FR/stream.md
@@ -1,4 +1,4 @@
-# ストリーミングAPI
+# API streaming
ストリーミングAPIを使ã†ã¨ã€ãƒªã‚¢ãƒ«ã‚¿ã‚¤ãƒ ã§æ§˜ã€…ãªæƒ…å ±(例ãˆã°ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã«æ–°ã—ã„æŠ•ç¨¿ãŒæµã‚Œã¦ããŸã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒå±Šã„ãŸã€ãƒ•ォローã•れãŸã€ãªã©)ã‚’å—ã‘å–ã£ãŸã‚Šã€æ§˜ã€…ãªæ“作を行ã£ãŸã‚Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
diff --git a/src/docs/fr-FR/theme.md b/src/docs/fr-FR/theme.md
index 72c60f1c6b..cf15c921e4 100644
--- a/src/docs/fr-FR/theme.md
+++ b/src/docs/fr-FR/theme.md
@@ -6,7 +6,7 @@ Vous pouvez modifier l'apparence de votre client Misskey à l'aide de thèmes.
Paramètres > Thèmes
## Créer un thème
-Les codes des thèmes sont écrits sous forme d'objets JSON5. Les thèmes comprennent les objets suivants :
+Le code des thèmes est écrit sous forme d'objets JSON5. Les thèmes comprennent les objets suivants :
``` js
{
id: '17587283-dd92-4a2c-a22c-be0637c9e22a',
@@ -43,7 +43,7 @@ Les codes des thèmes sont écrits sous forme d'objets JSON5. Les thèmes compre
* `props` ... Définir un style de thème.Voir les explications ci-après.
### Définir un style de thème
-C'est dans `props` que vous définirez le style de thème. Les propriétés deviendront des variables CSS et les valeurs spécifieront le contenu. Par ailleurs, les objets présents par défaut dans `props` sont hérités du thème de base. Ainsi, si le thème de `base` est clair `light` ce sera l'objet [_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5) ; et s'il est sombre `dark` ce sera l'objet [_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5). Cela signifie, par exemple, que s'il n'y pas de propriété `panel` définie dans les `props` du thème, alors ce sera la valeur `panel` du thème de base qui sera prise en compte.
+C'est dans `props` que vous définirez le style de thème. Les propriétés deviendront des variables CSS et les valeurs associées spécifieront le contenu de ces variables. Par ailleurs, les objets présents par défaut dans `props` sont hérités du thème de base. Ainsi, si le thème de `base` est clair `light` ce sera l'objet [_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5) ; et s'il est sombre `dark` ce sera l'objet [_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5). Cela signifie, par exemple, que s'il n'y pas de propriété `panel` définie dans les `props` du thème, alors ce sera la valeur `panel` du thème de base qui sera prise en compte.
#### Syntaxe des valeurs
* Codes de couleur Hex
diff --git a/src/docs/it-IT/custom-emoji.md b/src/docs/it-IT/custom-emoji.md
index ed2e92be16..900f115d3c 100644
--- a/src/docs/it-IT/custom-emoji.md
+++ b/src/docs/it-IT/custom-emoji.md
@@ -1,2 +1,2 @@
-# カスタム絵文字
-カスタム絵文字ã¯ã€ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã§ç”¨æ„ã•れãŸç”»åƒã‚’絵文字ã®ã‚ˆã†ã«ä½¿ãˆã‚‹æ©Ÿèƒ½ã§ã™ã€‚ ノートã€ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã€ãƒãƒ£ãƒƒãƒˆã€è‡ªå·±ç´¹ä»‹ã€åå‰ãªã©ã®å ´æ‰€ã§ä½¿ã†ã“ã¨ãŒã§ãã¾ã™ã€‚ カスタム絵文字をãれらã®å ´æ‰€ã§ä½¿ã†ã«ã¯ã€çµµæ–‡å­—ピッカーボタン(ã‚ã‚‹å ´åˆ)を押ã™ã‹ã€`:`を入力ã—ã¦çµµæ–‡å­—サジェストを表示ã—ã¾ã™ã€‚ テキスト内ã«`:foo:`ã®ã‚ˆã†ãªå½¢å¼ã®æ–‡å­—列ãŒè¦‹ã¤ã‹ã‚‹ã¨ã€`foo`ã®éƒ¨åˆ†ãŒã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—åã¨è§£é‡ˆã•れã€è¡¨ç¤ºæ™‚ã«ã¯å¯¾å¿œã—ãŸã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—ã«ç½®ãæ›ã‚りã¾ã™ã€‚
+# Emoji personalizzati
+Gli emoji personalizzati sono una funzionalità che ti permette di usare delle immagini preparate dalla tua istanza come emoji. Si possono usare in note, reazioni, chat, nella biografia di profilo, nel tuo nome, e altrove su Misskey. Per usare gli emoji personalizzati, puoi aprire la tastiera emoji (quando c'è), oppure visualizzare suggerimenti emoji scrivendo `:`. Quando una sequenza di caratteri del tipo `:foo:` è trovata in un testo, la parte centrale `foo` viene interpretata come un nome di emoji personalizzato e quindi viene sostituita dall'emoji corrispondente.
diff --git a/src/docs/it-IT/follow.md b/src/docs/it-IT/follow.md
index f636a710f3..c54099a361 100644
--- a/src/docs/it-IT/follow.md
+++ b/src/docs/it-IT/follow.md
@@ -1,2 +1,2 @@
-# Seiguiti
-ユーザーをフォローã™ã‚‹ã¨ã€ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã«ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•稿ãŒè¡¨ç¤ºã•れるよã†ã«ãªã‚Šã¾ã™ã€‚ãŸã ã—ã€ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«å¯¾ã™ã‚‹è¿”ä¿¡ã¯å«ã¾ã‚Œã¾ã›ã‚“。 ユーザーをフォローã™ã‚‹ã«ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒšãƒ¼ã‚¸ã®ã€Œãƒ•ォローã€ãƒœã‚¿ãƒ³ã‚’クリックã—ã¾ã™ã€‚フォローを解除ã™ã‚‹ã«ã¯ã€ã‚‚ã†ä¸€åº¦ã‚¯ãƒªãƒƒã‚¯ã—ã¾ã™ã€‚
+# Follow
+Se segui un utente, le sue pubblicazioni verranno mostrate sulla tua timeline. A esclusione delle sue risposte ad altrÉ™ utenti. Per seguire un utente, bisogna premere il pulsante "seguire" della sua pagina. Premi una seconda volta sul pulsante per smettere di seguire l'account.
diff --git a/src/docs/it-IT/keyboard-shortcut.md b/src/docs/it-IT/keyboard-shortcut.md
index a547e6115e..c9bb815bae 100644
--- a/src/docs/it-IT/keyboard-shortcut.md
+++ b/src/docs/it-IT/keyboard-shortcut.md
@@ -1,17 +1,17 @@
-# キーボードショートカット
+# Scorciatoie da tastiera
-## グローãƒãƒ«
-ã“れらã®ã‚·ãƒ§ãƒ¼ãƒˆã‚«ãƒƒãƒˆã¯åŸºæœ¬çš„ã«ã©ã“ã§ã‚‚使ãˆã¾ã™ã€‚
+## Generali
+Le scorciatoie da tastiera sotto citate si possono usare praticamente ovunque.
<table>
<thead>
- <tr><th>ショートカット</th><th>効果</th><th>ç”±æ¥</th></tr>
+ <tr><th>Scorciatoia</th><th>Effetto</th><th>Accesso universale</th></tr>
</thead>
<tbody>
- <tr><td><kbd class="key">P</kbd>, <kbd class="key">N</kbd></td><td>æ–°è¦æŠ•ç¨¿</td><td><b>P</b>ost, <b>N</b>ew, <b>N</b>ote</td></tr>
- <tr><td><kbd class="key">T</kbd></td><td>ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã®æœ€ã‚‚æ–°ã—ã„æŠ•ç¨¿ã«ãƒ•ォーカス</td><td><b>T</b>imeline, <b>T</b>op</td></tr>
- <tr><td><kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">N</kbd></kbd></td><td>通知を表示/éš ã™</td><td><b>N</b>otifications</td></tr>
+ <tr><td><kbd class="key">P</kbd>, <kbd class="key">N</kbd></td><td>Nuova pubblicazione</td><td><b>P</b>ost, <b>N</b>ew, <b>N</b>ote</td></tr>
+ <tr><td><kbd class="key">T</kbd></td><td>Evidenziare l'ultima pubblicazione sulla timeline</td><td><b>T</b>imeline, <b>T</b>op</td></tr>
+ <tr><td><kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">N</kbd></kbd></td><td>Mostrare/nascondere notifiche</td><td><b>N</b>otifications</td></tr>
<tr><td><kbd class="key">S</kbd></td><td>Cerca</td><td><b>S</b>earch</td></tr>
- <tr><td><kbd class="key">H</kbd>, <kbd class="key">?</kbd></td><td>ヘルプを表示</td><td><b>H</b>elp</td></tr>
+ <tr><td><kbd class="key">H</kbd>, <kbd class="key">?</kbd></td><td>Visualizzare l'aiuto</td><td><b>H</b>elp</td></tr>
</tbody>
</table>
@@ -19,7 +19,7 @@
<table>
<thead>
- <tr><th>ショートカット</th><th>効果</th><th>ç”±æ¥</th></tr>
+ <tr><th>Scorciatoia</th><th>Effetto</th><th>Accesso universale</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key">↑</kbd>, <kbd class="key">K</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>ä¸Šã®æŠ•ç¨¿ã«ãƒ•ォーカスを移動</td><td>-</td></tr>
@@ -37,24 +37,24 @@
</tbody>
</table>
-## Renoteフォーム
+## Finestra Rinota
<table>
<thead>
- <tr><th>ショートカット</th><th>効果</th><th>ç”±æ¥</th></tr>
+ <tr><th>Scorciatoia</th><th>Effetto</th><th>Accesso universale</th></tr>
</thead>
<tbody>
- <tr><td><kbd class="key">Enter</kbd></td><td>Renoteã™ã‚‹</td><td>-</td></tr>
- <tr><td><kbd class="key">Q</kbd></td><td>フォームを展開ã™ã‚‹</td><td><b>Q</b>uote</td></tr>
- <tr><td><kbd class="key">Esc</kbd></td><td>フォームを閉ã˜ã‚‹</td><td>-</td></tr>
+ <tr><td><kbd class="key">Enter</kbd></td><td>Rinotare</td><td>-</td></tr>
+ <tr><td><kbd class="key">Q</kbd></td><td>Aprire finestra</td><td><b>Q</b>uote</td></tr>
+ <tr><td><kbd class="key">Esc</kbd></td><td>Chiudere finestra</td><td>-</td></tr>
</tbody>
</table>
-## リアクションフォーム
-デフォルトã§ã€ŒðŸ‘ã€ã«ãƒ•ォーカスãŒå½“ãŸã£ã¦ã„る状態ã§ã™ã€‚
+## Pannello reazioni
+La reazione "ðŸ‘" è impostata come reazione predefinita.
<table>
<thead>
- <tr><th>ショートカット</th><th>効果</th><th>ç”±æ¥</th></tr>
+ <tr><th>Scorciatoia</th><th>Effetto</th><th>Accesso universale</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key">↑</kbd>, <kbd class="key">K</kbd></td><td>上ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã«ãƒ•ォーカスを移動</td><td>-</td></tr>
diff --git a/src/docs/it-IT/mute.md b/src/docs/it-IT/mute.md
index a6cb073755..d0fa672f4a 100644
--- a/src/docs/it-IT/mute.md
+++ b/src/docs/it-IT/mute.md
@@ -1,13 +1,13 @@
-# Silenzia
+# Silenziare
-ユーザーをミュートã™ã‚‹ã¨ã€ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é–¢ã™ã‚‹æ¬¡ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ãŒMisskeyã«è¡¨ç¤ºã•れãªããªã‚Šã¾ã™:
+Quando si silenzia un utente, i successivi contenuti che lo riguardano non saranno più visualizzati su Misskey:
-* ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã‚„æŠ•ç¨¿ã®æ¤œç´¢çµæžœå†…ã®ã€ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•稿(ãŠã‚ˆã³ãã‚Œã‚‰ã®æŠ•ç¨¿ã«å¯¾ã™ã‚‹è¿”ä¿¡ã‚„Renote)
-* ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‹ã‚‰ã®é€šçŸ¥
-* メッセージ履歴一覧内ã®ã€ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¨ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸å±¥æ­´
+* le pubblicazioni dell'utente sia nelle timeline che nei risultati di ricerca, così come le sue risposte e Rinote;
+* le notifiche riguardo all'utente;
+* la cronologia dei messaggi scambiati con l'utente nella chat.
-ユーザーをミュートã™ã‚‹ã«ã¯ã€å¯¾è±¡ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒšãƒ¼ã‚¸ã«è¡¨ç¤ºã•れã¦ã„る「ミュートã€ãƒœã‚¿ãƒ³ã‚’押ã—ã¾ã™ã€‚
+Per silenziare un utente, premi il pulsante "Silenzia" che si trova sulla sua pagina profilo.
-ミュートを行ã£ãŸã“ã¨ã¯ç›¸æ‰‹ã«é€šçŸ¥ã•れãšã€ãƒŸãƒ¥ãƒ¼ãƒˆã•れã¦ã„ã‚‹ã“ã¨ã‚’知るã“ã¨ã‚‚ã§ãã¾ã›ã‚“。
+Gli utenti silenziati da te non vengono informati; nello stesso modo, tu non sarai infomat@ se vieni silenziat@ da un altr@ utente.
-設定>ミュート ã‹ã‚‰ã€è‡ªåˆ†ãŒãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザー一覧を確èªã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
+Puoi controllare la lista di utenti che hai silenziato nelle Impostazioni account > "Silenziati / Bloccati".
diff --git a/src/docs/it-IT/pages.md b/src/docs/it-IT/pages.md
index 81c19dd20a..5a34971f1a 100644
--- a/src/docs/it-IT/pages.md
+++ b/src/docs/it-IT/pages.md
@@ -1,4 +1,4 @@
-# Pages
+# Pagine
## Variabili
変数を使ã†ã“ã¨ã§å‹•çš„ãªãƒšãƒ¼ã‚¸ã‚’作æˆã§ãã¾ã™ã€‚テキスト内㧠<b>{ 変数å }</b> ã¨æ›¸ãã¨ãã“ã«å¤‰æ•°ã®å€¤ã‚’埋ã‚è¾¼ã‚ã¾ã™ã€‚例ãˆã° <b>Hello { thing } world!</b> ã¨ã„ã†ãƒ†ã‚­ã‚¹ãƒˆã§ã€å¤‰æ•°(thing)ã®å€¤ãŒ <b>ai</b> ã ã£ãŸå ´åˆã€ãƒ†ã‚­ã‚¹ãƒˆã¯ <b>Hello ai world!</b> ã«ãªã‚Šã¾ã™ã€‚
diff --git a/src/docs/it-IT/reaction.md b/src/docs/it-IT/reaction.md
index eac6cc88e9..f88dd99c3e 100644
--- a/src/docs/it-IT/reaction.md
+++ b/src/docs/it-IT/reaction.md
@@ -1,11 +1,11 @@
-# Reazione
-ä»–ã®äººã®ãƒŽãƒ¼ãƒˆã«ã€çµµæ–‡å­—を付ã‘ã¦ç°¡å˜ã«ã‚ãªãŸã®å応をä¼ãˆã‚‰ã‚Œã‚‹æ©Ÿèƒ½ã§ã™ã€‚ リアクションã™ã‚‹ã«ã¯ã€ãƒŽãƒ¼ãƒˆã® + アイコンをクリックã—ã¦ãƒ”ッカーを表示ã—ã€çµµæ–‡å­—ã‚’é¸æŠžã—ã¾ã™ã€‚ リアクションã«ã¯[カスタム絵文字](./custom-emoji)も使用ã§ãã¾ã™ã€‚
+# Reazioni
+Puoi mandare una reazione rapida alle note degli/delle altrÉ™ utenti apponendoci emoji. Per reagire, premi il pulsante "+" della nota per aprire il pannello reazioni e scegliere un emoji. Si possono anche usare gli [emoji personalizzati](./custom-emoji).
-## リアクションピッカーã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º
-ピッカーã«è¡¨ç¤ºã•れる絵文字を自分好ã¿ã«ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚ºã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ 設定ã®ã€Œãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã€ã§è¨­å®šã—ã¾ã™ã€‚
+## Personalizzare il pannello reazioni
+È possibile personalizzare il pannello reazioni selezionando gli emoji che vuoi usare. Puoi cambiare i predefiniti nella scheda "Reazioni" delle impostazioni.
-## リモート投稿ã¸ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã«ã¤ã„ã¦
-リアクションã¯Misskeyã‚ªãƒªã‚¸ãƒŠãƒ«ã®æ©Ÿèƒ½ã§ã‚ã‚‹ãŸã‚ã€ãƒªãƒ¢ãƒ¼ãƒˆã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒMisskeyã§ãªã„é™ã‚Šã¯ã€ã»ã¨ã‚“ã©ã®å ´åˆã€ŒLikeã€ã¨ã—ã¦ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒé€ä¿¡ã•れã¾ã™ã€‚一般的ã«ã¯Likeã¯ã€ŒãŠæ°—ã«å…¥ã‚Šã€ã¨ã—ã¦å®Ÿè£…ã•れã¦ã„るよã†ã§ã™ã€‚ ã¾ãŸã€ç›¸æ‰‹ãŒMisskeyã§ã‚ã£ãŸã¨ã—ã¦ã‚‚ã€ã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—リアクションã¯ä¼ã‚らãšã€è‡ªå‹•çš„ã«ã€ŒðŸ‘ã€ç­‰ã«ãƒ•ォールãƒãƒƒã‚¯ã•れã¾ã™ã€‚
+## Inviare reazioni a server remoti
+Siccome le reazioni sono una funzionalità originale di Misskey, vengono ricevute come semplici "Mi piace" dalla maggior parte delle istanze remote del Fediverso, a meno che non sia un'altra istanza Misskey.In genere sul Fediverso, la funzionalità "Mi piace" viene implementata come funzione "Preferiti". Inoltre, se reagisci con un emoji personalizzato verrà automaticamente inoltrato come un "ðŸ‘" o simile, anche se quella destinataria è un'istanza Misskey.
-## リモートã‹ã‚‰ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã«ã¤ã„ã¦
-リモートã‹ã‚‰ã€ŒLikeã€ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティをå—ä¿¡ã—ãŸã¨ãã€Misskeyã§ã¯ã€ŒðŸ‘ã€ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¨ã—ã¦è§£é‡ˆã•れã¾ã™ã€‚
+## Ricevere reazioni da server remoti
+I "Mi piace" ricevuti da utenti di istanze remote vengono interpretati su Misskey come reazioni a forma di "ðŸ‘".
diff --git a/src/docs/it-IT/theme.md b/src/docs/it-IT/theme.md
index b877bcd467..ad21299e89 100644
--- a/src/docs/it-IT/theme.md
+++ b/src/docs/it-IT/theme.md
@@ -1,12 +1,12 @@
# Tema
-テーマを設定ã—ã¦ã€Misskeyクライアントã®è¦‹ãŸç›®ã‚’変更ã§ãã¾ã™ã€‚
+Puoi utilizzare i temi per cambiare l'aspetto del client Misskey.
-## テーマã®è¨­å®š
-設定 > テーマ
+## Impostazioni tema
+Impostazioni > Tema
-## テーマを作æˆã™ã‚‹
-テーマコードã¯JSON5ã§è¨˜è¿°ã•れãŸãƒ†ãƒ¼ãƒžã‚ªãƒ–ジェクトã§ã™ã€‚ テーマã¯ä»¥ä¸‹ã®ã‚ˆã†ãªã‚ªãƒ–ジェクトã§ã™ã€‚
+## Creare un tema
+Il codice dei temi è scritto a forma di oggetti JSON5. I temi contengono gli oggetti sotto citati:
``` js
{
id: '17587283-dd92-4a2c-a22c-be0637c9e22a',
@@ -42,10 +42,10 @@
* テーマã¯ã“ã“ã§è¨­å®šã•れãŸãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒžã‚’継承ã—ã¾ã™ã€‚
* `props` ... テーマã®ã‚¹ã‚¿ã‚¤ãƒ«å®šç¾©ã€‚ã“れã‹ã‚‰èª¬æ˜Žã—ã¾ã™ã€‚
-### テーマã®ã‚¹ã‚¿ã‚¤ãƒ«å®šç¾©
+### Impostare uno stile di tema
`props`下ã«ã¯ãƒ†ãƒ¼ãƒžã®ã‚¹ã‚¿ã‚¤ãƒ«ã‚’定義ã—ã¾ã™ã€‚ キーãŒCSSã®å¤‰æ•°åã«ãªã‚Šã€ãƒãƒªãƒ¥ãƒ¼ã§ä¸­èº«ã‚’指定ã—ã¾ã™ã€‚ ãªãŠã€ã“ã®`props`オブジェクトã¯ãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒžã‹ã‚‰ç¶™æ‰¿ã•れã¾ã™ã€‚ ベーステーマã¯ã€ã“ã®ãƒ†ãƒ¼ãƒžã®`base`ãŒ`light`ãªã‚‰[_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5)ã§ã€`dark`ãªã‚‰[_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5)ã§ã™ã€‚ ã¤ã¾ã‚Šã€ã“ã®ãƒ†ãƒ¼ãƒžå†…ã®`props`ã«`panel`ã¨ã„ã†ã‚­ãƒ¼ãŒç„¡ãã¦ã‚‚ã€ãã“ã«ã¯ãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒžã®`panel`ãŒã‚ã‚‹ã¨è¦‹ãªã•れã¾ã™ã€‚
-#### ãƒãƒªãƒ¥ãƒ¼ã§ä½¿ãˆã‚‹æ§‹æ–‡
+#### Sintassi dei valori
* 16進数ã§è¡¨ã•れãŸè‰²
* 例: `#00ff00`
* `rgb(r, g, b)`å½¢å¼ã§è¡¨ã•れãŸè‰²
@@ -61,8 +61,8 @@
* 関数(後述)
* `:{関数å}<{引数}<{色}`
-#### Costante
+#### Costanti
「CSS変数ã¨ã—ã¦å‡ºåŠ›ã¯ã—ãŸããªã„ãŒã€ä»–ã®CSS変数ã®å€¤ã¨ã—ã¦ä½¿ã„ã¾ã‚ã—ãŸã„ã€å€¤ãŒã‚ã‚‹ã¨ãã¯ã€å®šæ•°ã‚’使ã†ã¨ä¾¿åˆ©ã§ã™ã€‚ キーåã‚’`$`ã§å§‹ã‚ã‚‹ã¨ã€ãã®ã‚­ãƒ¼ã¯CSS変数ã¨ã—ã¦å‡ºåŠ›ã•れã¾ã›ã‚“。
-#### Funzione
+#### Funzioni
wip
diff --git a/src/docs/it-IT/timelines.md b/src/docs/it-IT/timelines.md
index eb2bb65cad..bd462541d2 100644
--- a/src/docs/it-IT/timelines.md
+++ b/src/docs/it-IT/timelines.md
@@ -1,15 +1,15 @@
-# ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã®æ¯”較
+# Confronto delle timeline
https://docs.google.com/spreadsheets/d/1lxQ2ugKrhz58Bg96HTDK_2F98BUritkMyIiBkOByjHA/edit?usp=sharing
## Home
-自分ã®ãƒ•ォローã—ã¦ã„ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•ç¨¿
+Pubblicazioni degli utenti che segui.
## Locale
-å…¨ã¦ã®ãƒ­ãƒ¼ã‚«ãƒ«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã€Œãƒ›ãƒ¼ãƒ ã€æŒ‡å®šã•れã¦ã„ãªã„投稿
+Pubblicazioni degli utenti della tua istanza. Non vengono mostrate le note pubblicate con lo stato "principale".
-## ソーシャル
-自分ã®ãƒ•ォローã—ã¦ã„ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•ç¨¿ã¨ã€å…¨ã¦ã®ãƒ­ãƒ¼ã‚«ãƒ«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã€Œãƒ›ãƒ¼ãƒ ã€æŒ‡å®šã•れã¦ã„ãªã„投稿
+## Sociale
+Raggruppa le timeline "home" e "locale".
## グローãƒãƒ«
-å…¨ã¦ã®ãƒ­ãƒ¼ã‚«ãƒ«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã€Œãƒ›ãƒ¼ãƒ ã€æŒ‡å®šã•れã¦ã„ãªã„投稿ã¨ã€ã‚µãƒ¼ãƒãƒ¼ã«å±Šã„ãŸå…¨ã¦ã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã€Œãƒ›ãƒ¼ãƒ ã€æŒ‡å®šã•れã¦ã„ãªã„投稿
+Tutte le pubblicazioni ricevute dall'istanza, sia locali che altre. Non vengono mostrate le note pubblicate con lo stato "home".
diff --git a/src/global.d.ts b/src/global.d.ts
new file mode 100644
index 0000000000..7343aa1994
--- /dev/null
+++ b/src/global.d.ts
@@ -0,0 +1 @@
+type FIXME = any;
diff --git a/src/misc/before-shutdown.ts b/src/misc/before-shutdown.ts
new file mode 100644
index 0000000000..8639d42b04
--- /dev/null
+++ b/src/misc/before-shutdown.ts
@@ -0,0 +1,90 @@
+// https://gist.github.com/nfantone/1eaa803772025df69d07f4dbf5df7e58
+
+'use strict';
+
+/**
+ * @callback BeforeShutdownListener
+ * @param {string} [signalOrEvent] The exit signal or event name received on the process.
+ */
+
+/**
+ * System signals the app will listen to initiate shutdown.
+ * @const {string[]}
+ */
+const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM'];
+
+/**
+ * Time in milliseconds to wait before forcing shutdown.
+ * @const {number}
+ */
+const SHUTDOWN_TIMEOUT = 15000;
+
+/**
+ * A queue of listener callbacks to execute before shutting
+ * down the process.
+ * @type {BeforeShutdownListener[]}
+ */
+const shutdownListeners = [];
+
+/**
+ * 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) => {
+ for (const sig of signals) {
+ process.once(sig, 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 => () => {
+ setTimeout(() => {
+ // Force shutdown after timeout
+ console.warn(`Could not close resources gracefully after ${timeout}ms: forcing shutdown`);
+ return process.exit(1);
+ }, timeout).unref();
+};
+
+/**
+ * Main process shutdown handler. Will invoke every previously registered async shutdown listener
+ * in the queue and exit with a code of `0`. Any `Promise` rejections from any listener will
+ * 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) {
+ console.warn(`Shutting down: received [${signalOrEvent}] signal`);
+
+ for (const listener of shutdownListeners) {
+ try {
+ await listener(signalOrEvent);
+ } catch (err) {
+ console.warn(`A shutdown handler failed before completing with: ${err.message || err}`);
+ }
+ }
+
+ return process.exit(0);
+}
+
+/**
+ * Registers a new shutdown listener to be invoked before exiting
+ * the main process. Listener handlers are guaranteed to be called in the order
+ * they were registered.
+ * @param {BeforeShutdownListener} listener The shutdown listener to register.
+ * @returns {BeforeShutdownListener} Echoes back the supplied `listener`.
+ */
+export function beforeShutdown(listener) {
+ shutdownListeners.push(listener);
+ return listener;
+}
+
+// Register shutdown callback that kills the process after `SHUTDOWN_TIMEOUT` milliseconds
+// This prevents custom shutdown handlers from hanging the process indefinitely
+processOnce(SHUTDOWN_SIGNALS, forceExitAfter(SHUTDOWN_TIMEOUT));
+
+// Register process shutdown callback
+// Will listen to incoming signal events and execute all registered handlers in the stack
+processOnce(SHUTDOWN_SIGNALS, shutdownHandler);
diff --git a/src/misc/cache.ts b/src/misc/cache.ts
new file mode 100644
index 0000000000..71fbbd8a4c
--- /dev/null
+++ b/src/misc/cache.ts
@@ -0,0 +1,43 @@
+export class Cache<T> {
+ private cache: Map<string | null, { date: number; value: T; }>;
+ private lifetime: number;
+
+ constructor(lifetime: Cache<never>['lifetime']) {
+ this.cache = new Map();
+ this.lifetime = lifetime;
+ }
+
+ public set(key: string | null, value: T): void {
+ this.cache.set(key, {
+ date: Date.now(),
+ value
+ });
+ }
+
+ public get(key: string | null): T | undefined {
+ const cached = this.cache.get(key);
+ if (cached == null) return undefined;
+ if ((Date.now() - cached.date) > this.lifetime) {
+ this.cache.delete(key);
+ return undefined;
+ }
+ return cached.value;
+ }
+
+ public delete(key: string | null) {
+ this.cache.delete(key);
+ }
+
+ public async fetch(key: string | null, fetcher: () => Promise<T>): Promise<T> {
+ const cachedValue = this.get(key);
+ if (cachedValue !== undefined) {
+ // Cache HIT
+ return cachedValue;
+ }
+
+ // Cache MISS
+ const value = await fetcher();
+ this.set(key, value);
+ return value;
+ }
+}
diff --git a/src/misc/fetch-meta.ts b/src/misc/fetch-meta.ts
index 680cf37a72..e7a945dc9e 100644
--- a/src/misc/fetch-meta.ts
+++ b/src/misc/fetch-meta.ts
@@ -32,4 +32,4 @@ setInterval(() => {
fetchMeta(true).then(meta => {
cache = meta;
});
-}, 5000);
+}, 1000 * 10);
diff --git a/src/misc/keypair-store.ts b/src/misc/keypair-store.ts
new file mode 100644
index 0000000000..c78fdd7555
--- /dev/null
+++ b/src/misc/keypair-store.ts
@@ -0,0 +1,10 @@
+import { UserKeypairs } from '../models';
+import { User } from '../models/entities/user';
+import { UserKeypair } from '../models/entities/user-keypair';
+import { Cache } from './cache';
+
+const cache = new Cache<UserKeypair>(Infinity);
+
+export async function getUserKeypair(userId: User['id']): Promise<UserKeypair> {
+ return await cache.fetch(userId, () => UserKeypairs.findOneOrFail(userId));
+}
diff --git a/src/misc/populate-emojis.ts b/src/misc/populate-emojis.ts
new file mode 100644
index 0000000000..8052c71489
--- /dev/null
+++ b/src/misc/populate-emojis.ts
@@ -0,0 +1,119 @@
+import { In } from 'typeorm';
+import { Emojis } from '../models';
+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';
+
+const cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12);
+
+/**
+ * 添付用絵文字情報
+ */
+type PopulatedEmoji = {
+ name: string;
+ url: string;
+};
+
+function normalizeHost(src: string | undefined, noteUserHost: string | null): string | null {
+ // クエリã«ä½¿ã†ãƒ›ã‚¹ãƒˆ
+ let host = src === '.' ? null // .ã¯ãƒ­ãƒ¼ã‚«ãƒ«ãƒ›ã‚¹ãƒˆ (ã“ã“ãŒãƒžãƒƒãƒã™ã‚‹ã®ã¯ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã®ã¿)
+ : src === undefined ? noteUserHost // ノートãªã©ã§ãƒ›ã‚¹ãƒˆçœç•¥è¡¨è¨˜ã®å ´åˆã¯ãƒ­ãƒ¼ã‚«ãƒ«ãƒ›ã‚¹ãƒˆ (ã“ã“ãŒãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã«ãƒžãƒƒãƒã™ã‚‹ã“ã¨ã¯ãªã„)
+ : isSelfHost(src) ? null // 自ホスト指定
+ : (src || noteUserHost); // 指定ã•れãŸãƒ›ã‚¹ãƒˆ || ノートãªã©ã®æ‰€æœ‰è€…ã®ãƒ›ã‚¹ãƒˆ (ã“ã£ã¡ãŒãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã«ãƒžãƒƒãƒã™ã‚‹ã“ã¨ã¯ãªã„)
+
+ host = toPunyNullable(host);
+
+ return host;
+}
+
+function parseEmojiStr(emojiName: string, noteUserHost: string | null) {
+ const match = emojiName.match(/^(\w+)(?:@([\w.-]+))?$/);
+ if (!match) return { name: null, host: null };
+
+ const name = match[1];
+
+ // ホスト正è¦åŒ–
+ const host = toPunyNullable(normalizeHost(match[2], noteUserHost));
+
+ return { name, host };
+}
+
+/**
+ * 添付用絵文字情報を解決ã™ã‚‹
+ * @param emojiName ãƒŽãƒ¼ãƒˆã‚„ãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒ—ãƒ­ãƒ•ã‚£ãƒ¼ãƒ«ã«æ·»ä»˜ã•れãŸã€ã¾ãŸã¯ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã®ã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—å (:ã¯å«ã‚ãªã„, リアクションã§ãƒ­ãƒ¼ã‚«ãƒ«ãƒ›ã‚¹ãƒˆã®å ´åˆã¯@.を付ã‘ã‚‹ (ã“れã¯decodeReactionã§å¯èƒ½))
+ * @param noteUserHost ãƒŽãƒ¼ãƒˆã‚„ãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒ—ãƒ­ãƒ•ã‚£ãƒ¼ãƒ«ã®æ‰€æœ‰è€…ã®ãƒ›ã‚¹ãƒˆ
+ * @returns 絵文字情報, nullã¯æœªãƒžãƒƒãƒã‚’æ„味ã™ã‚‹
+ */
+export async function populateEmoji(emojiName: string, noteUserHost: string | null): Promise<PopulatedEmoji | null> {
+ const { name, host } = parseEmojiStr(emojiName, noteUserHost);
+ if (name == null) return null;
+
+ const queryOrNull = async () => (await Emojis.findOne({
+ name,
+ host
+ })) || null;
+
+ const emoji = await cache.fetch(`${name} ${host}`, queryOrNull);
+
+ if (emoji == null) return null;
+
+ return {
+ name: emojiName,
+ url: emoji.url,
+ };
+}
+
+/**
+ * è¤‡æ•°ã®æ·»ä»˜ç”¨çµµæ–‡å­—情報を解決ã™ã‚‹ (キャシュ付ã, 存在ã—ãªã„ã‚‚ã®ã¯çµæžœã‹ã‚‰é™¤å¤–ã•れる)
+ */
+export async function populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise<PopulatedEmoji[]> {
+ const emojis = await Promise.all(emojiNames.map(x => populateEmoji(x, noteUserHost)));
+ return emojis.filter((x): x is PopulatedEmoji => x != null);
+}
+
+export function aggregateNoteEmojis(notes: Note[]) {
+ let emojis: { name: string | null; host: string | null; }[] = [];
+ for (const note of notes) {
+ emojis = emojis.concat(note.emojis
+ .map(e => parseEmojiStr(e, note.userHost)));
+ if (note.renote) {
+ emojis = emojis.concat(note.renote.emojis
+ .map(e => parseEmojiStr(e, note.renote!.userHost)));
+ if (note.renote.user) {
+ emojis = emojis.concat(note.renote.user.emojis
+ .map(e => parseEmojiStr(e, note.renote!.userHost)));
+ }
+ }
+ const customReactions = Object.keys(note.reactions).map(x => decodeReaction(x)).filter(x => x.name != null) as typeof emojis;
+ emojis = emojis.concat(customReactions);
+ if (note.user) {
+ emojis = emojis.concat(note.user.emojis
+ .map(e => parseEmojiStr(e, note.userHost)));
+ }
+ }
+ return emojis.filter(x => x.name != null) as { name: string; host: string | null; }[];
+}
+
+/**
+ * 与ãˆã‚‰ã‚ŒãŸçµµæ–‡å­—ã®ãƒªã‚¹ãƒˆã‚’データベースã‹ã‚‰å–å¾—ã—ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã«è¿½åŠ ã—ã¾ã™
+ */
+export async function prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise<void> {
+ const notCachedEmojis = emojis.filter(emoji => cache.get(`${emoji.name} ${emoji.host}`) == null);
+ const emojisQuery: any[] = [];
+ const hosts = new Set(notCachedEmojis.map(e => e.host));
+ for (const host of hosts) {
+ emojisQuery.push({
+ name: In(notCachedEmojis.filter(e => e.host === host).map(e => e.name)),
+ host: host
+ });
+ }
+ const _emojis = emojisQuery.length > 0 ? await Emojis.find({
+ where: emojisQuery,
+ select: ['name', 'host', 'url']
+ }) : [];
+ for (const emoji of _emojis) {
+ cache.set(`${emoji.name} ${emoji.host}`, emoji);
+ }
+}
diff --git a/src/models/entities/drive-file.ts b/src/models/entities/drive-file.ts
index 680a40bc06..698dfac222 100644
--- a/src/models/entities/drive-file.ts
+++ b/src/models/entities/drive-file.ts
@@ -77,7 +77,7 @@ export class DriveFile {
default: {},
comment: 'The any properties of the DriveFile. For example, it includes image width/height.'
})
- public properties: Record<string, any>;
+ public properties: { width?: number; height?: number; avgColor?: string };
@Index()
@Column('boolean')
diff --git a/src/models/entities/note-reaction.ts b/src/models/entities/note-reaction.ts
index 69bb663fd3..674dc3639e 100644
--- a/src/models/entities/note-reaction.ts
+++ b/src/models/entities/note-reaction.ts
@@ -23,7 +23,7 @@ export class NoteReaction {
onDelete: 'CASCADE'
})
@JoinColumn()
- public user: User | null;
+ public user?: User | null;
@Index()
@Column(id())
@@ -33,7 +33,7 @@ export class NoteReaction {
onDelete: 'CASCADE'
})
@JoinColumn()
- public note: Note | null;
+ public note?: Note | null;
// TODO: 対象noteã®userIdã‚’éžæ­£è¦åŒ–ã—ãŸã„(「å—ã‘å–ã£ãŸãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ä¸€è¦§ã€ã®ã‚ˆã†ãªã‚‚ã®ã‚’(JOINç„¡ã—ã§)実装ã—ãŸã„ãŸã‚)
diff --git a/src/models/repositories/antenna.ts b/src/models/repositories/antenna.ts
index 0f0a5c0171..84e082bd25 100644
--- a/src/models/repositories/antenna.ts
+++ b/src/models/repositories/antenna.ts
@@ -56,16 +56,24 @@ export const packedAntennaSchema = {
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
+ 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
+ }
}
},
- execludeKeywords: {
+ excludeKeywords: {
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
+ 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
+ }
}
},
src: {
diff --git a/src/models/repositories/drive-file.ts b/src/models/repositories/drive-file.ts
index 5085c76e92..61d24bd24e 100644
--- a/src/models/repositories/drive-file.ts
+++ b/src/models/repositories/drive-file.ts
@@ -12,6 +12,12 @@ import { fetchMeta } from '../../misc/fetch-meta';
export type PackedDriveFile = SchemaType<typeof packedDriveFileSchema>;
+type PackOptions = {
+ detail?: boolean,
+ self?: boolean,
+ withUser?: boolean,
+};
+
@EntityRepository(DriveFile)
export class DriveFileRepository extends Repository<DriveFile> {
public validateFileName(name: string): boolean {
@@ -89,20 +95,19 @@ export class DriveFileRepository extends Repository<DriveFile> {
return parseInt(sum, 10) || 0;
}
+ public async pack(src: DriveFile['id'], options?: PackOptions): Promise<PackedDriveFile | null>;
+ public async pack(src: DriveFile, options?: PackOptions): Promise<PackedDriveFile>;
public async pack(
src: DriveFile['id'] | DriveFile,
- options?: {
- detail?: boolean,
- self?: boolean,
- withUser?: boolean,
- }
- ): Promise<PackedDriveFile> {
+ options?: PackOptions
+ ): Promise<PackedDriveFile | null> {
const opts = Object.assign({
detail: false,
self: false
}, options);
- const file = typeof src === 'object' ? src : await this.findOneOrFail(src);
+ const file = typeof src === 'object' ? src : await this.findOne(src);
+ if (file == null) return null;
const meta = await fetchMeta();
@@ -128,15 +133,12 @@ export class DriveFileRepository extends Repository<DriveFile> {
});
}
- public packMany(
- files: any[],
- options?: {
- detail?: boolean
- self?: boolean,
- withUser?: boolean,
- }
+ public async packMany(
+ files: (DriveFile['id'] | DriveFile)[],
+ options?: PackOptions
) {
- return Promise.all(files.map(f => this.pack(f, options)));
+ const items = await Promise.all(files.map(f => this.pack(f, options)));
+ return items.filter(x => x != null);
}
}
@@ -197,12 +199,12 @@ export const packedDriveFileSchema = {
properties: {
width: {
type: 'number' as const,
- optional: false as const, nullable: false as const,
+ optional: true as const, nullable: false as const,
example: 1280
},
height: {
type: 'number' as const,
- optional: false as const, nullable: false as const,
+ optional: true as const, nullable: false as const,
example: 720
},
avgColor: {
diff --git a/src/models/repositories/note.ts b/src/models/repositories/note.ts
index 32552db2fe..73e18f6c5b 100644
--- a/src/models/repositories/note.ts
+++ b/src/models/repositories/note.ts
@@ -1,14 +1,14 @@
import { EntityRepository, Repository, In } from 'typeorm';
import { Note } from '../entities/note';
import { User } from '../entities/user';
-import { Emojis, Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls, Channels } from '..';
+import { Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls, Channels } from '..';
import { SchemaType } from '../../misc/schema';
import { awaitAll } from '../../prelude/await-all';
import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '../../misc/reaction-lib';
import { toString } from '../../mfm/to-string';
import { parse } from '../../mfm/parse';
-import { Emoji } from '../entities/emoji';
-import { concat } from '../../prelude/array';
+import { NoteReaction } from '../entities/note-reaction';
+import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '../../misc/populate-emojis';
export type PackedNote = SchemaType<typeof packedNoteSchema>;
@@ -83,6 +83,9 @@ export class NoteRepository extends Repository<Note> {
options?: {
detail?: boolean;
skipHide?: boolean;
+ _hint_?: {
+ myReactions: Map<Note['id'], NoteReaction | null>;
+ };
}
): Promise<PackedNote> {
const opts = Object.assign({
@@ -130,64 +133,17 @@ export class NoteRepository extends Repository<Note> {
};
}
- /**
- * 添付用emojisを解決ã™ã‚‹
- * @param emojiNames Noteç­‰ã«æ·»ä»˜ã•れãŸã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—å (:ã¯å«ã‚ãªã„)
- * @param noteUserHost Noteã®ãƒ›ã‚¹ãƒˆ
- * @param reactionNames Noteç­‰ã«ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã•れãŸã‚«ã‚¹ã‚¿ãƒ çµµæ–‡å­—å (:ã¯å«ã‚ãªã„)
- */
- async function populateEmojis(emojiNames: string[], noteUserHost: string | null, reactionNames: string[]) {
- let all = [] as {
- name: string,
- url: string
- }[];
-
- // カスタム絵文字
- if (emojiNames?.length > 0) {
- const tmp = await Emojis.find({
- where: {
- name: In(emojiNames),
- host: noteUserHost
- },
- select: ['name', 'host', 'url']
- }).then(emojis => emojis.map((emoji: Emoji) => {
- return {
- name: emoji.name,
- url: emoji.url,
- };
- }));
-
- all = concat([all, tmp]);
- }
-
- const customReactions = reactionNames?.map(x => decodeReaction(x)).filter(x => x.name);
-
- if (customReactions?.length > 0) {
- const where = [] as {}[];
-
- for (const customReaction of customReactions) {
- where.push({
- name: customReaction.name,
- host: customReaction.host
- });
+ async function populateMyReaction() {
+ if (options?._hint_?.myReactions) {
+ const reaction = options._hint_.myReactions.get(note.id);
+ if (reaction) {
+ return convertLegacyReaction(reaction.reaction);
+ } else if (reaction === null) {
+ return undefined;
}
-
- const tmp = await Emojis.find({
- where,
- select: ['name', 'host', 'url']
- }).then(emojis => emojis.map((emoji: Emoji) => {
- return {
- name: `${emoji.name}@${emoji.host || '.'}`, // @host付ãã§ãƒ­ãƒ¼ã‚«ãƒ«ã¯.
- url: emoji.url,
- };
- }));
- all = concat([all, tmp]);
+ // 実装上抜ã‘ãŒã‚ã‚‹ã ã‘ã‹ã‚‚ã—れãªã„ã®ã§ã€ã€Œãƒ’ントã«å«ã¾ã‚Œã¦ãªã‹ã£ãŸã‚‰(=undefinedãªã‚‰)returnã€ã®ã‚ˆã†ã«ã¯ã—ãªã„
}
- return all;
- }
-
- async function populateMyReaction() {
const reaction = await NoteReactions.findOne({
userId: meId!,
noteId: note.id,
@@ -212,11 +168,15 @@ export class NoteRepository extends Repository<Note> {
: await Channels.findOne(note.channelId)
: null;
+ const reactionEmojiNames = Object.keys(note.reactions).filter(x => x?.startsWith(':')).map(x => decodeReaction(x).reaction).map(x => x.replace(/:/g, ''));
+
const packed = await awaitAll({
id: note.id,
createdAt: note.createdAt.toISOString(),
userId: note.userId,
- user: Users.pack(note.user || note.userId, meId),
+ user: Users.pack(note.user || note.userId, meId, {
+ detail: false,
+ }),
text: text,
cw: note.cw,
visibility: note.visibility,
@@ -227,7 +187,7 @@ export class NoteRepository extends Repository<Note> {
repliesCount: note.repliesCount,
reactions: convertLegacyReactions(note.reactions),
tags: note.tags.length > 0 ? note.tags : undefined,
- emojis: populateEmojis(note.emojis, host, Object.keys(note.reactions)),
+ emojis: populateEmojis(note.emojis.concat(reactionEmojiNames), host),
fileIds: note.fileIds,
files: DriveFiles.packMany(note.fileIds),
replyId: note.replyId,
@@ -244,12 +204,14 @@ export class NoteRepository extends Repository<Note> {
_prId_: (note as any)._prId_ || undefined,
...(opts.detail ? {
- reply: note.replyId ? this.pack(note.replyId, meId, {
- detail: false
+ reply: note.replyId ? this.pack(note.reply || note.replyId, meId, {
+ detail: false,
+ _hint_: options?._hint_
}) : undefined,
- renote: note.renoteId ? this.pack(note.renoteId, meId, {
- detail: true
+ renote: note.renoteId ? this.pack(note.renote || note.renoteId, meId, {
+ detail: true,
+ _hint_: options?._hint_
}) : undefined,
poll: note.hasPoll ? populatePoll() : undefined,
@@ -272,15 +234,39 @@ export class NoteRepository extends Repository<Note> {
return packed;
}
- public packMany(
- notes: (Note['id'] | Note)[],
+ public async packMany(
+ notes: Note[],
me?: User['id'] | User | null | undefined,
options?: {
detail?: boolean;
skipHide?: boolean;
}
) {
- return Promise.all(notes.map(n => this.pack(n, me, options)));
+ if (notes.length === 0) return [];
+
+ const meId = me ? typeof me === 'string' ? me : me.id : null;
+ const myReactionsMap = new Map<Note['id'], NoteReaction | null>();
+ if (meId) {
+ const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!);
+ const targets = [...notes.map(n => n.id), ...renoteIds];
+ const myReactions = await NoteReactions.find({
+ userId: meId,
+ noteId: In(targets),
+ });
+
+ for (const target of targets) {
+ myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) || null);
+ }
+ }
+
+ await prefetchEmojis(aggregateNoteEmojis(notes));
+
+ return await Promise.all(notes.map(n => this.pack(n, me, {
+ ...options,
+ _hint_: {
+ myReactions: myReactionsMap
+ }
+ })));
}
}
diff --git a/src/models/repositories/notification.ts b/src/models/repositories/notification.ts
index 16de6c8c25..83fe11d5f7 100644
--- a/src/models/repositories/notification.ts
+++ b/src/models/repositories/notification.ts
@@ -1,8 +1,12 @@
-import { EntityRepository, Repository } from 'typeorm';
-import { Users, Notes, UserGroupInvitations, AccessTokens } from '..';
+import { EntityRepository, In, Repository } from 'typeorm';
+import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '..';
import { Notification } from '../entities/notification';
import { awaitAll } from '../../prelude/await-all';
import { SchemaType } from '../../misc/schema';
+import { Note } from '../entities/note';
+import { NoteReaction } from '../entities/note-reaction';
+import { User } from '../entities/user';
+import { aggregateNoteEmojis, prefetchEmojis } from '../../misc/populate-emojis';
export type PackedNotification = SchemaType<typeof packedNotificationSchema>;
@@ -10,6 +14,11 @@ export type PackedNotification = SchemaType<typeof packedNotificationSchema>;
export class NotificationRepository extends Repository<Notification> {
public async pack(
src: Notification['id'] | Notification,
+ options: {
+ _hintForEachNotes_?: {
+ myReactions: Map<Note['id'], NoteReaction | null>;
+ };
+ }
): Promise<PackedNotification> {
const notification = typeof src === 'object' ? src : await this.findOneOrFail(src);
const token = notification.appAccessTokenId ? await AccessTokens.findOneOrFail(notification.appAccessTokenId) : null;
@@ -22,23 +31,41 @@ export class NotificationRepository extends Repository<Notification> {
userId: notification.notifierId,
user: notification.notifierId ? Users.pack(notification.notifier || notification.notifierId) : null,
...(notification.type === 'mention' ? {
- note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId),
+ note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, {
+ detail: true,
+ _hint_: options._hintForEachNotes_
+ }),
} : {}),
...(notification.type === 'reply' ? {
- note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId),
+ note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, {
+ detail: true,
+ _hint_: options._hintForEachNotes_
+ }),
} : {}),
...(notification.type === 'renote' ? {
- note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId),
+ note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, {
+ detail: true,
+ _hint_: options._hintForEachNotes_
+ }),
} : {}),
...(notification.type === 'quote' ? {
- note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId),
+ note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, {
+ detail: true,
+ _hint_: options._hintForEachNotes_
+ }),
} : {}),
...(notification.type === 'reaction' ? {
- note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId),
+ note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, {
+ detail: true,
+ _hint_: options._hintForEachNotes_
+ }),
reaction: notification.reaction
} : {}),
...(notification.type === 'pollVote' ? {
- note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId),
+ note: Notes.pack(notification.note || notification.noteId!, notification.notifieeId, {
+ detail: true,
+ _hint_: options._hintForEachNotes_
+ }),
choice: notification.choice
} : {}),
...(notification.type === 'groupInvited' ? {
@@ -52,10 +79,33 @@ export class NotificationRepository extends Repository<Notification> {
});
}
- public packMany(
- notifications: any[],
+ public async packMany(
+ notifications: Notification[],
+ meId: User['id']
) {
- return Promise.all(notifications.map(x => this.pack(x)));
+ if (notifications.length === 0) return [];
+
+ const notes = notifications.filter(x => x.note != null).map(x => x.note!);
+ const noteIds = notes.map(n => n.id);
+ const myReactionsMap = new Map<Note['id'], NoteReaction | null>();
+ const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!);
+ const targets = [...noteIds, ...renoteIds];
+ const myReactions = await NoteReactions.find({
+ userId: meId,
+ noteId: In(targets),
+ });
+
+ for (const target of targets) {
+ myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) || null);
+ }
+
+ await prefetchEmojis(aggregateNoteEmojis(notes));
+
+ return await Promise.all(notifications.map(x => this.pack(x, {
+ _hintForEachNotes_: {
+ myReactions: myReactionsMap
+ }
+ })));
}
}
diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts
index 3a6ab48c5f..53c06f3f16 100644
--- a/src/models/repositories/user.ts
+++ b/src/models/repositories/user.ts
@@ -1,10 +1,11 @@
import $ from 'cafy';
import { EntityRepository, Repository, In, Not } from 'typeorm';
import { User, ILocalUser, IRemoteUser } from '../entities/user';
-import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '..';
+import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '..';
import config from '../../config';
import { SchemaType } from '../../misc/schema';
import { awaitAll } from '../../prelude/await-all';
+import { populateEmojis } from '../../misc/populate-emojis';
export type PackedUser = SchemaType<typeof packedUserSchema>;
@@ -160,10 +161,11 @@ export class UserRepository extends Repository<User> {
const meId = me ? typeof me === 'string' ? me : me.id : null;
const relation = meId && (meId !== user.id) && opts.detail ? await this.getRelation(meId, user.id) : null;
- const pins = opts.detail ? await UserNotePinings.find({
- where: { userId: user.id },
- order: { id: 'DESC' }
- }) : [];
+ const pins = opts.detail ? await UserNotePinings.createQueryBuilder('pin')
+ .where('pin.userId = :userId', { userId: user.id })
+ .innerJoinAndSelect('pin.note', 'note')
+ .orderBy('pin.id', 'DESC')
+ .getMany() : [];
const profile = opts.detail ? await UserProfiles.findOneOrFail(user.id) : null;
const falsy = opts.detail ? false : undefined;
@@ -188,15 +190,7 @@ export class UserRepository extends Repository<User> {
faviconUrl: instance.faviconUrl,
themeColor: instance.themeColor,
} : undefined) : undefined,
-
- // カスタム絵文字添付
- emojis: user.emojis.length > 0 ? Emojis.find({
- where: {
- name: In(user.emojis),
- host: user.host
- },
- select: ['name', 'host', 'url', 'aliases']
- }) : [],
+ emojis: populateEmojis(user.emojis, user.host),
...(opts.detail ? {
url: profile!.url,
@@ -218,7 +212,7 @@ export class UserRepository extends Repository<User> {
followingCount: user.followingCount,
notesCount: user.notesCount,
pinnedNoteIds: pins.map(pin => pin.noteId),
- pinnedNotes: Notes.packMany(pins.map(pin => pin.noteId), meId, {
+ pinnedNotes: Notes.packMany(pins.map(pin => pin.note!), meId, {
detail: true
}),
pinnedPageId: profile!.pinnedPageId,
diff --git a/src/queue/index.ts b/src/queue/index.ts
index 163c57d691..9fb4595a35 100644
--- a/src/queue/index.ts
+++ b/src/queue/index.ts
@@ -1,4 +1,3 @@
-import * as Queue from 'bull';
import * as httpSignature from 'http-signature';
import config from '../config';
@@ -13,22 +12,7 @@ import { queueLogger } from './logger';
import { DriveFile } from '../models/entities/drive-file';
import { getJobInfo } from './get-job-info';
import { IActivity } from '../remote/activitypub/type';
-
-function initializeQueue(name: string, limitPerSec = -1) {
- return new Queue(name, {
- redis: {
- port: config.redis.port,
- host: config.redis.host,
- password: config.redis.pass,
- db: config.redis.db || 0,
- },
- prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : 'queue',
- limiter: limitPerSec > 0 ? {
- max: limitPerSec * 5,
- duration: 5000
- } : undefined
- });
-}
+import { dbQueue, deliverQueue, inboxQueue, objectStorageQueue } from './queues';
export type InboxJobData = {
activity: IActivity,
@@ -44,11 +28,6 @@ function renderError(e: Error): any {
};
}
-export const deliverQueue = initializeQueue('deliver', config.deliverJobPerSec || 128);
-export const inboxQueue = initializeQueue('inbox', config.inboxJobPerSec || 16);
-export const dbQueue = initializeQueue('db');
-export const objectStorageQueue = initializeQueue('objectStorage');
-
const deliverLogger = queueLogger.createSubLogger('deliver');
const inboxLogger = queueLogger.createSubLogger('inbox');
const dbLogger = queueLogger.createSubLogger('db');
diff --git a/src/queue/initialize.ts b/src/queue/initialize.ts
new file mode 100644
index 0000000000..92579531e4
--- /dev/null
+++ b/src/queue/initialize.ts
@@ -0,0 +1,18 @@
+import * as Queue from 'bull';
+import config from '../config';
+
+export function initialize(name: string, limitPerSec = -1) {
+ return new Queue(name, {
+ redis: {
+ port: config.redis.port,
+ host: config.redis.host,
+ password: config.redis.pass,
+ db: config.redis.db || 0,
+ },
+ prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : 'queue',
+ limiter: limitPerSec > 0 ? {
+ max: limitPerSec * 5,
+ duration: 5000
+ } : undefined
+ });
+}
diff --git a/src/queue/processors/deliver.ts b/src/queue/processors/deliver.ts
index cb7587ef81..a8b4ed4fe3 100644
--- a/src/queue/processors/deliver.ts
+++ b/src/queue/processors/deliver.ts
@@ -7,11 +7,15 @@ import { instanceChart } from '../../services/chart';
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';
const logger = new Logger('deliver');
let latest: string | null = null;
+const suspendedHostsCache = new Cache<Instance[]>(1000 * 60 * 60);
+
export default async (job: Bull.Job) => {
const { host } = new URL(job.data.to);
@@ -22,12 +26,15 @@ export default async (job: Bull.Job) => {
}
// isSuspendedãªã‚‰ä¸­æ–­
- const suspendedHosts = await Instances.find({
- where: {
- isSuspended: true
- },
- cache: 60 * 1000
- });
+ let suspendedHosts = suspendedHostsCache.get(null);
+ if (suspendedHosts == null) {
+ suspendedHosts = await Instances.find({
+ where: {
+ isSuspended: true
+ },
+ });
+ suspendedHostsCache.set(null, suspendedHosts);
+ }
if (suspendedHosts.map(x => x.host).includes(toPuny(host))) {
return 'skip (suspended)';
}
diff --git a/src/queue/processors/inbox.ts b/src/queue/processors/inbox.ts
index b4e8b85a46..a5822ff25f 100644
--- a/src/queue/processors/inbox.ts
+++ b/src/queue/processors/inbox.ts
@@ -40,6 +40,7 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
return `Old keyId is no longer supported. ${keyIdLower}`;
}
+ // TDOO: キャッシュ
const dbResolver = new DbResolver();
// HTTP-Signature keyIdã‚’å…ƒã«DBã‹ã‚‰å–å¾—
diff --git a/src/queue/queues.ts b/src/queue/queues.ts
new file mode 100644
index 0000000000..d589d9f7da
--- /dev/null
+++ b/src/queue/queues.ts
@@ -0,0 +1,7 @@
+import config from '../config';
+import { initialize as initializeQueue } from './initialize';
+
+export const deliverQueue = initializeQueue('deliver', config.deliverJobPerSec || 128);
+export const inboxQueue = initializeQueue('inbox', config.inboxJobPerSec || 16);
+export const dbQueue = initializeQueue('db');
+export const objectStorageQueue = initializeQueue('objectStorage');
diff --git a/src/remote/activitypub/deliver-manager.ts b/src/remote/activitypub/deliver-manager.ts
index d147b3c9b0..92721f5525 100644
--- a/src/remote/activitypub/deliver-manager.ts
+++ b/src/remote/activitypub/deliver-manager.ts
@@ -76,7 +76,7 @@ export default class DeliverManager {
public async execute() {
if (!Users.isLocalUser(this.actor)) return;
- const inboxes: string[] = [];
+ const inboxes = new Set<string>();
// build inbox list
for (const recipe of this.recipes) {
@@ -89,13 +89,13 @@ export default class DeliverManager {
for (const following of followers) {
if (Followings.isRemoteFollower(following)) {
const inbox = following.followerSharedInbox || following.followerInbox;
- if (!inboxes.includes(inbox)) inboxes.push(inbox);
+ inboxes.add(inbox);
}
}
} else if (isDirect(recipe)) {
// direct deliver
const inbox = recipe.to.inbox;
- if (inbox && !inboxes.includes(inbox)) inboxes.push(inbox);
+ if (inbox) inboxes.add(inbox);
}
}
diff --git a/src/remote/activitypub/renderer/index.ts b/src/remote/activitypub/renderer/index.ts
index e74affdadf..4c33fdafb1 100644
--- a/src/remote/activitypub/renderer/index.ts
+++ b/src/remote/activitypub/renderer/index.ts
@@ -3,7 +3,7 @@ import { v4 as uuid } from 'uuid';
import { IActivity } from '../type';
import { LdSignature } from '../misc/ld-signature';
import { ILocalUser } from '../../../models/entities/user';
-import { UserKeypairs } from '../../../models';
+import { getUserKeypair } from '../../../misc/keypair-store';
export const renderActivity = (x: any): IActivity | null => {
if (x == null) return null;
@@ -23,9 +23,7 @@ export const renderActivity = (x: any): IActivity | null => {
export const attachLdSignature = async (activity: any, user: ILocalUser): Promise<IActivity | null> => {
if (activity == null) return null;
- const keypair = await UserKeypairs.findOneOrFail({
- userId: user.id
- });
+ const keypair = await getUserKeypair(user.id);
const obj = {
// as non-standards
diff --git a/src/remote/activitypub/renderer/person.ts b/src/remote/activitypub/renderer/person.ts
index 4907e3bc6f..479e6d76bf 100644
--- a/src/remote/activitypub/renderer/person.ts
+++ b/src/remote/activitypub/renderer/person.ts
@@ -8,7 +8,8 @@ import { getEmojis } from './note';
import renderEmoji from './emoji';
import { IIdentifier } from '../models/identifier';
import renderHashtag from './hashtag';
-import { DriveFiles, UserProfiles, UserKeypairs } from '../../../models';
+import { DriveFiles, UserProfiles } from '../../../models';
+import { getUserKeypair } from '../../../misc/keypair-store';
export async function renderPerson(user: ILocalUser) {
const id = `${config.url}/users/${user.id}`;
@@ -49,7 +50,7 @@ export async function renderPerson(user: ILocalUser) {
...hashtagTags,
];
- const keypair = await UserKeypairs.findOneOrFail(user.id);
+ const keypair = await getUserKeypair(user.id);
const person = {
type: isSystem ? 'Application' : user.isBot ? 'Service' : 'Person',
diff --git a/src/remote/activitypub/request.ts b/src/remote/activitypub/request.ts
index 2f07351635..5f15d5480c 100644
--- a/src/remote/activitypub/request.ts
+++ b/src/remote/activitypub/request.ts
@@ -5,11 +5,11 @@ import * as crypto from 'crypto';
import config from '../../config';
import { ILocalUser } from '../../models/entities/user';
-import { UserKeypairs } from '../../models';
import { getAgentByUrl } from '../../misc/fetch';
import { URL } from 'url';
import got from 'got';
import * as Got from 'got';
+import { getUserKeypair } from '../../misc/keypair-store';
export default async (user: ILocalUser, url: string, object: any) => {
const timeout = 10 * 1000;
@@ -22,9 +22,7 @@ export default async (user: ILocalUser, url: string, object: any) => {
sha256.update(data);
const hash = sha256.digest('base64');
- const keypair = await UserKeypairs.findOneOrFail({
- userId: user.id
- });
+ const keypair = await getUserKeypair(user.id);
await new Promise((resolve, reject) => {
const req = https.request({
@@ -74,9 +72,7 @@ export default async (user: ILocalUser, url: string, object: any) => {
export async function signedGet(url: string, user: ILocalUser) {
const timeout = 10 * 1000;
- const keypair = await UserKeypairs.findOneOrFail({
- userId: user.id
- });
+ const keypair = await getUserKeypair(user.id);
const req = got.get<any>(url, {
headers: {
diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts
index bf71258625..694807239b 100644
--- a/src/server/activitypub.ts
+++ b/src/server/activitypub.ts
@@ -13,10 +13,11 @@ import Following from './activitypub/following';
import Featured from './activitypub/featured';
import { inbox as processInbox } from '../queue';
import { isSelfHost } from '../misc/convert-host';
-import { Notes, Users, Emojis, UserKeypairs, NoteReactions } from '../models';
+import { Notes, Users, Emojis, NoteReactions } from '../models';
import { ILocalUser, User } from '../models/entities/user';
import { In } from 'typeorm';
import { renderLike } from '../remote/activitypub/renderer/like';
+import { getUserKeypair } from '../misc/keypair-store';
// Init router
const router = new Router();
@@ -135,7 +136,7 @@ router.get('/users/:user/publickey', async ctx => {
return;
}
- const keypair = await UserKeypairs.findOneOrFail(user.id);
+ const keypair = await getUserKeypair(user.id);
if (Users.isLocalUser(user)) {
ctx.body = renderActivity(renderKey(user, keypair));
diff --git a/src/server/api/authenticate.ts b/src/server/api/authenticate.ts
index 0374ca35ea..9c9ef74352 100644
--- a/src/server/api/authenticate.ts
+++ b/src/server/api/authenticate.ts
@@ -2,6 +2,11 @@ import isNativeToken from './common/is-native-token';
import { User } from '../../models/entities/user';
import { Users, AccessTokens, Apps } from '../../models';
import { AccessToken } from '../../models/entities/access-token';
+import { Cache } from '../../misc/cache';
+
+// TODO: TypeORMã®ã‚«ã‚¹ã‚¿ãƒ ã‚­ãƒ£ãƒƒã‚·ãƒ¥ãƒ—ロãƒã‚¤ãƒ€ã‚’使ã£ã¦ã‚‚良ã„ã‹ã‚‚
+// ref. https://github.com/typeorm/typeorm/blob/master/docs/caching.md
+const cache = new Cache<User>(1000 * 60 * 60);
export default async (token: string): Promise<[User | null | undefined, AccessToken | null | undefined]> => {
if (token == null) {
@@ -9,6 +14,11 @@ export default async (token: string): Promise<[User | null | undefined, AccessTo
}
if (isNativeToken(token)) {
+ const cached = cache.get(token);
+ if (cached) {
+ return [cached, null];
+ }
+
// Fetch user
const user = await Users
.findOne({ token });
@@ -17,8 +27,11 @@ export default async (token: string): Promise<[User | null | undefined, AccessTo
throw new Error('user not found');
}
+ cache.set(token, user);
+
return [user, null];
} else {
+ // TODO: cache
const accessToken = await AccessTokens.findOne({
where: [{
hash: token.toLowerCase() // app
diff --git a/src/server/api/common/inject-featured.ts b/src/server/api/common/inject-featured.ts
index 3f47c13385..bbed7f69cb 100644
--- a/src/server/api/common/inject-featured.ts
+++ b/src/server/api/common/inject-featured.ts
@@ -23,7 +23,7 @@ export async function injectFeatured(timeline: Note[], user?: User | null) {
.andWhere(`note.score > 0`)
.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) })
.andWhere(`note.visibility = 'public'`)
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user');
if (user) {
query.andWhere('note.userId != :userId', { userId: user.id });
diff --git a/src/server/api/define.ts b/src/server/api/define.ts
index 1c7ee26479..4e59357c13 100644
--- a/src/server/api/define.ts
+++ b/src/server/api/define.ts
@@ -18,6 +18,7 @@ type executor<T extends IEndpointMeta> =
(params: Params<T>, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any, cleanup?: Function) =>
Promise<T['res'] extends undefined ? Response : SchemaType<NonNullable<T['res']>>>;
+// TODO: API関数㫠user ã¾ã‚‹ã”ã¨æ¸¡ã™ã®ã§ã¯ãªãユーザーIDãªã©ã®æœ€å°é™ã®ãƒ—ロパティã ã‘渡ã™ã‚ˆã†ã«ã—ãŸã„(キャッシュã¨ã‹è€ƒãˆãªã„ã§ã‚ˆããªã‚‹ãŸã‚)
export default function <T extends IEndpointMeta>(meta: T, cb: executor<T>)
: (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any) => Promise<any> {
return (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any) => {
diff --git a/src/server/api/endpoints/admin/invite.ts b/src/server/api/endpoints/admin/invite.ts
index 4529d16adf..987105791f 100644
--- a/src/server/api/endpoints/admin/invite.ts
+++ b/src/server/api/endpoints/admin/invite.ts
@@ -38,7 +38,7 @@ export default define(meta, async () => {
chars: '2-9A-HJ-NP-Z', // [0-9A-Z] w/o [01IO] (32 patterns)
});
- await RegistrationTickets.save({
+ await RegistrationTickets.insert({
id: genId(),
createdAt: new Date(),
code,
diff --git a/src/server/api/endpoints/admin/promo/create.ts b/src/server/api/endpoints/admin/promo/create.ts
index 8b96d563c2..aa22e68ebd 100644
--- a/src/server/api/endpoints/admin/promo/create.ts
+++ b/src/server/api/endpoints/admin/promo/create.ts
@@ -53,7 +53,7 @@ export default define(meta, async (ps, user) => {
throw new ApiError(meta.errors.alreadyPromoted);
}
- await PromoNotes.save({
+ await PromoNotes.insert({
noteId: note.id,
createdAt: new Date(),
expiresAt: new Date(ps.expiresAt),
diff --git a/src/server/api/endpoints/antennas/notes.ts b/src/server/api/endpoints/antennas/notes.ts
index 750fc080cf..6fd3cf2df5 100644
--- a/src/server/api/endpoints/antennas/notes.ts
+++ b/src/server/api/endpoints/antennas/notes.ts
@@ -73,7 +73,11 @@ export default define(meta, async (ps, user) => {
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
.andWhere(`note.id IN (${ antennaQuery.getQuery() })`)
- .leftJoinAndSelect('note.user', 'user')
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser')
.setParameters(antennaQuery.getParameters());
generateVisibilityQuery(query, user);
diff --git a/src/server/api/endpoints/auth/accept.ts b/src/server/api/endpoints/auth/accept.ts
index 6d4d31fa1e..444053a946 100644
--- a/src/server/api/endpoints/auth/accept.ts
+++ b/src/server/api/endpoints/auth/accept.ts
@@ -58,7 +58,7 @@ export default define(meta, async (ps, user) => {
const now = new Date();
// Insert access token doc
- await AccessTokens.save({
+ await AccessTokens.insert({
id: genId(),
createdAt: now,
lastUsedAt: now,
diff --git a/src/server/api/endpoints/channels/follow.ts b/src/server/api/endpoints/channels/follow.ts
index bf2f2bbb57..c5976a8a34 100644
--- a/src/server/api/endpoints/channels/follow.ts
+++ b/src/server/api/endpoints/channels/follow.ts
@@ -4,6 +4,7 @@ import define from '../../define';
import { ApiError } from '../../error';
import { Channels, ChannelFollowings } from '../../../../models';
import { genId } from '../../../../misc/gen-id';
+import { publishUserEvent } from '../../../../services/stream';
export const meta = {
tags: ['channels'],
@@ -36,10 +37,12 @@ export default define(meta, async (ps, user) => {
throw new ApiError(meta.errors.noSuchChannel);
}
- await ChannelFollowings.save({
+ await ChannelFollowings.insert({
id: genId(),
createdAt: new Date(),
followerId: user.id,
followeeId: channel.id,
});
+
+ publishUserEvent(user.id, 'followChannel', channel);
});
diff --git a/src/server/api/endpoints/channels/timeline.ts b/src/server/api/endpoints/channels/timeline.ts
index acb34f124d..00a7cd86d5 100644
--- a/src/server/api/endpoints/channels/timeline.ts
+++ b/src/server/api/endpoints/channels/timeline.ts
@@ -87,7 +87,11 @@ export default define(meta, async (ps, user) => {
//#region Construct query
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('note.channelId = :channelId', { channelId: channel.id })
- .leftJoinAndSelect('note.user', 'user')
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser')
.leftJoinAndSelect('note.channel', 'channel');
//#endregion
diff --git a/src/server/api/endpoints/channels/unfollow.ts b/src/server/api/endpoints/channels/unfollow.ts
index 8cab5c36a6..3eb0f1519b 100644
--- a/src/server/api/endpoints/channels/unfollow.ts
+++ b/src/server/api/endpoints/channels/unfollow.ts
@@ -3,6 +3,7 @@ import { ID } from '../../../../misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Channels, ChannelFollowings } from '../../../../models';
+import { publishUserEvent } from '../../../../services/stream';
export const meta = {
tags: ['channels'],
@@ -39,4 +40,6 @@ export default define(meta, async (ps, user) => {
followerId: user.id,
followeeId: channel.id,
});
+
+ publishUserEvent(user.id, 'unfollowChannel', channel);
});
diff --git a/src/server/api/endpoints/clips/add-note.ts b/src/server/api/endpoints/clips/add-note.ts
index 4f5cc649e3..ee6a117b2d 100644
--- a/src/server/api/endpoints/clips/add-note.ts
+++ b/src/server/api/endpoints/clips/add-note.ts
@@ -68,7 +68,7 @@ export default define(meta, async (ps, user) => {
throw new ApiError(meta.errors.alreadyClipped);
}
- await ClipNotes.save({
+ await ClipNotes.insert({
id: genId(),
noteId: note.id,
clipId: clip.id
diff --git a/src/server/api/endpoints/clips/notes.ts b/src/server/api/endpoints/clips/notes.ts
index 6a507e2036..676629c328 100644
--- a/src/server/api/endpoints/clips/notes.ts
+++ b/src/server/api/endpoints/clips/notes.ts
@@ -71,7 +71,11 @@ export default define(meta, async (ps, user) => {
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
.andWhere(`note.id IN (${ clipQuery.getQuery() })`)
- .leftJoinAndSelect('note.user', 'user')
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser')
.setParameters(clipQuery.getParameters());
if (user) {
diff --git a/src/server/api/endpoints/i.ts b/src/server/api/endpoints/i.ts
index e5b65e0930..87f6ae778d 100644
--- a/src/server/api/endpoints/i.ts
+++ b/src/server/api/endpoints/i.ts
@@ -1,6 +1,5 @@
import define from '../define';
-import { RegistryItems, UserProfiles, Users } from '../../../models';
-import { genId } from '../../../misc/gen-id';
+import { Users } from '../../../models';
export const meta = {
desc: {
@@ -23,28 +22,8 @@ export const meta = {
export default define(meta, async (ps, user, token) => {
const isSecure = token == null;
- // TODO: ãã®ã†ã¡æ¶ˆã™
- const profile = await UserProfiles.findOneOrFail(user.id);
- for (const [k, v] of Object.entries(profile.clientData)) {
- await RegistryItems.insert({
- id: genId(),
- createdAt: new Date(),
- updatedAt: new Date(),
- userId: user.id,
- domain: null,
- scope: ['client', 'base'],
- key: k,
- value: v
- });
- }
- await UserProfiles.createQueryBuilder().update()
- .set({
- clientData: {},
- })
- .where('userId = :id', { id: user.id })
- .execute();
-
- return await Users.pack(user, user, {
+ // ã“ã“ã§æ¸¡ã£ã¦ãã¦ã„ã‚‹ user ã¯ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã•れã¦ã„ã¦å¤ã„å¯èƒ½æ€§ã‚‚ã‚ã‚‹ã®ã§ id ã ã‘渡ã™
+ return await Users.pack(user.id, user, {
detail: true,
includeSecrets: isSecure
});
diff --git a/src/server/api/endpoints/i/notifications.ts b/src/server/api/endpoints/i/notifications.ts
index 0e09bc73fd..812a4bd1dd 100644
--- a/src/server/api/endpoints/i/notifications.ts
+++ b/src/server/api/endpoints/i/notifications.ts
@@ -85,7 +85,13 @@ export default define(meta, async (ps, user) => {
const query = makePaginationQuery(Notifications.createQueryBuilder('notification'), ps.sinceId, ps.untilId)
.andWhere(`notification.notifieeId = :meId`, { meId: user.id })
- .leftJoinAndSelect('notification.notifier', 'notifier');
+ .leftJoinAndSelect('notification.notifier', 'notifier')
+ .leftJoinAndSelect('notification.note', 'note')
+ .leftJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
query.andWhere(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`);
query.setParameters(mutingQuery.getParameters());
@@ -110,5 +116,5 @@ export default define(meta, async (ps, user) => {
readNotification(user.id, notifications.map(x => x.id));
}
- return await Notifications.packMany(notifications);
+ return await Notifications.packMany(notifications, user.id);
});
diff --git a/src/server/api/endpoints/i/read-announcement.ts b/src/server/api/endpoints/i/read-announcement.ts
index 4a4a021af9..d6acb3d2e6 100644
--- a/src/server/api/endpoints/i/read-announcement.ts
+++ b/src/server/api/endpoints/i/read-announcement.ts
@@ -52,7 +52,7 @@ export default define(meta, async (ps, user) => {
}
// Create read
- await AnnouncementReads.save({
+ await AnnouncementReads.insert({
id: genId(),
createdAt: new Date(),
announcementId: ps.announcementId,
diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts
index a1faf8f1c2..92be2e9e6d 100644
--- a/src/server/api/endpoints/i/update.ts
+++ b/src/server/api/endpoints/i/update.ts
@@ -1,6 +1,6 @@
import $ from 'cafy';
import { ID } from '../../../../misc/cafy-id';
-import { publishMainStream } from '../../../../services/stream';
+import { publishMainStream, publishUserEvent } from '../../../../services/stream';
import acceptAllFollowRequests from '../../../../services/following/requests/accept-all';
import { publishToFollowers } from '../../../../services/i/update';
import define from '../../define';
@@ -317,6 +317,7 @@ export default define(meta, async (ps, user, token) => {
// Publish meUpdated event
publishMainStream(user.id, 'meUpdated', iObj);
+ publishUserEvent(user.id, 'updateUserProfile', await UserProfiles.findOne(user.id));
// éµåž¢ã‚’解除ã—ãŸã¨ãã€æºœã¾ã£ã¦ã„ãŸãƒ•ォローリクエストãŒã‚ã‚‹ãªã‚‰ã™ã¹ã¦æ‰¿èª
if (user.isLocked && ps.isLocked === false) {
diff --git a/src/server/api/endpoints/miauth/gen-token.ts b/src/server/api/endpoints/miauth/gen-token.ts
index 0634debb1e..401ed16389 100644
--- a/src/server/api/endpoints/miauth/gen-token.ts
+++ b/src/server/api/endpoints/miauth/gen-token.ts
@@ -52,7 +52,7 @@ export default define(meta, async (ps, user) => {
const now = new Date();
// Insert access token doc
- await AccessTokens.save({
+ await AccessTokens.insert({
id: genId(),
createdAt: now,
lastUsedAt: now,
diff --git a/src/server/api/endpoints/mute/create.ts b/src/server/api/endpoints/mute/create.ts
index 437ad96107..ebfc6028ed 100644
--- a/src/server/api/endpoints/mute/create.ts
+++ b/src/server/api/endpoints/mute/create.ts
@@ -6,6 +6,7 @@ import { getUser } from '../../common/getters';
import { genId } from '../../../../misc/gen-id';
import { Mutings, NoteWatchings } from '../../../../models';
import { Muting } from '../../../../models/entities/muting';
+import { publishUserEvent } from '../../../../services/stream';
export const meta = {
desc: {
@@ -82,6 +83,8 @@ export default define(meta, async (ps, user) => {
muteeId: mutee.id,
} as Muting);
+ publishUserEvent(user.id, 'mute', mutee);
+
NoteWatchings.delete({
userId: muter.id,
noteUserId: mutee.id
diff --git a/src/server/api/endpoints/mute/delete.ts b/src/server/api/endpoints/mute/delete.ts
index 217352acb4..67a59e3ae4 100644
--- a/src/server/api/endpoints/mute/delete.ts
+++ b/src/server/api/endpoints/mute/delete.ts
@@ -4,6 +4,7 @@ import define from '../../define';
import { ApiError } from '../../error';
import { getUser } from '../../common/getters';
import { Mutings } from '../../../../models';
+import { publishUserEvent } from '../../../../services/stream';
export const meta = {
desc: {
@@ -76,4 +77,6 @@ export default define(meta, async (ps, user) => {
await Mutings.delete({
id: exist.id
});
+
+ publishUserEvent(user.id, 'unmute', mutee);
});
diff --git a/src/server/api/endpoints/notes.ts b/src/server/api/endpoints/notes.ts
index fab8455d78..30e6e92fec 100644
--- a/src/server/api/endpoints/notes.ts
+++ b/src/server/api/endpoints/notes.ts
@@ -76,7 +76,11 @@ export default define(meta, async (ps) => {
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
.andWhere(`note.visibility = 'public'`)
.andWhere(`note.localOnly = FALSE`)
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
if (ps.local) {
query.andWhere('note.userHost IS NULL');
diff --git a/src/server/api/endpoints/notes/children.ts b/src/server/api/endpoints/notes/children.ts
index 0875e0f240..072a25e024 100644
--- a/src/server/api/endpoints/notes/children.ts
+++ b/src/server/api/endpoints/notes/children.ts
@@ -64,7 +64,11 @@ export default define(meta, async (ps, user) => {
}));
}));
}))
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateVisibilityQuery(query, user);
if (user) generateMutedUserQuery(query, user);
diff --git a/src/server/api/endpoints/notes/favorites/create.ts b/src/server/api/endpoints/notes/favorites/create.ts
index 952bbfd0eb..d66ce37a46 100644
--- a/src/server/api/endpoints/notes/favorites/create.ts
+++ b/src/server/api/endpoints/notes/favorites/create.ts
@@ -61,7 +61,7 @@ export default define(meta, async (ps, user) => {
}
// Create favorite
- await NoteFavorites.save({
+ await NoteFavorites.insert({
id: genId(),
createdAt: new Date(),
noteId: note.id,
diff --git a/src/server/api/endpoints/notes/featured.ts b/src/server/api/endpoints/notes/featured.ts
index 4dda7d0edb..b3dffa4272 100644
--- a/src/server/api/endpoints/notes/featured.ts
+++ b/src/server/api/endpoints/notes/featured.ts
@@ -49,7 +49,11 @@ export default define(meta, async (ps, user) => {
.andWhere(`note.score > 0`)
.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) })
.andWhere(`note.visibility = 'public'`)
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
if (user) generateMutedUserQuery(query, user);
diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts
index 6d99f1fdbc..64fc3cbf6c 100644
--- a/src/server/api/endpoints/notes/global-timeline.ts
+++ b/src/server/api/endpoints/notes/global-timeline.ts
@@ -8,8 +8,6 @@ import { Notes } from '../../../../models';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { activeUsersChart } from '../../../../services/chart';
import { generateRepliesQuery } from '../../common/generate-replies-query';
-import { injectPromo } from '../../common/inject-promo';
-import { injectFeatured } from '../../common/inject-featured';
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
export const meta = {
@@ -81,7 +79,11 @@ export default define(meta, async (ps, user) => {
ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('note.visibility = \'public\'')
.andWhere('note.channelId IS NULL')
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateRepliesQuery(query, user);
if (user) generateMutedUserQuery(query, user);
@@ -94,9 +96,6 @@ export default define(meta, async (ps, user) => {
const timeline = await query.take(ps.limit!).getMany();
- await injectPromo(timeline, user);
- await injectFeatured(timeline, user);
-
process.nextTick(() => {
if (user) {
activeUsersChart.update(user);
diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts
index 2b91b8c67b..19c4593f5b 100644
--- a/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ b/src/server/api/endpoints/notes/hybrid-timeline.ts
@@ -10,8 +10,6 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query'
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { activeUsersChart } from '../../../../services/chart';
import { generateRepliesQuery } from '../../common/generate-replies-query';
-import { injectPromo } from '../../common/inject-promo';
-import { injectFeatured } from '../../common/inject-featured';
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
import { generateChannelQuery } from '../../common/generate-channel-query';
@@ -129,7 +127,11 @@ export default define(meta, async (ps, user) => {
qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id })
.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)');
}))
- .leftJoinAndSelect('note.user', 'user')
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser')
.setParameters(followingQuery.getParameters());
generateChannelQuery(query, user);
@@ -175,9 +177,6 @@ export default define(meta, async (ps, user) => {
const timeline = await query.take(ps.limit!).getMany();
- await injectPromo(timeline, user);
- await injectFeatured(timeline, user);
-
process.nextTick(() => {
if (user) {
activeUsersChart.update(user);
diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts
index 51e35e6241..546d3619f7 100644
--- a/src/server/api/endpoints/notes/local-timeline.ts
+++ b/src/server/api/endpoints/notes/local-timeline.ts
@@ -10,8 +10,6 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query'
import { activeUsersChart } from '../../../../services/chart';
import { Brackets } from 'typeorm';
import { generateRepliesQuery } from '../../common/generate-replies-query';
-import { injectPromo } from '../../common/inject-promo';
-import { injectFeatured } from '../../common/inject-featured';
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
import { generateChannelQuery } from '../../common/generate-channel-query';
@@ -98,7 +96,11 @@ export default define(meta, async (ps, user) => {
const query = makePaginationQuery(Notes.createQueryBuilder('note'),
ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)')
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateChannelQuery(query, user);
generateRepliesQuery(query, user);
@@ -128,9 +130,6 @@ export default define(meta, async (ps, user) => {
const timeline = await query.take(ps.limit!).getMany();
- await injectPromo(timeline, user);
- await injectFeatured(timeline, user);
-
process.nextTick(() => {
if (user) {
activeUsersChart.update(user);
diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts
index 8a9d295d38..30368ea578 100644
--- a/src/server/api/endpoints/notes/mentions.ts
+++ b/src/server/api/endpoints/notes/mentions.ts
@@ -63,7 +63,11 @@ export default define(meta, async (ps, user) => {
.where(`:meId = ANY(note.mentions)`, { meId: user.id })
.orWhere(`:meId = ANY(note.visibleUserIds)`, { meId: user.id });
}))
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateVisibilityQuery(query, user);
generateMutedUserQuery(query, user);
@@ -79,9 +83,7 @@ export default define(meta, async (ps, user) => {
const mentions = await query.take(ps.limit!).getMany();
- for (const note of mentions) {
- read(user.id, note.id);
- }
+ read(user.id, mentions.map(note => note.id));
return await Notes.packMany(mentions, user);
});
diff --git a/src/server/api/endpoints/notes/renotes.ts b/src/server/api/endpoints/notes/renotes.ts
index 31c24f294a..dcda213918 100644
--- a/src/server/api/endpoints/notes/renotes.ts
+++ b/src/server/api/endpoints/notes/renotes.ts
@@ -68,7 +68,11 @@ export default define(meta, async (ps, user) => {
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
.andWhere(`note.renoteId = :renoteId`, { renoteId: note.id })
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateVisibilityQuery(query, user);
if (user) generateMutedUserQuery(query, user);
diff --git a/src/server/api/endpoints/notes/replies.ts b/src/server/api/endpoints/notes/replies.ts
index 9fad74c78e..6f33e2f233 100644
--- a/src/server/api/endpoints/notes/replies.ts
+++ b/src/server/api/endpoints/notes/replies.ts
@@ -59,7 +59,11 @@ export const meta = {
export default define(meta, async (ps, user) => {
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
.andWhere('note.replyId = :replyId', { replyId: ps.noteId })
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateVisibilityQuery(query, user);
if (user) generateMutedUserQuery(query, user);
diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts
index e0f7f4d62c..47b41d9294 100644
--- a/src/server/api/endpoints/notes/search-by-tag.ts
+++ b/src/server/api/endpoints/notes/search-by-tag.ts
@@ -95,7 +95,11 @@ export const meta = {
export default define(meta, async (ps, me) => {
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateVisibilityQuery(query, me);
if (me) generateMutedUserQuery(query, me);
diff --git a/src/server/api/endpoints/notes/search.ts b/src/server/api/endpoints/notes/search.ts
index 1aca056299..230d2b0294 100644
--- a/src/server/api/endpoints/notes/search.ts
+++ b/src/server/api/endpoints/notes/search.ts
@@ -79,7 +79,11 @@ export default define(meta, async (ps, me) => {
query
.andWhere('note.text ILIKE :q', { q: `%${ps.query}%` })
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateVisibilityQuery(query, me);
if (me) generateMutedUserQuery(query, me);
diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts
index f09f3d1733..d025944cc2 100644
--- a/src/server/api/endpoints/notes/timeline.ts
+++ b/src/server/api/endpoints/notes/timeline.ts
@@ -8,8 +8,6 @@ import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { activeUsersChart } from '../../../../services/chart';
import { Brackets } from 'typeorm';
import { generateRepliesQuery } from '../../common/generate-replies-query';
-import { injectPromo } from '../../common/inject-promo';
-import { injectFeatured } from '../../common/inject-featured';
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
import { generateChannelQuery } from '../../common/generate-channel-query';
@@ -122,7 +120,11 @@ export default define(meta, async (ps, user) => {
.where('note.userId = :meId', { meId: user.id });
if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`);
}))
- .leftJoinAndSelect('note.user', 'user')
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser')
.setParameters(followingQuery.getParameters());
generateChannelQuery(query, user);
@@ -168,9 +170,6 @@ export default define(meta, async (ps, user) => {
const timeline = await query.take(ps.limit!).getMany();
- await injectPromo(timeline, user);
- await injectFeatured(timeline, user);
-
process.nextTick(() => {
if (user) {
activeUsersChart.update(user);
diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts
index b0ff499d95..9ffb38bddc 100644
--- a/src/server/api/endpoints/notes/user-list-timeline.ts
+++ b/src/server/api/endpoints/notes/user-list-timeline.ts
@@ -130,7 +130,11 @@ export default define(meta, async (ps, user) => {
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
.andWhere(`note.userId IN (${ listQuery.getQuery() })`)
- .leftJoinAndSelect('note.user', 'user')
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser')
.setParameters(listQuery.getParameters());
generateVisibilityQuery(query, user);
diff --git a/src/server/api/endpoints/pages/like.ts b/src/server/api/endpoints/pages/like.ts
index 5c7e13f1c8..3fc2b6ca23 100644
--- a/src/server/api/endpoints/pages/like.ts
+++ b/src/server/api/endpoints/pages/like.ts
@@ -68,7 +68,7 @@ export default define(meta, async (ps, user) => {
}
// Create like
- await PageLikes.save({
+ await PageLikes.insert({
id: genId(),
createdAt: new Date(),
pageId: page.id,
diff --git a/src/server/api/endpoints/promo/read.ts b/src/server/api/endpoints/promo/read.ts
index 57eb0681e5..63c90e5d7f 100644
--- a/src/server/api/endpoints/promo/read.ts
+++ b/src/server/api/endpoints/promo/read.ts
@@ -46,7 +46,7 @@ export default define(meta, async (ps, user) => {
return;
}
- await PromoReads.save({
+ await PromoReads.insert({
id: genId(),
createdAt: new Date(),
noteId: note.id,
diff --git a/src/server/api/endpoints/sw/register.ts b/src/server/api/endpoints/sw/register.ts
index ceb70a9274..9fc70b5609 100644
--- a/src/server/api/endpoints/sw/register.ts
+++ b/src/server/api/endpoints/sw/register.ts
@@ -58,7 +58,7 @@ export default define(meta, async (ps, user) => {
};
}
- await SwSubscriptions.save({
+ await SwSubscriptions.insert({
id: genId(),
createdAt: new Date(),
userId: user.id,
diff --git a/src/server/api/endpoints/users/followers.ts b/src/server/api/endpoints/users/followers.ts
index bd4a2739c6..fb83d7beb8 100644
--- a/src/server/api/endpoints/users/followers.ts
+++ b/src/server/api/endpoints/users/followers.ts
@@ -76,7 +76,8 @@ export default define(meta, async (ps, me) => {
}
const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
- .andWhere(`following.followeeId = :userId`, { userId: user.id });
+ .andWhere(`following.followeeId = :userId`, { userId: user.id })
+ .innerJoinAndSelect('following.follower', 'follower');
const followings = await query
.take(ps.limit!)
diff --git a/src/server/api/endpoints/users/following.ts b/src/server/api/endpoints/users/following.ts
index 9efb8bfc93..d5e8dc1f92 100644
--- a/src/server/api/endpoints/users/following.ts
+++ b/src/server/api/endpoints/users/following.ts
@@ -76,7 +76,8 @@ export default define(meta, async (ps, me) => {
}
const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
- .andWhere(`following.followerId = :userId`, { userId: user.id });
+ .andWhere(`following.followerId = :userId`, { userId: user.id })
+ .innerJoinAndSelect('following.followee', 'followee');
const followings = await query
.take(ps.limit!)
diff --git a/src/server/api/endpoints/users/groups/create.ts b/src/server/api/endpoints/users/groups/create.ts
index ca011d5cd6..78d2714874 100644
--- a/src/server/api/endpoints/users/groups/create.ts
+++ b/src/server/api/endpoints/users/groups/create.ts
@@ -39,7 +39,7 @@ export default define(meta, async (ps, user) => {
} as UserGroup);
// Push the owner
- await UserGroupJoinings.save({
+ await UserGroupJoinings.insert({
id: genId(),
createdAt: new Date(),
userId: user.id,
diff --git a/src/server/api/endpoints/users/groups/invitations/accept.ts b/src/server/api/endpoints/users/groups/invitations/accept.ts
index e86709f83b..2fa22bcf7e 100644
--- a/src/server/api/endpoints/users/groups/invitations/accept.ts
+++ b/src/server/api/endpoints/users/groups/invitations/accept.ts
@@ -52,7 +52,7 @@ export default define(meta, async (ps, user) => {
}
// Push the user
- await UserGroupJoinings.save({
+ await UserGroupJoinings.insert({
id: genId(),
createdAt: new Date(),
userId: user.id,
diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts
index 33e3ecb03f..fc5998c378 100644
--- a/src/server/api/endpoints/users/notes.ts
+++ b/src/server/api/endpoints/users/notes.ts
@@ -131,7 +131,11 @@ export default define(meta, async (ps, me) => {
//#region Construct query
const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('note.userId = :userId', { userId: user.id })
- .leftJoinAndSelect('note.user', 'user');
+ .innerJoinAndSelect('note.user', 'user')
+ .leftJoinAndSelect('note.reply', 'reply')
+ .leftJoinAndSelect('note.renote', 'renote')
+ .leftJoinAndSelect('reply.user', 'replyUser')
+ .leftJoinAndSelect('renote.user', 'renoteUser');
generateVisibilityQuery(query, me);
if (me) generateMutedUserQuery(query, me, user);
diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts
index 7a5efc6cc9..d8f2e6d516 100644
--- a/src/server/api/private/signin.ts
+++ b/src/server/api/private/signin.ts
@@ -53,7 +53,7 @@ export default async (ctx: Koa.Context) => {
async function fail(status?: number, failure?: { error: string }) {
// Append signin history
- await Signins.save({
+ await Signins.insert({
id: genId(),
createdAt: new Date(),
userId: user.id,
@@ -198,7 +198,7 @@ export default async (ctx: Koa.Context) => {
const challengeId = genId();
- await AttestationChallenges.save({
+ await AttestationChallenges.insert({
userId: user.id,
id: challengeId,
challenge: hash(Buffer.from(challenge, 'utf-8')).toString('hex'),
diff --git a/src/server/api/stream/channels/antenna.ts b/src/server/api/stream/channels/antenna.ts
index b5a792f814..36a474f2ac 100644
--- a/src/server/api/stream/channels/antenna.ts
+++ b/src/server/api/stream/channels/antenna.ts
@@ -27,6 +27,8 @@ export default class extends Channel {
// æµã‚Œã¦ããŸNoteãŒãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーãŒé–¢ã‚ã‚‹ã‚‚ã®ã ã£ãŸã‚‰ç„¡è¦–ã™ã‚‹
if (isMutedUserRelated(note, this.muting)) return;
+ this.connection.cacheNote(note);
+
this.send('note', note);
} else {
this.send(type, body);
diff --git a/src/server/api/stream/channels/channel.ts b/src/server/api/stream/channels/channel.ts
index aa570d1ef4..47a52465b2 100644
--- a/src/server/api/stream/channels/channel.ts
+++ b/src/server/api/stream/channels/channel.ts
@@ -43,6 +43,8 @@ export default class extends Channel {
// æµã‚Œã¦ããŸNoteãŒãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーãŒé–¢ã‚ã‚‹ã‚‚ã®ã ã£ãŸã‚‰ç„¡è¦–ã™ã‚‹
if (isMutedUserRelated(note, this.muting)) return;
+ this.connection.cacheNote(note);
+
this.send('note', note);
}
diff --git a/src/server/api/stream/channels/global-timeline.ts b/src/server/api/stream/channels/global-timeline.ts
index 8c97e67226..8353f45323 100644
--- a/src/server/api/stream/channels/global-timeline.ts
+++ b/src/server/api/stream/channels/global-timeline.ts
@@ -56,6 +56,8 @@ export default class extends Channel {
// ãã®ãŸã‚レコードãŒå­˜åœ¨ã™ã‚‹ã‹ã®ãƒã‚§ãƒƒã‚¯ã§ã¯ä¸å分ãªã®ã§ã€æ”¹ã‚ã¦checkWordMuteを呼んã§ã„ã‚‹
if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return;
+ this.connection.cacheNote(note);
+
this.send('note', note);
}
diff --git a/src/server/api/stream/channels/hashtag.ts b/src/server/api/stream/channels/hashtag.ts
index 41447039d5..1b7f8efcc1 100644
--- a/src/server/api/stream/channels/hashtag.ts
+++ b/src/server/api/stream/channels/hashtag.ts
@@ -37,6 +37,8 @@ export default class extends Channel {
// æµã‚Œã¦ããŸNoteãŒãƒŸãƒ¥ãƒ¼ãƒˆã—ã¦ã„るユーザーãŒé–¢ã‚ã‚‹ã‚‚ã®ã ã£ãŸã‚‰ç„¡è¦–ã™ã‚‹
if (isMutedUserRelated(note, this.muting)) return;
+ this.connection.cacheNote(note);
+
this.send('note', note);
}
diff --git a/src/server/api/stream/channels/home-timeline.ts b/src/server/api/stream/channels/home-timeline.ts
index 6cfa6eae7b..59ba31c316 100644
--- a/src/server/api/stream/channels/home-timeline.ts
+++ b/src/server/api/stream/channels/home-timeline.ts
@@ -64,6 +64,8 @@ export default class extends Channel {
// ãã®ãŸã‚レコードãŒå­˜åœ¨ã™ã‚‹ã‹ã®ãƒã‚§ãƒƒã‚¯ã§ã¯ä¸å分ãªã®ã§ã€æ”¹ã‚ã¦checkWordMuteを呼んã§ã„ã‚‹
if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return;
+ this.connection.cacheNote(note);
+
this.send('note', note);
}
diff --git a/src/server/api/stream/channels/hybrid-timeline.ts b/src/server/api/stream/channels/hybrid-timeline.ts
index a9e577cacb..9715e9973f 100644
--- a/src/server/api/stream/channels/hybrid-timeline.ts
+++ b/src/server/api/stream/channels/hybrid-timeline.ts
@@ -73,6 +73,8 @@ export default class extends Channel {
// ãã®ãŸã‚レコードãŒå­˜åœ¨ã™ã‚‹ã‹ã®ãƒã‚§ãƒƒã‚¯ã§ã¯ä¸å分ãªã®ã§ã€æ”¹ã‚ã¦checkWordMuteを呼んã§ã„ã‚‹
if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return;
+ this.connection.cacheNote(note);
+
this.send('note', note);
}
diff --git a/src/server/api/stream/channels/local-timeline.ts b/src/server/api/stream/channels/local-timeline.ts
index a3a5e491fc..e159c72d60 100644
--- a/src/server/api/stream/channels/local-timeline.ts
+++ b/src/server/api/stream/channels/local-timeline.ts
@@ -58,6 +58,8 @@ export default class extends Channel {
// ãã®ãŸã‚レコードãŒå­˜åœ¨ã™ã‚‹ã‹ã®ãƒã‚§ãƒƒã‚¯ã§ã¯ä¸å分ãªã®ã§ã€æ”¹ã‚ã¦checkWordMuteを呼んã§ã„ã‚‹
if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return;
+ this.connection.cacheNote(note);
+
this.send('note', note);
}
diff --git a/src/server/api/stream/channels/main.ts b/src/server/api/stream/channels/main.ts
index b69c2ec355..780bc0b89f 100644
--- a/src/server/api/stream/channels/main.ts
+++ b/src/server/api/stream/channels/main.ts
@@ -18,18 +18,22 @@ export default class extends Channel {
case 'notification': {
if (this.muting.has(body.userId)) return;
if (body.note && body.note.isHidden) {
- body.note = await Notes.pack(body.note.id, this.user, {
+ const note = await Notes.pack(body.note.id, this.user, {
detail: true
});
+ this.connection.cacheNote(note);
+ body.note = note;
}
break;
}
case 'mention': {
if (this.muting.has(body.userId)) return;
if (body.isHidden) {
- body = await Notes.pack(body.id, this.user, {
+ const note = await Notes.pack(body.id, this.user, {
detail: true
});
+ this.connection.cacheNote(note);
+ body = note;
}
break;
}
diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts
index c56a0a157b..99ae558696 100644
--- a/src/server/api/stream/index.ts
+++ b/src/server/api/stream/index.ts
@@ -14,6 +14,7 @@ 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 { PackedNote } from '../../../models/repositories/note';
/**
* Main stream connection
@@ -29,10 +30,7 @@ export default class Connection {
public subscriber: EventEmitter;
private channels: Channel[] = [];
private subscribingNotes: any = {};
- private followingClock: ReturnType<typeof setInterval>;
- private mutingClock: ReturnType<typeof setInterval>;
- private followingChannelsClock: ReturnType<typeof setInterval>;
- private userProfileClock: ReturnType<typeof setInterval>;
+ private cachedNotes: PackedNote[] = [];
constructor(
wsConnection: websocket.connection,
@@ -53,16 +51,49 @@ export default class Connection {
if (this.user) {
this.updateFollowing();
- this.followingClock = setInterval(this.updateFollowing, 5000);
-
this.updateMuting();
- this.mutingClock = setInterval(this.updateMuting, 5000);
-
this.updateFollowingChannels();
- this.followingChannelsClock = setInterval(this.updateFollowingChannels, 5000);
-
this.updateUserProfile();
- this.userProfileClock = setInterval(this.updateUserProfile, 5000);
+
+ this.subscriber.on(`user:${this.user.id}`, ({ type, body }) => {
+ this.onUserEvent(type, body);
+ });
+ }
+ }
+
+ @autobind
+ private onUserEvent(type: string, body: any) {
+ switch (type) {
+ case 'follow':
+ this.following.add(body.id);
+ break;
+
+ case 'unfollow':
+ this.following.delete(body.id);
+ break;
+
+ case 'mute':
+ this.muting.add(body.id);
+ break;
+
+ case 'unmute':
+ this.muting.delete(body.id);
+ break;
+
+ case 'followChannel':
+ this.followingChannels.add(body.id);
+ break;
+
+ case 'unfollowChannel':
+ this.followingChannels.delete(body.id);
+ break;
+
+ case 'updateUserProfile':
+ this.userProfile = body;
+ break;
+
+ default:
+ break;
}
}
@@ -86,9 +117,9 @@ export default class Connection {
switch (type) {
case 'api': this.onApiRequest(body); break;
case 'readNotification': this.onReadNotification(body); break;
- case 'subNote': this.onSubscribeNote(body, true); break;
- case 'sn': this.onSubscribeNote(body, true); break; // alias
- case 's': this.onSubscribeNote(body, false); break;
+ case 'subNote': this.onSubscribeNote(body); break;
+ case 's': this.onSubscribeNote(body); break; // alias
+ case 'sr': this.onSubscribeNote(body); this.readNote(body); break;
case 'unsubNote': this.onUnsubscribeNote(body); break;
case 'un': this.onUnsubscribeNote(body); break; // alias
case 'connect': this.onChannelConnectRequested(body); break;
@@ -109,6 +140,48 @@ export default class Connection {
this.sendMessageToWs(type, body);
}
+ @autobind
+ public cacheNote(note: PackedNote) {
+ const add = (note: PackedNote) => {
+ const existIndex = this.cachedNotes.findIndex(n => n.id === note.id);
+ if (existIndex > -1) {
+ this.cachedNotes[existIndex] = note;
+ return;
+ }
+
+ this.cachedNotes.unshift(note);
+ if (this.cachedNotes.length > 32) {
+ this.cachedNotes.splice(32);
+ }
+ };
+
+ add(note);
+ if (note.reply) add(note.reply);
+ if (note.renote) add(note.renote);
+ }
+
+ @autobind
+ private readNote(body: any) {
+ const id = body.id;
+
+ const note = this.cachedNotes.find(n => n.id === id);
+ if (note == null) return;
+
+ if (this.user && (note.userId !== this.user.id)) {
+ if (note.mentions && note.mentions.includes(this.user.id)) {
+ readNote(this.user.id, [note]);
+ } else if (note.visibleUserIds && note.visibleUserIds.includes(this.user.id)) {
+ readNote(this.user.id, [note]);
+ }
+
+ if (this.followingChannels.has(note.channelId)) {
+ // TODO
+ }
+
+ // TODO: ã‚¢ãƒ³ãƒ†ãƒŠã®æ—¢èª­å‡¦ç†
+ }
+ }
+
/**
* APIãƒªã‚¯ã‚¨ã‚¹ãƒˆè¦æ±‚時
*/
@@ -145,7 +218,7 @@ export default class Connection {
* æŠ•ç¨¿è³¼èª­è¦æ±‚時
*/
@autobind
- private onSubscribeNote(payload: any, read: boolean) {
+ private onSubscribeNote(payload: any) {
if (!payload.id) return;
if (this.subscribingNotes[payload.id] == null) {
@@ -157,10 +230,6 @@ export default class Connection {
if (this.subscribingNotes[payload.id] === 1) {
this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage);
}
-
- if (this.user && read) {
- readNote(this.user.id, payload.id);
- }
}
/**
@@ -335,10 +404,5 @@ export default class Connection {
for (const c of this.channels.filter(c => c.dispose)) {
if (c.dispose) c.dispose();
}
-
- if (this.followingClock) clearInterval(this.followingClock);
- if (this.mutingClock) clearInterval(this.mutingClock);
- if (this.followingChannelsClock) clearInterval(this.followingChannelsClock);
- if (this.userProfileClock) clearInterval(this.userProfileClock);
}
}
diff --git a/src/server/web/index.ts b/src/server/web/index.ts
index 7b0b82eedf..ea356206ff 100644
--- a/src/server/web/index.ts
+++ b/src/server/web/index.ts
@@ -29,6 +29,7 @@ const markdown = MarkdownIt({
});
const staticAssets = `${__dirname}/../../../assets/`;
+const docAssets = `${__dirname}/../../../src/docs/`;
const assets = `${__dirname}/../../assets/`;
// Init app
@@ -44,7 +45,7 @@ app.use(views(__dirname + '/views', {
}));
// Serve favicon
-app.use(favicon(`${__dirname}/../../../assets/favicon.png`));
+app.use(favicon(`${__dirname}/../../../assets/favicon.ico`));
// Common request handler
app.use(async (ctx, next) => {
@@ -65,6 +66,13 @@ router.get('/static-assets/(.*)', async ctx => {
});
});
+router.get('/doc-assets/(.*)', async ctx => {
+ await send(ctx as any, ctx.path.replace('/doc-assets/', ''), {
+ root: docAssets,
+ maxage: ms('7 days'),
+ });
+});
+
router.get('/assets/(.*)', async ctx => {
await send(ctx as any, ctx.path.replace('/assets/', ''), {
root: assets,
@@ -75,7 +83,7 @@ router.get('/assets/(.*)', async ctx => {
// Apple touch icon
router.get('/apple-touch-icon.png', async ctx => {
await send(ctx as any, '/apple-touch-icon.png', {
- root: assets
+ root: staticAssets
});
});
diff --git a/src/server/web/views/flush.pug b/src/server/web/views/flush.pug
index 59fed1f15d..ec585a34db 100644
--- a/src/server/web/views/flush.pug
+++ b/src/server/web/views/flush.pug
@@ -4,35 +4,44 @@ html
#msg
script.
const msg = document.getElementById('msg');
+ const successText = `\nSuccess Flush! <a href="/">Back to Misskey</a>\næˆåŠŸã—ã¾ã—ãŸã€‚<a href="/">Misskeyã‚’é–‹ãç›´ã—ã¦ãã ã•ã„。</a>`;
- try {
- localStorage.clear();
- message('localStorage cleared');
+ message('Start flushing.');
- const delidb = indexedDB.deleteDatabase('MisskeyClient');
- delidb.onsuccess = () => message('indexedDB cleared');
+ (async function() {
+ try {
+ localStorage.clear();
+ message('localStorage cleared.');
- if (navigator.serviceWorker.controller) {
- navigator.serviceWorker.controller.postMessage('clear');
- navigator.serviceWorker.getRegistrations()
- .then(registrations => {
- return Promise.all(registrations.map(registration => registration.unregister()));
- })
- .then(() => {
- message('Success Flush! Please reopen Misskey.\næˆåŠŸã—ã¾ã—ãŸã€‚Misskeyã‚’é–‹ãç›´ã—ã¦ãã ã•ã„。');
- })
- .catch(e => { throw Error(e) });
- } else {
- message('Success Flush! Please reopen Misskey.\næˆåŠŸã—ã¾ã—ãŸã€‚Misskeyã‚’é–‹ãç›´ã—ã¦ãã ã•ã„。');
+ const idbPromises = ['MisskeyClient', 'keyval-store'].map((name, i, arr) => new Promise((res, rej) => {
+ const delidb = indexedDB.deleteDatabase(name);
+ delidb.onsuccess = () => res(message(`indexedDB "${name}" cleared. (${i + 1}/${arr.length})`));
+ delidb.onerror = e => rej(e)
+ }));
+
+ await Promise.all(idbPromises);
+
+ if (navigator.serviceWorker.controller) {
+ navigator.serviceWorker.controller.postMessage('clear');
+ await navigator.serviceWorker.getRegistrations()
+ .then(registrations => {
+ return Promise.all(registrations.map(registration => registration.unregister()));
+ })
+ .catch(e => { throw Error(e) });
+ }
+
+ message(successText);
+ } catch (e) {
+ message(`\n${e}\n\nFlush Failed. <a href="/flush">Please retry.</a>\n失敗ã—ã¾ã—ãŸã€‚<a href="/flush">ã‚‚ã†ä¸€åº¦è©¦ã—ã¦ã¿ã¦ãã ã•ã„。</a>`);
+ message(`\nIf you retry more than 3 times, clear the browser cache or contact to instance admin.\n3回以上試ã—ã¦ã‚‚失敗ã™ã‚‹å ´åˆã€ãƒ–ラウザã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’消去ã—ã€ãれã§ã‚‚ã ã‚ãªã‚‰ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ç®¡ç†è€…ã«é€£çµ¡ã—ã¦ã¿ã¦ãã ã•ã„。\n`)
+
+ console.error(e);
+ setTimeout(() => {
+ location = '/';
+ }, 10000)
}
- } catch (e) {
- console.error(e);
- message(`${e}Â¥nÂ¥nFlush Failed. Please reopen Misskey.\n失敗ã—ã¾ã—ãŸã€‚Misskeyã‚’é–‹ãç›´ã—ã¦ãã ã•ã„。`);
- setTimeout(() => {
- location = '/';
- }, 10000)
- }
+ })();
function message(text) {
- msg.insertAdjacentHTML('beforeend', `<p>[${(new Date()).toString()}] ${text.replace(/Â¥n/g,'<br>')}</p>`)
+ msg.insertAdjacentHTML('beforeend', `<p>[${(new Date()).toString()}] ${text.replace(/\n/g,'<br>')}</p>`)
}
diff --git a/src/services/add-note-to-antenna.ts b/src/services/add-note-to-antenna.ts
index 2c893488c3..3ba3d1eef5 100644
--- a/src/services/add-note-to-antenna.ts
+++ b/src/services/add-note-to-antenna.ts
@@ -10,7 +10,7 @@ export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: U
// 通知ã—ãªã„設定ã«ãªã£ã¦ã„ã‚‹ã‹ã€è‡ªåˆ†è‡ªèº«ã®æŠ•稿ãªã‚‰æ—¢èª­ã«ã™ã‚‹
const read = !antenna.notify || (antenna.userId === noteUser.id);
- AntennaNotes.save({
+ AntennaNotes.insert({
id: genId(),
antennaId: antenna.id,
noteId: note.id,
diff --git a/src/services/blocking/create.ts b/src/services/blocking/create.ts
index def4f33585..dec48d26de 100644
--- a/src/services/blocking/create.ts
+++ b/src/services/blocking/create.ts
@@ -1,4 +1,4 @@
-import { publishMainStream } from '../stream';
+import { publishMainStream, publishUserEvent } from '../stream';
import { renderActivity } from '../../remote/activitypub/renderer';
import renderFollow from '../../remote/activitypub/renderer/follow';
import renderUndo from '../../remote/activitypub/renderer/undo';
@@ -18,7 +18,7 @@ export default async function(blocker: User, blockee: User) {
unFollow(blockee, blocker)
]);
- await Blockings.save({
+ await Blockings.insert({
id: genId(),
createdAt: new Date(),
blockerId: blocker.id,
@@ -55,7 +55,10 @@ async function cancelRequest(follower: User, followee: User) {
if (Users.isLocalUser(follower)) {
Users.pack(followee, follower, {
detail: true
- }).then(packed => publishMainStream(follower.id, 'unfollow', packed));
+ }).then(packed => {
+ publishUserEvent(follower.id, 'unfollow', packed);
+ publishMainStream(follower.id, 'unfollow', packed);
+ });
}
// リモートã«ãƒ•ォローリクエストをã—ã¦ã„ãŸã‚‰UndoFollowé€ä¿¡
@@ -97,7 +100,10 @@ async function unFollow(follower: User, followee: User) {
if (Users.isLocalUser(follower)) {
Users.pack(followee, follower, {
detail: true
- }).then(packed => publishMainStream(follower.id, 'unfollow', packed));
+ }).then(packed => {
+ publishUserEvent(follower.id, 'unfollow', packed);
+ publishMainStream(follower.id, 'unfollow', packed);
+ });
}
// リモートã«ãƒ•ォローをã—ã¦ã„ãŸã‚‰UndoFollowé€ä¿¡
diff --git a/src/services/chart/charts/classes/active-users.ts b/src/services/chart/charts/classes/active-users.ts
index 5128150de6..4820f8281b 100644
--- a/src/services/chart/charts/classes/active-users.ts
+++ b/src/services/chart/charts/classes/active-users.ts
@@ -18,6 +18,18 @@ export default class ActiveUsersChart extends Chart<ActiveUsersLog> {
}
@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<DeepPartial<ActiveUsersLog>> {
return {};
}
@@ -25,11 +37,11 @@ export default class ActiveUsersChart extends Chart<ActiveUsersLog> {
@autobind
public async update(user: User) {
const update: Obj = {
- count: 1
+ users: [user.id]
};
- await this.incIfUnique({
+ await this.inc({
[Users.isLocalUser(user) ? 'local' : 'remote']: update
- }, 'users', user.id);
+ });
}
}
diff --git a/src/services/chart/charts/classes/drive.ts b/src/services/chart/charts/classes/drive.ts
index 57bb120beb..46399a34d8 100644
--- a/src/services/chart/charts/classes/drive.ts
+++ b/src/services/chart/charts/classes/drive.ts
@@ -28,6 +28,28 @@ export default class DriveChart extends Chart<DriveLog> {
}
@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),
+ },
+ };
+ }
+
+ @autobind
protected async fetchActual(): Promise<DeepPartial<DriveLog>> {
const [localCount, remoteCount, localSize, remoteSize] = await Promise.all([
DriveFiles.count({ userHost: null }),
diff --git a/src/services/chart/charts/classes/federation.ts b/src/services/chart/charts/classes/federation.ts
index bd2c497e7b..ab6ec2d4dd 100644
--- a/src/services/chart/charts/classes/federation.ts
+++ b/src/services/chart/charts/classes/federation.ts
@@ -21,6 +21,17 @@ export default class FederationChart extends Chart<FederationLog> {
}
@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),
+ },
+ };
+ }
+
+ @autobind
protected async fetchActual(): Promise<DeepPartial<FederationLog>> {
const [total] = await Promise.all([
Instances.count({})
diff --git a/src/services/chart/charts/classes/hashtag.ts b/src/services/chart/charts/classes/hashtag.ts
index 38c3a94f0c..43db5b0a83 100644
--- a/src/services/chart/charts/classes/hashtag.ts
+++ b/src/services/chart/charts/classes/hashtag.ts
@@ -18,6 +18,18 @@ export default class HashtagChart extends Chart<HashtagLog> {
}
@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<DeepPartial<HashtagLog>> {
return {};
}
@@ -25,11 +37,11 @@ export default class HashtagChart extends Chart<HashtagLog> {
@autobind
public async update(hashtag: string, user: User) {
const update: Obj = {
- count: 1
+ users: [user.id]
};
- await this.incIfUnique({
+ await this.inc({
[Users.isLocalUser(user) ? 'local' : 'remote']: update
- }, 'users', user.id, hashtag);
+ }, hashtag);
}
}
diff --git a/src/services/chart/charts/classes/instance.ts b/src/services/chart/charts/classes/instance.ts
index 7575abfb6f..c32b864d87 100644
--- a/src/services/chart/charts/classes/instance.ts
+++ b/src/services/chart/charts/classes/instance.ts
@@ -37,6 +37,50 @@ export default class InstanceChart extends Chart<InstanceLog> {
}
@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<DeepPartial<InstanceLog>> {
const [
notesCount,
diff --git a/src/services/chart/charts/classes/network.ts b/src/services/chart/charts/classes/network.ts
index 8b26e5c4c2..693af48f73 100644
--- a/src/services/chart/charts/classes/network.ts
+++ b/src/services/chart/charts/classes/network.ts
@@ -16,6 +16,17 @@ export default class NetworkChart extends Chart<NetworkLog> {
}
@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<DeepPartial<NetworkLog>> {
return {};
}
diff --git a/src/services/chart/charts/classes/notes.ts b/src/services/chart/charts/classes/notes.ts
index 815061c445..965087bc08 100644
--- a/src/services/chart/charts/classes/notes.ts
+++ b/src/services/chart/charts/classes/notes.ts
@@ -26,6 +26,32 @@ export default class NotesChart extends Chart<NotesLog> {
}
@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<DeepPartial<NotesLog>> {
const [localCount, remoteCount] = await Promise.all([
Notes.count({ userHost: null }),
diff --git a/src/services/chart/charts/classes/per-user-drive.ts b/src/services/chart/charts/classes/per-user-drive.ts
index aed9f6fce7..e778f7bf61 100644
--- a/src/services/chart/charts/classes/per-user-drive.ts
+++ b/src/services/chart/charts/classes/per-user-drive.ts
@@ -21,6 +21,18 @@ export default class PerUserDriveChart extends Chart<PerUserDriveLog> {
}
@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<DeepPartial<PerUserDriveLog>> {
const [count, size] = await Promise.all([
DriveFiles.count({ userId: group }),
diff --git a/src/services/chart/charts/classes/per-user-following.ts b/src/services/chart/charts/classes/per-user-following.ts
index 8295c0cb0d..8b536009c8 100644
--- a/src/services/chart/charts/classes/per-user-following.ts
+++ b/src/services/chart/charts/classes/per-user-following.ts
@@ -36,6 +36,36 @@ export default class PerUserFollowingChart extends Chart<PerUserFollowingLog> {
}
@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<DeepPartial<PerUserFollowingLog>> {
const [
localFollowingsCount,
diff --git a/src/services/chart/charts/classes/per-user-notes.ts b/src/services/chart/charts/classes/per-user-notes.ts
index cccd495604..8d1fb8d2b0 100644
--- a/src/services/chart/charts/classes/per-user-notes.ts
+++ b/src/services/chart/charts/classes/per-user-notes.ts
@@ -21,6 +21,20 @@ export default class PerUserNotesChart extends Chart<PerUserNotesLog> {
}
@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<DeepPartial<PerUserNotesLog>> {
const [count] = await Promise.all([
Notes.count({ userId: group }),
diff --git a/src/services/chart/charts/classes/per-user-reactions.ts b/src/services/chart/charts/classes/per-user-reactions.ts
index 124fb4153c..b4cdced40c 100644
--- a/src/services/chart/charts/classes/per-user-reactions.ts
+++ b/src/services/chart/charts/classes/per-user-reactions.ts
@@ -19,6 +19,18 @@ export default class PerUserReactionsChart extends Chart<PerUserReactionsLog> {
}
@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<DeepPartial<PerUserReactionsLog>> {
return {};
}
diff --git a/src/services/chart/charts/classes/test-grouped.ts b/src/services/chart/charts/classes/test-grouped.ts
index e32cbcf416..92c8df636e 100644
--- a/src/services/chart/charts/classes/test-grouped.ts
+++ b/src/services/chart/charts/classes/test-grouped.ts
@@ -22,6 +22,17 @@ export default class TestGroupedChart extends Chart<TestGroupedLog> {
}
@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),
+ },
+ };
+ }
+
+ @autobind
protected async fetchActual(group: string): Promise<DeepPartial<TestGroupedLog>> {
return {
foo: {
diff --git a/src/services/chart/charts/classes/test-unique.ts b/src/services/chart/charts/classes/test-unique.ts
index 1eb396c293..5680d713ec 100644
--- a/src/services/chart/charts/classes/test-unique.ts
+++ b/src/services/chart/charts/classes/test-unique.ts
@@ -16,14 +16,21 @@ export default class TestUniqueChart extends Chart<TestUniqueLog> {
}
@autobind
+ protected aggregate(logs: TestUniqueLog[]): TestUniqueLog {
+ return {
+ foo: logs.reduce((a, b) => a.concat(b.foo), [] as TestUniqueLog['foo']),
+ };
+ }
+
+ @autobind
protected async fetchActual(): Promise<DeepPartial<TestUniqueLog>> {
return {};
}
@autobind
public async uniqueIncrement(key: string) {
- await this.incIfUnique({
- foo: 1
- }, 'foos', key);
+ await this.inc({
+ foo: [key]
+ });
}
}
diff --git a/src/services/chart/charts/classes/test.ts b/src/services/chart/charts/classes/test.ts
index ea64040f3e..d37d298de7 100644
--- a/src/services/chart/charts/classes/test.ts
+++ b/src/services/chart/charts/classes/test.ts
@@ -22,6 +22,17 @@ export default class TestChart extends Chart<TestLog> {
}
@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),
+ },
+ };
+ }
+
+ @autobind
protected async fetchActual(): Promise<DeepPartial<TestLog>> {
return {
foo: {
diff --git a/src/services/chart/charts/classes/users.ts b/src/services/chart/charts/classes/users.ts
index 47e4caa1b7..87b19d88f9 100644
--- a/src/services/chart/charts/classes/users.ts
+++ b/src/services/chart/charts/classes/users.ts
@@ -26,6 +26,22 @@ export default class UsersChart extends Chart<UsersLog> {
}
@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<DeepPartial<UsersLog>> {
const [localCount, remoteCount] = await Promise.all([
Users.count({ host: null }),
diff --git a/src/services/chart/charts/schemas/active-users.ts b/src/services/chart/charts/schemas/active-users.ts
index 6e26bb4698..cdf0579efb 100644
--- a/src/services/chart/charts/schemas/active-users.ts
+++ b/src/services/chart/charts/schemas/active-users.ts
@@ -1,11 +1,15 @@
export const logSchema = {
/**
- * アクティブユーザー数
+ * アクティブユーザー
*/
- count: {
- type: 'number' as const,
+ users: {
+ type: 'array' as const,
optional: false as const, nullable: false as const,
- description: 'アクティブユーザー数',
+ description: 'アクティブユーザー',
+ items: {
+ type: 'string' as const,
+ optional: false as const, nullable: false as const,
+ }
},
};
diff --git a/src/services/chart/charts/schemas/hashtag.ts b/src/services/chart/charts/schemas/hashtag.ts
index 4dfd61c97f..791d0d1721 100644
--- a/src/services/chart/charts/schemas/hashtag.ts
+++ b/src/services/chart/charts/schemas/hashtag.ts
@@ -1,11 +1,15 @@
export const logSchema = {
/**
- * 投稿ã•ã‚ŒãŸæ•°
+ * 投稿ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼
*/
- count: {
- type: 'number' as const,
+ users: {
+ type: 'array' as const,
optional: false as const, nullable: false as const,
- description: '投稿ã•ã‚ŒãŸæ•°',
+ description: '投稿ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼',
+ items: {
+ type: 'string' as const,
+ optional: false as const, nullable: false as const,
+ }
},
};
diff --git a/src/services/chart/charts/schemas/test-unique.ts b/src/services/chart/charts/schemas/test-unique.ts
index 075a8092d9..51280400ac 100644
--- a/src/services/chart/charts/schemas/test-unique.ts
+++ b/src/services/chart/charts/schemas/test-unique.ts
@@ -3,9 +3,12 @@ export const schema = {
optional: false as const, nullable: false as const,
properties: {
foo: {
- type: 'number' as const,
+ type: 'array' as const,
optional: false as const, nullable: false as const,
- description: ''
+ items: {
+ type: 'string' as const,
+ optional: false as const, nullable: false as const,
+ }
},
}
};
diff --git a/src/services/chart/core.ts b/src/services/chart/core.ts
index dc09923ae4..10621be073 100644
--- a/src/services/chart/core.ts
+++ b/src/services/chart/core.ts
@@ -24,8 +24,6 @@ type ArrayValue<T> = {
[P in keyof T]: T[P] extends number ? T[P][] : ArrayValue<T[P]>;
};
-type Span = 'day' | 'hour';
-
type Log = {
id: number;
@@ -38,22 +36,14 @@ type Log = {
* 集計日時ã®Unixタイムスタンプ(ç§’)
*/
date: number;
-
- /**
- * 集計期間
- */
- span: Span;
-
- /**
- * ユニークインクリメント用
- */
- unique?: Record<string, any>;
};
const camelToSnake = (str: string) => {
return str.replace(/([A-Z])/g, s => '_' + s.charAt(0).toLowerCase());
};
+const removeDuplicates = (array: any[]) => Array.from(new Set(array));
+
/**
* 様々ãªãƒãƒ£ãƒ¼ãƒˆã®ç®¡ç†ã‚’å¸ã‚‹ã‚¯ãƒ©ã‚¹
*/
@@ -62,10 +52,21 @@ export default abstract class Chart<T extends Record<string, any>> {
private static readonly columnDot = '_';
private name: string;
+ private queue: {
+ diff: DeepPartial<T>;
+ group: string | null;
+ }[] = [];
public schema: Schema;
protected repository: Repository<Log>;
+
protected abstract genNewLog(latest: T): DeepPartial<T>;
- protected abstract async fetchActual(group: string | null): Promise<DeepPartial<T>>;
+
+ /**
+ * @param logs æ—¥æ™‚ãŒæ–°ã—ã„æ–¹ãŒå…ˆé ­
+ */
+ protected abstract aggregate(logs: T[]): T;
+
+ protected abstract fetchActual(group: string | null): Promise<DeepPartial<T>>;
@autobind
private static convertSchemaToFlatColumnDefinitions(schema: Schema) {
@@ -75,10 +76,15 @@ export default abstract class Chart<T extends Record<string, any>> {
const p = path ? `${path}${this.columnDot}${k}` : k;
if (v.type === 'object') {
flatColumns(v.properties, p);
- } else {
+ } 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,
+ };
}
}
};
@@ -99,11 +105,11 @@ export default abstract class Chart<T extends Record<string, any>> {
@autobind
private static convertObjectToFlattenColumns(x: Record<string, any>) {
- const columns = {} as Record<string, number>;
+ const columns = {} as Record<string, number | unknown[]>;
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') {
+ if (typeof v === 'object' && !Array.isArray(v)) {
flatten(v, p);
} else {
columns[this.columnPrefix + p] = v;
@@ -115,14 +121,37 @@ export default abstract class Chart<T extends Record<string, any>> {
}
@autobind
- private static convertQuery(x: Record<string, any>) {
- const query: Record<string, Function> = {};
+ private static countUniqueFields(x: Record<string, any>) {
+ const exec = (x: Obj) => {
+ const res = {} as Record<string, any>;
+ 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);
+ }
- const columns = Chart.convertObjectToFlattenColumns(x);
+ @autobind
+ private static convertQuery(diff: Record<string, number | unknown[]>) {
+ const query: Record<string, Function> = {};
- for (const [k, v] of Object.entries(columns)) {
- if (v > 0) query[k] = () => `"${k}" + ${v}`;
- if (v < 0) query[k] = () => `"${k}" - ${Math.abs(v)}`;
+ 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;
@@ -169,28 +198,14 @@ export default abstract class Chart<T extends Record<string, any>> {
length: 128,
nullable: true
},
- span: {
- type: 'enum',
- enum: ['hour', 'day']
- },
- unique: {
- type: 'jsonb',
- default: {}
- },
...Chart.convertSchemaToFlatColumnDefinitions(schema)
},
indices: [{
columns: ['date']
}, {
- columns: ['span']
- }, {
columns: ['group']
}, {
- columns: ['span', 'date']
- }, {
columns: ['date', 'group']
- }, {
- columns: ['span', 'date', 'group']
}]
});
}
@@ -200,7 +215,7 @@ export default abstract class Chart<T extends Record<string, any>> {
this.schema = schema;
const entity = Chart.schemaToEntity(name, schema);
- const keys = ['span', 'date'];
+ const keys = ['date'];
if (grouped) keys.push('group');
entity.options.uniques = [{
@@ -220,7 +235,8 @@ export default abstract class Chart<T extends Record<string, any>> {
flatColumns(v.properties, p);
} else {
if (nestedProperty.get(log, p) == null) {
- nestedProperty.set(log, p, 0);
+ const emptyValue = v.type === 'number' ? 0 : [];
+ nestedProperty.set(log, p, emptyValue);
}
}
}
@@ -230,10 +246,9 @@ export default abstract class Chart<T extends Record<string, any>> {
}
@autobind
- private getLatestLog(span: Span, group: string | null = null): Promise<Log | null> {
+ private getLatestLog(group: string | null = null): Promise<Log | null> {
return this.repository.findOne({
group: group,
- span: span
}, {
order: {
date: -1
@@ -242,17 +257,13 @@ export default abstract class Chart<T extends Record<string, any>> {
}
@autobind
- private async getCurrentLog(span: Span, group: string | null = null): Promise<Log> {
+ private async getCurrentLog(group: string | null = null): Promise<Log> {
const [y, m, d, h] = Chart.getCurrentDate();
- const current =
- span == 'day' ? dateUTC([y, m, d, 0]) :
- span == 'hour' ? dateUTC([y, m, d, h]) :
- null as never;
+ const current = dateUTC([y, m, d, h]);
- // ç¾åœ¨(今日ã¾ãŸã¯ä»Šã®Hour)ã®ãƒ­ã‚°
+ // ç¾åœ¨(=今ã®Hour)ã®ãƒ­ã‚°
const currentLog = await this.repository.findOne({
- span: span,
date: Chart.dateToTimestamp(current),
...(group ? { group: group } : {})
});
@@ -271,7 +282,7 @@ export default abstract class Chart<T extends Record<string, any>> {
// * 昨日何もãƒãƒ£ãƒ¼ãƒˆã‚’æ›´æ–°ã™ã‚‹ã‚ˆã†ãªå‡ºæ¥äº‹ãŒãªã‹ã£ãŸå ´åˆã¯ã€
// * ログãŒãã‚‚ãも作られãšãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆãŒå­˜åœ¨ã—ãªã„ã¨ã„ã†ã“ã¨ãŒã‚り得るãŸã‚ã€
// * 「昨日ã®ã€ã¨æ±ºã‚打ã¡ã›ãšã«ã€Œã‚‚ã£ã¨ã‚‚最近ã®ã€ã¨ã—ã¾ã™
- const latest = await this.getLatestLog(span, group);
+ const latest = await this.getLatestLog(group);
if (latest != null) {
const obj = Chart.convertFlattenColumnsToObject(
@@ -286,17 +297,16 @@ export default abstract class Chart<T extends Record<string, any>> {
// åˆæœŸãƒ­ã‚°ãƒ‡ãƒ¼ã‚¿ã‚’作æˆ
data = this.getNewLog(null);
- logger.info(`${this.name + (group ? `:${group}` : '')} (${span}): Initial commit created`);
+ logger.info(`${this.name + (group ? `:${group}` : '')}: Initial commit created`);
}
const date = Chart.dateToTimestamp(current);
- const lockKey = `${this.name}:${date}:${group}:${span}`;
+ const lockKey = `${this.name}:${date}:${group}`;
const unlock = await getChartInsertLock(lockKey);
try {
// ロック内ã§ã‚‚ã†1回ãƒã‚§ãƒƒã‚¯ã™ã‚‹
const currentLog = await this.repository.findOne({
- span: span,
date: date,
...(group ? { group: group } : {})
});
@@ -307,12 +317,11 @@ export default abstract class Chart<T extends Record<string, any>> {
// æ–°è¦ãƒ­ã‚°æŒ¿å…¥
log = await this.repository.save({
group: group,
- span: span,
date: date,
...Chart.convertObjectToFlattenColumns(data)
});
- logger.info(`${this.name + (group ? `:${group}` : '')} (${span}): New commit created`);
+ logger.info(`${this.name + (group ? `:${group}` : '')}: New commit created`);
return log;
} finally {
@@ -321,38 +330,62 @@ export default abstract class Chart<T extends Record<string, any>> {
}
@autobind
- protected commit(query: Record<string, Function>, group: string | null = null, uniqueKey?: string, uniqueValue?: string): Promise<any> {
+ protected commit(diff: DeepPartial<T>, group: string | null = null): void {
+ this.queue.push({
+ diff, group,
+ });
+ }
+
+ @autobind
+ public async save() {
+ if (this.queue.length === 0) {
+ logger.info(`${this.name}: Write skipped`);
+ return;
+ }
+
+ // TODO: å‰ã®æ™‚é–“ã®ãƒ­ã‚°ãŒqueueã«ã‚ã£ãŸå ´åˆã®ãƒãƒ³ãƒ‰ãƒªãƒ³ã‚°
+ // 例ãˆã°ã€save ãŒ20分ã”ã¨ã«è¡Œã‚れるã¨ã—ã¦ã€å‰å›žè¡Œã‚れãŸã®ã¯ 01:50 ã ã£ãŸã¨ã™ã‚‹ã€‚
+ // 次㫠save ãŒè¡Œã‚れるã®ã¯ 02:10 ã¨ã„ã†ã“ã¨ã«ãªã‚‹ãŒã€ã‚‚ã— 01:55 ã«æ–°è¦ãƒ­ã‚°ãŒ queue ã«è¿½åŠ ã•れãŸã¨ã™ã‚‹ã¨ã€
+ // ãã®ãƒ­ã‚°ã¯æœ¬æ¥ã¯ 01:00~ ã®ãƒ­ã‚°ã¨ã—ã¦DBã«ä¿å­˜ã•ã‚Œã¦æ¬²ã—ã„ã®ã«ã€02:00~ ã®ãƒ­ã‚°æ‰±ã„ã«ãªã£ã¦ã—ã¾ã†ã€‚
+ // ã“れを回é¿ã™ã‚‹ãŸã‚ã®å®Ÿè£…ã¯è¤‡é›‘ã«ãªã‚Šãã†ãªãŸã‚ã€ä¸€æ—¦ä¿ç•™ã€‚
+
const update = async (log: Log) => {
- // ユニークインクリメントã®å ´åˆã€æŒ‡å®šã®ã‚­ãƒ¼ã«æŒ‡å®šã®å€¤ãŒæ—¢ã«å­˜åœ¨ã—ã¦ã„ãŸã‚‰å¼¾ã
- if (
- uniqueKey && log.unique &&
- log.unique[uniqueKey] &&
- log.unique[uniqueKey].includes(uniqueValue)
- ) return;
+ const finalDiffs = {} as Record<string, number | unknown[]>;
- // ãƒ¦ãƒ‹ãƒ¼ã‚¯ã‚¤ãƒ³ã‚¯ãƒªãƒ¡ãƒ³ãƒˆã®æŒ‡å®šã®ã‚­ãƒ¼ã«å€¤ã‚’追加
- if (uniqueKey && log.unique) {
- if (log.unique[uniqueKey]) {
- const sql = `jsonb_set("unique", '{${uniqueKey}}', ("unique"->>'${uniqueKey}')::jsonb || '["${uniqueValue}"]'::jsonb)`;
- query['unique'] = () => sql;
- } else {
- const sql = `jsonb_set("unique", '{${uniqueKey}}', '["${uniqueValue}"]')`;
- query['unique'] = () => sql;
+ for (const diff of this.queue.filter(q => q.group === log.group).map(q => q.diff)) {
+ const columns = Chart.convertObjectToFlattenColumns(diff);
+
+ for (const [k, v] of Object.entries(columns)) {
+ 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);
+ }
+ }
}
}
+ const query = Chart.convertQuery(finalDiffs);
+
// ログ更新
await this.repository.createQueryBuilder()
.update()
.set(query)
.where('id = :id', { id: log.id })
.execute();
+
+ logger.info(`${this.name + (log.group ? `:${log.group}` : '')}: Updated`);
+
+ // TODO: ã“ã®ä¸€é€£ã®å‡¦ç†ãŒå§‹ã¾ã£ãŸå¾Œã«æ–°ãŸã«queueã«å…¥ã£ãŸã‚‚ã®ã¯æ¶ˆã•ãªã„よã†ã«ã™ã‚‹
+ this.queue = this.queue.filter(q => q.group !== log.group);
};
- return Promise.all([
- this.getCurrentLog('day', group).then(log => update(log)),
- this.getCurrentLog('hour', group).then(log => update(log)),
- ]);
+ const groups = removeDuplicates(this.queue.map(log => log.group));
+
+ await Promise.all(groups.map(group => this.getCurrentLog(group).then(log => update(log))));
}
@autobind
@@ -367,39 +400,30 @@ export default abstract class Chart<T extends Record<string, any>> {
.execute();
};
- return Promise.all([
- this.getCurrentLog('day', group).then(log => update(log)),
- this.getCurrentLog('hour', group).then(log => update(log)),
- ]);
+ return this.getCurrentLog(group).then(log => update(log));
}
@autobind
protected async inc(inc: DeepPartial<T>, group: string | null = null): Promise<void> {
- await this.commit(Chart.convertQuery(inc as any), group);
- }
-
- @autobind
- protected async incIfUnique(inc: DeepPartial<T>, key: string, value: string, group: string | null = null): Promise<void> {
- await this.commit(Chart.convertQuery(inc as any), group, key, value);
+ await this.commit(inc, group);
}
@autobind
- public async getChart(span: Span, amount: number, begin: Date | null, group: string | null = null): Promise<ArrayValue<T>> {
- const [y, m, d, h, _m, _s, _ms] = begin ? Chart.parseDate(subtractTime(addTime(begin, 1, span), 1)) : Chart.getCurrentDate();
- const [y2, m2, d2, h2] = begin ? Chart.parseDate(addTime(begin, 1, span)) : [] as never;
+ public async getChart(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise<ArrayValue<T>> {
+ 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;
const lt = dateUTC([y, m, d, h, _m, _s, _ms]);
const gt =
- span === 'day' ? subtractTime(begin ? dateUTC([y2, m2, d2, 0]) : dateUTC([y, m, d, 0]), amount - 1, 'day') :
- span === 'hour' ? subtractTime(begin ? dateUTC([y2, m2, d2, h2]) : dateUTC([y, m, d, h]), amount - 1, 'hour') :
+ span === 'day' ? subtractTime(cursor ? dateUTC([y2, m2, d2, 0]) : dateUTC([y, m, d, 0]), amount - 1, 'day') :
+ span === 'hour' ? subtractTime(cursor ? dateUTC([y2, m2, d2, h2]) : dateUTC([y, m, d, h]), amount - 1, 'hour') :
null as never;
// ログå–å¾—
let logs = await this.repository.find({
where: {
group: group,
- span: span,
date: Between(Chart.dateToTimestamp(gt), Chart.dateToTimestamp(lt))
},
order: {
@@ -413,7 +437,6 @@ export default abstract class Chart<T extends Record<string, any>> {
// (ã™ããªãã¨ã‚‚ã²ã¨ã¤ãƒ­ã‚°ãŒç„¡ã„ã¨éš™é–“埋ã‚ã§ããªã„ãŸã‚)
const recentLog = await this.repository.findOne({
group: group,
- span: span
}, {
order: {
date: -1
@@ -430,7 +453,6 @@ export default abstract class Chart<T extends Record<string, any>> {
// (隙間埋ã‚ã§ããªã„ãŸã‚)
const outdatedLog = await this.repository.findOne({
group: group,
- span: span,
date: LessThan(Chart.dateToTimestamp(gt))
}, {
order: {
@@ -445,23 +467,56 @@ export default abstract class Chart<T extends Record<string, any>> {
const chart: T[] = [];
- // æ•´å½¢
- for (let i = (amount - 1); i >= 0; i--) {
- const current =
- span === 'day' ? subtractTime(dateUTC([y, m, d, 0]), i, 'day') :
- span === 'hour' ? subtractTime(dateUTC([y, m, d, h]), i, 'hour') :
- null as never;
+ if (span === 'hour') {
+ for (let i = (amount - 1); i >= 0; i--) {
+ const current = subtractTime(dateUTC([y, m, d, h]), i, 'hour');
- const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current));
+ const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current));
+
+ if (log) {
+ const data = Chart.convertFlattenColumnsToObject(log as Record<string, any>);
+ chart.unshift(Chart.countUniqueFields(data));
+ } else {
+ // 隙間埋ã‚
+ const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current));
+ const data = latest ? Chart.convertFlattenColumnsToObject(latest as Record<string, any>) : null;
+ chart.unshift(Chart.countUniqueFields(this.getNewLog(data)));
+ }
+ }
+ } else if (span === 'day') {
+ const logsForEachDays: T[][] = [];
+ let currentDay = -1;
+ let currentDayIndex = -1;
+ for (let i = ((amount - 1) * 24) + h; i >= 0; i--) {
+ const current = subtractTime(dateUTC([y, m, d, h]), i, 'hour');
+ const _currentDay = Chart.parseDate(current)[2];
+ if (currentDay != _currentDay) currentDayIndex++;
+ currentDay = _currentDay;
+
+ const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current));
+
+ if (log) {
+ if (logsForEachDays[currentDayIndex]) {
+ logsForEachDays[currentDayIndex].unshift(Chart.convertFlattenColumnsToObject(log));
+ } else {
+ logsForEachDays[currentDayIndex] = [Chart.convertFlattenColumnsToObject(log)];
+ }
+ } else {
+ // 隙間埋ã‚
+ const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current));
+ const data = latest ? Chart.convertFlattenColumnsToObject(latest as Record<string, any>) : null;
+ const newLog = this.getNewLog(data);
+ if (logsForEachDays[currentDayIndex]) {
+ logsForEachDays[currentDayIndex].unshift(newLog);
+ } else {
+ logsForEachDays[currentDayIndex] = [newLog];
+ }
+ }
+ }
- if (log) {
- const data = Chart.convertFlattenColumnsToObject(log as Record<string, any>);
- chart.unshift(data);
- } else {
- // 隙間埋ã‚
- const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current));
- const data = latest ? Chart.convertFlattenColumnsToObject(latest as Record<string, any>) : null;
- chart.unshift(this.getNewLog(data));
+ for (const logs of logsForEachDays) {
+ const log = this.aggregate(logs);
+ chart.unshift(Chart.countUniqueFields(log));
}
}
@@ -473,20 +528,19 @@ export default abstract class Chart<T extends Record<string, any>> {
* { foo: [1, 2, 3], bar: [5, 6, 7] }
* ã«ã™ã‚‹
*/
- const dive = (x: Obj, path?: string) => {
+ const compact = (x: Obj, path?: string) => {
for (const [k, v] of Object.entries(x)) {
const p = path ? `${path}.${k}` : k;
- if (typeof v == 'object') {
- dive(v, p);
+ if (typeof v === 'object' && !Array.isArray(v)) {
+ compact(v, p);
} else {
- const values = chart.map(s => nestedProperty.get(s, p))
- .map(v => parseInt(v, 10)); // TypeORMã®ãƒã‚°(?)ã§ä½•æ•…ã‹æ•°å€¤ã‚«ãƒ©ãƒ ã®å€¤ãŒæ–‡å­—列型ã«ãªã£ã¦ã„ã‚‹ã®ã§æ•°å€¤ã«æˆ»ã™
+ const values = chart.map(s => nestedProperty.get(s, p));
nestedProperty.set(res, p, values);
}
}
};
- dive(chart[0]);
+ compact(chart[0]);
return res;
}
diff --git a/src/services/chart/index.ts b/src/services/chart/index.ts
index 9626e3d6b3..dde02bd64d 100644
--- a/src/services/chart/index.ts
+++ b/src/services/chart/index.ts
@@ -10,6 +10,7 @@ import PerUserReactionsChart from './charts/classes/per-user-reactions';
import HashtagChart from './charts/classes/hashtag';
import PerUserFollowingChart from './charts/classes/per-user-following';
import PerUserDriveChart from './charts/classes/per-user-drive';
+import { beforeShutdown } from '../../misc/before-shutdown';
export const federationChart = new FederationChart();
export const notesChart = new NotesChart();
@@ -23,3 +24,27 @@ export const perUserReactionsChart = new PerUserReactionsChart();
export const hashtagChart = new HashtagChart();
export const perUserFollowingChart = new PerUserFollowingChart();
export const perUserDriveChart = new PerUserDriveChart();
+
+const charts = [
+ federationChart,
+ notesChart,
+ usersChart,
+ networkChart,
+ activeUsersChart,
+ instanceChart,
+ perUserNotesChart,
+ driveChart,
+ perUserReactionsChart,
+ hashtagChart,
+ perUserFollowingChart,
+ perUserDriveChart,
+];
+
+// 20分ãŠãã«ãƒ¡ãƒ¢ãƒªæƒ…報をDBã«æ›¸ãè¾¼ã¿
+setInterval(() => {
+ for (const chart of charts) {
+ chart.save();
+ }
+}, 1000 * 60 * 20);
+
+beforeShutdown(() => Promise.all(charts.map(chart => chart.save())));
diff --git a/src/services/create-notification.ts b/src/services/create-notification.ts
index 6cd116040a..dedb8eac8d 100644
--- a/src/services/create-notification.ts
+++ b/src/services/create-notification.ts
@@ -30,7 +30,7 @@ export async function createNotification(
...data
} as Partial<Notification>);
- const packed = await Notifications.pack(notification);
+ const packed = await Notifications.pack(notification, {});
// Publish notification event
publishMainStream(notifieeId, 'notification', packed);
diff --git a/src/services/following/create.ts b/src/services/following/create.ts
index c0583cdb86..1ce75caca0 100644
--- a/src/services/following/create.ts
+++ b/src/services/following/create.ts
@@ -1,4 +1,4 @@
-import { publishMainStream } from '../stream';
+import { publishMainStream, publishUserEvent } from '../stream';
import { renderActivity } from '../../remote/activitypub/renderer';
import renderFollow from '../../remote/activitypub/renderer/follow';
import renderAccept from '../../remote/activitypub/renderer/accept';
@@ -22,7 +22,7 @@ export async function insertFollowingDoc(followee: User, follower: User) {
let alreadyFollowed = false;
- await Followings.save({
+ await Followings.insert({
id: genId(),
createdAt: new Date(),
followerId: follower.id,
@@ -88,12 +88,15 @@ export async function insertFollowingDoc(followee: User, follower: User) {
if (Users.isLocalUser(follower)) {
Users.pack(followee, follower, {
detail: true
- }).then(packed => publishMainStream(follower.id, 'follow', packed));
+ }).then(packed => {
+ publishUserEvent(follower.id, 'follow', packed);
+ publishMainStream(follower.id, 'follow', packed);
+ });
}
// Publish followed event
if (Users.isLocalUser(followee)) {
- Users.pack(follower, followee).then(packed => publishMainStream(followee.id, 'followed', packed)),
+ Users.pack(follower, followee).then(packed => publishMainStream(followee.id, 'followed', packed));
// 通知を作æˆ
createNotification(followee.id, 'follow', {
diff --git a/src/services/following/delete.ts b/src/services/following/delete.ts
index 8821611515..32c47ea7f4 100644
--- a/src/services/following/delete.ts
+++ b/src/services/following/delete.ts
@@ -1,4 +1,4 @@
-import { publishMainStream } from '../stream';
+import { publishMainStream, publishUserEvent } from '../stream';
import { renderActivity } from '../../remote/activitypub/renderer';
import renderFollow from '../../remote/activitypub/renderer/follow';
import renderUndo from '../../remote/activitypub/renderer/undo';
@@ -30,7 +30,10 @@ export default async function(follower: User, followee: User, silent = false) {
if (!silent && Users.isLocalUser(follower)) {
Users.pack(followee, follower, {
detail: true
- }).then(packed => publishMainStream(follower.id, 'unfollow', packed));
+ }).then(packed => {
+ publishUserEvent(follower.id, 'unfollow', packed);
+ publishMainStream(follower.id, 'unfollow', packed);
+ });
}
if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) {
diff --git a/src/services/following/requests/reject.ts b/src/services/following/requests/reject.ts
index 9a8b14bbfd..d8d3788088 100644
--- a/src/services/following/requests/reject.ts
+++ b/src/services/following/requests/reject.ts
@@ -2,7 +2,7 @@ import { renderActivity } from '../../../remote/activitypub/renderer';
import renderFollow from '../../../remote/activitypub/renderer/follow';
import renderReject from '../../../remote/activitypub/renderer/reject';
import { deliver } from '../../../queue';
-import { publishMainStream } from '../../stream';
+import { publishMainStream, publishUserEvent } from '../../stream';
import { User, ILocalUser } from '../../../models/entities/user';
import { Users, FollowRequests, Followings } from '../../../models';
import { decrementFollowing } from '../delete';
@@ -39,5 +39,8 @@ export default async function(followee: User, follower: User) {
Users.pack(followee, follower, {
detail: true
- }).then(packed => publishMainStream(follower.id, 'unfollow', packed));
+ }).then(packed => {
+ publishUserEvent(follower.id, 'unfollow', packed);
+ publishMainStream(follower.id, 'unfollow', packed);
+ });
}
diff --git a/src/services/i/pin.ts b/src/services/i/pin.ts
index 1ff5476b40..f727a10fb6 100644
--- a/src/services/i/pin.ts
+++ b/src/services/i/pin.ts
@@ -37,7 +37,7 @@ export async function addPinned(user: User, noteId: Note['id']) {
throw new IdentifiableError('23f0cf4e-59a3-4276-a91d-61a5891c1514', 'That note has already been pinned.');
}
- await UserNotePinings.save({
+ await UserNotePinings.insert({
id: genId(),
createdAt: new Date(),
userId: user.id,
diff --git a/src/services/insert-moderation-log.ts b/src/services/insert-moderation-log.ts
index 33dab97259..87587d3bed 100644
--- a/src/services/insert-moderation-log.ts
+++ b/src/services/insert-moderation-log.ts
@@ -3,7 +3,7 @@ import { ModerationLogs } from '../models';
import { genId } from '../misc/gen-id';
export async function insertModerationLog(moderator: ILocalUser, type: string, info?: Record<string, any>) {
- await ModerationLogs.save({
+ await ModerationLogs.insert({
id: genId(),
createdAt: new Date(),
userId: moderator.id,
diff --git a/src/services/messages/create.ts b/src/services/messages/create.ts
index 8646ce37fc..413266d029 100644
--- a/src/services/messages/create.ts
+++ b/src/services/messages/create.ts
@@ -14,7 +14,7 @@ import { renderActivity } from '../../remote/activitypub/renderer';
import { deliver } from '../../queue';
export async function createMessage(user: User, recipientUser: User | undefined, recipientGroup: UserGroup | undefined, text: string | undefined, file: DriveFile | null, uri?: string) {
- const message = await MessagingMessages.save({
+ const message = {
id: genId(),
createdAt: new Date(),
fileId: file ? file.id : null,
@@ -25,7 +25,9 @@ export async function createMessage(user: User, recipientUser: User | undefined,
isRead: false,
reads: [] as any[],
uri
- } as MessagingMessage);
+ } as MessagingMessage;
+
+ await MessagingMessages.insert(message);
const messageObj = await MessagingMessages.pack(message);
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 563eaac758..4a737e8516 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -247,7 +247,7 @@ export default async (user: User, data: Option, silent = false) => new Promise<N
for (const u of us) {
checkWordMute(note, { id: u.userId }, u.mutedWords).then(shouldMute => {
if (shouldMute) {
- MutedNotes.save({
+ MutedNotes.insert({
id: genId(),
userId: u.userId,
noteId: note.id,
@@ -259,21 +259,21 @@ export default async (user: User, data: Option, silent = false) => new Promise<N
});
// Antenna
- Antennas.find().then(async antennas => {
- const followings = await Followings.createQueryBuilder('following')
- .andWhere(`following.followeeId = :userId`, { userId: note.userId })
- .getMany();
-
- const followers = followings.map(f => f.followerId);
-
- for (const antenna of antennas) {
- checkHitAntenna(antenna, note, user, followers).then(hit => {
- if (hit) {
- addNoteToAntenna(antenna, note, user);
+ Followings.createQueryBuilder('following')
+ .andWhere(`following.followeeId = :userId`, { userId: note.userId })
+ .getMany()
+ .then(followings => {
+ const followers = followings.map(f => f.followerId);
+ Antennas.find().then(async antennas => {
+ for (const antenna of antennas) {
+ checkHitAntenna(antenna, note, user, followers).then(hit => {
+ if (hit) {
+ addNoteToAntenna(antenna, note, user);
+ }
+ });
}
});
- }
- });
+ });
// Channel
if (note.channelId) {
@@ -444,8 +444,13 @@ async function renderNoteOrRenoteActivity(data: Option, note: Note) {
}
function incRenoteCount(renote: Note) {
- Notes.increment({ id: renote.id }, 'renoteCount', 1);
- Notes.increment({ id: renote.id }, 'score', 1);
+ Notes.createQueryBuilder().update()
+ .set({
+ renoteCount: () => '"renoteCount" + 1',
+ score: () => '"score" + 1'
+ })
+ .where('id = :id', { id: renote.id })
+ .execute();
}
async function insertNote(user: User, data: Option, tags: string[], emojis: string[], mentionedUsers: User[]) {
@@ -525,7 +530,7 @@ async function insertNote(user: User, data: Option, tags: string[], emojis: stri
await Notes.insert(insert);
}
- return await Notes.findOneOrFail(insert.id);
+ return insert;
} catch (e) {
// duplicate key error
if (isDuplicateKeyValueError(e)) {
@@ -594,10 +599,13 @@ function saveReply(reply: Note, note: Note) {
}
function incNotesCountOfUser(user: User) {
- Users.increment({ id: user.id }, 'notesCount', 1);
- Users.update({ id: user.id }, {
- updatedAt: new Date()
- });
+ Users.createQueryBuilder().update()
+ .set({
+ updatedAt: new Date(),
+ notesCount: () => '"notesCount" + 1'
+ })
+ .where('id = :id', { id: user.id })
+ .execute();
}
async function extractMentionedUsers(user: User, tokens: ReturnType<typeof parse>): Promise<User[]> {
diff --git a/src/services/note/polls/vote.ts b/src/services/note/polls/vote.ts
index bfcaaa09be..b4ce03ab60 100644
--- a/src/services/note/polls/vote.ts
+++ b/src/services/note/polls/vote.ts
@@ -29,7 +29,7 @@ export default async function(user: User, note: Note, choice: number) {
}
// Create vote
- await PollVotes.save({
+ await PollVotes.insert({
id: genId(),
createdAt: new Date(),
noteId: note.id,
diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts
index adc96ddc1f..181099cc2d 100644
--- a/src/services/note/reaction/create.ts
+++ b/src/services/note/reaction/create.ts
@@ -11,45 +11,53 @@ import { perUserReactionsChart } from '../../chart';
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';
export default async (user: User, note: Note, reaction?: string) => {
+ // TODO: cache
reaction = await toDbReaction(reaction, user.host);
- const exist = await NoteReactions.findOne({
+ let record: NoteReaction = {
+ id: genId(),
+ createdAt: new Date(),
noteId: note.id,
userId: user.id,
- });
+ reaction
+ };
- if (exist) {
- if (exist.reaction !== reaction) {
- // 別ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ãŒã™ã§ã«ã•れã¦ã„ãŸã‚‰ç½®ãæ›ãˆã‚‹
- await deleteReaction(user, note);
+ // Create reaction
+ try {
+ await NoteReactions.insert(record);
+ } catch (e) {
+ if (isDuplicateKeyValueError(e)) {
+ record = await NoteReactions.findOneOrFail({
+ noteId: note.id,
+ userId: user.id,
+ });
+
+ if (record.reaction !== reaction) {
+ // 別ã®ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ãŒã™ã§ã«ã•れã¦ã„ãŸã‚‰ç½®ãæ›ãˆã‚‹
+ await deleteReaction(user, note);
+ } else {
+ // åŒã˜ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ãŒã™ã§ã«ã•れã¦ã„ãŸã‚‰ä½•ã‚‚ã—ãªã„
+ return;
+ }
} else {
- // åŒã˜ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ãŒã™ã§ã«ã•れã¦ã„ãŸã‚‰ä½•ã‚‚ã—ãªã„
- return;
+ throw e;
}
}
- // Create reaction
- const inserted = await NoteReactions.save({
- id: genId(),
- createdAt: new Date(),
- noteId: note.id,
- userId: user.id,
- reaction
- });
-
// Increment reactions count
const sql = `jsonb_set("reactions", '{${reaction}}', (COALESCE("reactions"->>'${reaction}', '0')::int + 1)::text::jsonb)`;
await Notes.createQueryBuilder().update()
.set({
reactions: () => sql,
+ score: () => '"score" + 1'
})
.where('id = :id', { id: note.id })
.execute();
- Notes.increment({ id: note.id }, 'score', 1);
-
perUserReactionsChart.update(user, note);
// カスタム絵文字リアクションã ã£ãŸã‚‰çµµæ–‡å­—情報もé€ã‚‹
@@ -101,7 +109,7 @@ export default async (user: User, note: Note, reaction?: string) => {
//#region é…ä¿¡
if (Users.isLocalUser(user) && !note.localOnly) {
- const content = renderActivity(await renderLike(inserted, note));
+ const content = renderActivity(await renderLike(record, note));
const dm = new DeliverManager(user, content);
if (note.userHost !== null) {
const reactee = await Users.findOne(note.userId);
diff --git a/src/services/note/read.ts b/src/services/note/read.ts
index 5a39ab30b7..35279db411 100644
--- a/src/services/note/read.ts
+++ b/src/services/note/read.ts
@@ -2,70 +2,54 @@ import { publishMainStream } from '../stream';
import { Note } from '../../models/entities/note';
import { User } from '../../models/entities/user';
import { NoteUnreads, Antennas, AntennaNotes, Users } from '../../models';
-import { Not, IsNull } from 'typeorm';
+import { Not, IsNull, In } from 'typeorm';
/**
- * Mark a note as read
+ * Mark notes as read
*/
export default async function(
userId: User['id'],
- noteId: Note['id']
+ noteIds: Note['id'][]
) {
async function careNoteUnreads() {
- const exist = await NoteUnreads.findOne({
- userId: userId,
- noteId: noteId,
- });
-
- if (!exist) return;
-
// Remove the record
await NoteUnreads.delete({
userId: userId,
- noteId: noteId,
+ noteId: In(noteIds),
});
- if (exist.isMentioned) {
- NoteUnreads.count({
- userId: userId,
- isMentioned: true
- }).then(mentionsCount => {
- if (mentionsCount === 0) {
- // å…¨ã¦æ—¢èª­ã«ãªã£ãŸã‚¤ãƒ™ãƒ³ãƒˆã‚’発行
- publishMainStream(userId, 'readAllUnreadMentions');
- }
- });
- }
+ NoteUnreads.count({
+ userId: userId,
+ isMentioned: true
+ }).then(mentionsCount => {
+ if (mentionsCount === 0) {
+ // å…¨ã¦æ—¢èª­ã«ãªã£ãŸã‚¤ãƒ™ãƒ³ãƒˆã‚’発行
+ publishMainStream(userId, 'readAllUnreadMentions');
+ }
+ });
- if (exist.isSpecified) {
- NoteUnreads.count({
- userId: userId,
- isSpecified: true
- }).then(specifiedCount => {
- if (specifiedCount === 0) {
- // å…¨ã¦æ—¢èª­ã«ãªã£ãŸã‚¤ãƒ™ãƒ³ãƒˆã‚’発行
- publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
- }
- });
- }
+ NoteUnreads.count({
+ userId: userId,
+ isSpecified: true
+ }).then(specifiedCount => {
+ if (specifiedCount === 0) {
+ // å…¨ã¦æ—¢èª­ã«ãªã£ãŸã‚¤ãƒ™ãƒ³ãƒˆã‚’発行
+ publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
+ }
+ });
- if (exist.noteChannelId) {
- NoteUnreads.count({
- userId: userId,
- noteChannelId: Not(IsNull())
- }).then(channelNoteCount => {
- if (channelNoteCount === 0) {
- // å…¨ã¦æ—¢èª­ã«ãªã£ãŸã‚¤ãƒ™ãƒ³ãƒˆã‚’発行
- publishMainStream(userId, 'readAllChannels');
- }
- });
- }
+ NoteUnreads.count({
+ userId: userId,
+ noteChannelId: Not(IsNull())
+ }).then(channelNoteCount => {
+ if (channelNoteCount === 0) {
+ // å…¨ã¦æ—¢èª­ã«ãªã£ãŸã‚¤ãƒ™ãƒ³ãƒˆã‚’発行
+ publishMainStream(userId, 'readAllChannels');
+ }
+ });
}
async function careAntenna() {
- const beforeUnread = await Users.getHasUnreadAntenna(userId);
- if (!beforeUnread) return;
-
const antennas = await Antennas.find({ userId });
await Promise.all(antennas.map(async antenna => {
@@ -78,7 +62,7 @@ export default async function(
await AntennaNotes.update({
antennaId: antenna.id,
- noteId: noteId
+ noteId: In(noteIds)
}, {
read: true
});
diff --git a/src/services/note/unread.ts b/src/services/note/unread.ts
index 6fd9ee2cfe..8e6fb4abe8 100644
--- a/src/services/note/unread.ts
+++ b/src/services/note/unread.ts
@@ -17,7 +17,7 @@ export default async function(userId: User['id'], note: Note, params: {
if (mute.map(m => m.muteeId).includes(note.userId)) return;
//#endregion
- const unread = await NoteUnreads.save({
+ const unread = {
id: genId(),
noteId: note.id,
userId: userId,
@@ -25,7 +25,9 @@ export default async function(userId: User['id'], note: Note, params: {
isMentioned: params.isMentioned,
noteChannelId: note.channelId,
noteUserId: note.userId,
- });
+ };
+
+ await NoteUnreads.insert(unread);
// 2秒経ã£ã¦ã‚‚既読ã«ãªã‚‰ãªã‹ã£ãŸã‚‰ã€Œæœªèª­ã®æŠ•稿ãŒã‚りã¾ã™ã‚ˆã€ã‚¤ãƒ™ãƒ³ãƒˆã‚’発行ã™ã‚‹
setTimeout(async () => {
diff --git a/src/services/note/watch.ts b/src/services/note/watch.ts
index d3c9553696..966b7f0054 100644
--- a/src/services/note/watch.ts
+++ b/src/services/note/watch.ts
@@ -10,7 +10,7 @@ export default async (me: User['id'], note: Note) => {
return;
}
- await NoteWatchings.save({
+ await NoteWatchings.insert({
id: genId(),
createdAt: new Date(),
noteId: note.id,
diff --git a/src/services/register-or-fetch-instance-doc.ts b/src/services/register-or-fetch-instance-doc.ts
index 3501e20de1..2c39502288 100644
--- a/src/services/register-or-fetch-instance-doc.ts
+++ b/src/services/register-or-fetch-instance-doc.ts
@@ -3,10 +3,16 @@ import { Instances } from '../models';
import { federationChart } from './chart';
import { genId } from '../misc/gen-id';
import { toPuny } from '../misc/convert-host';
+import { Cache } from '../misc/cache';
+
+const cache = new Cache<Instance>(1000 * 60 * 60);
export async function registerOrFetchInstanceDoc(host: string): Promise<Instance> {
host = toPuny(host);
+ const cached = cache.get(host);
+ if (cached) return cached;
+
const index = await Instances.findOne({ host });
if (index == null) {
@@ -19,8 +25,10 @@ export async function registerOrFetchInstanceDoc(host: string): Promise<Instance
federationChart.update(true);
+ cache.set(host, i);
return i;
} else {
+ cache.set(host, index);
return index;
}
}
diff --git a/src/services/stream.ts b/src/services/stream.ts
index d833d700fe..75385847ce 100644
--- a/src/services/stream.ts
+++ b/src/services/stream.ts
@@ -20,6 +20,10 @@ class Publisher {
}));
}
+ public publishUserEvent = (userId: User['id'], type: string, value?: any): void => {
+ this.publish(`user:${userId}`, type, typeof value === 'undefined' ? null : value);
+ }
+
public publishBroadcastStream = (type: string, value?: any): void => {
this.publish('broadcast', type, typeof value === 'undefined' ? null : value);
}
@@ -84,6 +88,7 @@ const publisher = new Publisher();
export default publisher;
+export const publishUserEvent = publisher.publishUserEvent;
export const publishBroadcastStream = publisher.publishBroadcastStream;
export const publishMainStream = publisher.publishMainStream;
export const publishDriveStream = publisher.publishDriveStream;
diff --git a/src/services/update-hashtag.ts b/src/services/update-hashtag.ts
index 1dcb582791..3e22846731 100644
--- a/src/services/update-hashtag.ts
+++ b/src/services/update-hashtag.ts
@@ -86,7 +86,7 @@ export async function updateHashtag(user: User, tag: string, isUserAttached = fa
}
} else {
if (isUserAttached) {
- Hashtags.save({
+ Hashtags.insert({
id: genId(),
name: tag,
mentionedUserIds: [],
@@ -103,7 +103,7 @@ export async function updateHashtag(user: User, tag: string, isUserAttached = fa
attachedRemoteUsersCount: Users.isRemoteUser(user) ? 1 : 0,
} as Hashtag);
} else {
- Hashtags.save({
+ Hashtags.insert({
id: genId(),
name: tag,
mentionedUserIds: [user.id],
diff --git a/src/services/user-list/push.ts b/src/services/user-list/push.ts
index e67be4b027..ba54c04475 100644
--- a/src/services/user-list/push.ts
+++ b/src/services/user-list/push.ts
@@ -8,7 +8,7 @@ import { fetchProxyAccount } from '../../misc/fetch-proxy-account';
import createFollowing from '../following/create';
export async function pushUserToUserList(target: User, list: UserList) {
- await UserListJoinings.save({
+ await UserListJoinings.insert({
id: genId(),
createdAt: new Date(),
userId: target.id,
diff --git a/tsconfig.json b/src/tsconfig.json
index 075450bf64..95cb35fc5f 100644
--- a/tsconfig.json
+++ b/src/tsconfig.json
@@ -22,8 +22,8 @@
"resolveJsonModule": true,
"isolatedModules": true,
"typeRoots": [
- "node_modules/@types",
- "src/@types"
+ "../node_modules/@types",
+ "./@types"
],
"lib": [
"esnext"
@@ -31,9 +31,9 @@
},
"compileOnSave": false,
"include": [
- "./src/**/*.ts"
+ "./**/*.ts"
],
"exclude": [
- "./src/client/**/*.ts"
+ "./client/**/*.ts"
]
}
diff --git a/test/.eslintrc b/test/.eslintrc
new file mode 100644
index 0000000000..cea1b11388
--- /dev/null
+++ b/test/.eslintrc
@@ -0,0 +1,7 @@
+{
+ "env": {
+ "node": true,
+ "mocha": true,
+ "commonjs": true
+ }
+}
diff --git a/test/chart.ts b/test/chart.ts
index 25b083db17..55f6bd696c 100644
--- a/test/chart.ts
+++ b/test/chart.ts
@@ -72,7 +72,7 @@ describe('Chart', () => {
testUniqueChart = new TestUniqueChart();
clock = lolex.install({
- now: new Date('2000-01-01 00:00:00')
+ now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0))
});
done();
});
@@ -85,6 +85,7 @@ describe('Chart', () => {
it('Can updates', async(async () => {
await testChart.increment();
+ await testChart.save();
const chartHours = await testChart.getChart('hour', 3, null);
const chartDays = await testChart.getChart('day', 3, null);
@@ -105,9 +106,10 @@ describe('Chart', () => {
},
});
}));
-
+
it('Can updates (dec)', async(async () => {
await testChart.decrement();
+ await testChart.save();
const chartHours = await testChart.getChart('hour', 3, null);
const chartDays = await testChart.getChart('day', 3, null);
@@ -154,6 +156,7 @@ describe('Chart', () => {
await testChart.increment();
await testChart.increment();
await testChart.increment();
+ await testChart.save();
const chartHours = await testChart.getChart('hour', 3, null);
const chartDays = await testChart.getChart('day', 3, null);
@@ -177,10 +180,12 @@ describe('Chart', () => {
it('Can updates at different times', async(async () => {
await testChart.increment();
+ await testChart.save();
clock.tick('01:00:00');
await testChart.increment();
+ await testChart.save();
const chartHours = await testChart.getChart('hour', 3, null);
const chartDays = await testChart.getChart('day', 3, null);
@@ -202,12 +207,45 @@ describe('Chart', () => {
});
}));
+ // 仕様上ã¯ã“ã†ãªã£ã¦ã»ã—ã„ã‘ã©ã€å®Ÿè£…ã¯é›£ã—ãã†ãªã®ã§skip
+ /*
+ it('Can updates at different times without save', async(async () => {
+ await testChart.increment();
+
+ clock.tick('01:00:00');
+
+ await testChart.increment();
+ await testChart.save();
+
+ const chartHours = await testChart.getChart('hour', 3, null);
+ const chartDays = await testChart.getChart('day', 3, null);
+
+ assert.deepStrictEqual(chartHours, {
+ foo: {
+ dec: [0, 0, 0],
+ inc: [1, 1, 0],
+ total: [2, 1, 0]
+ },
+ });
+
+ assert.deepStrictEqual(chartDays, {
+ foo: {
+ dec: [0, 0, 0],
+ inc: [2, 0, 0],
+ total: [2, 0, 0]
+ },
+ });
+ }));
+ */
+
it('Can padding', async(async () => {
await testChart.increment();
+ await testChart.save();
clock.tick('02:00:00');
await testChart.increment();
+ await testChart.save();
const chartHours = await testChart.getChart('hour', 3, null);
const chartDays = await testChart.getChart('day', 3, null);
@@ -232,6 +270,7 @@ describe('Chart', () => {
// è¦æ±‚ã•れãŸç¯„囲ã«ãƒ­ã‚°ãŒã²ã¨ã¤ã‚‚ãªã„å ´åˆã§ã‚‚パディングã§ãã‚‹
it('Can padding from past range', async(async () => {
await testChart.increment();
+ await testChart.save();
clock.tick('05:00:00');
@@ -259,8 +298,12 @@ describe('Chart', () => {
// Issue #3190
it('Can padding from past range 2', async(async () => {
await testChart.increment();
+ await testChart.save();
+
clock.tick('05:00:00');
+
await testChart.increment();
+ await testChart.save();
const chartHours = await testChart.getChart('hour', 3, null);
const chartDays = await testChart.getChart('day', 3, null);
@@ -284,10 +327,12 @@ describe('Chart', () => {
it('Can specify offset', async(async () => {
await testChart.increment();
+ await testChart.save();
clock.tick('01:00:00');
await testChart.increment();
+ await testChart.save();
const chartHours = await testChart.getChart('hour', 3, new Date(Date.UTC(2000, 0, 1, 0, 0, 0)));
const chartDays = await testChart.getChart('day', 3, new Date(Date.UTC(2000, 0, 1, 0, 0, 0)));
@@ -313,10 +358,12 @@ describe('Chart', () => {
clock.tick('00:30:00');
await testChart.increment();
+ await testChart.save();
clock.tick('01:30:00');
await testChart.increment();
+ await testChart.save();
const chartHours = await testChart.getChart('hour', 3, new Date(Date.UTC(2000, 0, 1, 0, 0, 0)));
const chartDays = await testChart.getChart('day', 3, new Date(Date.UTC(2000, 0, 1, 0, 0, 0)));
@@ -341,6 +388,7 @@ describe('Chart', () => {
describe('Grouped', () => {
it('Can updates', async(async () => {
await testGroupedChart.increment('alice');
+ await testGroupedChart.save();
const aliceChartHours = await testGroupedChart.getChart('hour', 3, null, 'alice');
const aliceChartDays = await testGroupedChart.getChart('day', 3, null, 'alice');
@@ -386,6 +434,7 @@ describe('Chart', () => {
await testUniqueChart.uniqueIncrement('alice');
await testUniqueChart.uniqueIncrement('alice');
await testUniqueChart.uniqueIncrement('bob');
+ await testUniqueChart.save();
const chartHours = await testUniqueChart.getChart('hour', 3, null);
const chartDays = await testUniqueChart.getChart('day', 3, null);
@@ -428,6 +477,7 @@ describe('Chart', () => {
it('Can resync (2)', async(async () => {
await testChart.increment();
+ await testChart.save();
clock.tick('01:00:00');
diff --git a/test/fetch-resource.ts b/test/fetch-resource.ts
new file mode 100644
index 0000000000..12a37b6cb0
--- /dev/null
+++ b/test/fetch-resource.ts
@@ -0,0 +1,187 @@
+/*
+ * Tests for Fetch resource
+ *
+ * How to run the tests:
+ * > npx cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true npx mocha test/fetch-resource.ts --require ts-node/register
+ *
+ * To specify test:
+ * > npx cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true npx mocha test/fetch-resource.ts --require ts-node/register -g 'test name'
+ */
+
+process.env.NODE_ENV = 'test';
+
+import * as assert from 'assert';
+import * as childProcess from 'child_process';
+import { async, launchServer, signup, post, request, simpleGet } from './utils';
+
+// Request Accept
+const ONLY_AP = 'application/activity+json';
+const PREFER_AP = 'application/activity+json, */*';
+const PREFER_HTML = 'text/html, */*';
+const UNSPECIFIED = '*/*';
+
+// Response Contet-Type
+const AP = 'application/activity+json; charset=utf-8';
+const JSON = 'application/json; charset=utf-8';
+const HTML = 'text/html; charset=utf-8';
+
+describe('Fetch resource', () => {
+ let p: childProcess.ChildProcess;
+
+ let alice: any;
+ let alicesPost: any;
+
+ before(launchServer(g => p = g, async () => {
+ alice = await signup({ username: 'alice' });
+ alicesPost = await post(alice, {
+ text: 'test'
+ });
+ }));
+
+ after(() => {
+ p.kill();
+ });
+
+ describe('Common', () => {
+ it('meta', async(async () => {
+ const res = await request('/meta', {
+ });
+
+ assert.strictEqual(res.status, 200);
+ }));
+
+ it('GET root', async(async () => {
+ const res = await simpleGet('/');
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, HTML);
+ }));
+
+ it('GET docs', async(async () => {
+ const res = await simpleGet('/docs/ja-JP/about');
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, HTML);
+ }));
+
+ it('GET api-doc', async(async () => {
+ const res = await simpleGet('/api-doc');
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, HTML);
+ }));
+
+ it('GET api.json', async(async () => {
+ const res = await simpleGet('/api.json');
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, JSON);
+ }));
+
+ it('GET favicon.ico', async(async () => {
+ const res = await simpleGet('/favicon.ico');
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, 'image/x-icon');
+ }));
+
+ it('GET apple-touch-icon.png', async(async () => {
+ const res = await simpleGet('/apple-touch-icon.png');
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, 'image/png');
+ }));
+ });
+
+ describe('/@:username', () => {
+ it('Only AP => AP', async(async () => {
+ const res = await simpleGet(`/@${alice.username}`, ONLY_AP);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, AP);
+ }));
+
+ it('Prefer AP => AP', async(async () => {
+ const res = await simpleGet(`/@${alice.username}`, PREFER_AP);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, AP);
+ }));
+
+ it('Prefer HTML => HTML', async(async () => {
+ const res = await simpleGet(`/@${alice.username}`, PREFER_HTML);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, HTML);
+ }));
+
+ it('Unspecified => HTML', async(async () => {
+ const res = await simpleGet(`/@${alice.username}`, UNSPECIFIED);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, HTML);
+ }));
+ });
+
+ describe('/users/:id', () => {
+ it('Only AP => AP', async(async () => {
+ const res = await simpleGet(`/users/${alice.id}`, ONLY_AP);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, AP);
+ }));
+
+ it('Prefer AP => AP', async(async () => {
+ const res = await simpleGet(`/users/${alice.id}`, PREFER_AP);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, AP);
+ }));
+
+ it('Prefer HTML => Redirect to /@:username', async(async () => {
+ const res = await simpleGet(`/users/${alice.id}`, PREFER_HTML);
+ assert.strictEqual(res.status, 302);
+ assert.strictEqual(res.location, `/@${alice.username}`);
+ }));
+
+ it('Undecided => HTML', async(async () => {
+ const res = await simpleGet(`/users/${alice.id}`, UNSPECIFIED);
+ assert.strictEqual(res.status, 302);
+ assert.strictEqual(res.location, `/@${alice.username}`);
+ }));
+ });
+
+ describe('/notes/:id', () => {
+ it('Only AP => AP', async(async () => {
+ const res = await simpleGet(`/notes/${alicesPost.id}`, ONLY_AP);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, AP);
+ }));
+
+ it('Prefer AP => AP', async(async () => {
+ const res = await simpleGet(`/notes/${alicesPost.id}`, PREFER_AP);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, AP);
+ }));
+
+ it('Prefer HTML => HTML', async(async () => {
+ const res = await simpleGet(`/notes/${alicesPost.id}`, PREFER_HTML);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, HTML);
+ }));
+
+ it('Unspecified => HTML', async(async () => {
+ const res = await simpleGet(`/notes/${alicesPost.id}`, UNSPECIFIED);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, HTML);
+ }));
+ });
+
+ describe('Feeds', () => {
+ it('RSS', async(async () => {
+ const res = await simpleGet(`/@${alice.username}.rss`, UNSPECIFIED);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, 'application/rss+xml; charset=utf-8');
+ }));
+
+ it('ATOM', async(async () => {
+ const res = await simpleGet(`/@${alice.username}.atom`, UNSPECIFIED);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, 'application/atom+xml; charset=utf-8');
+ }));
+
+ it('JSON', async(async () => {
+ const res = await simpleGet(`/@${alice.username}.json`, UNSPECIFIED);
+ assert.strictEqual(res.status, 200);
+ assert.strictEqual(res.type, 'application/json; charset=utf-8');
+ }));
+ });
+});
diff --git a/test/get-file-info.ts b/test/get-file-info.ts
index 312b225aa2..8757d5a901 100644
--- a/test/get-file-info.ts
+++ b/test/get-file-info.ts
@@ -2,10 +2,10 @@
* Tests for detection of file information
*
* How to run the tests:
- * > TS_NODE_FILES=true npx mocha test/get-file-info.ts --require ts-node/register
+ * > npx cross-env TS_NODE_FILES=true npx mocha test/get-file-info.ts --require ts-node/register
*
* To specify test:
- * > TS_NODE_FILES=true npx mocha test/get-file-info.ts --require ts-node/register -g 'test name'
+ * > npx cross-env TS_NODE_FILES=true npx mocha test/get-file-info.ts --require ts-node/register -g 'test name'
*/
import * as assert from 'assert';
diff --git a/test/tsconfig.json b/test/tsconfig.json
new file mode 100644
index 0000000000..987067ba81
--- /dev/null
+++ b/test/tsconfig.json
@@ -0,0 +1,36 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "noEmitOnError": false,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "noUnusedParameters": false,
+ "noUnusedLocals": true,
+ "noFallthroughCasesInSwitch": true,
+ "declaration": false,
+ "sourceMap": true,
+ "target": "es2017",
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "removeComments": false,
+ "noLib": false,
+ "strict": true,
+ "strictNullChecks": true,
+ "strictPropertyInitialization": false,
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "typeRoots": [
+ "../node_modules/@types",
+ "../src/@types"
+ ],
+ "lib": [
+ "esnext"
+ ]
+ },
+ "compileOnSave": false,
+ "include": [
+ "./**/*.ts"
+ ]
+}
diff --git a/test/utils.ts b/test/utils.ts
index 066bd33a56..b0393ee192 100644
--- a/test/utils.ts
+++ b/test/utils.ts
@@ -3,6 +3,10 @@ import * as WebSocket from 'ws';
import fetch from 'node-fetch';
const FormData = require('form-data');
import * as childProcess from 'child_process';
+import * as http from 'http';
+import loadConfig from '../src/config/load';
+
+const port = loadConfig().port;
export const async = (fn: Function) => (done: Function) => {
fn().then(() => {
@@ -17,26 +21,20 @@ export const request = async (endpoint: string, params: any, me?: any): Promise<
i: me.token
} : {};
- try {
- const res = await fetch('http://localhost:8080/api' + endpoint, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(Object.assign(auth, params))
- });
+ const res = await fetch(`http://localhost:${port}/api${endpoint}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(Object.assign(auth, params))
+ });
- const status = res.status;
- const body = res.status !== 204 ? await res.json().catch() : null;
+ const status = res.status;
+ const body = res.status !== 204 ? await res.json().catch() : null;
- return {
- body, status
- };
- } catch (e) {
- return {
- body: null, status: 500
- };
- }
+ return {
+ body, status
+ };
};
export const signup = async (params?: any): Promise<any> => {
@@ -72,7 +70,7 @@ export const uploadFile = (user: any, path?: string): Promise<any> => {
formData.append('i', user.token);
formData.append('file', fs.createReadStream(path || __dirname + '/resources/Lenna.png'));
- return fetch('http://localhost:8080/api/drive/files/create', {
+ return fetch(`http://localhost:${port}/api/drive/files/create`, {
method: 'post',
body: formData,
timeout: 30 * 1000,
@@ -87,7 +85,7 @@ export const uploadFile = (user: any, path?: string): Promise<any> => {
export function connectStream(user: any, channel: string, listener: (message: Record<string, any>) => any, params?: any): Promise<WebSocket> {
return new Promise((res, rej) => {
- const ws = new WebSocket(`ws://localhost:8080/streaming?i=${user.token}`);
+ const ws = new WebSocket(`ws://localhost:${port}/streaming?i=${user.token}`);
ws.on('open', () => {
ws.on('message', data => {
@@ -112,6 +110,29 @@ export function connectStream(user: any, channel: string, listener: (message: Re
});
}
+export const simpleGet = async (path: string, accept = '*/*'): Promise<{ status?: number, type?: string, location?: string }> => {
+ // node-fetchã ã¨3xxã‚’å–れãªã„
+ return await new Promise((resolve, reject) => {
+ const req = http.request(`http://localhost:${port}${path}`, {
+ headers: {
+ Accept: accept
+ }
+ }, res => {
+ if (res.statusCode! >= 400) {
+ reject(res);
+ } else {
+ resolve({
+ status: res.statusCode,
+ type: res.headers['content-type'],
+ location: res.headers.location,
+ });
+ }
+ });
+
+ req.end();
+ });
+};
+
export function launchServer(callbackSpawnedProcess: (p: childProcess.ChildProcess) => void, moreProcess: () => Promise<void> = async () => {}) {
return (done: (err?: Error) => any) => {
const p = childProcess.spawn('node', [__dirname + '/../index.js'], {
diff --git a/yarn.lock b/yarn.lock
index c03fa4182e..eecd562aac 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -89,11 +89,6 @@
dependencies:
"@babel/types" "^7.12.13"
-"@babel/helper-validator-identifier@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
- integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
-
"@babel/helper-validator-identifier@^7.12.11":
version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
@@ -113,20 +108,15 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.12.0", "@babel/parser@^7.6.0":
- version "7.12.0"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.0.tgz#2ad388f3960045b22f9b7d4bf85e80b15a1c9e3a"
- integrity sha512-dYmySMYnlus2jwl7JnnajAj11obRStZoW9cG04wh4ZuhozDn11tDUrhHcUZ9iuNHqALAhh60XqNaYXpvuuE/Gg==
-
-"@babel/parser@^7.12.13", "@babel/parser@^7.13.0":
- version "7.13.4"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.4.tgz#340211b0da94a351a6f10e63671fa727333d13ab"
- integrity sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA==
-
-"@babel/plugin-transform-runtime@7.13.9":
+"@babel/parser@^7.12.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6":
version "7.13.9"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.13.9.tgz#744d3103338a0d6c90dee0497558150b490cee07"
- integrity sha512-XCxkY/wBI6M6Jj2mlWxkmqbKPweRanszWbF3Tyut+hKh+PHcuIH/rSr/7lmmE7C3WW+HSIm2GT+d5jwmheuB0g==
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.9.tgz#ca34cb95e1c2dd126863a84465ae8ef66114be99"
+ integrity sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==
+
+"@babel/plugin-transform-runtime@7.13.10":
+ version "7.13.10"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.13.10.tgz#a1e40d22e2bf570c591c9c7e5ab42d6bf1e419e1"
+ integrity sha512-Y5k8ipgfvz5d/76tx7JYbKQTcgFSU6VgJ3kKQv4zGTKr+a9T/KBvfRvGtSFgKDQGt/DBykQixV0vNWKIdzWErA==
dependencies:
"@babel/helper-module-imports" "^7.12.13"
"@babel/helper-plugin-utils" "^7.13.0"
@@ -166,25 +156,7 @@
globals "^11.1.0"
lodash "^4.17.19"
-"@babel/types@^7.12.0", "@babel/types@^7.6.1":
- version "7.12.7"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.7.tgz#6039ff1e242640a29452c9ae572162ec9a8f5d13"
- integrity sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==
- dependencies:
- "@babel/helper-validator-identifier" "^7.10.4"
- lodash "^4.17.19"
- to-fast-properties "^2.0.0"
-
-"@babel/types@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.13.tgz#8be1aa8f2c876da11a9cf650c0ecf656913ad611"
- integrity sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==
- dependencies:
- "@babel/helper-validator-identifier" "^7.12.11"
- lodash "^4.17.19"
- to-fast-properties "^2.0.0"
-
-"@babel/types@^7.13.0":
+"@babel/types@^7.12.0", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.6.1", "@babel/types@^7.9.6":
version "7.13.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80"
integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==
@@ -229,38 +201,38 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
-"@fortawesome/fontawesome-common-types@^0.2.34":
- version "0.2.34"
- resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.34.tgz#0a8c348bb23b7b760030f5b1d912e582be4ec915"
- integrity sha512-XcIn3iYbTEzGIxD0/dY5+4f019jIcEIWBiHc3KrmK/ROahwxmZ/s+tdj97p/5K0klz4zZUiMfUlYP0ajhSJjmA==
+"@fortawesome/fontawesome-common-types@^0.2.35":
+ version "0.2.35"
+ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz#01dd3d054da07a00b764d78748df20daf2b317e9"
+ integrity sha512-IHUfxSEDS9dDGqYwIW7wTN6tn/O8E0n5PcAHz9cAaBoZw6UpG20IG/YM3NNLaGPwPqgjBAFjIURzqoQs3rrtuw==
-"@fortawesome/fontawesome-svg-core@1.2.34":
- version "1.2.34"
- resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.34.tgz#1d1a7c92537cbc2b8a83eef6b6d824b4b5b46b26"
- integrity sha512-0KNN0nc5eIzaJxlv43QcDmTkDY1CqeN6J7OCGSs+fwGPdtv0yOQqRjieopBCmw+yd7uD3N2HeNL3Zm5isDleLg==
+"@fortawesome/fontawesome-svg-core@1.2.35":
+ version "1.2.35"
+ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.35.tgz#85aea8c25645fcec88d35f2eb1045c38d3e65cff"
+ integrity sha512-uLEXifXIL7hnh2sNZQrIJWNol7cTVIzwI+4qcBIq9QWaZqUblm0IDrtSqbNg+3SQf8SMGHkiSigD++rHmCHjBg==
dependencies:
- "@fortawesome/fontawesome-common-types" "^0.2.34"
+ "@fortawesome/fontawesome-common-types" "^0.2.35"
-"@fortawesome/free-brands-svg-icons@5.15.2":
- version "5.15.2"
- resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.2.tgz#d74e2540b5552b915d6bef719f17e361b70a8d65"
- integrity sha512-YPlVjE1cEO+OJ9I9ay3TQ3I88+XkxMTYwnnddqAboxLhPNGncsHV0DjWOVLCyuAY66yPfyndWwVn4v7vuqsO1g==
+"@fortawesome/free-brands-svg-icons@5.15.3":
+ version "5.15.3"
+ resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.3.tgz#bec2821d23b9c667be1d192a6c5bfb2667e588eb"
+ integrity sha512-1hirPcbjj72ZJtFvdnXGPbAbpn3Ox6mH3g5STbANFp3vGSiE5u5ingAKV06mK6ZVqNYxUPlh4DlTnaIvLtF2kw==
dependencies:
- "@fortawesome/fontawesome-common-types" "^0.2.34"
+ "@fortawesome/fontawesome-common-types" "^0.2.35"
-"@fortawesome/free-regular-svg-icons@5.15.2":
- version "5.15.2"
- resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.2.tgz#61eeb8c206e792c530eaa58279cc32c55332fe8f"
- integrity sha512-Uv5NQCYjyisNVTu/1Xjs+z8vwQjbfT6hiqYvQNfF0n8qdgfWLM581bAfVMQ3BCs1SPy+eEUKNcGkK4n0FihFHg==
+"@fortawesome/free-regular-svg-icons@5.15.3":
+ version "5.15.3"
+ resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.3.tgz#1ec4f2410ff638db549c5c5484fc60b66407dbe6"
+ integrity sha512-q4/p8Xehy9qiVTdDWHL4Z+o5PCLRChePGZRTXkl+/Z7erDVL8VcZUuqzJjs6gUz6czss4VIPBRdCz6wP37/zMQ==
dependencies:
- "@fortawesome/fontawesome-common-types" "^0.2.34"
+ "@fortawesome/fontawesome-common-types" "^0.2.35"
-"@fortawesome/free-solid-svg-icons@5.15.2":
- version "5.15.2"
- resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.2.tgz#25bb035de57cf85aee8072965732368ccc8e8943"
- integrity sha512-ZfCU+QjaFsdNZmOGmfqEWhzI3JOe37x5dF4kz9GeXvKn/sTxhqMtZ7mh3lBf76SvcYY5/GKFuyG7p1r4iWMQqw==
+"@fortawesome/free-solid-svg-icons@5.15.3":
+ version "5.15.3"
+ resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.3.tgz#52eebe354f60dc77e0bde934ffc5c75ffd04f9d8"
+ integrity sha512-XPeeu1IlGYqz4VWGRAT5ukNMd4VHUEEJ7ysZ7pSSgaEtNvSo+FLurybGJVmiqkQdK50OkSja2bfZXOeyMGRD8Q==
dependencies:
- "@fortawesome/fontawesome-common-types" "^0.2.34"
+ "@fortawesome/fontawesome-common-types" "^0.2.35"
"@fortawesome/vue-fontawesome@3.0.0-3":
version "3.0.0-3"
@@ -386,10 +358,10 @@
dependencies:
type-detect "4.0.8"
-"@sinonjs/fake-timers@6.0.1":
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40"
- integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==
+"@sinonjs/fake-timers@7.0.2":
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.0.2.tgz#a53e71d4154ee704ea9b36a6d0b0780e246fadd1"
+ integrity sha512-dF84L5YC90gIOegPDCYymPIsDmwMWWSh7BwfDXQYePi8lVIEp7IZ1UVGkME8FjXOsDPxan12x4aaK+Lo6wVh9A==
dependencies:
"@sinonjs/commons" "^1.7.0"
@@ -524,11 +496,6 @@
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
-"@types/double-ended-queue@2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@types/double-ended-queue/-/double-ended-queue-2.1.1.tgz#f077386134f0f736d927812c85c43a04f21ddc27"
- integrity sha512-O2+umEIlHBVyi+ePmucPjpINqTvSnsz+hAok0D4IpvrOsIsDr6c34B0AbNXW2UDVYuxbv51z5dxnrRt23ohgWg==
-
"@types/escape-regexp@0.0.0":
version "0.0.0"
resolved "https://registry.yarnpkg.com/@types/escape-regexp/-/escape-regexp-0.0.0.tgz#bff0225f9ef30d0dbdbe0e2a24283ee5342990c3"
@@ -681,10 +648,10 @@
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.0.tgz#d1a11688112091f2c711674df3a65ea2f47b5dfb"
integrity sha512-4vlpCM5KPCL5CfGmTbpjwVKbISRYhduEJvvUWsH5EB7QInhEj94XPZ3ts/9FPiLZFqYO0xoW4ZL8z2AabTGgJA==
-"@types/jsdom@16.2.6":
- version "16.2.6"
- resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.6.tgz#9ddf0521e49be5365797e690c3ba63148e562c29"
- integrity sha512-yQA+HxknGtW9AkRTNyiSH3OKW5V+WzO8OPTdne99XwJkYC+KYxfNIcoJjeiSqP3V00PUUpFP6Myoo9wdIu78DQ==
+"@types/jsdom@16.2.7":
+ version "16.2.7"
+ resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.7.tgz#27d2f77d655a3db15f7c3f104f1a6d15e3112938"
+ integrity sha512-jJ0QDvwZxAO+SninBaQdW6najEs1dCZ1uMsXFBTitwfAtz+0wfDZWd3GFEqkL4flD3IefB+VGBcrN9HbRdAdog==
dependencies:
"@types/node" "*"
"@types/parse5" "*"
@@ -700,10 +667,10 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
-"@types/jsonld@1.5.4":
- version "1.5.4"
- resolved "https://registry.yarnpkg.com/@types/jsonld/-/jsonld-1.5.4.tgz#37e7869fae65bd9b35aa3467cbfc60c52f881a36"
- integrity sha512-e51UoELQzKJWGsVNqoKI5nnXazupqoOYTBMAGe3Iram0sWxeVTzgk38BKYgmOZmuIXaMFfuAz1ZimK2oyQNnRA==
+"@types/jsonld@1.5.5":
+ version "1.5.5"
+ resolved "https://registry.yarnpkg.com/@types/jsonld/-/jsonld-1.5.5.tgz#c2238462a83e90f003929cef6a36eded2ceed069"
+ integrity sha512-/4PvZJJh3Lqz9bkwvSwfyLWnR1xFQ7h4KLq8i0yaGjBBq09qLMJlCqvfXfE5qFEnClmWM+GK2Edjbb6QDS2SXQ==
"@types/katex@0.11.0":
version "0.11.0"
@@ -778,24 +745,10 @@
dependencies:
"@types/koa" "*"
-"@types/koa@*":
- version "2.11.6"
- resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.11.6.tgz#b7030caa6b44af801c2aea13ba77d74aff7484d5"
- integrity sha512-BhyrMj06eQkk04C97fovEDQMpLpd2IxCB4ecitaXwOKGq78Wi2tooaDOWOFGajPk8IkQOAtMppApgSVkYe1F/A==
- dependencies:
- "@types/accepts" "*"
- "@types/content-disposition" "*"
- "@types/cookies" "*"
- "@types/http-assert" "*"
- "@types/http-errors" "*"
- "@types/keygrip" "*"
- "@types/koa-compose" "*"
- "@types/node" "*"
-
-"@types/koa@2.13.0":
- version "2.13.0"
- resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.0.tgz#6356c48521c0941103b6fcfb97bb01426a99d56d"
- integrity sha512-hNs1Z2lX+R5sZroIy/WIGbPlH/719s/Nd5uIjSIAdHn9q+g7z6mxOnhwMjK1urE4/NUP0SOoYUOD4MnvD9FRNw==
+"@types/koa@*", "@types/koa@2.13.1", "@types/koa@^2.13.1":
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.1.tgz#e29877a6b5ad3744ab1024f6ec75b8cbf6ec45db"
+ integrity sha512-Qbno7FWom9nNqu0yHZ6A0+RWt4mrYBhw3wpBAQ3+IuzGcLlfeYkzZrnMq5wsxulN2np8M4KKeUpTodsOsSad5Q==
dependencies:
"@types/accepts" "*"
"@types/content-disposition" "*"
@@ -875,22 +828,27 @@
form-data "^3.0.0"
"@types/node@*":
- version "14.14.13"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.13.tgz#9e425079799322113ae8477297ae6ef51b8e0cdf"
- integrity sha512-vbxr0VZ8exFMMAjCW8rJwaya0dMCDyYW2ZRdTyjtrCvJoENMpdUHOT/eTzvgyA5ZnqRZ/sI0NwqAxNHKYokLJQ==
-
-"@types/node@14.14.31":
version "14.14.31"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055"
integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==
-"@types/nodemailer@6.4.0":
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.0.tgz#d8c039be3ed685c4719a026455555be82c124b74"
- integrity sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==
+"@types/node@14.14.35":
+ version "14.14.35"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313"
+ integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==
+
+"@types/nodemailer@6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.1.tgz#31f96f4410632f781d3613bd1f4293649e423f75"
+ integrity sha512-8081UY/0XTTDpuGqCnDc8IY+Q3DSg604wB3dBH0CaZlj4nZWHWuxtZ3NRZ9c9WUrz1Vfm6wioAUnqL3bsh49uQ==
dependencies:
"@types/node" "*"
+"@types/normalize-package-data@^2.4.0":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
+ integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
+
"@types/nprogress@0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.0.tgz#86c593682d4199212a0509cc3c4d562bbbd6e45f"
@@ -1158,10 +1116,10 @@
"@types/webpack-sources" "*"
source-map "^0.6.0"
-"@types/websocket@1.0.1":
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.1.tgz#039272c196c2c0e4868a0d8a1a27bbb86e9e9138"
- integrity sha512-f5WLMpezwVxCLm1xQe/kdPpQIOmL0TXYx2O15VYfYzc7hTIdxiOoOvez+McSIw3b7z/1zGovew9YSL7+h4h7/Q==
+"@types/websocket@1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.2.tgz#d2855c6a312b7da73ed16ba6781815bf30c6187a"
+ integrity sha512-B5m9aq7cbbD/5/jThEr33nUY8WEfVi6A2YKCTOvw5Ldy7mtsOkqRvGjnzy6g7iMMDsgu7xREuCzqATLDLQVKcQ==
dependencies:
"@types/node" "*"
@@ -1172,48 +1130,48 @@
dependencies:
"@types/node" "*"
-"@typescript-eslint/parser@4.16.1":
- version "4.16.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.16.1.tgz#3bbd3234dd3c5b882b2bcd9899bc30e1e1586d2a"
- integrity sha512-/c0LEZcDL5y8RyI1zLcmZMvJrsR6SM1uetskFkoh3dvqDKVXPsXI+wFB/CbVw7WkEyyTKobC1mUNp/5y6gRvXg==
+"@typescript-eslint/parser@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.18.0.tgz#a211edb14a69fc5177054bec04c95b185b4dde21"
+ integrity sha512-W3z5S0ZbecwX3PhJEAnq4mnjK5JJXvXUDBYIYGoweCyWyuvAKfGHvzmpUzgB5L4cRBb+cTu9U/ro66dx7dIimA==
dependencies:
- "@typescript-eslint/scope-manager" "4.16.1"
- "@typescript-eslint/types" "4.16.1"
- "@typescript-eslint/typescript-estree" "4.16.1"
+ "@typescript-eslint/scope-manager" "4.18.0"
+ "@typescript-eslint/types" "4.18.0"
+ "@typescript-eslint/typescript-estree" "4.18.0"
debug "^4.1.1"
-"@typescript-eslint/scope-manager@4.16.1":
- version "4.16.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz#244e2006bc60cfe46987e9987f4ff49c9e3f00d5"
- integrity sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw==
+"@typescript-eslint/scope-manager@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.18.0.tgz#d75b55234c35d2ff6ac945758d6d9e53be84a427"
+ integrity sha512-olX4yN6rvHR2eyFOcb6E4vmhDPsfdMyfQ3qR+oQNkAv8emKKlfxTWUXU5Mqxs2Fwe3Pf1BoPvrwZtwngxDzYzQ==
dependencies:
- "@typescript-eslint/types" "4.16.1"
- "@typescript-eslint/visitor-keys" "4.16.1"
+ "@typescript-eslint/types" "4.18.0"
+ "@typescript-eslint/visitor-keys" "4.18.0"
-"@typescript-eslint/types@4.16.1":
- version "4.16.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.16.1.tgz#5ba2d3e38b1a67420d2487519e193163054d9c15"
- integrity sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA==
+"@typescript-eslint/types@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.18.0.tgz#bebe323f81f2a7e2e320fac9415e60856267584a"
+ integrity sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A==
-"@typescript-eslint/typescript-estree@4.16.1":
- version "4.16.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz#c2fc46b05a48fbf8bbe8b66a63f0a9ba04b356f1"
- integrity sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg==
+"@typescript-eslint/typescript-estree@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz#756d3e61da8c16ab99185532c44872f4cd5538cb"
+ integrity sha512-wt4xvF6vvJI7epz+rEqxmoNQ4ZADArGQO9gDU+cM0U5fdVv7N+IAuVoVAoZSOZxzGHBfvE3XQMLdy+scsqFfeg==
dependencies:
- "@typescript-eslint/types" "4.16.1"
- "@typescript-eslint/visitor-keys" "4.16.1"
+ "@typescript-eslint/types" "4.18.0"
+ "@typescript-eslint/visitor-keys" "4.18.0"
debug "^4.1.1"
globby "^11.0.1"
is-glob "^4.0.1"
semver "^7.3.2"
tsutils "^3.17.1"
-"@typescript-eslint/visitor-keys@4.16.1":
- version "4.16.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz#d7571fb580749fae621520deeb134370bbfc7293"
- integrity sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w==
+"@typescript-eslint/visitor-keys@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz#4e6fe2a175ee33418318a029610845a81e2ff7b6"
+ integrity sha512-Q9t90JCvfYaN0OfFUgaLqByOfz8yPeTAdotn/XYNm5q9eHax90gzdb+RJ6E9T5s97Kv/UHWKERTmqA0jTKAEHw==
dependencies:
- "@typescript-eslint/types" "4.16.1"
+ "@typescript-eslint/types" "4.18.0"
eslint-visitor-keys "^2.0.0"
"@ungap/promise-all-settled@1.1.2":
@@ -1221,83 +1179,83 @@
resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
-"@vue/compiler-core@3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.5.tgz#a6e54cabe9536e74c6513acd2649f311af1d43ac"
- integrity sha512-iFXwk2gmU/GGwN4hpBwDWWMLvpkIejf/AybcFtlQ5V1ur+5jwfBaV0Y1RXoR6ePfBPJixtKZ3PmN+M+HgMAtfQ==
+"@vue/compiler-core@3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.7.tgz#421782a4c67cc3f2b7c30457ef446d74f8524f74"
+ integrity sha512-JFohgBXoyUc3mdeI2WxlhjQZ5fakfemJkZHX8Gu/nFbEg3+lKVUZmNKWmmnp9aOzJQZKoj77LjmFxiP+P+7lMQ==
dependencies:
"@babel/parser" "^7.12.0"
"@babel/types" "^7.12.0"
- "@vue/shared" "3.0.5"
+ "@vue/shared" "3.0.7"
estree-walker "^2.0.1"
source-map "^0.6.1"
-"@vue/compiler-dom@3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.0.5.tgz#7885a13e6d18f64dde8ebceec052ed2c102696c2"
- integrity sha512-HSOSe2XSPuCkp20h4+HXSiPH9qkhz6YbW9z9ZtL5vef2T2PMugH7/osIFVSrRZP/Ul5twFZ7MIRlp8tPX6e4/g==
+"@vue/compiler-dom@3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.0.7.tgz#54d2e12fb9a7aff53abd19dac2c2679533f0c919"
+ integrity sha512-VnIH9EbWQm/Tkcp+8dCaNVsVvhm/vxCrIKWRkXY9215hTqOqQOvejT8IMjd2kc++nIsYMsdQk6H9qqBvoLe/Cw==
dependencies:
- "@vue/compiler-core" "3.0.5"
- "@vue/shared" "3.0.5"
+ "@vue/compiler-core" "3.0.7"
+ "@vue/shared" "3.0.7"
-"@vue/compiler-sfc@3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.0.5.tgz#3ae08e60244a72faf9598361874fb7bdb5b1d37c"
- integrity sha512-uOAC4X0Gx3SQ9YvDC7YMpbDvoCmPvP0afVhJoxRotDdJ+r8VO3q4hFf/2f7U62k4Vkdftp6DVni8QixrfYzs+w==
+"@vue/compiler-sfc@3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.0.7.tgz#900414750cc726553b870490f48073451fd14f07"
+ integrity sha512-37/QILpGE+J3V+bP9Slg9e6xGqfk+MmS2Yj8ChR4fS0/qWUU/YoYHE0GPIzjmBdH0JVOOmJqunxowIXmqNiHng==
dependencies:
"@babel/parser" "^7.12.0"
"@babel/types" "^7.12.0"
- "@vue/compiler-core" "3.0.5"
- "@vue/compiler-dom" "3.0.5"
- "@vue/compiler-ssr" "3.0.5"
- "@vue/shared" "3.0.5"
+ "@vue/compiler-core" "3.0.7"
+ "@vue/compiler-dom" "3.0.7"
+ "@vue/compiler-ssr" "3.0.7"
+ "@vue/shared" "3.0.7"
consolidate "^0.16.0"
estree-walker "^2.0.1"
hash-sum "^2.0.0"
lru-cache "^5.1.1"
magic-string "^0.25.7"
merge-source-map "^1.1.0"
- postcss "^7.0.32"
- postcss-modules "^3.2.2"
+ postcss "^8.1.10"
+ postcss-modules "^4.0.0"
postcss-selector-parser "^6.0.4"
source-map "^0.6.1"
-"@vue/compiler-ssr@3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.0.5.tgz#7661ad891a0be948726c7f7ad1e425253c587b83"
- integrity sha512-Wm//Kuxa1DpgjE4P9W0coZr8wklOfJ35Jtq61CbU+t601CpPTK4+FL2QDBItaG7aoUUDCWL5nnxMkuaOgzTBKg==
+"@vue/compiler-ssr@3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.0.7.tgz#28b85d497381d75fe44234057b140b0065ca9dbf"
+ integrity sha512-nHRbHeSpfXwjypettjrA16TjgfDcPEwq3m/zHnGyLC1QqdLtklXmpSM43/CPwwTCRa/qdt0pldJf22MiCEuTSQ==
dependencies:
- "@vue/compiler-dom" "3.0.5"
- "@vue/shared" "3.0.5"
+ "@vue/compiler-dom" "3.0.7"
+ "@vue/shared" "3.0.7"
-"@vue/reactivity@3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.5.tgz#e3789e4d523d845f9ae0b4d770e2b45594742fd2"
- integrity sha512-3xodUE3sEIJgS7ntwUbopIpzzvi7vDAOjVamfb2l+v1FUg0jpd3gf62N2wggJw3fxBMr+QvyxpD+dBoxLsmAjw==
+"@vue/reactivity@3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.7.tgz#e6ccc7bef7fc10b0972e4d974bad71679d3b26ad"
+ integrity sha512-FotWcNNaKhqpFZrdgsUOZ1enlJ5lhTt01CNTtLSyK7jYFgZBTuw8vKsEutZKDYZ1XKotOfoeO8N3pZQqmM6Etw==
dependencies:
- "@vue/shared" "3.0.5"
+ "@vue/shared" "3.0.7"
-"@vue/runtime-core@3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.0.5.tgz#da6331d5f300d5794e9e0ebdc8a8bd72a9e19962"
- integrity sha512-Cnyi2NqREwOLcTEsIi1DQX1hHtkVj4eGm4hBG7HhokS05DqpK4/80jG6PCCnCH9rIJDB2FqtaODX397210plXg==
+"@vue/runtime-core@3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.0.7.tgz#d44c0b0a57d7e392912a87362a4430ccf446ecea"
+ integrity sha512-DBAZAwVvdmMXuyd6/9qqj/kYr/GaLTmn1L2/QLxLwP+UfhIboiTSBc/tUUb8MRk7Bb98GzNeAWkkT6AfooS3dQ==
dependencies:
- "@vue/reactivity" "3.0.5"
- "@vue/shared" "3.0.5"
+ "@vue/reactivity" "3.0.7"
+ "@vue/shared" "3.0.7"
-"@vue/runtime-dom@3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.0.5.tgz#1ce2c9c449e26ab06963da0064096e882a7a8935"
- integrity sha512-iilX1KySeIzHHtErT6Y44db1rhWK5tAI0CiJIPr+SJoZ2jbjoOSE6ff/jfIQakchbm1d6jq6VtRVnp5xYdOXKA==
+"@vue/runtime-dom@3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.0.7.tgz#b70668d729020bc4ad608c20367223f259576ba6"
+ integrity sha512-Oij4ruOtnpQpCj+/Q3JPzgpTJ1Q7+N67pA53A8KVITEtxfvKL46NN6dhAZ5NGqwX6RWZpYqWQNewITeF0pHr8g==
dependencies:
- "@vue/runtime-core" "3.0.5"
- "@vue/shared" "3.0.5"
+ "@vue/runtime-core" "3.0.7"
+ "@vue/shared" "3.0.7"
csstype "^2.6.8"
-"@vue/shared@3.0.5":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.0.5.tgz#c131d88bd6713cc4d93b3bb1372edb1983225ff0"
- integrity sha512-gYsNoGkWejBxNO6SNRjOh/xKeZ0H0V+TFzaPzODfBjkAIb0aQgBuixC1brandC/CDJy1wYPwSoYrXpvul7m6yw==
+"@vue/shared@3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.0.7.tgz#96d52988efc07444c108c7c6803ba7cc93e40045"
+ integrity sha512-dn5FyfSc4ky424jH4FntiHno7Ss5yLkqKNmM/NXwANRnlkmqu74pnGetexDFVG5phMk9/FhwovUZCWGxsotVKg==
"@webassemblyjs/ast@1.11.0":
version "1.11.0"
@@ -1447,10 +1405,10 @@
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
-abab@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a"
- integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==
+abab@^2.0.3, abab@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
+ integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==
abbrev@1:
version "1.1.1"
@@ -1472,13 +1430,6 @@ accepts@^1.3.5:
mime-types "~2.1.24"
negotiator "0.6.2"
-acorn-globals@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
- integrity sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=
- dependencies:
- acorn "^4.0.4"
-
acorn-globals@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
@@ -1502,25 +1453,15 @@ acorn-walk@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e"
integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==
-acorn@^3.1.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
- integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
-
-acorn@^4.0.4, acorn@~4.0.2:
- version "4.0.13"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
- integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=
-
acorn@^7.1.1, acorn@^7.4.0:
version "7.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-acorn@^8.0.4:
- version "8.0.4"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.0.4.tgz#7a3ae4191466a6984eee0fe3407a4f3aa9db8354"
- integrity sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==
+acorn@^8.0.4, acorn@^8.0.5:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.1.0.tgz#52311fd7037ae119cbb134309e901aa46295b3fe"
+ integrity sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==
agent-base@6:
version "6.0.0"
@@ -1544,15 +1485,6 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.5.5:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
-align-text@^0.1.1, align-text@^0.1.3:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
- integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=
- dependencies:
- kind-of "^3.0.2"
- longest "^1.0.1"
- repeat-string "^1.5.2"
-
alphanum-sort@^1.0.0, alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
@@ -1643,10 +1575,10 @@ anymatch@~3.1.1:
normalize-path "^3.0.0"
picomatch "^2.0.4"
-apexcharts@3.25.0:
- version "3.25.0"
- resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.25.0.tgz#f3f0f9f344f997230f5c7f2918408aa072627496"
- integrity sha512-uM7OF+jLL4ba79noYcrMwMgJW8DI+Ff28CCQoGq23g25z8nGSQEoU+u12YWlECA9gBA5tbmdaQhMxjlK+M6B9Q==
+apexcharts@3.26.0:
+ version "3.26.0"
+ resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.26.0.tgz#a78abc108b2e1b3086a738f0ec7c98e292f4a14b"
+ integrity sha512-zdYHs3k3tgmCn1BpYLj7rhGEndBYF33Pq1+g0ora37xAr+3act5CJrpdXM2jx2boVUyXgavoSp6sa8WpK7RkSA==
dependencies:
svg.draggable.js "^2.2.2"
svg.easing.js "^2.0.0"
@@ -1807,6 +1739,11 @@ asn1@~0.2.3:
dependencies:
safer-buffer "~2.1.0"
+assert-never@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe"
+ integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==
+
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
@@ -1902,10 +1839,10 @@ autwh@0.1.0:
dependencies:
oauth "0.9.15"
-aws-sdk@2.848.0:
- version "2.848.0"
- resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.848.0.tgz#5e7706ddd30a55a2d5a5b64c29682a757607ee64"
- integrity sha512-c/e5kaEFl+9aYkrYDkmu5mSZlL+EfP6DnBOMD06fH12gIsaFSMBGtbsDTHABhvSu++LxeI1dJAD148O17MuZvg==
+aws-sdk@2.867.0:
+ version "2.867.0"
+ resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.867.0.tgz#3fae9a583bfd89f6098dc9bca6553b5b85e2a2fc"
+ integrity sha512-6iXRTW6dlCU4UwMivDGHoRyMCvX9Ch1G2gIZZl5yKwzVNaBNpJiAyByWFuxrcBqQsSIFKBEbxeRjePE6QiBbkw==
dependencies:
buffer "4.9.2"
events "1.1.1"
@@ -1951,6 +1888,13 @@ babel-plugin-polyfill-regenerator@^0.1.2:
dependencies:
"@babel/helper-define-polyfill-provider" "^0.1.2"
+babel-walk@3.0.0-canary-5:
+ version "3.0.0-canary-5"
+ resolved "https://registry.yarnpkg.com/babel-walk/-/babel-walk-3.0.0-canary-5.tgz#f66ecd7298357aee44955f235a6ef54219104b11"
+ integrity sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==
+ dependencies:
+ "@babel/types" "^7.9.6"
+
bach@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880"
@@ -2040,7 +1984,7 @@ bl@^4.0.1, bl@^4.0.3:
inherits "^2.0.4"
readable-stream "^3.4.0"
-bluebird@^3.1.1, bluebird@^3.7.2:
+bluebird@^3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
@@ -2091,10 +2035,10 @@ braces@^3.0.1, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
-broadcast-channel@3.4.1:
- version "3.4.1"
- resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.4.1.tgz#65b63068d0a5216026a19905c9b2d5e9adf0928a"
- integrity sha512-VXYivSkuBeQY+pL5hNQQNvBdKKQINBAROm4G8lAbWQfOZ7Yn4TMcgLNlJyEqlkxy5G8JJBsI3VJ1u8FUTOROcg==
+broadcast-channel@3.5.3:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.5.3.tgz#c75c39d923ae8af6284a893bfdc8bd3996d2dd2d"
+ integrity sha512-OLOXfwReZa2AAAh9yOUyiALB3YxBe0QpThwwuyRHLgpl8bSznSDmV6Mz7LeBJg1VZsMcDcNMy7B53w12qHrIhQ==
dependencies:
"@babel/runtime" "^7.7.2"
detect-node "^2.0.4"
@@ -2200,16 +2144,16 @@ builtin-modules@^1.1.1:
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
-bull@3.20.1:
- version "3.20.1"
- resolved "https://registry.yarnpkg.com/bull/-/bull-3.20.1.tgz#97c4156f48001565baf3c04b81267a5604f40754"
- integrity sha512-wDwpVu47WKaGhiguEPa/US5UMrtGLPKNPiGFPo4OgVs3EEGzJEWwv3LRPfjJVIf1COdMAN/yowGhZwYmoOonjQ==
+bull@3.21.1:
+ version "3.21.1"
+ resolved "https://registry.yarnpkg.com/bull/-/bull-3.21.1.tgz#f0ff54b73c6a5ec54c5e12bb9d3ceb54229d055d"
+ integrity sha512-7IjQBz+mm2GYwlNOf5Pbq8F+EwqkBv0RjwWpG+5Kfk/QDWylQ6eL3FzJbvFQQ7uHjTVPsuzsQocArjhm/SUsqA==
dependencies:
cron-parser "^2.13.0"
debuglog "^1.0.0"
get-port "^5.1.1"
ioredis "^4.22.0"
- lodash "^4.17.19"
+ lodash "^4.17.21"
p-timeout "^3.2.0"
promise.prototype.finally "^3.1.2"
semver "^7.3.2"
@@ -2307,11 +2251,6 @@ camel-case@^3.0.0:
no-case "^2.2.0"
upper-case "^1.1.1"
-camelcase@^1.0.2:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
- integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=
-
camelcase@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
@@ -2372,32 +2311,24 @@ caseless@~0.12.0:
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-cbor@7.0.3:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/cbor/-/cbor-7.0.3.tgz#216d292f2aedd1bb61414a8f949b63e4de11b33b"
- integrity sha512-Io+lJytjYBJKgJqZQUz2bFaMPj+HtlsnT9kHSUiIJFqzWa05lm5/ycQ+NiZWpks3DR2Fz7j7axiTGeT57w/syg==
+cbor@7.0.4:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cbor/-/cbor-7.0.4.tgz#8a3ef39f07ac3fdb69dda461b87db7113233481b"
+ integrity sha512-9hBTn31l7+9qteBso7+HPp2R5ytqFRBd98fHK4ZTpvrba8V7CuoOsEL0S6vf7+11gubMTd3RW97lOgMTl5SNfg==
dependencies:
"@cto.af/textdecoder" "^0.0.0"
nofilter "^2.0.3"
-center-align@^0.1.1:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
- integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60=
- dependencies:
- align-text "^0.1.3"
- lazy-cache "^1.0.3"
-
-chai@4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.0.tgz#5523a5faf7f819c8a92480d70a8cccbadacfc25f"
- integrity sha512-/BFd2J30EcOwmdOgXvVsmM48l0Br0nmZPlO0uOW4XKh6kpsUumRXBgPV+IlaqFaqr9cYbeoZAM1Npx0i4A+aiA==
+chai@4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49"
+ integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==
dependencies:
assertion-error "^1.1.0"
check-error "^1.0.2"
deep-eql "^3.0.1"
get-func-name "^2.0.0"
- pathval "^1.1.0"
+ pathval "^1.1.1"
type-detect "^4.0.5"
chalk@4.0.0:
@@ -2441,7 +2372,7 @@ char-regex@^1.0.2:
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
-character-parser@^2.1.1:
+character-parser@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0"
integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A=
@@ -2576,7 +2507,7 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
-clean-css@^4.1.11, clean-css@^4.2.1:
+clean-css@^4.2.1:
version "4.2.3"
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==
@@ -2604,15 +2535,6 @@ clipboard@^2.0.0:
select "^1.1.2"
tiny-emitter "^2.0.0"
-cliui@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
- integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=
- dependencies:
- center-align "^0.1.1"
- right-align "^0.1.1"
- wordwrap "0.0.2"
-
cliui@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
@@ -2871,6 +2793,11 @@ commander@^2.12.1, commander@^2.19.0, commander@^2.20.0, commander@~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==
+commander@^6.0.0:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
+ integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
+
commander@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.0.0.tgz#3e2bbfd8bb6724760980988fb5b22b7ee6b71ab2"
@@ -2901,6 +2828,21 @@ concat-stream@^1.5.2, concat-stream@^1.6.0:
readable-stream "^2.2.2"
typedarray "^0.0.6"
+concurrently@6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.0.0.tgz#c1a876dd99390979c71f8c6fe6796882f3a13199"
+ integrity sha512-Ik9Igqnef2ONLjN2o/OVx1Ow5tymVvvEwQeYCQdD/oV+CN9oWhxLk7ibcBdOtv0UzBqHCEKRwbKceYoTK8t3fQ==
+ dependencies:
+ chalk "^4.1.0"
+ date-fns "^2.16.1"
+ lodash "^4.17.20"
+ read-pkg "^5.2.0"
+ rxjs "^6.6.3"
+ spawn-command "^0.0.2-1"
+ supports-color "^8.1.0"
+ tree-kill "^1.2.2"
+ yargs "^16.2.0"
+
condense-newlines@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f"
@@ -2923,13 +2865,6 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
-consolidate@0.15.1:
- version "0.15.1"
- resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7"
- integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==
- dependencies:
- bluebird "^3.1.1"
-
consolidate@^0.16.0:
version "0.16.0"
resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.16.0.tgz#a11864768930f2f19431660a65906668f5fbdc16"
@@ -2937,7 +2872,7 @@ consolidate@^0.16.0:
dependencies:
bluebird "^3.7.2"
-constantinople@^3.0.1, constantinople@^3.1.2, constantinople@^4.0.1:
+constantinople@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-4.0.1.tgz#0def113fa0e4dc8de83331a5cf79c8b325213151"
integrity sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==
@@ -3006,10 +2941,10 @@ core-js-compat@^3.8.1:
browserslist "^4.16.3"
semver "7.0.0"
-core-js@3.9.0:
- version "3.9.0"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.9.0.tgz#790b1bb11553a2272b36e2625c7179db345492f8"
- integrity sha512-PyFBJaLq93FlyYdsndE5VaueA9K5cNB7CGzeCj191YYLhkQM0gdZR2SKihM70oF0wdqKSKClv/tEBOpoRmdOVQ==
+core-js@3.9.1:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.9.1.tgz#cec8de593db8eb2a85ffb0dbdeb312cb6e5460ae"
+ integrity sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
@@ -3098,16 +3033,16 @@ css-declaration-sorter@^4.0.1:
postcss "^7.0.1"
timsort "^0.3.0"
-css-loader@5.0.2:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.0.2.tgz#24f758dae349bad0a440c50d7e2067742e0899cb"
- integrity sha512-gbkBigdcHbmNvZ1Cg6aV6qh6k9N6XOr8YWzISLQGrwk2mgOH8LLrizhkxbDhQtaLtktyKHD4970S0xwz5btfTA==
+css-loader@5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.1.3.tgz#87f6fc96816b20debe3cf682f85c7e56a963d0d1"
+ integrity sha512-CoPZvyh8sLiGARK3gqczpfdedbM74klGWurF2CsNZ2lhNaXdLIUks+3Mfax3WBeRuHoglU+m7KG/+7gY6G4aag==
dependencies:
camelcase "^6.2.0"
cssesc "^3.0.0"
icss-utils "^5.1.0"
loader-utils "^2.0.0"
- postcss "^8.2.4"
+ postcss "^8.2.8"
postcss-modules-extract-imports "^3.0.0"
postcss-modules-local-by-default "^4.0.0"
postcss-modules-scope "^3.0.0"
@@ -3303,10 +3238,10 @@ cssom@~0.3.6:
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
-cssstyle@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.2.0.tgz#e4c44debccd6b7911ed617a4395e5754bba59992"
- integrity sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==
+cssstyle@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852"
+ integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==
dependencies:
cssom "~0.3.6"
@@ -3339,6 +3274,11 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
+date-fns@^2.16.1:
+ version "2.19.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.19.0.tgz#65193348635a28d5d916c43ec7ce6fbd145059e1"
+ integrity sha512-X3bf2iTPgCAQp9wvjOQytnf5vO5rESYRXlPIVcgSbtT5OTScPcsf9eZU+B/YIkKAtYr5WeCii58BgATrNitlWg==
+
dateformat@4.5.1:
version "4.5.1"
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.5.1.tgz#c20e7a9ca77d147906b6dc2261a8be0a5bd2173c"
@@ -3365,7 +3305,7 @@ debug@4, debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
dependencies:
ms "2.1.2"
-debug@^3.1.0, debug@^3.2.6:
+debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
@@ -3377,7 +3317,7 @@ debuglog@^1.0.0:
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
-decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
+decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
@@ -3387,10 +3327,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.0:
- version "10.2.0"
- resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.0.tgz#39466113a9e036111d02f82489b5fd6b0b5ed231"
- integrity sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==
+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==
decode-uri-component@^0.2.0:
version "0.2.0"
@@ -3662,11 +3602,6 @@ dotenv@^8.2.0:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
-double-ended-queue@2.1.0-0:
- version "2.1.0-0"
- resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
- integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=
-
duplexify@^3.6.0:
version "3.7.1"
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
@@ -3922,27 +3857,27 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-escodegen@^1.14.1:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457"
- integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==
+escodegen@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
+ integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==
dependencies:
esprima "^4.0.1"
- estraverse "^4.2.0"
+ estraverse "^5.2.0"
esutils "^2.0.2"
optionator "^0.8.1"
optionalDependencies:
source-map "~0.6.1"
-eslint-plugin-vue@7.6.0:
- version "7.6.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.6.0.tgz#ea616e6dfd45d545adb16cba628c5a992cc31f0b"
- integrity sha512-qYpKwAvpcQXyUXVcG8Zd+fxHDx9iSgTQuO7dql7Ug/2BCvNNDr6s3I9p8MoUo23JJdO7ZAjW3vSwY/EBf4uBcw==
+eslint-plugin-vue@7.7.0:
+ version "7.7.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.7.0.tgz#a90df4595e670821bf243bd2750ededdb74948b8"
+ integrity sha512-mYz4bpLGv5jx6YG/GvKkqbGSfV7uma2u1P3mLA41Q5vQl8W1MeuTneB8tfsLq6xxxesFubcrOC0BZBJ5R+eaCQ==
dependencies:
eslint-utils "^2.1.0"
natural-compare "^1.4.0"
semver "^7.3.2"
- vue-eslint-parser "^7.5.0"
+ vue-eslint-parser "^7.6.0"
eslint-scope@^5.0.0, eslint-scope@^5.1.1:
version "5.1.1"
@@ -3969,10 +3904,10 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
-eslint@7.21.0:
- version "7.21.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.21.0.tgz#4ecd5b8c5b44f5dedc9b8a110b01bbfeb15d1c83"
- integrity sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==
+eslint@7.22.0:
+ version "7.22.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.22.0.tgz#07ecc61052fec63661a2cab6bd507127c07adc6f"
+ integrity sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==
dependencies:
"@babel/code-frame" "7.12.11"
"@eslint/eslintrc" "^0.4.0"
@@ -3991,7 +3926,7 @@ eslint@7.21.0:
file-entry-cache "^6.0.1"
functional-red-black-tree "^1.0.1"
glob-parent "^5.0.0"
- globals "^12.1.0"
+ globals "^13.6.0"
ignore "^4.0.6"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
@@ -3999,7 +3934,7 @@ eslint@7.21.0:
js-yaml "^3.13.1"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
- lodash "^4.17.20"
+ lodash "^4.17.21"
minimatch "^3.0.4"
natural-compare "^1.4.0"
optionator "^0.9.1"
@@ -4054,7 +3989,7 @@ esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"
-estraverse@^4.1.1, estraverse@^4.2.0:
+estraverse@^4.1.1:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
@@ -4245,6 +4180,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+fast-xml-parser@^3.19.0:
+ version "3.19.0"
+ resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz#cb637ec3f3999f51406dd8ff0e6fc4d83e520d01"
+ integrity sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==
+
fastest-levenshtein@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
@@ -4283,10 +4223,10 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
-file-type@16.2.0:
- version "16.2.0"
- resolved "https://registry.yarnpkg.com/file-type/-/file-type-16.2.0.tgz#d4f1da71ddda758db7f15f93adfaed09ce9e2715"
- integrity sha512-1Wwww3mmZCMmLjBfslCluwt2mxH80GsAXYrvPnfQ42G1EGWag336kB1iyCgyn7UXiKY3cJrNykXPrCwA7xb5Ag==
+file-type@16.3.0:
+ version "16.3.0"
+ resolved "https://registry.yarnpkg.com/file-type/-/file-type-16.3.0.tgz#f03af91db30f92cc9a0b335c0644c46101522f6d"
+ integrity sha512-ZA0hV64611vJT42ltw0T9IDwHApQuxRdrmQZWTeDmeAUtZBBVSQW3nSQqhhW1cAgpXgqcJvm410BYHXJQ9AymA==
dependencies:
readable-web-to-node-stream "^3.0.0"
strtok3 "^6.0.3"
@@ -4693,6 +4633,13 @@ globals@^12.1.0:
dependencies:
type-fest "^0.8.1"
+globals@^13.6.0:
+ version "13.7.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.7.0.tgz#aed3bcefd80ad3ec0f0be2cf0c895110c0591795"
+ integrity sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==
+ dependencies:
+ type-fest "^0.20.2"
+
globby@^11.0.1:
version "11.0.1"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357"
@@ -4719,10 +4666,10 @@ good-listener@^1.2.2:
dependencies:
delegate "^3.1.2"
-got@11.8.1:
- version "11.8.1"
- resolved "https://registry.yarnpkg.com/got/-/got-11.8.1.tgz#df04adfaf2e782babb3daabc79139feec2f7e85d"
- integrity sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q==
+got@11.8.2:
+ version "11.8.2"
+ resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599"
+ integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==
dependencies:
"@sindresorhus/is" "^4.0.0"
"@szmarczak/http-timer" "^4.0.5"
@@ -5000,7 +4947,7 @@ hsla-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38"
integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg=
-html-comment-regex@^1.1.0, html-comment-regex@^1.1.2:
+html-comment-regex@^1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
@@ -5155,22 +5102,15 @@ icss-replace-symbols@^1.1.0:
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
-icss-utils@^4.0.0, icss-utils@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467"
- integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==
- dependencies:
- postcss "^7.0.14"
-
icss-utils@^5.0.0, icss-utils@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
-idb-keyval@5.0.2:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-5.0.2.tgz#243cf2b7db1bee2a8a41b78c14a18a85db0e1646"
- integrity sha512-1DYjY/nX2U9pkTkwFoAmKcK1ZWmkNgO32Oon9tp/9+HURizxUQ4fZRxMJZs093SldP7q6dotVj03kIkiqOILyA==
+idb-keyval@5.0.4:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-5.0.4.tgz#182881b1eafbb47d11a269422ae6d5243f0db0c7"
+ integrity sha512-qS0kplHuadZujoE90ze0NUkhW0/Fbfib7d+mYNMXNEn45NSh2NWY3fBewoX4GZUsKkGHBgc8JiAwMx0zrfL3LQ==
ieee754@1.1.13, ieee754@^1.1.13, ieee754@^1.1.4:
version "1.1.13"
@@ -5427,13 +5367,13 @@ is-directory@^0.3.1:
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=
-is-expression@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-3.0.0.tgz#39acaa6be7fd1f3471dc42c7416e61c24317ac9f"
- integrity sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=
+is-expression@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab"
+ integrity sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==
dependencies:
- acorn "~4.0.2"
- object-assign "^4.0.1"
+ acorn "^7.1.1"
+ object-assign "^4.1.1"
is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1"
@@ -5590,12 +5530,12 @@ is-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
-is-svg@4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-4.2.1.tgz#095b496e345fec9211c2a7d5d021003e040d6f81"
- integrity sha512-PHx3ANecKsKNl5y5+Jvt53Y4J7MfMpbNZkv384QNiswMKAWIbvcqbPz+sYbFKJI8Xv3be01GSFniPmoaP+Ai5A==
+is-svg@4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-4.3.1.tgz#8c63ec8c67c8c7f0a8de0a71c8c7d58eccf4406b"
+ integrity sha512-h2CGs+yPUyvkgTJQS9cJzo9lYK06WgRiXUqBBHtglSzVKAuH4/oWsqk7LGfbSa1hGk9QcZ0SyQtVggvBA8LZXA==
dependencies:
- html-comment-regex "^1.1.2"
+ fast-xml-parser "^3.19.0"
is-svg@^2.0.0:
version "2.1.0"
@@ -5736,7 +5676,7 @@ js-sha3@0.8.0:
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
-js-stringify@^1.0.1:
+js-stringify@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db"
integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds=
@@ -5779,36 +5719,36 @@ jschardet@^2.1.0:
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184"
integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q==
-jsdom@16.4.0:
- version "16.4.0"
- resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb"
- integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==
+jsdom@16.5.1:
+ version "16.5.1"
+ resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.5.1.tgz#4ced6bbd7b77d67fb980e64d9e3e6fb900f97dd6"
+ integrity sha512-pF73EOsJgwZekbDHEY5VO/yKXUkab/DuvrQB/ANVizbr6UAHJsDdHXuotZYwkJSGQl1JM+ivXaqY+XBDDL4TiA==
dependencies:
- abab "^2.0.3"
- acorn "^7.1.1"
+ abab "^2.0.5"
+ acorn "^8.0.5"
acorn-globals "^6.0.0"
cssom "^0.4.4"
- cssstyle "^2.2.0"
+ cssstyle "^2.3.0"
data-urls "^2.0.0"
- decimal.js "^10.2.0"
+ decimal.js "^10.2.1"
domexception "^2.0.1"
- escodegen "^1.14.1"
+ escodegen "^2.0.0"
html-encoding-sniffer "^2.0.1"
is-potential-custom-element-name "^1.0.0"
nwsapi "^2.2.0"
- parse5 "5.1.1"
+ parse5 "6.0.1"
request "^2.88.2"
- request-promise-native "^1.0.8"
- saxes "^5.0.0"
+ request-promise-native "^1.0.9"
+ saxes "^5.0.1"
symbol-tree "^3.2.4"
- tough-cookie "^3.0.1"
+ 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.0.0"
- ws "^7.2.3"
+ ws "^7.4.4"
xml-name-validator "^3.0.0"
jsesc@^2.5.1:
@@ -5938,12 +5878,12 @@ jws@^4.0.0:
jwa "^2.0.0"
safe-buffer "^5.0.1"
-katex@0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/katex/-/katex-0.12.0.tgz#2fb1c665dbd2b043edcf8a1f5c555f46beaa0cb9"
- integrity sha512-y+8btoc/CK70XqcHqjxiGWBOeIL8upbS0peTPXTvgrh21n1RiWWcIpSWM+4uXq+IAgNh9YYQWdc7LVDPDAEEAg==
+katex@0.13.0:
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/katex/-/katex-0.13.0.tgz#62900e56c1ad8fdf7da23399e50d7a7b690b39ab"
+ integrity sha512-6cHbzbegYgS9vvVGuH8UA+o97X+ZshtboSqJJCdq7trBYzuD75JNwr7Ef606xkUjecPPhFnyB+afx1dVafielg==
dependencies:
- commander "^2.19.0"
+ commander "^6.0.0"
keygrip@~1.0.3:
version "1.0.3"
@@ -6058,7 +5998,7 @@ koa-mount@4.0.0:
debug "^4.0.1"
koa-compose "^4.1.0"
-koa-send@5.0.1:
+koa-send@5.0.1, koa-send@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.1.tgz#39dceebfafb395d0d60beaffba3a70b4f543fe79"
integrity sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==
@@ -6067,16 +6007,6 @@ koa-send@5.0.1:
http-errors "^1.7.3"
resolve-path "^1.4.0"
-koa-send@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb"
- integrity sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ==
- dependencies:
- debug "^3.1.0"
- http-errors "^1.6.3"
- mz "^2.7.0"
- resolve-path "^1.4.0"
-
koa-slow@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/koa-slow/-/koa-slow-2.1.0.tgz#39007ca628c620f2b307b90dbf423d7a0c9be971"
@@ -6085,17 +6015,19 @@ koa-slow@2.1.0:
lodash.isregexp "3.0.5"
q "1.4.1"
-koa-views@6.3.1:
- version "6.3.1"
- resolved "https://registry.yarnpkg.com/koa-views/-/koa-views-6.3.1.tgz#8d23fa2118c71e9119fb47a75a58053345e37356"
- integrity sha512-weIaPs2cCHWT2qK8qHRmwlZ29xRCvUVy1v/z12AGavVV5j4QIU0W/Y7OVBBu1sTkcO9dDJ25ajGYHGZ/aY43IQ==
+koa-views@7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/koa-views/-/koa-views-7.0.1.tgz#0c8f8e65d5cd2e08249430cb83dc361e49a17a5a"
+ integrity sha512-yS8751DXHXXDbdl/oUZd0PsgnxR0MLiguu77Eqrgu6yawE9Hi99wNKiVENb0Kfgsmvq/8px7YCI+USgxaTB1LA==
dependencies:
- consolidate "0.15.1"
+ "@types/koa" "^2.13.1"
+ consolidate "^0.16.0"
debug "^4.1.0"
get-paths "0.0.7"
koa-send "^5.0.0"
mz "^2.4.0"
pretty "^2.0.0"
+ resolve-path "^1.4.0"
koa@2.13.1:
version "2.13.1"
@@ -6169,11 +6101,6 @@ last-run@^1.1.0:
default-resolution "^2.0.0"
es6-weak-map "^2.0.1"
-lazy-cache@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
- integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=
-
lazystream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
@@ -6400,7 +6327,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20:
+lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
@@ -6412,11 +6339,6 @@ log-symbols@4.0.0:
dependencies:
chalk "^4.0.0"
-longest@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
- integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
-
lookup-dns-cache@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/lookup-dns-cache/-/lookup-dns-cache-2.1.0.tgz#6362340e269071e20b6f0bcf51da98873411e051"
@@ -6516,10 +6438,10 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
-markdown-it-anchor@7.0.2:
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-7.0.2.tgz#1ac28261e0ea377b8298a1a6760e422921346a03"
- integrity sha512-UtYFAkce16mJlixXUMXUf14ZmOWK2YHLGKUpkZUn98w3qP8nVhb7k5sCBZmVHGMq3SpYtrxQ5XOdHQHRuLR40Q==
+markdown-it-anchor@7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-7.1.0.tgz#30fb21497bf59e83ff4d1ddc052d821962e2489e"
+ integrity sha512-loQggrwsIkkP7TOrESvmYkV2ikbQNNKhHcWyqC7/C2CmfHl1tkUizJJU8C5aGgg7J6oXVQJx17gk7i47tNn/lQ==
markdown-it@12.0.4:
version "12.0.4"
@@ -6742,10 +6664,10 @@ 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.3.0:
- version "8.3.0"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.3.0.tgz#a83a7432d382ae1ca29686062d7fdc2c36f63fe5"
- integrity sha512-TQqyC89V1J/Vxx0DhJIXlq9gbbL9XFNdeLQ1+JsnZsVaSOV1z3tWfw0qZmQJGQRIfkvZcs7snQnZnOCKoldq1Q==
+mocha@8.3.2:
+ version "8.3.2"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.3.2.tgz#53406f195fa86fbdebe71f8b1c6fb23221d69fcc"
+ integrity sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==
dependencies:
"@ungap/promise-all-settled" "1.1.2"
ansi-colors "4.1.1"
@@ -7010,7 +6932,7 @@ nopt@^5.0.0:
dependencies:
abbrev "1"
-normalize-package-data@^2.3.2:
+normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
@@ -7333,7 +7255,7 @@ osenv@^0.1.4:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
-p-cancelable@2.0.0, p-cancelable@^2.0.0:
+p-cancelable@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e"
integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==
@@ -7487,16 +7409,16 @@ parse5-htmlparser2-tree-adapter@^6.0.0:
dependencies:
parse5 "^6.0.1"
-parse5@5.1.1, parse5@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
- integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
-
parse5@6.0.1, parse5@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
+parse5@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
+ integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
+
parseurl@^1.3.2:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@@ -7590,10 +7512,10 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-pathval@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
- integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
+pathval@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
+ integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
peek-readable@^3.1.0:
version "3.1.0"
@@ -7855,10 +7777,10 @@ postcss-filter-plugins@^2.0.0:
dependencies:
postcss "^5.0.4"
-postcss-loader@5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-5.0.0.tgz#bea95363dcb550d72ceb612ce44663356b7782d7"
- integrity sha512-bOvyWP5VHCJbThbv7wrBwCBc3DsVpyCfd+k/wHOL3wTAMMHmSSfNts90EADf8bHa6I810ird1JBEKmBRgJu3cg==
+postcss-loader@5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-5.2.0.tgz#ccd6668a778902d653602289c765a8bc481986dc"
+ integrity sha512-uSuCkENFeUaOYsKrXm0eNNgVIxc71z8RcckLMbVw473rGojFnrUeqEz6zBgXsH2q1EIzXnO/4pEz9RhALjlITA==
dependencies:
cosmiconfig "^7.0.0"
klona "^2.0.4"
@@ -7995,28 +7917,11 @@ postcss-minify-selectors@^4.0.2:
postcss "^7.0.0"
postcss-selector-parser "^3.0.0"
-postcss-modules-extract-imports@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
- integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==
- dependencies:
- postcss "^7.0.5"
-
postcss-modules-extract-imports@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
-postcss-modules-local-by-default@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0"
- integrity sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==
- dependencies:
- icss-utils "^4.1.1"
- postcss "^7.0.32"
- postcss-selector-parser "^6.0.2"
- postcss-value-parser "^4.1.0"
-
postcss-modules-local-by-default@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c"
@@ -8026,14 +7931,6 @@ postcss-modules-local-by-default@^4.0.0:
postcss-selector-parser "^6.0.2"
postcss-value-parser "^4.1.0"
-postcss-modules-scope@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee"
- integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==
- dependencies:
- postcss "^7.0.6"
- postcss-selector-parser "^6.0.0"
-
postcss-modules-scope@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06"
@@ -8041,14 +7938,6 @@ postcss-modules-scope@^3.0.0:
dependencies:
postcss-selector-parser "^6.0.4"
-postcss-modules-values@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10"
- integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==
- dependencies:
- icss-utils "^4.0.0"
- postcss "^7.0.6"
-
postcss-modules-values@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
@@ -8056,19 +7945,18 @@ postcss-modules-values@^4.0.0:
dependencies:
icss-utils "^5.0.0"
-postcss-modules@^3.2.2:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-3.2.2.tgz#ee390de0f9f18e761e1778dfb9be26685c02c51f"
- integrity sha512-JQ8IAqHELxC0N6tyCg2UF40pACY5oiL6UpiqqcIFRWqgDYO8B0jnxzoQ0EOpPrWXvcpu6BSbQU/3vSiq7w8Nhw==
+postcss-modules@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-4.0.0.tgz#2bc7f276ab88f3f1b0fadf6cbd7772d43b5f3b9b"
+ integrity sha512-ghS/ovDzDqARm4Zj6L2ntadjyQMoyJmi0JkLlYtH2QFLrvNlxH5OAVRPWPeKilB0pY7SbuhO173KOWkPAxRJcw==
dependencies:
generic-names "^2.0.1"
icss-replace-symbols "^1.1.0"
lodash.camelcase "^4.3.0"
- postcss "^7.0.32"
- postcss-modules-extract-imports "^2.0.0"
- postcss-modules-local-by-default "^3.0.2"
- postcss-modules-scope "^2.2.0"
- postcss-modules-values "^3.0.0"
+ postcss-modules-extract-imports "^3.0.0"
+ postcss-modules-local-by-default "^4.0.0"
+ postcss-modules-scope "^3.0.0"
+ postcss-modules-values "^4.0.0"
string-hash "^1.1.1"
postcss-normalize-charset@^1.1.0:
@@ -8248,7 +8136,7 @@ postcss-selector-parser@^3.0.0:
indexes-of "^1.0.1"
uniq "^1.0.1"
-postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
version "6.0.4"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3"
integrity sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==
@@ -8315,10 +8203,10 @@ postcss-zindex@^2.0.1:
postcss "^5.0.4"
uniqs "^2.0.0"
-postcss@8.2.7, postcss@^8.2.4:
- version "8.2.7"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.7.tgz#48ed8d88b4de10afa0dfd1c3f840aa57b55c4d47"
- integrity sha512-DsVLH3xJzut+VT+rYr0mtvOtpTjSyqDwPf5EZWXcb0uAKfitGpTY9Ec+afi2+TgdN8rWS9Cs88UDYehKo/RvOw==
+postcss@8.2.8, postcss@^8.1.10, postcss@^8.2.8:
+ version "8.2.8"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.8.tgz#0b90f9382efda424c4f0f69a2ead6f6830d08ece"
+ integrity sha512-1F0Xb2T21xET7oQV9eKuctbM9S7BC0fetoHCc4H13z0PT6haiRLP4T0ZY4XWh7iLP0usgqykT6p9B2RtOf4FPw==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.20"
@@ -8334,7 +8222,7 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0
source-map "^0.5.6"
supports-color "^3.2.3"
-postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6:
+postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.27:
version "7.0.32"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d"
integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==
@@ -8365,10 +8253,10 @@ postgres-interval@^1.1.0:
dependencies:
xtend "^4.0.0"
-prebuild-install@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.0.0.tgz#669022bcde57c710a869e39c5ca6bf9cd207f316"
- integrity sha512-h2ZJ1PXHKWZpp1caLw0oX9sagVpL2YTk+ZwInQbQ3QqNd4J03O6MpFNmMTJlkfgPENWqe5kP0WjQLqz5OjLfsw==
+prebuild-install@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.0.1.tgz#5902172f7a40eb67305b96c2a695db32636ee26d"
+ integrity sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ==
dependencies:
detect-libc "^1.0.3"
expand-template "^2.0.3"
@@ -8435,10 +8323,10 @@ prismjs@1.23.0:
optionalDependencies:
clipboard "^2.0.0"
-probe-image-size@6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/probe-image-size/-/probe-image-size-6.0.0.tgz#4a85b19d5af4e29a8de7d53a9aa036f6fd02f5f4"
- integrity sha512-99PZ5+RU4gqiTfK5ZDMDkZtn6eL4WlKfFyVJV7lFQvH3iGmQ85DqMTOdxorERO26LHkevR2qsxnHp0x/2UDJPA==
+probe-image-size@7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/probe-image-size/-/probe-image-size-7.0.1.tgz#ac815d78bdf8c5643af6e541a572c0077c75f2c1"
+ integrity sha512-4ua2TGdO761JWaTgbLD2Uq9yFvB34QBAxnqz9GOs3w4+SC4dfbQcnnNY8loHjZV5NRW8PSQRz+WZ6NfUvbuRDA==
dependencies:
deepmerge "^4.0.0"
needle "^2.5.2"
@@ -8495,115 +8383,113 @@ pseudomap@^1.0.2:
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
-psl@^1.1.24, psl@^1.1.28:
+psl@^1.1.24, psl@^1.1.28, psl@^1.1.33:
version "1.8.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
-pug-attrs@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-2.0.4.tgz#b2f44c439e4eb4ad5d4ef25cac20d18ad28cc336"
- integrity sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==
+pug-attrs@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41"
+ integrity sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==
dependencies:
- constantinople "^3.0.1"
- js-stringify "^1.0.1"
- pug-runtime "^2.0.5"
+ constantinople "^4.0.1"
+ js-stringify "^1.0.2"
+ pug-runtime "^3.0.0"
-pug-code-gen@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-2.0.3.tgz#122eb9ada9b5bf601705fe15aaa0a7d26bc134ab"
- integrity sha512-r9sezXdDuZJfW9J91TN/2LFbiqDhmltTFmGpHTsGdrNGp3p4SxAjjXEfnuK2e4ywYsRIVP0NeLbSAMHUcaX1EA==
+pug-code-gen@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-3.0.2.tgz#ad190f4943133bf186b60b80de483100e132e2ce"
+ integrity sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==
dependencies:
- constantinople "^3.1.2"
+ constantinople "^4.0.1"
doctypes "^1.1.0"
- js-stringify "^1.0.1"
- pug-attrs "^2.0.4"
- pug-error "^1.3.3"
- pug-runtime "^2.0.5"
- void-elements "^2.0.1"
- with "^5.0.0"
+ js-stringify "^1.0.2"
+ pug-attrs "^3.0.0"
+ pug-error "^2.0.0"
+ pug-runtime "^3.0.0"
+ void-elements "^3.1.0"
+ with "^7.0.0"
-pug-error@^1.3.3:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-1.3.3.tgz#f342fb008752d58034c185de03602dd9ffe15fa6"
- integrity sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==
+pug-error@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5"
+ integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==
-pug-filters@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-3.1.1.tgz#ab2cc82db9eeccf578bda89130e252a0db026aa7"
- integrity sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==
+pug-filters@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e"
+ integrity sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==
dependencies:
- clean-css "^4.1.11"
- constantinople "^3.0.1"
+ constantinople "^4.0.1"
jstransformer "1.0.0"
- pug-error "^1.3.3"
- pug-walk "^1.1.8"
- resolve "^1.1.6"
- uglify-js "^2.6.1"
+ pug-error "^2.0.0"
+ pug-walk "^2.0.0"
+ resolve "^1.15.1"
-pug-lexer@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-4.1.0.tgz#531cde48c7c0b1fcbbc2b85485c8665e31489cfd"
- integrity sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==
+pug-lexer@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-5.0.1.tgz#ae44628c5bef9b190b665683b288ca9024b8b0d5"
+ integrity sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==
dependencies:
- character-parser "^2.1.1"
- is-expression "^3.0.0"
- pug-error "^1.3.3"
+ character-parser "^2.2.0"
+ is-expression "^4.0.0"
+ pug-error "^2.0.0"
-pug-linker@^3.0.6:
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-3.0.6.tgz#f5bf218b0efd65ce6670f7afc51658d0f82989fb"
- integrity sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==
+pug-linker@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708"
+ integrity sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==
dependencies:
- pug-error "^1.3.3"
- pug-walk "^1.1.8"
+ pug-error "^2.0.0"
+ pug-walk "^2.0.0"
-pug-load@^2.0.12:
- version "2.0.12"
- resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-2.0.12.tgz#d38c85eb85f6e2f704dea14dcca94144d35d3e7b"
- integrity sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==
+pug-load@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662"
+ integrity sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==
dependencies:
- object-assign "^4.1.0"
- pug-walk "^1.1.8"
+ object-assign "^4.1.1"
+ pug-walk "^2.0.0"
-pug-parser@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-5.0.1.tgz#03e7ada48b6840bd3822f867d7d90f842d0ffdc9"
- integrity sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==
+pug-parser@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260"
+ integrity sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==
dependencies:
- pug-error "^1.3.3"
- token-stream "0.0.1"
+ pug-error "^2.0.0"
+ token-stream "1.0.0"
-pug-runtime@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-2.0.5.tgz#6da7976c36bf22f68e733c359240d8ae7a32953a"
- integrity sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==
+pug-runtime@^3.0.0, pug-runtime@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-3.0.1.tgz#f636976204723f35a8c5f6fad6acda2a191b83d7"
+ integrity sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==
-pug-strip-comments@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz#cc1b6de1f6e8f5931cf02ec66cdffd3f50eaf8a8"
- integrity sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==
+pug-strip-comments@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e"
+ integrity sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==
dependencies:
- pug-error "^1.3.3"
+ pug-error "^2.0.0"
-pug-walk@^1.1.8:
- version "1.1.8"
- resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-1.1.8.tgz#b408f67f27912f8c21da2f45b7230c4bd2a5ea7a"
- integrity sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==
+pug-walk@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe"
+ integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==
-pug@2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/pug/-/pug-2.0.4.tgz#ee7682ec0a60494b38d48a88f05f3b0ac931377d"
- integrity sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==
+pug@3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.2.tgz#f35c7107343454e43bc27ae0ff76c731b78ea535"
+ integrity sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==
dependencies:
- pug-code-gen "^2.0.2"
- pug-filters "^3.1.1"
- pug-lexer "^4.1.0"
- pug-linker "^3.0.6"
- pug-load "^2.0.12"
- pug-parser "^5.0.1"
- pug-runtime "^2.0.5"
- pug-strip-comments "^1.0.4"
+ pug-code-gen "^3.0.2"
+ pug-filters "^4.0.0"
+ pug-lexer "^5.0.1"
+ pug-linker "^4.0.0"
+ pug-load "^3.0.0"
+ pug-parser "^6.0.0"
+ pug-runtime "^3.0.1"
+ pug-strip-comments "^2.0.0"
pump@^2.0.0:
version "2.0.1"
@@ -8645,10 +8531,10 @@ punycode@^1.4.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
-pureimage@0.2.5:
- version "0.2.5"
- resolved "https://registry.yarnpkg.com/pureimage/-/pureimage-0.2.5.tgz#10c9d314bcdfba712229ec70c3849164f537c248"
- integrity sha512-D/oP8uaS8HLIOPqaxeVU0ZcJHUwvvFjeclKwn0RBeZJn3TBtZgKn7FVBN5auuCHQTC4K/wDAHfkY/JOuGCiohQ==
+pureimage@0.2.7:
+ version "0.2.7"
+ resolved "https://registry.yarnpkg.com/pureimage/-/pureimage-0.2.7.tgz#e6da5868e42d03a94aab7ad1f9da67c865914ab8"
+ integrity sha512-F3z3QAoIpgqI0Uu122Y18oTRo0Y/aloQSqaAfRSiO4LRIQIHOjP+qUFl8sJ04mhOJ1sHsRfgZ8CUjQqVSXfV1g==
dependencies:
jpeg-js "^0.4.1"
opentype.js "^0.4.3"
@@ -8783,6 +8669,16 @@ read-pkg@^1.0.0:
normalize-package-data "^2.3.2"
path-type "^1.0.0"
+read-pkg@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+ integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+ dependencies:
+ "@types/normalize-package-data" "^2.4.0"
+ normalize-package-data "^2.5.0"
+ parse-json "^5.0.0"
+ type-fest "^0.6.0"
+
readable-stream@1.1.x:
version "1.1.14"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
@@ -8964,7 +8860,7 @@ repeat-element@^1.1.2:
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
-repeat-string@^1.5.2, repeat-string@^1.6.1:
+repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
@@ -8999,12 +8895,12 @@ request-promise-core@1.1.2:
dependencies:
lodash "^4.17.11"
-request-promise-core@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9"
- integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==
+request-promise-core@1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f"
+ integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==
dependencies:
- lodash "^4.17.15"
+ lodash "^4.17.19"
request-promise-native@1.0.7:
version "1.0.7"
@@ -9015,12 +8911,12 @@ request-promise-native@1.0.7:
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
-request-promise-native@^1.0.8:
- version "1.0.8"
- resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36"
- integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==
+request-promise-native@^1.0.9:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28"
+ integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==
dependencies:
- request-promise-core "1.1.3"
+ request-promise-core "1.1.4"
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
@@ -9172,7 +9068,7 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.4.0,
is-core-module "^2.0.0"
path-parse "^1.0.6"
-resolve@^1.14.2:
+resolve@^1.14.2, resolve@^1.15.1:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
@@ -9207,13 +9103,6 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
-right-align@^0.1.1:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
- integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8=
- dependencies:
- align-text "^0.1.1"
-
rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@@ -9251,6 +9140,13 @@ run-parallel@^1.1.9:
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
+rxjs@^6.6.3:
+ version "6.6.6"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70"
+ integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==
+ dependencies:
+ tslib "^1.9.0"
+
s-age@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/s-age/-/s-age-1.1.2.tgz#c0cf15233ccc93f41de92ea42c36d957977d1ea2"
@@ -9308,7 +9204,7 @@ sax@>=0.6.0, sax@^1.2.4, sax@~1.2.1, sax@~1.2.4:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-saxes@^5.0.0:
+saxes@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==
@@ -9425,17 +9321,17 @@ shallow-clone@^3.0.0:
dependencies:
kind-of "^6.0.2"
-sharp@0.27.1:
- version "0.27.1"
- resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.27.1.tgz#cd04926406a697b58dfc5fb62e3c7a3a2d68389a"
- integrity sha512-IQNXWdspb4nZcJemXa6cfgz+JvKONsuqP8Mwi1Oti23Uo7+J+UF2jihJDf6I1BQbrmhcZ0lagH/1WYG+ReAzyQ==
+sharp@0.27.2:
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.27.2.tgz#a939775e630e88600c0b5e68f20593aea722252f"
+ integrity sha512-w3FVoONPG/x5MXCc3wsjOS+b9h3CI60qkus6EPQU4dkT0BDm0PyGhDCK6KhtfT3/vbeOMOXAKFNSw+I3QGWkMA==
dependencies:
array-flatten "^3.0.0"
color "^3.1.3"
detect-libc "^1.0.3"
node-addon-api "^3.1.0"
npmlog "^4.1.2"
- prebuild-install "^6.0.0"
+ prebuild-install "^6.0.1"
semver "^7.3.4"
simple-get "^4.0.0"
tar-fs "^2.1.1"
@@ -9597,7 +9493,7 @@ source-map-url@^0.4.0:
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
-source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1:
+source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
@@ -9622,6 +9518,11 @@ sparkles@^1.0.0:
resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c"
integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==
+spawn-command@^0.0.2-1:
+ version "0.0.2-1"
+ resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0"
+ integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=
+
spawn-sync@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-2.0.0.tgz#3af5ba4b73cc5dc8a41d3747eede71e98d949555"
@@ -9951,7 +9852,7 @@ summaly@2.4.0:
require-all "2.2.0"
trace-redirect "1.0.6"
-supports-color@8.1.1:
+supports-color@8.1.1, supports-color@^8.1.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
@@ -10098,10 +9999,10 @@ syslog-pro@1.0.0:
dependencies:
moment "^2.22.2"
-systeminformation@5.6.1:
- version "5.6.1"
- resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.6.1.tgz#3726ee88b0ba50ec2268f64242fbd9a93df6546c"
- integrity sha512-5wJlHB4fzcrNENaqDVzy51+NlL0QRrLQ6pSRQOKl4k8v4jvYTlJUxChZYwpphk3McUw9iWPRcjdpKbTEj2Ucuw==
+systeminformation@5.6.7:
+ version "5.6.7"
+ resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.6.7.tgz#f56bbc89cac2de4bcb085b96a93b9d627bd6aba8"
+ integrity sha512-NTgaL6AsRoXKbfZs6t+BkCUwLZjqIiT4IwqGUV2f7PgvDz8359HzOF0xYgDlTHCBR2GeWhFQAfo2wmoYTpz/og==
syuilo-password-strength@0.0.1:
version "0.0.1"
@@ -10370,10 +10271,10 @@ toidentifier@1.0.0:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
-token-stream@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-0.0.1.tgz#ceeefc717a76c4316f126d0b9dbaa55d7e7df01a"
- integrity sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=
+token-stream@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4"
+ integrity sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=
token-types@^2.0.0:
version "2.0.0"
@@ -10400,6 +10301,15 @@ tough-cookie@^3.0.1:
psl "^1.1.28"
punycode "^2.1.1"
+tough-cookie@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
+ integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==
+ dependencies:
+ psl "^1.1.33"
+ punycode "^2.1.1"
+ universalify "^0.1.2"
+
tough-cookie@~2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
@@ -10420,10 +10330,15 @@ trace-redirect@1.0.6:
resolved "https://registry.yarnpkg.com/trace-redirect/-/trace-redirect-1.0.6.tgz#ac629b5bf8247d30dde5a35fe9811b811075b504"
integrity sha512-UUfa1DjjU5flcjMdaFIiIEGDTyu2y/IiMjOX4uGXa7meKBS4vD4f2Uy/tken9Qkd4Jsm4sRsfZcIIPqrRVF3Mg==
-ts-loader@8.0.17:
- version "8.0.17"
- resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.17.tgz#98f2ccff9130074f4079fd89b946b4c637b1f2fc"
- integrity sha512-OeVfSshx6ot/TCxRwpBHQ/4lRzfgyTkvi7ghDVrLXOHzTbSK413ROgu/xNqM72i3AFeAIJgQy78FwSMKmOW68w==
+tree-kill@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
+ integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
+
+ts-loader@8.0.18:
+ version "8.0.18"
+ resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.18.tgz#b2385cbe81c34ad9f997915129cdde3ad92a61ea"
+ integrity sha512-hRZzkydPX30XkLaQwJTDcWDoxZHK6IrEMDQpNd7tgcakFruFkeUp/aY+9hBb7BUGb+ZWKI0jiOGMo0MckwzdDQ==
dependencies:
chalk "^4.1.0"
enhanced-resolve "^4.0.0"
@@ -10534,6 +10449,16 @@ type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5:
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+ integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
+
type-fest@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
@@ -10596,26 +10521,16 @@ typeorm@0.2.31:
yargonaut "^1.1.2"
yargs "^16.0.3"
-typescript@4.1.5:
- version "4.1.5"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.5.tgz#123a3b214aaff3be32926f0d8f1f6e704eb89a72"
- integrity sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==
+typescript@4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
+ integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
-uglify-js@^2.6.1:
- version "2.8.29"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
- integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0=
- dependencies:
- source-map "~0.5.1"
- yargs "~3.10.0"
- optionalDependencies:
- uglify-to-browserify "~1.0.0"
-
uglify-js@^3.5.1:
version "3.9.1"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.9.1.tgz#a56a71c8caa2d36b5556cc1fd57df01ae3491539"
@@ -10623,11 +10538,6 @@ uglify-js@^3.5.1:
dependencies:
commander "~2.20.3"
-uglify-to-browserify@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
- integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc=
-
ulid@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f"
@@ -10686,6 +10596,11 @@ unique-stream@^2.0.2:
json-stable-stringify-without-jsonify "^1.0.1"
through2-filter "^3.0.0"
+universalify@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
unload@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
@@ -10912,10 +10827,10 @@ vinyl@^2.0.0, vinyl@^2.2.0:
remove-trailing-separator "^1.0.1"
replace-ext "^1.0.0"
-void-elements@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
- integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
+void-elements@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
+ integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=
vue-color@2.8.1:
version "2.8.1"
@@ -10927,10 +10842,10 @@ vue-color@2.8.1:
material-colors "^1.0.0"
tinycolor2 "^1.1.2"
-vue-eslint-parser@^7.5.0:
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.5.0.tgz#b68221c55fee061899afcfb4441ec74c1495285e"
- integrity sha512-6EHzl00hIpy4yWZo3qSbtvtVw1A1cTKOv1w95QSuAqGgk4113XtRjvNIiEGo49r0YWOPYsrmI4Dl64axL5Agrw==
+vue-eslint-parser@^7.6.0:
+ version "7.6.0"
+ resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.6.0.tgz#01ea1a2932f581ff244336565d712801f8f72561"
+ integrity sha512-QXxqH8ZevBrtiZMZK0LpwaMfevQi9UL7lY6Kcp+ogWHC88AuwUPwwCIzkOUc1LR4XsYAt/F9yHXAB/QoD17QXA==
dependencies:
debug "^4.1.1"
eslint-scope "^5.0.0"
@@ -10958,10 +10873,10 @@ vue-prism-editor@2.0.0-alpha.2:
resolved "https://registry.yarnpkg.com/vue-prism-editor/-/vue-prism-editor-2.0.0-alpha.2.tgz#aa53a88efaaed628027cbb282c2b1d37fc7c5c69"
integrity sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==
-vue-router@4.0.4:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.4.tgz#ad9b4b7bbdad622407b4ff189b1646f48c1e9053"
- integrity sha512-uN6PDEaYdU9aRO7mU+Dkr1uaY49hV3fucEDG/Vre/Qj8ct3RoJS16vcPrvKVzn69zDDjBV5b9Xw7fZA9r6b/Iw==
+vue-router@4.0.5:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.5.tgz#dd0a4134bc950c37aef64b973e9ee1008428d8fa"
+ integrity sha512-AQq+pllb6FCc7rS6vh4PPcce3XA1jgK3hKNkQ4hXHwoVN7jOeAOMKCnX7XAX3etV9rmN7iNW8iIwgPk95ckBjw==
vue-style-loader@4.1.3:
version "4.1.3"
@@ -10971,14 +10886,14 @@ vue-style-loader@4.1.3:
hash-sum "^1.0.2"
loader-utils "^1.0.2"
-vue@3.0.5:
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.5.tgz#de1b82eba24abfe71e0970fc9b8d4b2babdc3fe1"
- integrity sha512-TfaprOmtsAfhQau7WsomXZ8d9op/dkQLNIq8qPV3A0Vxs6GR5E+c1rfJS1SDkXRQj+dFyfnec7+U0Be1huiScg==
+vue@3.0.7:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.7.tgz#8bcff51f8be570f9e4ce8cc5f52e2ab0fe3c74a1"
+ integrity sha512-8h4TikD+JabbMK9aRlBO4laG0AtNHRPHynxYgWZ9sq1YUPfzynd9Jeeb27XNyZytC7aCQRX9xe1+TQJuc181Tw==
dependencies:
- "@vue/compiler-dom" "3.0.5"
- "@vue/runtime-dom" "3.0.5"
- "@vue/shared" "3.0.5"
+ "@vue/compiler-dom" "3.0.7"
+ "@vue/runtime-dom" "3.0.7"
+ "@vue/shared" "3.0.7"
vuedraggable@4.0.1:
version "4.0.1"
@@ -11075,10 +10990,10 @@ webpack-sources@^2.1.1:
source-list-map "^2.0.1"
source-map "^0.6.1"
-webpack@5.24.2:
- version "5.24.2"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.24.2.tgz#33790dad631e8b639f4246d762e257720875fe54"
- integrity sha512-uxxKYEY4kMNjP+D2Y+8aw5Vd7ar4pMuKCNemxV26ysr1nk0YDiQTylg9U3VZIdkmI0YHa0uC8ABxL+uGxGWWJg==
+webpack@5.26.3:
+ version "5.26.3"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.26.3.tgz#bafd439abac08fbb82657ec855d038743b725ab8"
+ integrity sha512-z/F2lt2N1fZqaud1B4SzjL3OW03eULThbBXQ2OX4LSrZX4N9k1A5d0Rje3zS2g887DTWyAV0KGqEf64ois2dhg==
dependencies:
"@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.46"
@@ -11183,29 +11098,21 @@ wildcard@^2.0.0:
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
-window-size@0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
- integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=
-
-with@^5.0.0:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/with/-/with-5.1.1.tgz#fa4daa92daf32c4ea94ed453c81f04686b575dfe"
- integrity sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=
+with@^7.0.0:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/with/-/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac"
+ integrity sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==
dependencies:
- acorn "^3.1.0"
- acorn-globals "^3.0.0"
+ "@babel/parser" "^7.9.6"
+ "@babel/types" "^7.9.6"
+ assert-never "^1.2.1"
+ babel-walk "3.0.0-canary-5"
word-wrap@^1.2.3, word-wrap@~1.2.3:
version "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==
-wordwrap@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
- integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
-
workerpool@6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b"
@@ -11263,15 +11170,10 @@ write-json-file@^2.3.0:
sort-keys "^2.0.0"
write-file-atomic "^2.0.0"
-ws@7.4.3:
- version "7.4.3"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.3.tgz#1f9643de34a543b8edb124bdcbc457ae55a6e5cd"
- integrity sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==
-
-ws@^7.2.3:
- version "7.4.1"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.1.tgz#a333be02696bd0e54cea0434e21dcc8a9ac294bb"
- integrity sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==
+ws@7.4.4, ws@^7.4.4:
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59"
+ integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==
xev@2.0.1:
version "2.0.1"
@@ -11406,7 +11308,7 @@ yargs-unparser@2.0.0:
flat "^5.0.2"
is-plain-obj "^2.1.0"
-yargs@16.2.0, yargs@^16.0.0, yargs@^16.0.3:
+yargs@16.2.0, yargs@^16.0.0, yargs@^16.0.3, yargs@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
@@ -11454,16 +11356,6 @@ yargs@^7.1.0:
y18n "^3.2.1"
yargs-parser "^5.0.0"
-yargs@~3.10.0:
- version "3.10.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
- integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=
- dependencies:
- camelcase "^1.0.2"
- cliui "^2.1.0"
- decamelize "^1.0.0"
- window-size "0.1.0"
-
ylru@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f"