Compare commits

...

29 commits

Author SHA1 Message Date
556a5c2c46 Merge branch 'web-worker' into mk.absturztau.be 2022-11-27 09:27:07 +01:00
4b82d23594 Merge branch 'main' into mk.absturztau.be 2022-11-27 09:24:34 +01:00
a6e05226ab
client: update vue and eslint-plugin-vue 2022-11-26 19:07:57 -05:00
1f037e18d6
client: autofocus on search input field
This should better replicate the previous behaviour of the text input dialog.
2022-11-27 00:14:42 +01:00
cb65e1556f Lower .node-version to 18.7.0
Some distros might not have the latest 18.x minor version in their repos, so lower it to one that's reasonably expected to be available on most distros that ship Node 18.
2022-11-26 16:59:37 +00:00
6de3771943
meta: add mailmap to merge authors 2022-11-26 16:32:52 +01:00
f9ba3ab996
client: fix undefined variable when searching for handle 2022-11-26 16:26:38 +01:00
6600f6e52e fixup: make cluster limit into a per-mode warning rather than error 2022-11-26 13:28:39 +01:00
d0c504ec85
server: fix unknown variable in signin endpoint 2022-11-25 19:09:08 +01:00
062cba1b3c
server: fix undefined variable for instance actor 2022-11-25 19:05:37 +01:00
48a60b03ea
BREAKING: implement separate web workers
There are now separate web and queue workers.

The configuration entry `clusterLimit` has been replaced by
`clusterLimits` which allows separate configuration of web and
queue workers.

Changelog: Changed
2022-11-25 12:56:49 +01:00
c7255dbea0
Update dockerfile to node 18.12.1 2022-11-25 02:07:21 -05:00
f817d45210
update eslint and typescript-eslint 2022-11-25 02:07:21 -05:00
b67799ad3f
BREAKING: Remove support for Node 16.x and upgrade to TypeScript 4.9
Now that Node 18 is the new LTS version of Node, it should be safe to
support ES2022 features. The install docs have already been updated to
recommend Node 18.x in 41a710854e.

This will break support on Node 16.x and earlier.

Also update TypeScript to 4.9 which contains various typechecking
improvements: https://devblogs.microsoft.com/typescript/announcing-typescript-4-9/

Ref: FoundKeyGang/FoundKey#238
Changelog: Changed
2022-11-25 02:07:21 -05:00
m33
7f4117371a Translated using Weblate (French)
Currently translated at 98.3% (1363 of 1386 strings)

Co-authored-by: m33 <m33_akkomadev@tok715.net>
Translate-URL: http://translate.akkoma.dev/projects/foundkey/foundkey/fr/
Translation: Foundkey/foundkey
2022-11-25 06:52:59 +00:00
2b71328c6c
meta: Update to Yarn 3.3.0 2022-11-22 01:07:12 -05:00
7ee6a09cf2
fix errors from quote string removal
The parse5 tree does not have the full DOM methods and attributes.
2022-11-21 19:43:56 +01:00
Weblate
0f6cf83add Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/foundkey/foundkey/
Translation: Foundkey/foundkey
2022-11-20 22:15:47 +00:00
9e2553909e
server: use time constants 2022-11-20 23:15:40 +01:00
66a7c62342 activitypub: remove akkoma quote URLs
Changelog: Fixed
2022-11-20 20:48:15 +00:00
512351746f Merge pull request 'Add LibreTranslate support' (#224) from libretranslate into main
Reviewed-on: FoundKeyGang/FoundKey#224
Changelog: Added
2022-11-20 16:21:17 +00:00
hayabusa
19ee132930
client: files in some states could not be dropped and uploaded
* Fixed association between dropEffect and effectAllowed as well as the submission form
* Fixed that strings can be dropped

Reviewed-on: https://github.com/misskey-dev/misskey/pull/9114
Changelog: Fixed
2022-11-20 16:17:26 +01:00
3c4302cf3b
client: close webhook settings page automatically
Changelog: Fixed
2022-11-20 12:33:04 +01:00
e59706e36f
client: delete webhooks
Changelog: Added
2022-11-20 12:29:17 +01:00
0e0411f9e0
client: fix editing webhooks
Co-authored-by: hayabusa <s.hashimoto@hs-sh.net>
Changelog: Fixed
2022-11-20 11:41:21 +01:00
kabo2468
b7f32be512
server: don't nyaize quoted lines
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
Changelog: Changed
2022-11-20 11:15:03 +01:00
aefb11959f
fix: translator settings on admin/meta endpoint 2022-11-20 10:37:50 +01:00
cfe0f3ca67
client: Add LibreTranslate support
This adds a new "Translation Settings" page to the admin interface where
the admin can configure the instance's translation settings. The
existing settigns for DeepL translation settings will now be located in
that page alongside the new LibreTranslate stuff.

Also made the translation service settings localizable, which funnily
enough was not already the case.
2022-11-19 23:00:33 -05:00
8cde66b8ac
backend: Add LibreTranslate support 2022-11-19 23:00:33 -05:00
88 changed files with 1742 additions and 1257 deletions

View file

@ -78,8 +78,11 @@ redis:
# Whether disable HSTS
#disableHsts: true
# Number of worker processes
#clusterLimit: 1
# Number of worker processes by type.
# The sum must not exceed the number of available cores.
#clusterLimits:
# web: 1
# queue: 1
# Job concurrency per worker
# deliverJobConcurrency: 128

32
.mailmap Normal file
View file

@ -0,0 +1,32 @@
Andreas Nedbal <git@pixelde.su> <andreas.nedbal@in2code.de>
Andreas Nedbal <git@pixelde.su> <github-bf215181b5140522137b3d4f6b73544a@desu.email>
Balazs Nadasdi <balazs@weave.works> <yitsushi@gmail.com>
Chloe Kudryavtsev <code@code.bunkerlabs.net> <code@toast.bunkerlabs.net>
Chloe Kudryavtsev <code@code.bunkerlabs.net> <toast+git@toast.cafe>
Chloe Kudryavtsev <code@code.bunkerlabs.net> <toast@toast.cafe>
Dr. Gutfuck LLC <40531868+gutfuckllc@users.noreply.github.com>
Ehsan Javadynia <31900907+ehsanjavadynia@users.noreply.github.com> <ehsan.javadynia@gmail.com>
Francis Dinh <normandy@biribiri.dev>
Hakaba Hitoyo <tsukadayoshio@gmail.com> Hakaba Hitoyo <example@example.com>
Johann150 <johann.galle@protonmail.com> <johann@qwertqwefsday.eu>
Michcio <public+git@meekchopp.es> <michcio@noreply.akkoma>
Nya Candy <20502130+Candinya@users.noreply.github.com> <dev@candinya.com>
Nya Candy <20502130+Candinya@users.noreply.github.com> <github@lcy.moe>
Skehmatics <skeh@is.nota.live>
Skehmatics <skeh@is.nota.live> <skehmatics@gmail.com>
ThatOneCalculator <kainoa@t1c.dev> <44733677+ThatOneCalculator@users.noreply.github.com>
Weblate <noreply@weblate.org>
Xeltica <7106976+Xeltica@users.noreply.github.com>
YuzuRyo61 <yuzuryo61@yuzulia.com> <cyberman.craft@gmail.com>
YuzuRyo61 <yuzuryo61@yuzulia.com> <yuzuryo61@yuzulia.work>
dependabot[bot] <dependabot[bot]@users.noreply.github.com> <27856297+dependabot-preview[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com> <49699333+dependabot[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com> <support@dependabot.com>
imgbot[bot] <imgbot[bot]@users.noreply.github.com> <31301654+imgbot[bot]@users.noreply.github.com>
imgbot[bot] <imgbot[bot]@users.noreply.github.com> <ImgBotHelp@gmail.com>
marihachi <marihachi0620@gmail.com>
mei23 <m@m544.net> <30769358+mei23@users.noreply.github.com>
nullobsi <me@nullob.si>
otofune <otofune@gmail.com> <otofune@users.noreply.github.com>
syuilo <syuilotan@yahoo.co.jp> <Syuilotan@yahoo.co.jp>
xianon <xianon@hotmail.co.jp>

View file

@ -1 +1 @@
v16.15.0
v18.7.0

File diff suppressed because one or more lines are too long

807
.yarn/releases/yarn-3.3.0.cjs vendored Executable file

File diff suppressed because one or more lines are too long

View file

@ -8,4 +8,4 @@ plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
yarnPath: .yarn/releases/yarn-3.2.3.cjs
yarnPath: .yarn/releases/yarn-3.3.0.cjs

View file

@ -2,7 +2,7 @@ Unless otherwise stated this repository is
Copyright © 2014-2022 syuilo and contributors
Copyright © 2022 FoundKey contributors
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
(You may be able to run `git shortlog -se` to see a full list of authors.)
FoundKey includes several third-party Open-Source softwares.

View file

@ -1,4 +1,4 @@
FROM node:18.9.0-alpine3.16 AS base
FROM node:18.12.1-alpine3.16 AS base
ARG NODE_ENV=production

View file

@ -157,7 +157,6 @@ general: "الرئيسية"
wallpaper: "الخلفية"
setWallpaper: "عيّن خلفية"
removeWallpaper: "أزل الخلفية"
searchWith: "البحث: {q}"
youHaveNoLists: "لا تمتلك أية قائمة"
followConfirm: "أتريد متابعة {name}؟"
proxyAccount: "حساب وكيل البروكسي"

View file

@ -165,7 +165,6 @@ general: "সাধারণ"
wallpaper: "ওয়ালপেপার"
setWallpaper: "ওয়ালপেপার সেট করুন"
removeWallpaper: "ওয়ালপেপার সরান"
searchWith: "খুঁজুন: {q}"
youHaveNoLists: "আপনার কোন লিস্ট নেই"
followConfirm: "{name} কে ফলোও করার ব্যাপারে নিশ্চিত?"
proxyAccount: "প্রক্সি অ্যাকাউন্ট"

View file

@ -159,7 +159,6 @@ general: "Obecně"
wallpaper: "Obrázek na pozadí"
setWallpaper: "Nastavení obrázku na pozadí"
removeWallpaper: "Odstranit pozadí"
searchWith: "Hledat: {q}"
youHaveNoLists: "Nemáte žádné seznamy"
followConfirm: "Jste si jisti, že chcete sledovat {name}?"
proxyAccount: "Proxy účet"

View file

@ -171,7 +171,6 @@ general: "Allgemein"
wallpaper: "Hintergrund"
setWallpaper: "Hintergrund festlegen"
removeWallpaper: "Hintergrund entfernen"
searchWith: "Suchen: {q}"
youHaveNoLists: "Du hast keine Listen"
followConfirm: "Möchtest du {name} wirklich folgen?"
proxyAccount: "Proxy-Benutzerkonto"

View file

@ -849,6 +849,8 @@ misskeyUpdated: "FoundKey has been updated!"
whatIsNew: "Show changes"
translate: "Translate"
translatedFrom: "Translated from {x}"
translationSettings: "Translation Settings"
translationService: "Translation Service"
accountDeletionInProgress: "Account deletion is currently in progress."
usernameInfo: "A name that identifies your account from others on this server. You\
\ can use the alphabet (a~z, A~Z), digits (0~9) or underscores (_). Usernames cannot\
@ -1526,3 +1528,10 @@ _services:
_github:
connected: "GitHub: @{login} connected to FoundKey: @{userName}!"
disconnected: "GitHub linkage has been removed."
_translationService:
_deepl:
authKey: "DeepL Auth Key"
pro: "Pro Account"
_libreTranslate:
endpoint: "LibreTranslate API Endpoint"
authKey: "LibreTranslate Auth Key (optional)"

View file

@ -167,7 +167,6 @@ general: "General"
wallpaper: "Fondo de pantalla"
setWallpaper: "Establecer fondo de pantalla"
removeWallpaper: "Quitar fondo de pantalla"
searchWith: "Buscar: {q}"
youHaveNoLists: "No tienes listas"
followConfirm: "¿Desea seguir a {name}?"
proxyAccount: "Cuenta proxy"

View file

@ -56,7 +56,7 @@ copyUsername: "Copier le nom dutilisateur·rice"
searchUser: "Chercher un·e utilisateur·rice"
reply: "Répondre"
loadMore: "Afficher plus …"
showMore: "Afficher plus"
showMore: "Afficher plus"
youGotNewFollower: "Vous suit"
receiveFollowRequest: "Demande dabonnement reçue"
followRequestAccepted: "La demande dabonnement a été acceptée"
@ -86,7 +86,7 @@ manageLists: "Gérer les listes"
error: "Erreur"
somethingHappened: "Une erreur est survenue"
retry: "Réessayer"
pageLoadError: "Le chargement de la page a échoué"
pageLoadError: "Le chargement de la page a échoué."
pageLoadErrorDescription: "Cela est généralement causé par le cache du navigateur\
\ ou par un problème réseau. Veuillez vider votre cache ou attendre un peu et réessayer."
serverIsDead: "Le serveur ne répond pas. Patientez quelques instants puis essayez\
@ -167,7 +167,6 @@ general: "Général"
wallpaper: "Fond décran"
setWallpaper: "Définir le fond décran"
removeWallpaper: "Supprimer le fond décran"
searchWith: "Recherche : {q}"
youHaveNoLists: "Vous navez aucune liste"
followConfirm: "Êtes-vous sûr·e de vouloir suivre {name} ?"
proxyAccount: "Compte proxy"
@ -514,7 +513,7 @@ hideThisNote: "Masquer cette note"
showFeaturedNotesInTimeline: "Afficher les notes des Tendances dans le fil d'actualité"
objectStorage: "Stockage d'objets"
useObjectStorage: "Utiliser le stockage d'objets"
objectStorageBaseUrl: "Base URL"
objectStorageBaseUrl: "URL de base"
objectStorageBaseUrlDesc: "Préfixe dURL utilisé pour construire lURL vers le référencement\
\ dobjet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon\
\ spécifiez ladresse accessible au public selon le guide de service que vous allez\
@ -588,7 +587,7 @@ divider: "Séparateur"
addItem: "Ajouter un élément"
relays: "Relais"
addRelay: "Ajouter un relais"
inboxUrl: "Inbox URL"
inboxUrl: "URL de la boite de réception"
addedRelays: "Relais ajoutés"
serviceworkerInfo: "Devrait être activé pour les notifications push."
deletedNote: "Note supprimée"
@ -608,7 +607,7 @@ leaveConfirm: "Vous avez des modifications non-sauvegardées. Voulez-vous les ig
\ ?"
manage: "Gestion"
plugins: "Extensions"
deck: "Deck"
deck: "Cartes"
undeck: "Quitter le deck"
useBlurEffectForModal: "Utiliser un effet de flou pour les modals"
useFullReactionPicker: "Utiliser l'intégralité du panneau de réactions"
@ -884,7 +883,8 @@ ffVisibility: "Visibilité des abonnés/abonnements"
ffVisibilityDescription: "Permet de configurer qui peut voir les personnes que tu\
\ suis et les personnes qui te suivent."
continueThread: "Afficher la suite du fil"
deleteAccountConfirm: "Votre compte sera supprimé. Êtes vous certain ?"
deleteAccountConfirm: "Le compte {handle} sera définitivement supprimé. Êtes vous\
\ certain ?"
incorrectPassword: "Le mot de passe est incorrect."
voteConfirm: "Confirmez-vous votre vote pour « {choice} » ?"
hide: "Masquer"
@ -912,6 +912,7 @@ _emailUnavailable:
format: "Le format de cette adresse de courriel est invalide"
mx: "Ce serveur de courriels est invalide"
smtp: "Ce serveur de courriels ne répond pas"
disposable: Il ne faut pas utiliser d'adresses email jetables
_ffVisibility:
public: "Public"
followers: "Visible uniquement pour les abonné·e·s"
@ -1001,7 +1002,7 @@ _mfm:
blockCode: "Bloc de code"
blockCodeDescription: "Coloration syntaxique des lignes de code pour les blocs multi-lignes."
inlineMath: "Formule mathématique (inline)"
inlineMathDescription: "Afficher les formules mathématiques (KaTeX)."
inlineMathDescription: "Afficher les formules mathématiques (KaTeX) dans le texte."
blockMath: "Formule mathématique (bloc)"
blockMathDescription: "Afficher les formules mathématiques (KaTeX) multi-lignes\
\ dans un bloc."
@ -1043,6 +1044,7 @@ _mfm:
sparkle: "Paillettes"
sparkleDescription: "Ajoute un effet scintillant au contenu."
rotate: "Pivoter"
rotateDescription: Rotation du contenu selon l'angle spécifié.
_instanceTicker:
none: "Cacher "
remote: "Montrer pour les utilisateur·ice·s distant·e·s"
@ -1083,6 +1085,9 @@ _instanceMute:
instanceMuteDescription2: "Séparer avec de nouvelles lignes"
title: "Masque les notes venant des instances listées."
heading: "Instances à mettre en sourdine"
instanceMuteDescription: Cela va mettre en sourdine toutes les notes/renotes des
instances listées, y compris celles des utilisateurs répondant à un utilisateur
à partir d'une instance désactivée.
_theme:
explore: "Explorer les thèmes"
install: "Installer un thème"
@ -1236,6 +1241,8 @@ _2fa:
\ davantage le processus de connexion grâce à une clé de sécurité matérielle qui\
\ prend en charge FIDO2, ou bien en configurant l'authentification par empreinte\
\ digitale ou par code PIN sur votre appareil."
step2Url: 'Vous pouvez aussi entrer cette URL si vous utilisez un programme sur
ordinateur:'
_permissions:
"read:account": "Afficher les informations du compte"
"write:account": "Mettre à jour les informations de votre compte"
@ -1311,6 +1318,7 @@ _widgets:
serverMetric: "Statistiques du serveur"
aiscript: "Console AiScript"
aichan: "Ai"
rssMarquee: Flux RSS
_cw:
hide: "Masquer"
show: "Afficher plus …"
@ -1473,9 +1481,13 @@ _notification:
followRequestAccepted: "Demande d'abonnement acceptée"
groupInvited: "Invitation à un groupe"
app: "Notifications provenant des apps"
pollEnded: Sondages terminés
_actions:
reply: "Répondre"
renote: "Renoter"
followBack: vous suis aussi
pollEnded: Les résultats d'un sondage sont disponibles
emptyPushNotificationMessage: L'envoi des notifications à été mis à jour
_deck:
alwaysShowMainColumn: "Toujours afficher la colonne principale"
columnAlign: "Aligner les colonnes"
@ -1498,4 +1510,84 @@ _deck:
list: "Listes"
mentions: "Mentions"
direct: "Direct"
_services: {}
_services:
_discord:
connected: '@{username}#{discriminator} sur Discord est connecté à @{mkUsername}!
sur FoundKey'
disconnected: La liaison avec Discord à été supprimée.
_twitter:
connected: '@{twitterUserName} sur Twitter est connecté à @{userName}! sur FoundKey'
disconnected: La liaison avec Twitter à été supprimée.
_github:
disconnected: La liaison avec Github à été supprimée.
connected: '@{login} sur Github est connecté à @{userName}! sur FoundKey'
exportAll: Tout exporter
stopActivityDeliveryDescription: L'activité locale ne sera pas envoyé à cette instance.
La réception de l'activité continuera de fonctionner comme avant.
blockThisInstanceDescription: L'activité locale ne sera pas envoyée à cette instance.
L'activité de cette instance sera ignorée.
signinHistoryExpires: Les données des connexions précédentes seront effacées automatiquement
après 60 jours conformément à la règlementation sur la vie privée.
reflectMayTakeTime: Il se peut que cet affichage ne soit pas immédiat.
failedToFetchAccountInformation: Impossible de récupérer les informations du compte
cropImageAsk: Voulez-vous rogner cette image ?
numberOfPageCache: Nombre de pages en cache
numberOfPageCacheDescription: Augmenter cette valeur améliorera l'expérience utilisateur
mais la charge du serveur et la consommation mémoire vont augmenter.
confirmToUnclipAlreadyClippedNote: Cette note est déjà associée avec le groupe "{name}".
Voulez-vous plutôt l'enlever ?
selectMode: Sélection multiple
maxCustomEmojiPicker: Nombre maximum d'émoticônes personnalisés proposés dans la sélection
maxUnicodeEmojiPicker: Nombre maximum d'émoticônes unicodes proposés dans la sélection
threadMuteNotificationsDesc: Sélectionnez les notifications que vous souhaitez voir
depuis ce fil. Les paramètres de notifications généraux s'appliquent aussi. Les
désactivations sont prioritaires.
renoteMute: Cacher les notes
renoteUnmute: Montrer les notes
translationSettings: Paramètres de traduction
translationService: Service de traduction
rateLimitExceeded: Dépassement de la limite de débit
cropImage: Rognez l'image
recentNHours: '{n} dernières heures'
recentNDays: '{n} derniers jours'
isSystemAccount: Un compte créé et géré automatiquement par le système.
typeToConfirm: Entrez {x} pour confirmer SVP
deleteAccount: Supprimer le compte
documentation: Documentation
file: Fichier
unclip: Déclipser
noEmailServerWarning: Le serveur de messagerie n'est pas configuré.
thereIsUnresolvedAbuseReportWarning: Il y a des signalements non traités.
recommended: Recommandé
check: Vérifier
unlimited: Illimité
selectAll: Tout sélectionner
setCategory: Définir la catégorie
addTag: Ajouter une étiquette
setTag: Définir une étiquette
removeTag: Enlever une étiquette
externalCssSnippets: Quelques CSS pour vous inspirer (pas gérés par FoundKey)
_translationService:
_deepl:
authKey: Clé d'authentification pour DeepL
pro: Compte Pro
_libreTranslate:
endpoint: Point de connexion pour l'API LibreTranslate
authKey: Clé d'authentification pour LibreTranslate (optionnel)
exportSelected: Exporter la sélection
instanceDefaultThemeDescription: Saisissez le code de thème au format objet.
federateBlocks: Fédérations bloquées
federateBlocksDescription: Si désactivé, les blocages d'activités ne seront pas envoyé.
showLess: Afficher moins
flagShowTimelineRepliesDescription: Afficher les réponses des utilisateurs aux notes
des autres utilisateurs dans le fil.
keepOriginalUploadingDescription: Enregistre l'image importée d'origine tel quel.
Si désactivé, une version affichable sur internet sera générée après l'import.
disableDrawer: Ne pas utiliser de menus à tiroir
regexpErrorDescription: "Il y a une erreur dans l'expression régulière de la ligne\
\ {line} de vos mots ignorées {tab}:"
forwardReportIsAnonymous: Un compte système anonyme sera affiché, à la place de votre
compte, lors du signalement à l'instance distante.
attachmentRequired: Un attachement au moins est nécessaire.
useDrawerReactionPickerForMobile: Sur mobile afficher un tiroir pour le panneau de
réaction

View file

@ -165,7 +165,6 @@ general: "Umum"
wallpaper: "Wallpaper"
setWallpaper: "Atur wallpaper"
removeWallpaper: "Hapus wallpaper"
searchWith: "Cari: {q}"
youHaveNoLists: "Kamu tidak memiliki daftar apapun"
followConfirm: "Apakah kamu yakin ingin mengikuti {name}?"
proxyAccount: "Akun proksi"

View file

@ -165,7 +165,6 @@ 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"

View file

@ -152,7 +152,6 @@ general: "全般"
wallpaper: "壁紙"
setWallpaper: "壁紙を設定"
removeWallpaper: "壁紙を削除"
searchWith: "検索: {q}"
youHaveNoLists: "リストがありません"
followConfirm: "{name}をフォローしますか?"
proxyAccount: "プロキシアカウント"

View file

@ -153,7 +153,6 @@ general: "全般"
wallpaper: "壁紙"
setWallpaper: "壁紙を設定"
removeWallpaper: "壁紙を削除"
searchWith: "検索: {q}"
youHaveNoLists: "リストがあらへんで?"
followConfirm: "{name}をフォローしてええか?"
proxyAccount: "プロキシアカウント"

View file

@ -149,7 +149,6 @@ general: "Algemeen"
wallpaper: "Achtergrond"
setWallpaper: "Achtergrond instellen"
removeWallpaper: "Achtergrond verwijderen"
searchWith: "Zoeken: {q}"
youHaveNoLists: "Je hebt geen lijsten"
followConfirm: "Weet je zeker dat je {name} wilt volgen?"
proxyAccount: "Proxy account"

View file

@ -162,7 +162,6 @@ general: "Ogólne"
wallpaper: "Tapeta"
setWallpaper: "Ustaw tapetę"
removeWallpaper: "Usuń tapetę"
searchWith: "Szukaj: {q}"
youHaveNoLists: "Nie masz żadnej listy"
followConfirm: "Czy na pewno chcesz zaobserwować {name}?"
proxyAccount: "Konto proxy"

View file

@ -146,7 +146,6 @@ flagAsCatDescription: "Ative essa opção para marcar essa conta como gato."
flagShowTimelineReplies: "Mostrar respostas na linha de tempo"
general: "Geral"
wallpaper: "Papel de parede"
searchWith: "Buscar: {q}"
youHaveNoLists: "Não tem nenhuma lista"
followConfirm: "Tem certeza que quer deixar de seguir {name}?"
instances: "Instância"

View file

@ -167,7 +167,6 @@ general: "General"
wallpaper: "Imagine de fundal"
setWallpaper: "Setați imaginea de fundal"
removeWallpaper: "Șterge imagine de fundal"
searchWith: "Caută: {q}"
youHaveNoLists: "Nu ai nici o listă"
followConfirm: "Ești sigur ca vrei să urmărești pe {name}?"
proxyAccount: "Cont proxy"

View file

@ -162,7 +162,6 @@ general: "Общее"
wallpaper: "Обои"
setWallpaper: "Установить обои"
removeWallpaper: "Удалить обои"
searchWith: "Найденное «{q}»"
youHaveNoLists: "У вас нет ни одного списка"
followConfirm: "Подписаться на {name}?"
proxyAccount: "Учётная запись прокси"

View file

@ -162,7 +162,6 @@ general: "Všeobecné"
wallpaper: "Tapeta"
setWallpaper: "Nastaviť tapetu"
removeWallpaper: "Odstrániť tapetu"
searchWith: "Hľadať: {q}"
youHaveNoLists: "Nemáte žiadne zoznamy"
followConfirm: "Naozaj chcete sledovať {name}?"
proxyAccount: "Proxy účet"

View file

@ -165,7 +165,6 @@ general: "Allmänt"
wallpaper: "Bakgrundsbild"
setWallpaper: "Välj bakgrund"
removeWallpaper: "Ta bort bakgrund"
searchWith: "Sök: {q}"
youHaveNoLists: "Du har inga listor"
followConfirm: "Är du säker att du vill följa {name}?"
proxyAccount: "Proxykonto"

View file

@ -164,7 +164,6 @@ general: "Загальне"
wallpaper: "Шпалери"
setWallpaper: "Встановити шпалери"
removeWallpaper: "Прибрати шпалери"
searchWith: "Пошук: {q}"
youHaveNoLists: "У вас немає списків"
followConfirm: "Підписатися на {name}?"
proxyAccount: "Проксі-акаунт"

View file

@ -162,7 +162,6 @@ general: "Tổng quan"
wallpaper: "Ảnh bìa"
setWallpaper: "Đặt ảnh bìa"
removeWallpaper: "Xóa ảnh bìa"
searchWith: "Tìm kiếm: {q}"
youHaveNoLists: "Bạn chưa có danh sách nào"
followConfirm: "Bạn có chắc muốn theo dõi {name}"
proxyAccount: "Tài khoản proxy"

View file

@ -150,7 +150,6 @@ general: "常规设置"
wallpaper: "壁纸"
setWallpaper: "设置壁纸"
removeWallpaper: "移除壁纸"
searchWith: "搜索:{q}"
youHaveNoLists: "列表为空"
followConfirm: "你确定要关注{name}吗?"
proxyAccount: "代理账户"

View file

@ -150,7 +150,6 @@ general: "一般"
wallpaper: "桌布"
setWallpaper: "設定桌布"
removeWallpaper: "移除桌布"
searchWith: "搜尋: {q}"
youHaveNoLists: "你沒有任何清單"
followConfirm: "你真的要追隨{name}嗎?"
proxyAccount: "代理帳戶"

View file

@ -46,11 +46,11 @@
"devDependencies": {
"@types/gulp": "4.0.9",
"@types/gulp-rename": "2.0.1",
"@typescript-eslint/parser": "^5.36.2",
"@typescript-eslint/parser": "^5.44.0",
"cross-env": "7.0.3",
"cypress": "10.3.0",
"start-server-and-test": "1.14.0",
"typescript": "4.8.3"
"typescript": "^4.9.3"
},
"packageManager": "yarn@3.2.3"
"packageManager": "yarn@3.3.0"
}

View file

@ -0,0 +1,19 @@
export class addLibretranslate1668661888188 {
name = 'addLibretranslate1668661888188'
async up(queryRunner) {
await queryRunner.query(`CREATE TYPE "public"."meta_translationservice_enum" AS ENUM('deepl', 'libretranslate')`);
await queryRunner.query(`ALTER TABLE "meta" ADD "translationService" "public"."meta_translationservice_enum"`);
await queryRunner.query(`ALTER TABLE "meta" ADD "libreTranslateAuthKey" character varying(128)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "libreTranslateEndpoint" character varying(2048)`);
// Set translationService to 'deepl' if auth key is already set
await queryRunner.query(`UPDATE "meta" SET "translationService"='deepl' WHERE "deeplAuthKey" IS NOT NULL`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "libreTranslateEndpoint"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "libreTranslateAuthKey"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "translationService"`);
await queryRunner.query(`DROP TYPE "public"."meta_translationservice_enum"`);
}
}

View file

@ -167,14 +167,14 @@
"@types/web-push": "3.3.2",
"@types/websocket": "1.0.5",
"@types/ws": "8.5.3",
"@typescript-eslint/eslint-plugin": "^5.36.2",
"@typescript-eslint/parser": "^5.36.2",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.44.0",
"cross-env": "7.0.3",
"eslint": "^8.20.0",
"eslint": "^8.28.0",
"eslint-plugin-import": "^2.26.0",
"execa": "6.1.0",
"form-data": "^4.0.0",
"sinon": "^14.0.2",
"typescript": "^4.8.3"
"typescript": "^4.9.3"
}
}

View file

@ -66,7 +66,7 @@ export async function masterMain(): Promise<void> {
bootLogger.succ('FoundKey initialized');
if (!envOption.disableClustering) {
await spawnWorkers(config.clusterLimit);
await spawnWorkers(config.clusterLimits);
}
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
@ -139,16 +139,26 @@ async function connectDb(): Promise<void> {
}
}
async function spawnWorkers(limit = 1): Promise<void> {
const workers = Math.min(limit, os.cpus().length);
bootLogger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`);
await Promise.all([...Array(workers)].map(spawnWorker));
bootLogger.succ('All workers started');
async function spawnWorkers(clusterLimits: Required<Config['clusterLimits']>): Promise<void> {
const modes = ['web', 'queue'];
const cpus = os.cpus().length;
for (const mode of modes.filter(mode => clusterLimits[mode] > cpus)) {
bootLogger.warn(`configuration warning: cluster limit for ${mode} exceeds number of cores (${cpus})`);
}
const total = modes.reduce((acc, mode) => acc + clusterLimits[mode], 0);
const workers = new Array(total);
workers.fill('web', 0, clusterLimits.web);
workers.fill('queue', clusterLimits.web);
bootLogger.info(`Starting ${total} workers...`);
await Promise.all(workers.map(mode => spawnWorker(mode)));
bootLogger.succ(`All workers started`);
}
function spawnWorker(): Promise<void> {
function spawnWorker(mode: 'web' | 'queue'): Promise<void> {
return new Promise(res => {
const worker = cluster.fork();
const worker = cluster.fork({ mode });
worker.on('message', message => {
if (message === 'listenFailed') {
bootLogger.error('The server Listen failed due to the previous error.');

View file

@ -1,3 +1,4 @@
import os from 'node:os';
import cluster from 'node:cluster';
import { initDb } from '@/db/postgre.js';
@ -7,11 +8,20 @@ import { initDb } from '@/db/postgre.js';
export async function workerMain(): Promise<void> {
await initDb();
// start server
await import('../server/index.js').then(x => x.default());
if (!process.env.mode || process.env.mode === 'web') {
// start server
await import('../server/index.js').then(x => x.default());
}
// start job queue
import('../queue/index.js').then(x => x.default());
if (!process.env.mode || process.env.mode === 'queue') {
// start job queue
import('../queue/index.js').then(x => x.default());
if (process.env.mode === 'queue') {
// if this is an exclusive queue worker, renice to have higher priority
os.setPriority(os.constants.priority.PRIORITY_BELOW_NORMAL);
}
}
if (cluster.isWorker) {
// Send a 'ready' message to parent process

View file

@ -54,6 +54,23 @@ export default function load(): Config {
if (!config.redis.prefix) config.redis.prefix = mixin.host;
if (!config.clusterLimits) {
config.clusterLimits = {
web: 1,
queue: 1,
};
} else {
config.clusterLimits = {
web: 1,
queue: 1,
...config.clusterLimits,
};
if (config.clusterLimits.web < 1 || config.clusterLimits.queue < 1) {
throw new Error('invalid cluster limits');
}
}
return Object.assign(config, mixin);
}

View file

@ -45,7 +45,10 @@ export type Source = {
accesslog?: string;
clusterLimit?: number;
clusterLimits?: {
web?: number;
queue?: number;
};
id: string;

View file

@ -1,9 +1,10 @@
import Xev from 'xev';
import { deliverQueue, inboxQueue } from '@/queue/queues.js';
import { SECOND } from '@/const.js';
const ev = new Xev();
const interval = 10000;
const interval = 10 * SECOND;
/**
* Report queue stats regularly

View file

@ -1,5 +1,7 @@
// https://github.com/typeorm/typeorm/issues/2400
import pg from 'pg';
import { SECOND } from '@/const.js';
pg.types.setTypeParser(20, Number);
import { Logger, DataSource } from 'typeorm';
@ -182,7 +184,7 @@ export const db = new DataSource({
password: config.db.pass,
database: config.db.db,
extra: {
statement_timeout: 1000 * 10,
statement_timeout: 10 * SECOND,
...config.db.extra,
},
synchronize: process.env.NODE_ENV === 'test',
@ -234,7 +236,7 @@ export async function resetDb() {
if (i === 3) {
throw e;
} else {
await new Promise(resolve => setTimeout(resolve, 1000));
await new Promise(resolve => setTimeout(resolve, SECOND));
continue;
}
}

View file

@ -7,7 +7,7 @@ const treeAdapter = parse5.defaultTreeAdapter;
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
export function fromHtml(html: string, hashtagNames?: string[]): string {
export function fromHtml(html: string, hashtagNames?: string[], quoteUri?: string | null): string {
const dom = parse5.parseFragment(
// some AP servers like Pixelfed use br tags as well as newlines
html.replace(/<br\s?\/?>\r?\n/gi, '\n'),
@ -202,6 +202,17 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
break;
}
case 'span':
{
const nodeClass = node.attrs.find(({ name }) => name === 'class');
if (/\bquote-inline\b/.test(nodeClass) && quoteUri && getText(node).trim() === `RE: ${quoteUri}`) {
// embedded quote thingy for backwards compatibility, don't show it
} else {
appendChildren(node.childNodes);
}
break;
}
default: // includes inline elements
{
appendChildren(node.childNodes);

View file

@ -1,6 +1,7 @@
import { promisify } from 'node:util';
import redisLock from 'redis-lock';
import { redisClient } from '@/db/redis.js';
import { SECOND } from '@/const.js';
/**
* Retry delay (ms) for lock acquisition
@ -18,14 +19,14 @@ const lock: (key: string, timeout?: number) => Promise<() => void>
* @param timeout Lock timeout (ms), The timeout releases previous lock.
* @returns Unlock function
*/
export function getApLock(uri: string, timeout = 30 * 1000) {
export function getApLock(uri: string, timeout = 30 * SECOND) {
return lock(`ap-object:${uri}`, timeout);
}
export function getFetchInstanceMetadataLock(host: string, timeout = 30 * 1000) {
export function getFetchInstanceMetadataLock(host: string, timeout = 30 * SECOND) {
return lock(`instance:${host}`, timeout);
}
export function getChartInsertLock(lockKey: string, timeout = 30 * 1000) {
export function getChartInsertLock(lockKey: string, timeout = 30 * SECOND) {
return lock(`chart-insert:${lockKey}`, timeout);
}

View file

@ -5,6 +5,7 @@ import chalk from 'chalk';
import got, * as Got from 'got';
import IPCIDR from 'ip-cidr';
import PrivateIp from 'private-ip';
import { SECOND, MINUTE } from '@/const.js';
import config from '@/config/index.js';
import Logger from '@/services/logger.js';
import { httpAgent, httpsAgent, StatusError } from './fetch.js';
@ -16,8 +17,8 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
logger.info(`Downloading ${chalk.cyan(url)} ...`);
const timeout = 30 * 1000;
const operationTimeout = 60 * 1000;
const timeout = 30 * SECOND;
const operationTimeout = MINUTE;
const maxSize = config.maxFileSize || 262144000;
const req = got.stream(url, {

View file

@ -4,9 +4,10 @@ import { URL } from 'node:url';
import CacheableLookup from 'cacheable-lookup';
import fetch from 'node-fetch';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
import { SECOND } from '@/const.js';
import config from '@/config/index.js';
export async function getJson(url: string, accept = 'application/json, */*', timeout = 10000, headers?: Record<string, string>) {
export async function getJson(url: string, accept = 'application/json, */*', timeout = 10 * SECOND, headers?: Record<string, string>) {
const res = await getResponse({
url,
method: 'GET',
@ -20,7 +21,7 @@ export async function getJson(url: string, accept = 'application/json, */*', tim
return await res.json();
}
export async function getHtml(url: string, accept = 'text/html, */*', timeout = 10000, headers?: Record<string, string>) {
export async function getHtml(url: string, accept = 'text/html, */*', timeout = 10 * SECOND, headers?: Record<string, string>) {
const res = await getResponse({
url,
method: 'GET',
@ -35,7 +36,7 @@ export async function getHtml(url: string, accept = 'text/html, */*', timeout =
}
export async function getResponse(args: { url: string, method: string, body?: string, headers: Record<string, string>, timeout?: number, size?: number }) {
const timeout = args.timeout || 10 * 1000;
const timeout = args.timeout || 10 * SECOND;
const controller = new AbortController();
setTimeout(() => {
@ -70,7 +71,7 @@ const cache = new CacheableLookup({
*/
const _http = new http.Agent({
keepAlive: true,
keepAliveMsecs: 30 * 1000,
keepAliveMsecs: 30 * SECOND,
lookup: cache.lookup,
} as http.AgentOptions);
@ -79,7 +80,7 @@ const _http = new http.Agent({
*/
const _https = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30 * 1000,
keepAliveMsecs: 30 * SECOND,
lookup: cache.lookup,
} as https.AgentOptions);
@ -91,7 +92,7 @@ const maxSockets = Math.max(256, config.deliverJobConcurrency || 128);
export const httpAgent = config.proxy
? new HttpProxyAgent({
keepAlive: true,
keepAliveMsecs: 30 * 1000,
keepAliveMsecs: 30 * SECOND,
maxSockets,
maxFreeSockets: 256,
scheduling: 'lifo',
@ -105,7 +106,7 @@ export const httpAgent = config.proxy
export const httpsAgent = config.proxy
? new HttpsProxyAgent({
keepAlive: true,
keepAliveMsecs: 30 * 1000,
keepAliveMsecs: 30 * SECOND,
maxSockets,
maxFreeSockets: 256,
scheduling: 'lifo',

View file

@ -3,6 +3,11 @@ import { id } from '../id.js';
import { User } from './user.js';
import { Clip } from './clip.js';
export enum TranslationService {
DeepL = 'deepl',
LibreTranslate = 'libretranslate',
}
@Entity()
export class Meta {
@PrimaryColumn({
@ -299,6 +304,12 @@ export class Meta {
})
public discordClientSecret: string | null;
@Column('enum', {
enum: TranslationService,
nullable: true,
})
public translationService: TranslationService | null;
@Column('varchar', {
length: 128,
nullable: true,
@ -310,6 +321,18 @@ export class Meta {
})
public deeplIsPro: boolean;
@Column('varchar', {
length: 128,
nullable: true,
})
public libreTranslateAuthKey: string | null;
@Column('varchar', {
length: 2048,
nullable: true,
})
public libreTranslateEndpoint: string | null;
@Column('varchar', {
length: 512,
nullable: true,

View file

@ -216,12 +216,20 @@ export const NoteRepository = db.getRepository(Note).extend({
if (packed.user.isCat && packed.text) {
const tokens = packed.text ? mfm.parse(packed.text) : [];
mfm.inspect(tokens, node => {
function nyaizeNode(node: mfm.Node) {
if (node.type === 'quote') return;
if (node.type === 'text') {
// TODO: quoteなtextはskip
node.props.text = nyaize(node.props.text);
}
});
if (node.children) {
for (const child of node.children) {
nyaizeNode(child);
}
}
}
for (const node of tokens) {
nyaizeNode(node);
}
packed.text = mfm.toString(tokens);
}

View file

@ -6,6 +6,7 @@ import { DriveFile } from '@/models/entities/drive-file.js';
import { Webhook, webhookEventTypes } from '@/models/entities/webhook.js';
import { IActivity } from '@/remote/activitypub/type.js';
import { envOption } from '@/env.js';
import { MINUTE } from '@/const.js';
import processDeliver from './processors/deliver.js';
import processInbox from './processors/inbox.js';
@ -96,7 +97,7 @@ export function deliver(user: ThinUser, content: unknown, to: string | null) {
return deliverQueue.add(data, {
attempts: config.deliverJobMaxAttempts || 12,
timeout: 1 * 60 * 1000, // 1min
timeout: MINUTE,
backoff: {
type: 'apBackoff',
},
@ -113,7 +114,7 @@ export function inbox(activity: IActivity, signature: httpSignature.IParsedSigna
return inboxQueue.add(data, {
attempts: config.inboxJobMaxAttempts || 8,
timeout: 5 * 60 * 1000, // 5min
timeout: 5 * MINUTE,
backoff: {
type: 'apBackoff',
},
@ -278,7 +279,7 @@ export function webhookDeliver(webhook: Webhook, type: typeof webhookEventTypes[
return webhookDeliverQueue.add(data, {
attempts: 4,
timeout: 1 * 60 * 1000, // 1min
timeout: MINUTE,
backoff: {
type: 'apBackoff',
},

View file

@ -1,4 +1,5 @@
import Bull from 'bull';
import { SECOND, MINUTE, HOUR } from '@/const.js';
import config from '@/config/index.js';
import { getRedisOptions } from '@/config/redis.js';
@ -8,7 +9,7 @@ export function initialize<T>(name: string, limitPerSec = -1): Bull.Queue<T> {
prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : 'queue',
limiter: limitPerSec > 0 ? {
max: limitPerSec,
duration: 1000,
duration: SECOND,
} : undefined,
settings: {
backoffStrategies: {
@ -20,8 +21,8 @@ export function initialize<T>(name: string, limitPerSec = -1): Bull.Queue<T> {
// ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019
function apBackoff(attemptsMade: number, err: Error) {
const baseDelay = 60 * 1000; // 1min
const maxBackoff = 8 * 60 * 60 * 1000; // 8hours
const baseDelay = MINUTE;
const maxBackoff = 8 * HOUR;
let backoff = (Math.pow(2, attemptsMade) - 1) * baseDelay;
backoff = Math.min(backoff, maxBackoff);
backoff += Math.round(backoff * Math.random() * 0.2);

View file

@ -3,6 +3,7 @@ import Bull from 'bull';
import { format as dateFormat } from 'date-fns';
import { In, MoreThan, Not } from 'typeorm';
import { MONTH } from '@/const.js';
import { getFullApAccount } from '@/misc/convert-host.js';
import { createTemp } from '@/misc/create-temp.js';
import { Following } from '@/models/entities/following.js';
@ -61,7 +62,7 @@ export async function exportFollowing(job: Bull.Job<DbUserJobData>, done: () =>
continue;
}
if (job.data.excludeInactive && u.updatedAt && (Date.now() - u.updatedAt.getTime() > 1000 * 60 * 60 * 24 * 90)) {
if (job.data.excludeInactive && u.updatedAt && (Date.now() - u.updatedAt.getTime() > 3 * MONTH)) {
continue;
}

View file

@ -2,8 +2,8 @@ import { IObject } from '../type.js';
import { extractApHashtagObjects } from '../models/tag.js';
import { fromHtml } from '@/mfm/from-html.js';
export function htmlToMfm(html: string, tag?: IObject | IObject[]) {
export function htmlToMfm(html: string, tag?: IObject | IObject[], quoteUri?: string | null) {
const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null);
return fromHtml(html, hashtagNames);
return fromHtml(html, hashtagNames, quoteUri);
}

View file

@ -194,14 +194,14 @@ export async function createNote(value: string | IObject, resolver?: Resolver =
const cw = note.summary === '' ? null : note.summary;
// テキストのパース
// text parsing
let text: string | null = null;
if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') {
text = note.source.content;
} else if (typeof note._misskey_content !== 'undefined') {
text = note._misskey_content;
} else if (typeof note.content === 'string') {
text = htmlToMfm(note.content, note.tag);
text = htmlToMfm(note.content, note.tag, quote?.uri);
}
// vote

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { CacheableRemoteUser } from '@/models/entities/user.js';
import { IObject } from './type.js';
import { performActivity } from './kernel/index.js';
@ -6,9 +7,9 @@ import { updatePerson } from './models/person.js';
export default async (actor: CacheableRemoteUser, activity: IObject): Promise<void> => {
await performActivity(actor, activity);
// ついでにリモートユーザーの情報が古かったら更新しておく
// And while I'm at it, I'll update the remote user information if it's out of date.
if (actor.uri) {
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > DAY) {
setImmediate(() => {
updatePerson(actor.uri!);
});

View file

@ -1,6 +1,7 @@
import { URL } from 'node:url';
import chalk from 'chalk';
import { IsNull } from 'typeorm';
import { DAY } from '@/const.js';
import config from '@/config/index.js';
import { isSelfHost, toPuny } from '@/misc/convert-host.js';
import { User, IRemoteUser } from '@/models/entities/user.js';
@ -49,9 +50,9 @@ export async function resolveUser(username: string, idnHost: string | null): Pro
return await createPerson(self.href);
}
// ユーザー情報が古い場合は、WebFilgerからやりなおして返す
if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
// 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する
// If user information is out of date, start over with webfinger
if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > DAY) {
// Prevent race conditions
await Users.update(user.id, {
lastFetchedAt: new Date(),
});

View file

@ -1,4 +1,5 @@
import rndstr from 'rndstr';
import { DAY } from '@/const.js';
import { Note } from '@/models/entities/note.js';
import { User } from '@/models/entities/user.js';
import { Notes, UserProfiles, NoteReactions } from '@/models/index.js';
@ -16,13 +17,13 @@ export async function injectFeatured(timeline: Note[], user?: User | null) {
}
const max = 30;
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで
const offset = 3 * DAY;
const query = Notes.createQueryBuilder('note')
.addSelect('note.score')
.where('note.userHost IS NULL')
.andWhere('note.score > 0')
.andWhere('note.createdAt > :date', { date: new Date(Date.now() - day) })
.andWhere('note.createdAt > :date', { date: new Date(Date.now() - offset) })
.andWhere("note.visibility = 'public'")
.innerJoinAndSelect('note.user', 'user');

View file

@ -0,0 +1,12 @@
import { Meta, TranslationService } from '@/models/entities/meta.js';
export function translatorAvailable(instance: Meta): boolean {
switch (instance.translationService) {
case TranslationService.DeepL:
return instance.deeplAuthKey != null;
case TranslationService.LibreTranslate:
return instance.libreTranslateEndpoint != null;
default:
return false;
}
}

View file

@ -1,5 +1,7 @@
import config from '@/config/index.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
import { TranslationService } from '@/models/entities/meta.js';
import { translatorAvailable } from '../../common/translator.js';
import define from '../../define.js';
export const meta = {
@ -269,6 +271,27 @@ export const meta = {
type: 'boolean',
optional: true, nullable: false,
},
translatorService: {
type: 'string',
enum: [null, ...Object.values(TranslationService)],
optional: false, nullable: true,
},
deeplAuthKey: {
type: 'string',
optional: true, nullable: true,
},
deeplIsPro: {
type: 'boolean',
optional: true, nullable: false,
},
libreTranslateEndpoint: {
type: 'string',
optional: true, nullable: true,
},
libreTranslateAuthKey: {
type: 'string',
optional: true, nullable: true,
},
},
},
} as const;
@ -317,7 +340,6 @@ export default define(meta, paramDef, async (ps, me) => {
enableGithubIntegration: instance.enableGithubIntegration,
enableDiscordIntegration: instance.enableDiscordIntegration,
enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null,
pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId,
cacheRemoteFiles: instance.cacheRemoteFiles,
@ -356,7 +378,12 @@ export default define(meta, paramDef, async (ps, me) => {
objectStorageUseProxy: instance.objectStorageUseProxy,
objectStorageSetPublicRead: instance.objectStorageSetPublicRead,
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
translatorAvailable: translatorAvailable(instance),
translationService: instance.translationService,
deeplAuthKey: instance.deeplAuthKey,
deeplIsPro: instance.deeplIsPro,
libreTranslateEndpoint: instance.libreTranslateEndpoint,
libreTranslateAuthKey: instance.libreTranslateAuthKey,
};
});

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { Users } from '@/models/index.js';
import define from '../../define.js';
@ -46,7 +47,7 @@ export default define(meta, paramDef, async (ps, me) => {
case 'admin': query.where('user.isAdmin = TRUE'); break;
case 'moderator': query.where('user.isModerator = TRUE'); break;
case 'adminOrModerator': query.where('user.isAdmin = TRUE OR user.isModerator = TRUE'); break;
case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break;
case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 5 * DAY) }); break;
case 'silenced': query.where('user.isSilenced = TRUE'); break;
case 'suspended': query.where('user.isSuspended = TRUE'); break;
}

View file

@ -1,5 +1,6 @@
import { insertModerationLog } from '@/services/insert-moderation-log.js';
import { fetchMeta, setMeta } from '@/misc/fetch-meta.js';
import { TranslationService } from '@/models/entities/meta.js';
import define from '../../define.js';
export const meta = {
@ -55,8 +56,11 @@ export const paramDef = {
type: 'string',
} },
summalyProxy: { type: 'string', nullable: true },
translationService: { type: 'string', nullable: true, enum: [null, ...Object.values(TranslationService)] },
deeplAuthKey: { type: 'string', nullable: true },
deeplIsPro: { type: 'boolean' },
libreTranslateAuthKey: { type: 'string', nullable: true },
libreTranslateEndpoint: { type: 'string', nullable: true },
enableTwitterIntegration: { type: 'boolean' },
twitterConsumerKey: { type: 'string', nullable: true },
twitterConsumerSecret: { type: 'string', nullable: true },
@ -362,6 +366,10 @@ export default define(meta, paramDef, async (ps, me) => {
set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle;
}
if (ps.translationService !== undefined) {
set.translationService = ps.translationService;
}
if (ps.deeplAuthKey !== undefined) {
if (ps.deeplAuthKey === '') {
set.deeplAuthKey = null;
@ -374,6 +382,22 @@ export default define(meta, paramDef, async (ps, me) => {
set.deeplIsPro = ps.deeplIsPro;
}
if (ps.libreTranslateEndpoint !== undefined) {
if (ps.libreTranslateEndpoint === '') {
set.libreTranslateEndpoint = null;
} else {
set.libreTranslateEndpoint = ps.libreTranslateEndpoint;
}
}
if (ps.libreTranslateAuthKey !== undefined) {
if (ps.libreTranslateAuthKey === '') {
set.libreTranslateAuthKey = null;
} else {
set.libreTranslateAuthKey = ps.libreTranslateAuthKey;
}
}
const meta = await fetchMeta();
await setMeta({
...meta,

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { GalleryPosts } from '@/models/index.js';
import define from '../../define.js';
@ -26,7 +27,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => {
const query = GalleryPosts.createQueryBuilder('post')
.andWhere('post.createdAt > :date', { date: new Date(Date.now() - (1000 * 60 * 60 * 24 * 3)) })
.andWhere('post.createdAt > :date', { date: new Date(Date.now() - 3 * DAY) })
.andWhere('post.likedCount > 0')
.orderBy('post.likedCount', 'DESC');

View file

@ -1,4 +1,5 @@
import { Brackets } from 'typeorm';
import { MINUTE, HOUR } from '@/const.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
import { Notes } from '@/models/index.js';
import { Note } from '@/models/entities/note.js';
@ -13,8 +14,8 @@ import define from '../../define.js';
..PostgreSQLでどうするのか分からないので単にAの内に投稿されたユニーク投稿数が多いハッシュタグ
*/
const rangeA = 1000 * 60 * 60; // 60分
//const rangeB = 1000 * 60 * 120; // 2時間
const rangeA = HOUR;
//const rangeB = 2 * HOUR;
//const coefficient = 1.25; // 「n倍」の部分
//const requiredUsers = 3; // 最低何人がそのタグを投稿している必要があるか
@ -116,8 +117,7 @@ export default define(meta, paramDef, async () => {
const range = 20;
// 10分
const interval = 1000 * 60 * 10;
const interval = 10 * MINUTE;
for (let i = 0; i < range; i++) {
countPromises.push(Promise.all(hots.map(tag => Notes.createQueryBuilder('note')

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { Users } from '@/models/index.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import define from '../../define.js';
@ -35,7 +36,7 @@ export default define(meta, paramDef, async (ps, me) => {
const query = Users.createQueryBuilder('user')
.where(':tag = ANY(user.tags)', { tag: normalizeForSearch(ps.tag) });
const recent = new Date(Date.now() - (1000 * 60 * 60 * 24 * 5));
const recent = new Date(Date.now() - 5 * DAY);
if (ps.state === 'alive') {
query.andWhere('user.updatedAt > :date', { date: recent });

View file

@ -1,6 +1,7 @@
import { promisify } from 'node:util';
import bcrypt from 'bcryptjs';
import * as cbor from 'cbor';
import { MINUTE } from '@/const.js';
import {
UserProfiles,
UserSecurityKeys,
@ -112,10 +113,10 @@ export default define(meta, paramDef, async (ps, user) => {
id: ps.challengeId,
});
// Expired challenge (> 5min old)
// Expired challenge
if (
new Date().getTime() - attestationChallenge.createdAt.getTime() >=
5 * 60 * 1000
5 * MINUTE
) {
throw new Error('expired challenge');
}

View file

@ -3,6 +3,7 @@ import config from '@/config/index.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
import { Emojis, Users } from '@/models/index.js';
import define from '../define.js';
import { translatorAvailable } from '../common/translator.js';
export const meta = {
tags: ['meta'],
@ -322,7 +323,7 @@ export default define(meta, paramDef, async (ps, me) => {
enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null,
translatorAvailable: translatorAvailable(instance),
pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId,

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { Notes } from '@/models/index.js';
import define from '../../define.js';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js';
@ -31,7 +32,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, user) => {
const max = 30;
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで
const day = 3 * DAY;
const query = Notes.createQueryBuilder('note')
.addSelect('note.score')

View file

@ -4,6 +4,7 @@ import config from '@/config/index.js';
import { getAgentByUrl } from '@/misc/fetch.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
import { Notes } from '@/models/index.js';
import { TranslationService } from '@/models/entities/meta.js';
import { ApiError } from '../../error.js';
import { getNote } from '../../common/getters.js';
import define from '../../define.js';
@ -113,50 +114,101 @@ export default define(meta, paramDef, async (ps, user) => {
if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError('NO_SUCH_NOTE');
throw err;
});
const instance = await fetchMeta();
if (note.text == null) {
if (instance.translationService == null) {
return 204;
}
const instance = await fetchMeta();
type Translation = {
sourceLang: string;
text: string;
};
if (instance.deeplAuthKey == null) {
return 204; // TODO: 良い感じのエラー返す
async function translateDeepL(): Promise<Translation | number> {
if (note.text == null || instance.deeplAuthKey == null) {
return 204; // TODO: Return a better error
}
const sourceLang = ps.sourceLang;
const targetLang = ps.targetLang;
const params = new URLSearchParams();
params.append('auth_key', instance.deeplAuthKey);
params.append('text', note.text);
params.append('target_lang', targetLang);
if (sourceLang) params.append('source_lang', sourceLang);
const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate';
const res = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': config.userAgent,
Accept: 'application/json, */*',
},
body: params,
// TODO
//timeout: 10000,
agent: getAgentByUrl,
});
const json = (await res.json()) as {
translations: {
detected_source_language: string;
text: string;
}[];
};
return {
sourceLang: json.translations[0].detected_source_language,
text: json.translations[0].text,
};
}
async function translateLibreTranslate(): Promise<Translation | number> {
if (note.text == null || instance.libreTranslateEndpoint == null) {
return 204;
}
// LibteTranslate only understands 2-letter codes
const source = ps.sourceLang?.toLowerCase().split('-', 1)[0] ?? 'auto';
const target = ps.targetLang.toLowerCase().split('-', 1)[0];
const api_key = instance.libreTranslateAuthKey ?? undefined;
const endpoint = instance.libreTranslateEndpoint;
const params = {
q: note.text,
source,
target,
api_key,
};
const res = await fetch(endpoint, {
method: 'POST',
body: JSON.stringify(params),
headers: { 'Content-Type': 'application/json' },
});
const json = (await res.json()) as {
detectedLanguage?: {
confidence: number;
language: string;
};
translatedText: string;
};
return {
sourceLang: (json.detectedLanguage?.language ?? source).toUpperCase(),
text: json.translatedText,
};
}
const sourceLang = ps.sourceLang;
const targetLang = ps.targetLang;
const params = new URLSearchParams();
params.append('auth_key', instance.deeplAuthKey);
params.append('text', note.text);
params.append('target_lang', targetLang);
if (sourceLang) params.append('source_lang', sourceLang);
const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate';
const res = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': config.userAgent,
Accept: 'application/json, */*',
},
body: params,
// TODO
//timeout: 10000,
agent: getAgentByUrl,
});
const json = (await res.json()) as {
translations: {
detected_source_language: string;
text: string;
}[];
};
return {
sourceLang: json.translations[0].detected_source_language,
text: json.translations[0].text,
};
switch (instance.translationService) {
case TranslationService.DeepL:
return await translateDeepL();
case TranslationService.LibreTranslate:
return await translateLibreTranslate();
}
});

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { Users } from '@/models/index.js';
import define from '../define.js';
import { generateMutedUserQueryForUsers } from '../common/generate-muted-user-query.js';
@ -46,7 +47,7 @@ export default define(meta, paramDef, async (ps, me) => {
case 'admin': query.andWhere('user.isAdmin = TRUE'); break;
case 'moderator': query.andWhere('user.isModerator = TRUE'); break;
case 'adminOrModerator': query.andWhere('user.isAdmin = TRUE OR user.isModerator = TRUE'); break;
case 'alive': query.andWhere('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break;
case 'alive': query.andWhere('user.updatedAt > :date', { date: new Date(Date.now() - 5 * DAY) }); break;
}
switch (ps.origin) {

View file

@ -1,3 +1,4 @@
import { MONTH } from '@/const.js';
import { Brackets } from 'typeorm';
import { Followings, Users } from '@/models/index.js';
import { User } from '@/models/entities/user.js';
@ -39,7 +40,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => {
const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日
const activeThreshold = new Date(Date.now() - MONTH);
if (ps.host) {
const q = Users.createQueryBuilder('user')

View file

@ -1,4 +1,5 @@
import { Brackets } from 'typeorm';
import { MONTH } from '@/const.js';
import { UserProfiles, Users } from '@/models/index.js';
import { User } from '@/models/entities/user.js';
import define from '../../define.js';
@ -35,7 +36,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => {
const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日
const activeThreshold = new Date(Date.now() - MONTH);
const isUsername = ps.query.startsWith('@');

View file

@ -3,6 +3,7 @@ import { IsNull } from 'typeorm';
import Koa from 'koa';
import bcrypt from 'bcryptjs';
import * as speakeasy from 'speakeasy';
import { SECOND, MINUTE, HOUR } from '@/const.js';
import config from '@/config/index.js';
import { Users, Signins, UserProfiles, UserSecurityKeys, AttestationChallenges } from '@/models/index.js';
import { ILocalUser } from '@/models/entities/user.js';
@ -31,14 +32,14 @@ export default async (ctx: Koa.Context) => {
message: e!.message,
code: e!.code,
...(e!.info ? { info: e!.info } : {}),
endpoint: endpoint.name,
endpoint: 'signin',
},
};
}
try {
// not more than 1 attempt per second and not more than 10 attempts per hour
await limiter({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, getIpHash(ctx.ip));
await limiter({ key: 'signin', duration: HOUR, max: 10, minInterval: SECOND }, getIpHash(ctx.ip));
} catch (err) {
error(new ApiError('RATE_LIMIT_EXCEEDED'));
return;
@ -149,7 +150,7 @@ export default async (ctx: Koa.Context) => {
id: body.challengeId,
});
if (new Date().getTime() - challenge.createdAt.getTime() >= 5 * 60 * 1000) {
if (new Date().getTime() - challenge.createdAt.getTime() >= 5 * MINUTE) {
await fail();
return;
}

View file

@ -1,13 +1,10 @@
import { WEEK, MONTH, YEAR } from '@/const.js';
import { User } from '@/models/entities/user.js';
import Chart, { KVs } from '../core.js';
import { name, schema } from './entities/active-users.js';
const week = 1000 * 60 * 60 * 24 * 7;
const month = 1000 * 60 * 60 * 24 * 30;
const year = 1000 * 60 * 60 * 24 * 365;
/**
*
* Chart on Active Users
*/
// eslint-disable-next-line import/no-default-export
export default class ActiveUsersChart extends Chart<typeof schema> {
@ -26,12 +23,12 @@ export default class ActiveUsersChart extends Chart<typeof schema> {
public async read(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> {
await this.commit({
'read': [user.id],
'registeredWithinWeek': (Date.now() - user.createdAt.getTime() < week) ? [user.id] : [],
'registeredWithinMonth': (Date.now() - user.createdAt.getTime() < month) ? [user.id] : [],
'registeredWithinYear': (Date.now() - user.createdAt.getTime() < year) ? [user.id] : [],
'registeredOutsideWeek': (Date.now() - user.createdAt.getTime() > week) ? [user.id] : [],
'registeredOutsideMonth': (Date.now() - user.createdAt.getTime() > month) ? [user.id] : [],
'registeredOutsideYear': (Date.now() - user.createdAt.getTime() > year) ? [user.id] : [],
'registeredWithinWeek': (Date.now() - user.createdAt.getTime() < WEEK) ? [user.id] : [],
'registeredWithinMonth': (Date.now() - user.createdAt.getTime() < MONTH) ? [user.id] : [],
'registeredWithinYear': (Date.now() - user.createdAt.getTime() < YEAR) ? [user.id] : [],
'registeredOutsideWeek': (Date.now() - user.createdAt.getTime() > WEEK) ? [user.id] : [],
'registeredOutsideMonth': (Date.now() - user.createdAt.getTime() > MONTH) ? [user.id] : [],
'registeredOutsideYear': (Date.now() - user.createdAt.getTime() > YEAR) ? [user.id] : [],
});
}

View file

@ -1,3 +1,4 @@
import { MONTH } from '@/const.js';
import { Followings, Instances } from '@/models/index.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
import Chart, { KVs } from '../core.js';
@ -65,7 +66,7 @@ export default class FederationChart extends Chart<typeof schema> {
.where(`instance.host IN (${ subInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere('instance.isSuspended = false')
.andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) })
.andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - MONTH) })
.getRawOne()
.then(x => parseInt(x.count, 10)),
Instances.createQueryBuilder('instance')
@ -73,7 +74,7 @@ export default class FederationChart extends Chart<typeof schema> {
.where(`instance.host IN (${ pubInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere('instance.isSuspended = false')
.andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) })
.andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - MONTH) })
.getRawOne()
.then(x => parseInt(x.count, 10)),
]);

View file

@ -2,6 +2,7 @@ import { URL } from 'node:url';
import { DOMWindow, JSDOM } from 'jsdom';
import fetch from 'node-fetch';
import tinycolor from 'tinycolor2';
import { DAY } from '@/const.js';
import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js';
import { Instance } from '@/models/entities/instance.js';
import { Instances } from '@/models/index.js';
@ -16,7 +17,7 @@ export async function fetchInstanceMetadata(instance: Instance, force = false):
if (!force) {
const _instance = await Instances.findOneBy({ host: instance.host });
const now = Date.now();
if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) {
if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < DAY)) {
unlock();
return;
}

View file

@ -11,10 +11,9 @@ let instanceActor = await Users.findOneBy({
}) as ILocalUser | undefined;
export async function getInstanceActor(): Promise<ILocalUser> {
if (instanceActor) {
return instanceActor;
} else {
if (!instanceActor) {
instanceActor = await createSystemUser(ACTOR_USERNAME) as ILocalUser;
return created;
}
return instanceActor;
}

View file

@ -10,8 +10,8 @@
"noFallthroughCasesInSwitch": true,
"declaration": false,
"sourceMap": false,
"target": "ES2021",
"module": "esnext",
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "Node16",
"allowSyntheticDefaultImports": true,
"removeComments": false,
@ -39,7 +39,7 @@
"./src/@types"
],
"lib": [
"esnext"
"ES2022"
]
},
"compileOnSave": false,

View file

@ -66,12 +66,12 @@
"tsc-alias": "1.7.0",
"tsconfig-paths": "4.1.0",
"twemoji-parser": "14.0.0",
"typescript": "4.8.3",
"typescript": "^4.9.3",
"uuid": "8.3.2",
"v-debounce": "0.1.2",
"vanilla-tilt": "1.7.2",
"vite": "3.1.0",
"vue": "3.2.39",
"vue": "3.2.45",
"vue-prism-editor": "2.0.0-alpha.2",
"vuedraggable": "4.0.1",
"wavesurfer.js": "6.0.1",
@ -96,13 +96,13 @@
"@types/uuid": "8.3.4",
"@types/websocket": "1.0.5",
"@types/ws": "8.5.3",
"@typescript-eslint/eslint-plugin": "^5.36.2",
"@typescript-eslint/parser": "^5.36.2",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.44.0",
"cross-env": "7.0.3",
"cypress": "10.3.0",
"eslint": "^8.20.0",
"eslint": "^8.28.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-vue": "^9.1.1",
"eslint-plugin-vue": "^9.8.0",
"start-server-and-test": "1.14.0"
}
}

View file

@ -90,7 +90,22 @@ function onDragover(ev: DragEvent) {
const isDriveFolder = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FOLDER_;
if (isFile || isDriveFile || isDriveFolder) {
ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
switch (ev.dataTransfer.effectAllowed) {
case 'all':
case 'uninitialized':
case 'copy':
case 'copyLink':
case 'copyMove':
ev.dataTransfer.dropEffect = 'copy';
break;
case 'linkMove':
case 'move':
ev.dataTransfer.dropEffect = 'move';
break;
default:
ev.dataTransfer.dropEffect = 'none';
break;
}
} else {
ev.dataTransfer.dropEffect = 'none';
}

View file

@ -50,7 +50,22 @@ function onDragover(ev: DragEvent) {
const isDriveFolder = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FOLDER_;
if (isFile || isDriveFile || isDriveFolder) {
ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
switch (ev.dataTransfer.effectAllowed) {
case 'all':
case 'uninitialized':
case 'copy':
case 'copyLink':
case 'copyMove':
ev.dataTransfer.dropEffect = 'copy';
break;
case 'linkMove':
case 'move':
ev.dataTransfer.dropEffect = 'move';
break;
default:
ev.dataTransfer.dropEffect = 'none';
break;
}
} else {
ev.dataTransfer.dropEffect = 'none';
}

View file

@ -221,7 +221,22 @@ function onDragover(ev: DragEvent): any {
const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
const isDriveFolder = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FOLDER_;
if (isFile || isDriveFile || isDriveFolder) {
ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
switch (ev.dataTransfer.effectAllowed) {
case 'all':
case 'uninitialized':
case 'copy':
case 'copyLink':
case 'copyMove':
ev.dataTransfer.dropEffect = 'copy';
break;
case 'linkMove':
case 'move':
ev.dataTransfer.dropEffect = 'move';
break;
default:
ev.dataTransfer.dropEffect = 'none';
break;
}
} else {
ev.dataTransfer.dropEffect = 'none';
}

View file

@ -172,6 +172,11 @@ const menuDef = $computed(() => [{
text: i18n.ts.proxyAccount,
to: '/admin/proxy-account',
active: props.initialPage === 'proxy-account',
}, {
icon: 'fas fa-language',
text: i18n.ts.translationSettings,
to: '/admin/translation-settings',
active: props.initialPage === 'translation-settings',
}],
}, {
title: i18n.ts.info,
@ -202,6 +207,7 @@ const component = $computed(() => {
case 'integrations': return defineAsyncComponent(() => import('./integrations.vue'));
case 'instance-block': return defineAsyncComponent(() => import('./instance-block.vue'));
case 'proxy-account': return defineAsyncComponent(() => import('./proxy-account.vue'));
case 'translation-settings': return defineAsyncComponent(() => import('./translation-settings.vue'));
default: return null;
}
});

View file

@ -128,18 +128,6 @@
</FormInput>
</template>
</FormSection>
<FormSection>
<template #label>DeepL Translation</template>
<FormInput v-model="deeplAuthKey" class="_formBlock">
<template #prefix><i class="fas fa-key"></i></template>
<template #label>DeepL Auth Key</template>
</FormInput>
<FormSwitch v-model="deeplIsPro" class="_formBlock">
<template #label>Pro account</template>
</FormSwitch>
</FormSection>
</div>
</FormSuspense>
</MkSpacer>
@ -182,8 +170,6 @@ let emailRequiredForSignup: boolean = $ref(false);
let enableServiceWorker: boolean = $ref(false);
let swPublicKey: any = $ref(null);
let swPrivateKey: any = $ref(null);
let deeplAuthKey: string = $ref('');
let deeplIsPro: boolean = $ref(false);
async function init(): Promise<void> {
const meta = await os.api('admin/meta');
@ -209,11 +195,9 @@ async function init(): Promise<void> {
enableServiceWorker = meta.enableServiceWorker;
swPublicKey = meta.swPublickey;
swPrivateKey = meta.swPrivateKey;
deeplAuthKey = meta.deeplAuthKey;
deeplIsPro = meta.deeplIsPro;
}
function save() {
function save(): void {
os.apiWithDialog('admin/update-meta', {
name,
description,
@ -237,8 +221,6 @@ function save() {
enableServiceWorker,
swPublicKey,
swPrivateKey,
deeplAuthKey,
deeplIsPro,
}).then(() => {
fetchInstance();
});

View file

@ -0,0 +1,86 @@
<template>
<MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions"/></template>
<MkSpacer :content-max="700" :margin-min="16" :margin-max="32">
<FormSuspense :p="init">
<div class="_formRoot">
<FormSelect v-model="translationService" class="_formBlock">
<template #label>{{ i18n.ts.translationService }}</template>
<option value="none">{{ i18n.ts.none }}</option>
<option value="deepl">DeepL</option>
<option value="libretranslate">LibreTranslate</option>
</FormSelect>
<template v-if="translationService === 'deepl'">
<FormSwitch v-model="deeplIsPro" class="_formBlock">
<template #label>{{ i18n.ts._translationService._deepl.pro }}</template>
</FormSwitch>
<FormInput v-model="deeplAuthKey" class="_formBlock">
<template #prefix><i class="fas fa-key"></i></template>
<template #label>{{ i18n.ts._translationService._deepl.authKey }}</template>
</FormInput>
</template>
<template v-else-if="translationService === 'libretranslate'">
<FormInput v-model="libreTranslateEndpoint" class="_formBlock">
<template #label>{{ i18n.ts._translationService._libreTranslate.endpoint }}</template>
</FormInput>
<FormInput v-model="libreTranslateAuthKey" class="_formBlock">
<template #prefix><i class="fas fa-key"></i></template>
<template #label>{{ i18n.ts._translationService._libreTranslate.authKey }}</template>
</FormInput>
</template>
</div>
</FormSuspense>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import FormInput from '@/components/form/input.vue';
import FormSelect from '@/components/form/select.vue';
import FormSuspense from '@/components/form/suspense.vue';
import FormSwitch from '@/components/form/switch.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { fetchInstance } from '@/instance';
import { definePageMetadata } from '@/scripts/page-metadata';
let translationService: string = $ref('none');
let deeplIsPro: boolean = $ref(false);
let deeplAuthKey: string = $ref('');
let libreTranslateEndpoint: string = $ref('');
let libreTranslateAuthKey: string = $ref('');
async function init(): Promise<void> {
const meta = await os.api('admin/meta');
translationService = meta.translationService ?? 'none';
deeplIsPro = meta.deeplIsPro;
deeplAuthKey = meta.deeplAuthKey;
libreTranslateEndpoint = meta.libreTranslateEndpoint;
libreTranslateAuthKey = meta.libreTranslateAuthKey;
}
function save(): void {
os.apiWithDialog('admin/update-meta', {
translationService: translationService === 'none' ? null : translationService,
deeplAuthKey,
deeplIsPro,
libreTranslateEndpoint,
libreTranslateAuthKey,
}).then(() => {
fetchInstance();
});
}
const headerActions = $computed(() => [{
asFullButton: true,
icon: 'fas fa-check',
text: i18n.ts.save,
handler: save,
}]);
definePageMetadata({
title: i18n.ts.translationSettings,
icon: 'fas fa-language',
});
</script>

View file

@ -93,7 +93,22 @@ function onDragover(ev: DragEvent) {
const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
if (isFile || isDriveFile) {
ev.preventDefault();
ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
switch (ev.dataTransfer.effectAllowed) {
case 'all':
case 'uninitialized':
case 'copy':
case 'copyLink':
case 'copyMove':
ev.dataTransfer.dropEffect = 'copy';
break;
case 'linkMove':
case 'move':
ev.dataTransfer.dropEffect = 'move';
break;
default:
ev.dataTransfer.dropEffect = 'none';
break;
}
}
}

View file

@ -154,7 +154,22 @@ function onDragover(ev: DragEvent) {
const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
if (isFile || isDriveFile) {
ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
switch (ev.dataTransfer.effectAllowed) {
case 'all':
case 'uninitialized':
case 'copy':
case 'copyLink':
case 'copyMove':
ev.dataTransfer.dropEffect = 'copy';
break;
case 'linkMove':
case 'move':
ev.dataTransfer.dropEffect = 'move';
break;
default:
ev.dataTransfer.dropEffect = 'none';
break;
}
} else {
ev.dataTransfer.dropEffect = 'none';
}

View file

@ -4,7 +4,7 @@
<MkSpacer :content-max="800">
<MkFolder>
<template #header>{{ i18n.ts.search }}</template>
<MkInput v-model="query" class="input" tabindex="1" @keydown="keydown">
<MkInput v-model="query" :autofocus="true" class="input" tabindex="1" @keydown="keydown">
<template #prefix><i class="fas fa-magnifying-glass"></i></template>
<template v-if="tab === 'users'" #label>{{ i18n.ts.username }}</template>
<template v-if="tab === 'all'" #caption>Try entering a URL or user handle!</template>
@ -120,7 +120,7 @@ async function search(): void {
query = query.trim();
// process special query strings
if (query.startsWith('@') && !query.includes(' ')) {
mainRouter.push('/' + q);
mainRouter.push('/' + query);
} else if (query.startsWith('#')) {
mainRouter.push('/tags/' + encodeURIComponent(query.slice(1)));
} else if (query.startsWith('https://')) {

View file

@ -29,6 +29,7 @@
<div class="_formBlock" style="display: flex; gap: var(--margin); flex-wrap: wrap;">
<FormButton primary inline @click="save"><i class="fas fa-check"></i> {{ i18n.ts.save }}</FormButton>
<FormButton danger inline @click="del"><i class="fas fa-trash-alt"></i> {{ i18n.ts.delete }}</FormButton>
</div>
</div>
</template>
@ -41,6 +42,9 @@ import FormButton from '@/components/ui/button.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { useRouter } from '@/router';
const router = useRouter();
const webhook = await os.api('i/webhooks/show', {
webhookId: new URLSearchParams(window.location.search).get('id'),
@ -69,13 +73,28 @@ async function save(): Promise<void> {
if (event_reaction) events.push('reaction');
if (event_mention) events.push('mention');
os.apiWithDialog('i/webhooks/update', {
await os.apiWithDialog('i/webhooks/update', {
webhookId: webhook.id,
name,
url,
secret,
on: events,
active,
});
router.push('/settings/webhook');
}
async function del(): Promise<void> {
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.ts.deleteConfirm,
});
if (canceled) return;
await os.apiWithDialog('i/webhooks/delete', {
webhookId: webhook.id,
});
router.push('/settings/webhook');
}
definePageMetadata({

View file

@ -39,6 +39,9 @@ import FormButton from '@/components/ui/button.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { useRouter } from '@/router';
const router = useRouter();
let name = $ref('');
let url = $ref('');
@ -62,12 +65,14 @@ async function create(): Promise<void> {
if (event_reaction) events.push('reaction');
if (event_mention) events.push('mention');
os.apiWithDialog('i/webhooks/create', {
await os.apiWithDialog('i/webhooks/create', {
name,
url,
secret,
on: events,
});
router.push('/settings/webhook');
}
definePageMetadata({

View file

@ -20,9 +20,9 @@
"@microsoft/api-extractor": "^7.19.3",
"@types/jest": "^27.4.0",
"@types/node": "18.7.16",
"@typescript-eslint/eslint-plugin": "5.36.2",
"@typescript-eslint/parser": "^5.36.2",
"eslint": "^8.23.0",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.44.0",
"eslint": "^8.28.0",
"jest": "^27.4.5",
"jest-fetch-mock": "^3.0.3",
"jest-websocket-mock": "^2.2.1",
@ -30,7 +30,7 @@
"ts-jest": "^27.1.5",
"ts-node": "10.9.1",
"tsd": "^0.23.0",
"typescript": "4.8.3"
"typescript": "^4.9.3"
},
"files": [
"built"

View file

@ -13,6 +13,6 @@
"idb-keyval": "^6.0.3"
},
"devDependencies": {
"eslint": "^8.20.0"
"eslint": "^8.28.0"
}
}

466
yarn.lock
View file

@ -656,26 +656,9 @@ __metadata:
languageName: node
linkType: hard
"@eslint/eslintrc@npm:^1.3.0":
version: 1.3.0
resolution: "@eslint/eslintrc@npm:1.3.0"
dependencies:
ajv: ^6.12.4
debug: ^4.3.2
espree: ^9.3.2
globals: ^13.15.0
ignore: ^5.2.0
import-fresh: ^3.2.1
js-yaml: ^4.1.0
minimatch: ^3.1.2
strip-json-comments: ^3.1.1
checksum: a1e734ad31a8b5328dce9f479f185fd4fc83dd7f06c538e1fa457fd8226b89602a55cc6458cd52b29573b01cdfaf42331be8cfc1fec732570086b591f4ed6515
languageName: node
linkType: hard
"@eslint/eslintrc@npm:^1.3.1":
version: 1.3.1
resolution: "@eslint/eslintrc@npm:1.3.1"
"@eslint/eslintrc@npm:^1.3.3":
version: 1.3.3
resolution: "@eslint/eslintrc@npm:1.3.3"
dependencies:
ajv: ^6.12.4
debug: ^4.3.2
@ -686,7 +669,7 @@ __metadata:
js-yaml: ^4.1.0
minimatch: ^3.1.2
strip-json-comments: ^3.1.1
checksum: 9844dcc58a44399649926d5a17a2d53d529b80d3e8c3e9d0964ae198bac77ee6bb1cf44940f30cd9c2e300f7568ec82500be42ace6cacefb08aebf9905fe208e
checksum: f03e9d6727efd3e0719da2051ea80c0c73d20e28c171121527dbb868cd34232ca9c1d0525a66e517a404afea26624b1e47895b6a92474678418c2f50c9566694
languageName: node
linkType: hard
@ -720,21 +703,14 @@ __metadata:
languageName: node
linkType: hard
"@humanwhocodes/config-array@npm:^0.10.4":
version: 0.10.4
resolution: "@humanwhocodes/config-array@npm:0.10.4"
"@humanwhocodes/config-array@npm:^0.11.6":
version: 0.11.7
resolution: "@humanwhocodes/config-array@npm:0.11.7"
dependencies:
"@humanwhocodes/object-schema": ^1.2.1
debug: ^4.1.1
minimatch: ^3.0.4
checksum: d480e5d57e6d787565b6cff78e27c3d1b380692d4ffb0ada7d7f5957a56c9032f034da05a3e443065dbd0671ebf4d859036ced34e96b325bbc1badbae3c05300
languageName: node
linkType: hard
"@humanwhocodes/gitignore-to-minimatch@npm:^1.0.2":
version: 1.0.2
resolution: "@humanwhocodes/gitignore-to-minimatch@npm:1.0.2"
checksum: aba5c40c9e3770ed73a558b0bfb53323842abfc2ce58c91d7e8b1073995598e6374456d38767be24ab6176915f0a8d8b23eaae5c85e2b488c0dccca6d795e2ad
minimatch: ^3.0.5
checksum: cf506dc45d9488af7fbf108ea6ac2151ba1a25e6d2b94b9b4fc36d2c1e4099b89ff560296dbfa13947e44604d4ca4a90d97a4fb167370bf8dd01a6ca2b6d83ac
languageName: node
linkType: hard
@ -1186,7 +1162,7 @@ __metadata:
languageName: node
linkType: hard
"@nodelib/fs.walk@npm:^1.2.3":
"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8":
version: 1.2.8
resolution: "@nodelib/fs.walk@npm:1.2.8"
dependencies:
@ -2386,6 +2362,13 @@ __metadata:
languageName: node
linkType: hard
"@types/semver@npm:^7.3.12":
version: 7.3.13
resolution: "@types/semver@npm:7.3.13"
checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0
languageName: node
linkType: hard
"@types/serve-static@npm:*":
version: 1.15.0
resolution: "@types/serve-static@npm:1.15.0"
@ -2575,16 +2558,16 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/eslint-plugin@npm:5.36.2, @typescript-eslint/eslint-plugin@npm:^5.36.2":
version: 5.36.2
resolution: "@typescript-eslint/eslint-plugin@npm:5.36.2"
"@typescript-eslint/eslint-plugin@npm:^5.44.0":
version: 5.44.0
resolution: "@typescript-eslint/eslint-plugin@npm:5.44.0"
dependencies:
"@typescript-eslint/scope-manager": 5.36.2
"@typescript-eslint/type-utils": 5.36.2
"@typescript-eslint/utils": 5.36.2
"@typescript-eslint/scope-manager": 5.44.0
"@typescript-eslint/type-utils": 5.44.0
"@typescript-eslint/utils": 5.44.0
debug: ^4.3.4
functional-red-black-tree: ^1.0.1
ignore: ^5.2.0
natural-compare-lite: ^1.4.0
regexpp: ^3.2.0
semver: ^7.3.7
tsutils: ^3.21.0
@ -2594,43 +2577,43 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: edcd9fcecdeb22a689b421cafe3b7adc859bf2fd6227aecdd7412c319c808e7bab063c8f94af32116cfc971962f9780d181cb0a4aa999951c2d2be1f84c6c376
checksum: 88784e77e8e35ea50ca9c49d46df94cabc3447f4b332f3ca53974d3b5370cb5dcd85cc9ee0e317b91083812012369209574725dcfc3b2b4056b60371b68ca854
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:^5.36.2":
version: 5.36.2
resolution: "@typescript-eslint/parser@npm:5.36.2"
"@typescript-eslint/parser@npm:^5.44.0":
version: 5.44.0
resolution: "@typescript-eslint/parser@npm:5.44.0"
dependencies:
"@typescript-eslint/scope-manager": 5.36.2
"@typescript-eslint/types": 5.36.2
"@typescript-eslint/typescript-estree": 5.36.2
"@typescript-eslint/scope-manager": 5.44.0
"@typescript-eslint/types": 5.44.0
"@typescript-eslint/typescript-estree": 5.44.0
debug: ^4.3.4
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
typescript:
optional: true
checksum: d6cc22cbc7aacb5ecebf55eb1d681cb6b964b108e147b418295c3e48701a77768cff128c16da421ae50eabb9f1296ecec7fa3cc5f2ccb63a3febf79f98b4195f
checksum: 2d09a1a1547a7ae3f76c9a33a54e11d79a194fbb9dbae69988e7aed3370bdf12bafde669211152769d89db822e0cdee4173affc126664fa6f17abba56daa7261
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:5.36.2":
version: 5.36.2
resolution: "@typescript-eslint/scope-manager@npm:5.36.2"
"@typescript-eslint/scope-manager@npm:5.44.0":
version: 5.44.0
resolution: "@typescript-eslint/scope-manager@npm:5.44.0"
dependencies:
"@typescript-eslint/types": 5.36.2
"@typescript-eslint/visitor-keys": 5.36.2
checksum: 93ff655f7c237c88ec6dc5911202dd8f81bd8909b27f1a758a9d77e9791040f1ee6fe2891314bde75c808ce586246e98003a1b1396937b0312f2440016dea751
"@typescript-eslint/types": 5.44.0
"@typescript-eslint/visitor-keys": 5.44.0
checksum: 4cfe4b55eb428eda740e6b967e3a87f3e1f9c4bbd8e1d6b8d64a11666abe33ffe7a21e4e614444ccde2da6930fa85f3e0ffca43d6e339943ff7a4fbccb09c8fc
languageName: node
linkType: hard
"@typescript-eslint/type-utils@npm:5.36.2":
version: 5.36.2
resolution: "@typescript-eslint/type-utils@npm:5.36.2"
"@typescript-eslint/type-utils@npm:5.44.0":
version: 5.44.0
resolution: "@typescript-eslint/type-utils@npm:5.44.0"
dependencies:
"@typescript-eslint/typescript-estree": 5.36.2
"@typescript-eslint/utils": 5.36.2
"@typescript-eslint/typescript-estree": 5.44.0
"@typescript-eslint/utils": 5.44.0
debug: ^4.3.4
tsutils: ^3.21.0
peerDependencies:
@ -2638,23 +2621,23 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: c202b7d2cd08ed7f7d1ad7e430e9e1596478e147f0d485d02babfda0211c55fa950de1dc4d1c950008a8a047a31c1e982e97fe5558f93d496830eb9d9532bc71
checksum: 4c7b594f8afa52d57d0512951a874fa390eb791dcefcd0e1efff8817872293b2e4e04eff3c54d1595c1720a34d5fd315729af4e459882033d13cb6069ae9d28f
languageName: node
linkType: hard
"@typescript-eslint/types@npm:5.36.2":
version: 5.36.2
resolution: "@typescript-eslint/types@npm:5.36.2"
checksum: 736cb8a76b58f2f9a7d066933094c5510ffe31479ea8b804a829ec85942420f1b55e0eb2688fbdaaaa9c0e5b3b590fb8f14bbd745353696b4fd33fda620d417b
"@typescript-eslint/types@npm:5.44.0":
version: 5.44.0
resolution: "@typescript-eslint/types@npm:5.44.0"
checksum: ced7d32abecfc62ccb67cf27e30c0785b9c153ec7b1a05153ced58fa5a2031ab3845bc2e477b83e4cebdcc5881c5845d23053c6739c62549d41ae6208e547e85
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:5.36.2":
version: 5.36.2
resolution: "@typescript-eslint/typescript-estree@npm:5.36.2"
"@typescript-eslint/typescript-estree@npm:5.44.0":
version: 5.44.0
resolution: "@typescript-eslint/typescript-estree@npm:5.44.0"
dependencies:
"@typescript-eslint/types": 5.36.2
"@typescript-eslint/visitor-keys": 5.36.2
"@typescript-eslint/types": 5.44.0
"@typescript-eslint/visitor-keys": 5.44.0
debug: ^4.3.4
globby: ^11.1.0
is-glob: ^4.0.3
@ -2663,33 +2646,35 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 2827ff57a114b6107ea6d555f3855007133b08a7c2bafba0cfa0c935d8b99fd7b49e982d48cccc1c5ba550d95748d0239f5e2109893f12a165d76ed64a0d261b
checksum: 758731108497cca7ff81cf0a78d086b5a85757a983979d6bb25ad8252b7acbc738c642ecb5f5df82f925a45926b9846e431d5cf9fee5ed2613300b4d0c5d6c3f
languageName: node
linkType: hard
"@typescript-eslint/utils@npm:5.36.2":
version: 5.36.2
resolution: "@typescript-eslint/utils@npm:5.36.2"
"@typescript-eslint/utils@npm:5.44.0":
version: 5.44.0
resolution: "@typescript-eslint/utils@npm:5.44.0"
dependencies:
"@types/json-schema": ^7.0.9
"@typescript-eslint/scope-manager": 5.36.2
"@typescript-eslint/types": 5.36.2
"@typescript-eslint/typescript-estree": 5.36.2
"@types/semver": ^7.3.12
"@typescript-eslint/scope-manager": 5.44.0
"@typescript-eslint/types": 5.44.0
"@typescript-eslint/typescript-estree": 5.44.0
eslint-scope: ^5.1.1
eslint-utils: ^3.0.0
semver: ^7.3.7
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
checksum: 45356cf55a8733e3ab1f2c3c19cdaefdb79857e35eb1433c29b81f3df071e9cef8a286bc407abe243889a21d9e793e999f92f03b9c727a0fac1c17a48e64c42a
checksum: bc5bb28e41898464d35b8eb47cc452103852541e3b6be56252c15a5a81c45e10aad3db4c749eb92d752b0c358df8074e23ec6f9e65f8089baadeda7f395c7e31
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:5.36.2":
version: 5.36.2
resolution: "@typescript-eslint/visitor-keys@npm:5.36.2"
"@typescript-eslint/visitor-keys@npm:5.44.0":
version: 5.44.0
resolution: "@typescript-eslint/visitor-keys@npm:5.44.0"
dependencies:
"@typescript-eslint/types": 5.36.2
"@typescript-eslint/types": 5.44.0
eslint-visitor-keys: ^3.3.0
checksum: 87ccdcfa5cdedaa3a1aac30d656969f4f5910b62bcaacdf80a514dbf0cbbd8e79b55f8e987eab34cc79ece8ce4b8c19d5caf8b0afb74e0b0d7ab39fb29aa8eba
checksum: a012c888209e1d6ae684b2a44fd460ae5a80f5faf07bca4bda6c9c0d8c063ad3297d4c53f7151ae86cf1a43dee09625dc3ee72183323c91089c7288fd573c6f4
languageName: node
linkType: hard
@ -2710,115 +2695,115 @@ __metadata:
languageName: node
linkType: hard
"@vue/compiler-core@npm:3.2.39":
version: 3.2.39
resolution: "@vue/compiler-core@npm:3.2.39"
"@vue/compiler-core@npm:3.2.45":
version: 3.2.45
resolution: "@vue/compiler-core@npm:3.2.45"
dependencies:
"@babel/parser": ^7.16.4
"@vue/shared": 3.2.39
"@vue/shared": 3.2.45
estree-walker: ^2.0.2
source-map: ^0.6.1
checksum: dd70ed60b14faba2f46a2a99ddf20819db7dff124dd49ec15ba76ea3c6d8311feca4256d4dac8e8316c6670434cbb7c0c6a2cb5f6e97b321ba42ff454102c3be
checksum: e3c687b24c16c2b320c02ed38960f8bee7dcb88bddb09e60a80d2d4dc004070cbbd4eccbc99cc168d48d753ff60d0b9eefba835e1dec3b7f233a98c89af31c07
languageName: node
linkType: hard
"@vue/compiler-dom@npm:3.2.39":
version: 3.2.39
resolution: "@vue/compiler-dom@npm:3.2.39"
"@vue/compiler-dom@npm:3.2.45":
version: 3.2.45
resolution: "@vue/compiler-dom@npm:3.2.45"
dependencies:
"@vue/compiler-core": 3.2.39
"@vue/shared": 3.2.39
checksum: 505a8f8515f8551795e3a01859d451645e0bd77be2d70d5c48f6edd02ebc255d911230c66ccfc478fd0218ab8a7b69bd99e2c12b406db4889285058f52d13363
"@vue/compiler-core": 3.2.45
"@vue/shared": 3.2.45
checksum: 89115538635f0da9cce615de5488d2759256fa573976a09a049536dbb94e9b5086b46f2f11e743cf0a7b14837161b3191c67611e0493054a5d4c4b96a322c901
languageName: node
linkType: hard
"@vue/compiler-sfc@npm:3.2.39":
version: 3.2.39
resolution: "@vue/compiler-sfc@npm:3.2.39"
"@vue/compiler-sfc@npm:3.2.45":
version: 3.2.45
resolution: "@vue/compiler-sfc@npm:3.2.45"
dependencies:
"@babel/parser": ^7.16.4
"@vue/compiler-core": 3.2.39
"@vue/compiler-dom": 3.2.39
"@vue/compiler-ssr": 3.2.39
"@vue/reactivity-transform": 3.2.39
"@vue/shared": 3.2.39
"@vue/compiler-core": 3.2.45
"@vue/compiler-dom": 3.2.45
"@vue/compiler-ssr": 3.2.45
"@vue/reactivity-transform": 3.2.45
"@vue/shared": 3.2.45
estree-walker: ^2.0.2
magic-string: ^0.25.7
postcss: ^8.1.10
source-map: ^0.6.1
checksum: b82755eec28c03800e38b99603a90b85af03d670558c845f9916650fea5cac8c2eb1511d66aa71e602ca9af8d2795e9f6a16fc867efce8c8694a6ea106f0ac95
checksum: bec375faa0012e953dc0887482cc01d52003ad424b6a8a9c8a2506fd4f0197ad62be22f77ce5691c2306068ae7bc0028399f25399e7d4beee668285d431f4d8f
languageName: node
linkType: hard
"@vue/compiler-ssr@npm:3.2.39":
version: 3.2.39
resolution: "@vue/compiler-ssr@npm:3.2.39"
"@vue/compiler-ssr@npm:3.2.45":
version: 3.2.45
resolution: "@vue/compiler-ssr@npm:3.2.45"
dependencies:
"@vue/compiler-dom": 3.2.39
"@vue/shared": 3.2.39
checksum: 27323a548df3696d38a8b029b55e136fc94195f1a9e12a25161a8d524cc779dbcc5f69db525a8d86f6ed28326f9f8595db5ba94ccaa7c8f127f752be36bffe5f
"@vue/compiler-dom": 3.2.45
"@vue/shared": 3.2.45
checksum: 830c475506d2b6d1a6872b3fde1024ef5132f725121fd9c34832c5cefcc8cfddf0dcaa3acc9b2da4754162fccdff48b3275b9ff31415a7793b224c04355dc632
languageName: node
linkType: hard
"@vue/reactivity-transform@npm:3.2.39":
version: 3.2.39
resolution: "@vue/reactivity-transform@npm:3.2.39"
"@vue/reactivity-transform@npm:3.2.45":
version: 3.2.45
resolution: "@vue/reactivity-transform@npm:3.2.45"
dependencies:
"@babel/parser": ^7.16.4
"@vue/compiler-core": 3.2.39
"@vue/shared": 3.2.39
"@vue/compiler-core": 3.2.45
"@vue/shared": 3.2.45
estree-walker: ^2.0.2
magic-string: ^0.25.7
checksum: b609d9367d875bf326ca8f31779407723cad2b2b4a26e7fb8860089c720e1b0bb8d5fe19604e8baff1d9ffc1fdbafb21a43db9063a24ae4ad30cb70b1c712de3
checksum: 401040818947eb04c782487a7861d3ba20f95c9f3ca14282b3d7624002bfe6000547bb48c561afe87ae6d302143fec71a7e0bc3ed3ae2bfad8a228adf7fd90d6
languageName: node
linkType: hard
"@vue/reactivity@npm:3.2.39":
version: 3.2.39
resolution: "@vue/reactivity@npm:3.2.39"
"@vue/reactivity@npm:3.2.45":
version: 3.2.45
resolution: "@vue/reactivity@npm:3.2.45"
dependencies:
"@vue/shared": 3.2.39
checksum: c4d440a53b2196e46129271affdb22182586a8123bc44d082468cd089242023890bccd6eaa1acc72919ea2c1febad979504be737720632afefee6ec6b75370a9
"@vue/shared": 3.2.45
checksum: 4ba609744a6b4d6235e81afc3f455ae9349c04f54be11c15770139f58ff687b105b06ca78649218fab907fb76048c3dcf34144c677718192ce8b9927eb335f03
languageName: node
linkType: hard
"@vue/runtime-core@npm:3.2.39":
version: 3.2.39
resolution: "@vue/runtime-core@npm:3.2.39"
"@vue/runtime-core@npm:3.2.45":
version: 3.2.45
resolution: "@vue/runtime-core@npm:3.2.45"
dependencies:
"@vue/reactivity": 3.2.39
"@vue/shared": 3.2.39
checksum: 13f6b92d70fb3bc8b12caef9eaf9cc1fb3aa1f1bd07e2392013f02d65c74b09d4121e62d149d7f7c316ef2c6b3496c9ec828795286480f08e5f45e910b0f2671
"@vue/reactivity": 3.2.45
"@vue/shared": 3.2.45
checksum: 0ac376a7602663d51a37b460c1184e2e035649090e53e972c18d24b30f3c47e5d61b921baf2492203f041d9edd864b3e9024a3ecef243b840637b62e9c0169a1
languageName: node
linkType: hard
"@vue/runtime-dom@npm:3.2.39":
version: 3.2.39
resolution: "@vue/runtime-dom@npm:3.2.39"
"@vue/runtime-dom@npm:3.2.45":
version: 3.2.45
resolution: "@vue/runtime-dom@npm:3.2.45"
dependencies:
"@vue/runtime-core": 3.2.39
"@vue/shared": 3.2.39
"@vue/runtime-core": 3.2.45
"@vue/shared": 3.2.45
csstype: ^2.6.8
checksum: 0c47f941148a000ac0cb93add51edb08eca5ae16fa7898dd070300f22e4ba77533c85342f0ceca0cab8637b80b1f92cfab10adb2160e4c6dd4be4a5b27ae1ff3
checksum: c66c71a2fc3921b57a930999b1fb0ea64f1a9d1bc7019984b06f2dbdd93f51b5a328cc60ec5904d1754b9dc1c85653b536db9017ef86616fa4a35f53836a2f9d
languageName: node
linkType: hard
"@vue/server-renderer@npm:3.2.39":
version: 3.2.39
resolution: "@vue/server-renderer@npm:3.2.39"
"@vue/server-renderer@npm:3.2.45":
version: 3.2.45
resolution: "@vue/server-renderer@npm:3.2.45"
dependencies:
"@vue/compiler-ssr": 3.2.39
"@vue/shared": 3.2.39
"@vue/compiler-ssr": 3.2.45
"@vue/shared": 3.2.45
peerDependencies:
vue: 3.2.39
checksum: ae6ccd08b85ad8c18cae461404ad8c4b3b602c779fe07ab3a69e0a9a4cef274ea8dcd662fa365f3717f67d4ba02a9eac88dd2ebf5194072ae43dd5db99c2cb2c
vue: 3.2.45
checksum: 062812235c2be41ed699fb7b802cf4fc94618bf4efae7832210431ad16ea1b852056e4fb83f6c17b919bfe87bc8624afcadd973dab3e0965d3cf9875baaf7373
languageName: node
linkType: hard
"@vue/shared@npm:3.2.39":
version: 3.2.39
resolution: "@vue/shared@npm:3.2.39"
checksum: 0bf9f5b4851b634cfae92c08d64173c2db674bd817424473d28fc58af7c17c54a255f9b3e837d3857e1e62f9092ab1d74b4714237e45c94fcd46f92155ef653f
"@vue/shared@npm:3.2.45":
version: 3.2.45
resolution: "@vue/shared@npm:3.2.45"
checksum: ff3205056caed2a965aa0980e21319515ce13c859a9b269fdab0ee8b3c9f3d8eec7eefdb7fd6c6b47c12acdc7bf23c6c187b6191054221b4a29108139b20c221
languageName: node
linkType: hard
@ -3711,8 +3696,8 @@ __metadata:
"@types/web-push": 3.3.2
"@types/websocket": 1.0.5
"@types/ws": 8.5.3
"@typescript-eslint/eslint-plugin": ^5.36.2
"@typescript-eslint/parser": ^5.36.2
"@typescript-eslint/eslint-plugin": ^5.44.0
"@typescript-eslint/parser": ^5.44.0
abort-controller: 3.0.0
ajv: 8.11.0
archiver: 5.3.1
@ -3733,7 +3718,7 @@ __metadata:
date-fns: 2.28.0
deep-email-validator: 0.1.21
escape-regexp: 0.0.1
eslint: ^8.20.0
eslint: ^8.28.0
eslint-plugin-import: ^2.26.0
execa: 6.1.0
feed: 4.2.2
@ -3806,7 +3791,7 @@ __metadata:
tsconfig-paths: 4.1.0
twemoji-parser: 14.0.0
typeorm: 0.3.7
typescript: ^4.8.3
typescript: ^4.9.3
unzipper: 0.10.11
uuid: 8.3.2
web-push: 3.5.0
@ -4728,8 +4713,8 @@ __metadata:
"@types/uuid": 8.3.4
"@types/websocket": 1.0.5
"@types/ws": 8.5.3
"@typescript-eslint/eslint-plugin": ^5.36.2
"@typescript-eslint/parser": ^5.36.2
"@typescript-eslint/eslint-plugin": ^5.44.0
"@typescript-eslint/parser": ^5.44.0
"@vitejs/plugin-vue": ^3.1.0
abort-controller: 3.0.0
autobind-decorator: 2.4.0
@ -4749,9 +4734,9 @@ __metadata:
cypress: 10.3.0
date-fns: 2.28.0
escape-regexp: 0.0.1
eslint: ^8.20.0
eslint: ^8.28.0
eslint-plugin-import: ^2.26.0
eslint-plugin-vue: ^9.1.1
eslint-plugin-vue: ^9.8.0
eventemitter3: 4.0.7
feed: 4.2.2
foundkey-js: "workspace:*"
@ -4788,12 +4773,12 @@ __metadata:
tsc-alias: 1.7.0
tsconfig-paths: 4.1.0
twemoji-parser: 14.0.0
typescript: 4.8.3
typescript: ^4.9.3
uuid: 8.3.2
v-debounce: 0.1.2
vanilla-tilt: 1.7.2
vite: 3.1.0
vue: 3.2.39
vue: 3.2.45
vue-prism-editor: 2.0.0-alpha.2
vuedraggable: 4.0.1
wavesurfer.js: 6.0.1
@ -7003,9 +6988,9 @@ __metadata:
languageName: node
linkType: hard
"eslint-plugin-vue@npm:^9.1.1":
version: 9.4.0
resolution: "eslint-plugin-vue@npm:9.4.0"
"eslint-plugin-vue@npm:^9.8.0":
version: 9.8.0
resolution: "eslint-plugin-vue@npm:9.8.0"
dependencies:
eslint-utils: ^3.0.0
natural-compare: ^1.4.0
@ -7016,7 +7001,7 @@ __metadata:
xml-name-validator: ^4.0.0
peerDependencies:
eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
checksum: 1eb085e7d52285eff05e4a3f0f4d65619e943eb7e976b0ef59c3adc75bf4a089df8e8cdba223cf27e2623c0fc6b306e3b1ca460d0ce27cc421ca91b7880eb0d8
checksum: f3fc36512fa124a81332e353b161a84dd7b55ae07c69c0e9eabc85d56fdc2940422e1f33172d90af0f7913fc5cd25cfc7dfe025db37311d15a2ba5ea486b7602
languageName: node
linkType: hard
@ -7072,63 +7057,14 @@ __metadata:
languageName: node
linkType: hard
"eslint@npm:^8.20.0":
version: 8.22.0
resolution: "eslint@npm:8.22.0"
"eslint@npm:^8.28.0":
version: 8.28.0
resolution: "eslint@npm:8.28.0"
dependencies:
"@eslint/eslintrc": ^1.3.0
"@humanwhocodes/config-array": ^0.10.4
"@humanwhocodes/gitignore-to-minimatch": ^1.0.2
ajv: ^6.10.0
chalk: ^4.0.0
cross-spawn: ^7.0.2
debug: ^4.3.2
doctrine: ^3.0.0
escape-string-regexp: ^4.0.0
eslint-scope: ^7.1.1
eslint-utils: ^3.0.0
eslint-visitor-keys: ^3.3.0
espree: ^9.3.3
esquery: ^1.4.0
esutils: ^2.0.2
fast-deep-equal: ^3.1.3
file-entry-cache: ^6.0.1
find-up: ^5.0.0
functional-red-black-tree: ^1.0.1
glob-parent: ^6.0.1
globals: ^13.15.0
globby: ^11.1.0
grapheme-splitter: ^1.0.4
ignore: ^5.2.0
import-fresh: ^3.0.0
imurmurhash: ^0.1.4
is-glob: ^4.0.0
js-yaml: ^4.1.0
json-stable-stringify-without-jsonify: ^1.0.1
levn: ^0.4.1
lodash.merge: ^4.6.2
minimatch: ^3.1.2
natural-compare: ^1.4.0
optionator: ^0.9.1
regexpp: ^3.2.0
strip-ansi: ^6.0.1
strip-json-comments: ^3.1.0
text-table: ^0.2.0
v8-compile-cache: ^2.0.3
bin:
eslint: bin/eslint.js
checksum: 2d84a7a2207138cdb250759b047fdb05a57fede7f87b7a039d9370edba7f26e23a873a208becfd4b2c9e4b5499029f3fc3b9318da3290e693d25c39084119c80
languageName: node
linkType: hard
"eslint@npm:^8.23.0":
version: 8.23.0
resolution: "eslint@npm:8.23.0"
dependencies:
"@eslint/eslintrc": ^1.3.1
"@humanwhocodes/config-array": ^0.10.4
"@humanwhocodes/gitignore-to-minimatch": ^1.0.2
"@eslint/eslintrc": ^1.3.3
"@humanwhocodes/config-array": ^0.11.6
"@humanwhocodes/module-importer": ^1.0.1
"@nodelib/fs.walk": ^1.2.8
ajv: ^6.10.0
chalk: ^4.0.0
cross-spawn: ^7.0.2
@ -7144,15 +7080,15 @@ __metadata:
fast-deep-equal: ^3.1.3
file-entry-cache: ^6.0.1
find-up: ^5.0.0
functional-red-black-tree: ^1.0.1
glob-parent: ^6.0.1
glob-parent: ^6.0.2
globals: ^13.15.0
globby: ^11.1.0
grapheme-splitter: ^1.0.4
ignore: ^5.2.0
import-fresh: ^3.0.0
imurmurhash: ^0.1.4
is-glob: ^4.0.0
is-path-inside: ^3.0.3
js-sdsl: ^4.1.4
js-yaml: ^4.1.0
json-stable-stringify-without-jsonify: ^1.0.1
levn: ^0.4.1
@ -7166,11 +7102,11 @@ __metadata:
text-table: ^0.2.0
bin:
eslint: bin/eslint.js
checksum: ff6075daa28d817a7ac4508f31bc108a04d9ab5056608c8651b5bf9cfea5d708ca16dea6cdab2c3c0ae99b0bf0e726af8504eaa8e17c8e12e242cb68237ead64
checksum: 1b793486b2ec80f0602d75fff7116f7c39a3286f523608a999eead9bec4154a06841785d2b4fb87f8292a94cf85778c1dbfaec727772a09c4d604fdb9ff0809a
languageName: node
linkType: hard
"espree@npm:^9.3.1, espree@npm:^9.3.2, espree@npm:^9.3.3":
"espree@npm:^9.3.1":
version: 9.3.3
resolution: "espree@npm:9.3.3"
dependencies:
@ -7888,10 +7824,10 @@ __metadata:
"@microsoft/api-extractor": ^7.19.3
"@types/jest": ^27.4.0
"@types/node": 18.7.16
"@typescript-eslint/eslint-plugin": 5.36.2
"@typescript-eslint/parser": ^5.36.2
"@typescript-eslint/eslint-plugin": ^5.44.0
"@typescript-eslint/parser": ^5.44.0
autobind-decorator: ^2.4.0
eslint: ^8.23.0
eslint: ^8.28.0
eventemitter3: ^4.0.7
jest: ^27.4.5
jest-fetch-mock: ^3.0.3
@ -7901,7 +7837,7 @@ __metadata:
ts-jest: ^27.1.5
ts-node: 10.9.1
tsd: ^0.23.0
typescript: 4.8.3
typescript: ^4.9.3
languageName: unknown
linkType: soft
@ -7911,7 +7847,7 @@ __metadata:
dependencies:
"@types/gulp": 4.0.9
"@types/gulp-rename": 2.0.1
"@typescript-eslint/parser": ^5.36.2
"@typescript-eslint/parser": ^5.44.0
cross-env: 7.0.3
cypress: 10.3.0
execa: 5.1.1
@ -7922,7 +7858,7 @@ __metadata:
gulp-terser: 2.1.0
js-yaml: 4.1.0
start-server-and-test: 1.14.0
typescript: 4.8.3
typescript: ^4.9.3
languageName: unknown
linkType: soft
@ -8038,7 +7974,7 @@ __metadata:
"fsevents@patch:fsevents@^2.3.2#~builtin<compat/fsevents>, fsevents@patch:fsevents@~2.3.2#~builtin<compat/fsevents>":
version: 2.3.2
resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin<compat/fsevents>::version=2.3.2&hash=18f3a7"
resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin<compat/fsevents>::version=2.3.2&hash=df0bf1"
dependencies:
node-gyp: latest
conditions: os=darwin
@ -8047,7 +7983,7 @@ __metadata:
"fsevents@patch:fsevents@~2.1.2#~builtin<compat/fsevents>":
version: 2.1.3
resolution: "fsevents@patch:fsevents@npm%3A2.1.3#~builtin<compat/fsevents>::version=2.1.3&hash=18f3a7"
resolution: "fsevents@patch:fsevents@npm%3A2.1.3#~builtin<compat/fsevents>::version=2.1.3&hash=31d12a"
dependencies:
node-gyp: latest
conditions: os=darwin
@ -8085,13 +8021,6 @@ __metadata:
languageName: node
linkType: hard
"functional-red-black-tree@npm:^1.0.1":
version: 1.0.1
resolution: "functional-red-black-tree@npm:1.0.1"
checksum: ca6c170f37640e2d94297da8bb4bf27a1d12bea3e00e6a3e007fd7aa32e37e000f5772acf941b4e4f3cf1c95c3752033d0c509af157ad8f526e7f00723b9eb9f
languageName: node
linkType: hard
"functions-have-names@npm:^1.2.2":
version: 1.2.3
resolution: "functions-have-names@npm:1.2.3"
@ -8261,7 +8190,7 @@ __metadata:
languageName: node
linkType: hard
"glob-parent@npm:^6.0.1":
"glob-parent@npm:^6.0.2":
version: 6.0.2
resolution: "glob-parent@npm:6.0.2"
dependencies:
@ -9630,7 +9559,7 @@ __metadata:
languageName: node
linkType: hard
"is-path-inside@npm:^3.0.2":
"is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3":
version: 3.0.3
resolution: "is-path-inside@npm:3.0.3"
checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9
@ -10531,6 +10460,13 @@ __metadata:
languageName: node
linkType: hard
"js-sdsl@npm:^4.1.4":
version: 4.2.0
resolution: "js-sdsl@npm:4.2.0"
checksum: 2cd0885f7212afb355929d72ca105cb37de7e95ad6031e6a32619eaefa46735a7d0fb682641a0ba666e1519cb138fe76abc1eea8a34e224140c9d94c995171f1
languageName: node
linkType: hard
"js-stringify@npm:^1.0.2":
version: 1.0.2
resolution: "js-stringify@npm:1.0.2"
@ -11907,7 +11843,7 @@ __metadata:
languageName: node
linkType: hard
"minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
"minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
dependencies:
@ -12283,6 +12219,13 @@ __metadata:
languageName: node
linkType: hard
"natural-compare-lite@npm:^1.4.0":
version: 1.4.0
resolution: "natural-compare-lite@npm:1.4.0"
checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225
languageName: node
linkType: hard
"natural-compare@npm:^1.4.0":
version: 1.4.0
resolution: "natural-compare@npm:1.4.0"
@ -14919,7 +14862,7 @@ __metadata:
"resolve@patch:resolve@^1.1.6#~builtin<compat/resolve>, resolve@patch:resolve@^1.1.7#~builtin<compat/resolve>, resolve@patch:resolve@^1.10.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.4.0#~builtin<compat/resolve>":
version: 1.18.1
resolution: "resolve@patch:resolve@npm%3A1.18.1#~builtin<compat/resolve>::version=1.18.1&hash=07638b"
resolution: "resolve@patch:resolve@npm%3A1.18.1#~builtin<compat/resolve>::version=1.18.1&hash=c3c19d"
dependencies:
is-core-module: ^2.0.0
path-parse: ^1.0.6
@ -14929,7 +14872,7 @@ __metadata:
"resolve@patch:resolve@^1.15.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.20.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.22.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.22.1#~builtin<compat/resolve>":
version: 1.22.1
resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin<compat/resolve>::version=1.22.1&hash=07638b"
resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin<compat/resolve>::version=1.22.1&hash=c3c19d"
dependencies:
is-core-module: ^2.9.0
path-parse: ^1.0.7
@ -14942,7 +14885,7 @@ __metadata:
"resolve@patch:resolve@~1.17.0#~builtin<compat/resolve>":
version: 1.17.0
resolution: "resolve@patch:resolve@npm%3A1.17.0#~builtin<compat/resolve>::version=1.17.0&hash=07638b"
resolution: "resolve@patch:resolve@npm%3A1.17.0#~builtin<compat/resolve>::version=1.17.0&hash=c3c19d"
dependencies:
path-parse: ^1.0.6
checksum: 6fd799f282ddf078c4bc20ce863e3af01fa8cb218f0658d9162c57161a2dbafe092b13015b9a4c58d0e1e801cf7aa7a4f13115fea9db98c3f9a0c43e429bad6f
@ -14951,7 +14894,7 @@ __metadata:
"resolve@patch:resolve@~1.19.0#~builtin<compat/resolve>":
version: 1.19.0
resolution: "resolve@patch:resolve@npm%3A1.19.0#~builtin<compat/resolve>::version=1.19.0&hash=07638b"
resolution: "resolve@patch:resolve@npm%3A1.19.0#~builtin<compat/resolve>::version=1.19.0&hash=c3c19d"
dependencies:
is-core-module: ^2.1.0
path-parse: ^1.0.6
@ -16217,7 +16160,7 @@ __metadata:
resolution: "sw@workspace:packages/sw"
dependencies:
esbuild: ^0.14.13
eslint: ^8.20.0
eslint: ^8.28.0
foundkey-js: "workspace:*"
idb-keyval: ^6.0.3
languageName: unknown
@ -17033,13 +16976,13 @@ __metadata:
languageName: node
linkType: hard
"typescript@npm:4.8.3, typescript@npm:^4.8.3":
version: 4.8.3
resolution: "typescript@npm:4.8.3"
"typescript@npm:^4.9.3":
version: 4.9.3
resolution: "typescript@npm:4.9.3"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 8286a5edcaf3d68e65c451aa1e7150ad1cf53ee0813c07ec35b7abdfdb10f355ecaa13c6a226a694ae7a67785fd7eeebf89f845da0b4f7e4a35561ddc459aba0
checksum: 17b8f816050b412403e38d48eef0e893deb6be522d6dc7caf105e54a72e34daf6835c447735fd2b28b66784e72bfbf87f627abb4818a8e43d1fa8106396128dc
languageName: node
linkType: hard
@ -17053,19 +16996,19 @@ __metadata:
languageName: node
linkType: hard
"typescript@patch:typescript@4.8.3#~builtin<compat/typescript>, typescript@patch:typescript@^4.8.3#~builtin<compat/typescript>":
version: 4.8.3
resolution: "typescript@patch:typescript@npm%3A4.8.3#~builtin<compat/typescript>::version=4.8.3&hash=a1c5e5"
"typescript@patch:typescript@^4.9.3#~builtin<compat/typescript>":
version: 4.9.3
resolution: "typescript@patch:typescript@npm%3A4.9.3#~builtin<compat/typescript>::version=4.9.3&hash=d73830"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 2222d2382fb3146089b1d27ce2b55e9d1f99cc64118f1aba75809b693b856c5d3c324f052f60c75b577947fc538bc1c27bad0eb76cbdba9a63a253489504ba7e
checksum: 67ca21a387c0572f1c04936e638dde7782c5aa520c3754aadc7cc9b7c915da9ebc3e27c601bfff4ccb7d7264e82dce6d277ada82ec09dc75024349e0ef64926d
languageName: node
linkType: hard
"typescript@patch:typescript@~4.7.4#~builtin<compat/typescript>":
version: 4.7.4
resolution: "typescript@patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=a1c5e5"
resolution: "typescript@patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=65a307"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
@ -17372,13 +17315,6 @@ __metadata:
languageName: node
linkType: hard
"v8-compile-cache@npm:^2.0.3":
version: 2.3.0
resolution: "v8-compile-cache@npm:2.3.0"
checksum: adb0a271eaa2297f2f4c536acbfee872d0dd26ec2d76f66921aa7fc437319132773483344207bdbeee169225f4739016d8d2dbf0553913a52bb34da6d0334f8e
languageName: node
linkType: hard
"v8-to-istanbul@npm:^8.1.0":
version: 8.1.1
resolution: "v8-to-istanbul@npm:8.1.1"
@ -17583,16 +17519,16 @@ __metadata:
languageName: node
linkType: hard
"vue@npm:3.2.39":
version: 3.2.39
resolution: "vue@npm:3.2.39"
"vue@npm:3.2.45":
version: 3.2.45
resolution: "vue@npm:3.2.45"
dependencies:
"@vue/compiler-dom": 3.2.39
"@vue/compiler-sfc": 3.2.39
"@vue/runtime-dom": 3.2.39
"@vue/server-renderer": 3.2.39
"@vue/shared": 3.2.39
checksum: f096a3f0a5f72c65d26246ff7989729eda2b996dc30c63fd8cd7ccda07e9c318d478e3e24661ff01e49bcf5fed6f330142fcf29d6ad46c13423f36b3ae1a54cc
"@vue/compiler-dom": 3.2.45
"@vue/compiler-sfc": 3.2.45
"@vue/runtime-dom": 3.2.45
"@vue/server-renderer": 3.2.45
"@vue/shared": 3.2.45
checksum: df60ca80cb9fdce408eccd0c7a4d44720df9855c62e340448650d8048b1edd25da6f3bd99ed7efc19efbe1f3fdcec4ae8067ab10ae50be5bb363d996ad29251a
languageName: node
linkType: hard