Compare commits

...

38 Commits

Author SHA1 Message Date
binwiederhier
a75fb08ef1 Tidy 2023-03-30 21:06:22 -04:00
binwiederhier
58a0c2a6c6 Bump 2023-03-30 21:04:03 -04:00
binwiederhier
d050956007 Added Ansible role 2023-03-30 14:56:14 -04:00
binwiederhier
bdae48afba Disable iOS polling entirely 2023-03-30 14:48:52 -04:00
binwiederhier
cb5c4c5483 Thank you @R-Gld for your sponsorship 2023-03-30 12:56:47 -04:00
binwiederhier
e91f07a081 I still don't understand 2023-03-29 21:20:43 -04:00
binwiederhier
7d96be6fb3 Deps 2023-03-29 21:18:17 -04:00
binwiederhier
46c798c71a Just comment the test for now 2023-03-29 15:03:41 -04:00
binwiederhier
037a51a9d0 Bump 2023-03-29 14:56:16 -04:00
binwiederhier
4596e4bcab Blog posts, fix lint 2023-03-29 00:23:08 -04:00
Philipp C. Heckel
9b30ada880 Merge pull request #688 from Raistlingru/patch-1
add hostux server
2023-03-29 00:13:34 -04:00
Raistlingru
96d711e19e add hostux server 2023-03-29 06:12:19 +02:00
binwiederhier
5af5565fb1 Thank you @johman10 for your donation 2023-03-28 14:42:15 -04:00
binwiederhier
29c9551548 Profiling support 2023-03-28 14:41:16 -04:00
binwiederhier
23c5d4e345 Adjust battery FAQ 2023-03-26 17:01:08 -04:00
binwiederhier
ff5bf4acd0 Thank you @samliebow for your sponsorship 2023-03-25 14:11:58 -04:00
binwiederhier
34c42c55f6 Changelog 2023-03-25 14:11:23 -04:00
binwiederhier
07e5b28868 Fix other languages 2023-03-25 14:09:51 -04:00
binwiederhier
06a0654a5a Merge branch 'main' into i18n-plural-forms 2023-03-25 14:03:09 -04:00
binwiederhier
8cc23117fe Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web into i18n-plural-forms 2023-03-25 14:02:50 -04:00
Nick
f8c4f20a8f Translated using Weblate (Russian)
Currently translated at 100.0% (354 of 354 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ru/
2023-03-24 07:37:58 +01:00
109247019824
8053e992e4 Translated using Weblate (Bulgarian)
Currently translated at 79.0% (280 of 354 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2023-03-24 07:37:58 +01:00
binwiederhier
9db96140e2 Bump 2023-03-22 16:26:00 -04:00
binwiederhier
502d0a0abd Fix delayed message sending from authenticated users, closes #679 2023-03-22 15:30:20 -04:00
Bartosz Moczulski
80b0a94f7e i18n-pl: Provide translations for plural forms of reservations. emails, messages
Following up on the previous commit this one introduces Polish
translations for plural forms of reservations. emails, messages in
upgrade modal.
2023-03-21 10:14:39 +01:00
Bartosz Moczulski
338cab1660 i18n: Introduce plural forms for reservations, emails, messages
In many languages there is more than one plural form of nouns and rules
for choosing the correct one are often far more complex than in English.
Luckily both react-i18next and Weblate provide built-in support for
translating and selecting plural forms in accordance with grammatical
rules of any given language.

In order to enable plural forms `{count: n}` option is added to relevant
`t()` calls. In translations files "_one" and "_other" suffix is added
to English labels such that Weblate can detect which entries represent a
set of plural forms and show appropriate language-specific form on the
translation page. E.g. in Polish there are 2 plural forms and hence 3
resulting suffixes: "_one", "_few", "_many".

Note on transition period: in the absence of expected suffixed variants
react-i18next will use non-suffixed one (if present) so existing
translations will continue to work just fine even if they happen to be
grammatically imperfect. Translators can provide proper plural forms in
once this change is merged and Weblate will then replace non-suffixed
labels with the suffixed ones.
2023-03-21 10:03:36 +01:00
binwiederhier
b8836d674a Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-03-20 21:55:35 -04:00
binwiederhier
c6a96d19e2 Troubleshooting doc update 2023-03-20 21:50:54 -04:00
binwiederhier
bcb24aecd3 Troubleshooting docs page 2023-03-20 15:34:10 -04:00
ssantos
d72ae47d1f Translated using Weblate (Portuguese)
Currently translated at 61.0% (216 of 354 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt/
2023-03-20 10:37:29 +01:00
Poesty Li
a5d2fc172b Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (354 of 354 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hans/
2023-03-20 10:37:29 +01:00
Emanuele Cisbani
bbab81a1a2 Translated using Weblate (Italian)
Currently translated at 72.8% (258 of 354 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-03-20 10:37:28 +01:00
109247019824
78a1ca81e3 Translated using Weblate (Bulgarian)
Currently translated at 78.5% (278 of 354 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2023-03-20 10:37:28 +01:00
binwiederhier
f090d1313e Merge branch 'main' of github.com:binwiederhier/ntfy 2023-03-19 15:46:56 -04:00
binwiederhier
afa4efa140 Add Grafana dashboard to docs 2023-03-19 15:46:37 -04:00
Philipp C. Heckel
d2b88005f0 Merge pull request #674 from caseodilla/main
fix misc typos
2023-03-19 10:03:53 -04:00
caseodilla
9eb1f6a186 fix typo 2023-03-19 09:59:52 -04:00
caseodilla
2d8d5b3b95 Update README.md
fix contributor logo
2023-03-19 09:45:18 -04:00
41 changed files with 3248 additions and 349 deletions

View File

@@ -141,25 +141,25 @@ web-deps-update:
# Main server/client build
cli: cli-deps
goreleaser build --snapshot --rm-dist
goreleaser build --snapshot --clean
cli-linux-amd64: cli-deps-static-sites
goreleaser build --snapshot --rm-dist --id ntfy_linux_amd64
goreleaser build --snapshot --clean --id ntfy_linux_amd64
cli-linux-armv6: cli-deps-static-sites cli-deps-gcc-armv6-armv7
goreleaser build --snapshot --rm-dist --id ntfy_linux_armv6
goreleaser build --snapshot --clean --id ntfy_linux_armv6
cli-linux-armv7: cli-deps-static-sites cli-deps-gcc-armv6-armv7
goreleaser build --snapshot --rm-dist --id ntfy_linux_armv7
goreleaser build --snapshot --clean --id ntfy_linux_armv7
cli-linux-arm64: cli-deps-static-sites cli-deps-gcc-arm64
goreleaser build --snapshot --rm-dist --id ntfy_linux_arm64
goreleaser build --snapshot --clean --id ntfy_linux_arm64
cli-windows-amd64: cli-deps-static-sites
goreleaser build --snapshot --rm-dist --id ntfy_windows_amd64
goreleaser build --snapshot --clean --id ntfy_windows_amd64
cli-darwin-all: cli-deps-static-sites
goreleaser build --snapshot --rm-dist --id ntfy_darwin_all
goreleaser build --snapshot --clean --id ntfy_darwin_all
cli-linux-server: cli-deps-static-sites
# This is a target to build the CLI (including the server) manually.

View File

@@ -126,7 +126,10 @@ account costs. Even small donations are very much appreciated. A big fat **Thank
<a href="https://github.com/caseodilla"><img src="https://github.com/caseodilla.png" width="40px" /></a>
<a href="https://github.com/0xAF"><img src="https://github.com/0xAF.png" width="40px" /></a>
<a href="https://github.com/soonoo"><img src="https://github.com/soonoo.png" width="40px" /></a>
<a href="https://github.com/nichu42"><img src="https://github.com/soonoo.png" width="40px" /></a>
<a href="https://github.com/nichu42"><img src="https://github.com/nichu42.png" width="40px" /></a>
<a href="https://github.com/samliebow"><img src="https://github.com/samliebow.png" width="40px" /></a>
<a href="https://github.com/johman10"><img src="https://github.com/johman10.png" width="40px" /></a>
<a href="https://github.com/R-Gld"><img src="https://github.com/R-Gld.png" width="40px" /></a>
I'd also like to thank JetBrains for providing their awesome [IntelliJ IDEA](https://www.jetbrains.com/idea/) to me for free,
and [DigitalOcean](https://m.do.co/c/442b929528db) (*referral link*) for supporting the project:

View File

@@ -88,6 +88,7 @@ var flagsServe = append(
altsrc.NewStringFlag(&cli.StringFlag{Name: "billing-contact", Aliases: []string{"billing_contact"}, EnvVars: []string{"NTFY_BILLING_CONTACT"}, Value: "", Usage: "e-mail or website to display in upgrade dialog (only if payments are enabled)"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-metrics", Aliases: []string{"enable_metrics"}, EnvVars: []string{"NTFY_ENABLE_METRICS"}, Value: false, Usage: "if set, Prometheus metrics are exposed via the /metrics endpoint"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "metrics-listen-http", Aliases: []string{"metrics_listen_http"}, EnvVars: []string{"NTFY_METRICS_LISTEN_HTTP"}, Usage: "ip:port used to expose the metrics endpoint (implicitly enables metrics)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "profile-listen-http", Aliases: []string{"profile_listen_http"}, EnvVars: []string{"NTFY_PROFILE_LISTEN_HTTP"}, Usage: "ip:port used to expose the profiling endpoints (implicitly enables profiling)"}),
)
var cmdServe = &cli.Command{
@@ -167,6 +168,7 @@ func execServe(c *cli.Context) error {
billingContact := c.String("billing-contact")
metricsListenHTTP := c.String("metrics-listen-http")
enableMetrics := c.Bool("enable-metrics") || metricsListenHTTP != ""
profileListenHTTP := c.String("profile-listen-http")
// Check values
if firebaseKeyFile != "" && !util.FileExists(firebaseKeyFile) {
@@ -321,6 +323,7 @@ func execServe(c *cli.Context) error {
conf.EnableReservations = enableReservations
conf.EnableMetrics = enableMetrics
conf.MetricsListenHTTP = metricsListenHTTP
conf.ProfileListenHTTP = profileListenHTTP
conf.Version = c.App.Version
// Set up hot-reloading of config

View File

@@ -1111,16 +1111,38 @@ doing, and/or secure access to the endpoint in your reverse proxy.
- `metrics-listen-http` exposes the metrics endpoint via a dedicated `[IP]:port`. If set, this option implicitly
enables metrics as well, e.g. "10.0.1.1:9090" or ":9090"
=== "Using default port"
=== "server.yml (Using default port)"
```yaml
enable-metrics: true
```
=== "Using dedicated IP/port"
=== "server.yml (Using dedicated IP/port)"
```yaml
metrics-listen-http: "10.0.1.1:9090"
```
In Prometheus, an example scrape config would look like this:
=== "prometheus.yml"
```yaml
scrape_configs:
- job_name: "ntfy"
static_configs:
- targets: ["10.0.1.1:9090"]
```
Here's an example Grafana dashboard built from the metrics (see [Grafana JSON on GitHub](https://raw.githubusercontent.com/binwiederhier/ntfy/main/examples/grafana-dashboard/ntfy-grafana.json)):
<figure markdown style="padding-left: 50px; padding-right: 50px">
<a href="../../static/img/grafana-dashboard.png" target="_blank"><img src="../../static/img/grafana-dashboard.png"/></a>
<figcaption>ntfy Grafana dashboard</figcaption>
</figure>
## Profiling
ntfy can expose Go's [net/http/pprof](https://pkg.go.dev/net/http/pprof) endpoints to support profiling of the ntfy server.
If enabled, ntfy will listen on a dedicated listen IP/port, which can be accessed via the web browser on `http://<ip>:<port>/debug/pprof/`.
This can be helpful to expose bottlenecks, and visualize call flows. To enable, simply set the `profile-listen-http` config option.
## Logging & debugging
By default, ntfy logs to the console (stderr), with an `info` log level, and in a human-readable text format.

View File

@@ -43,9 +43,9 @@ of the app and [self-host your own ntfy server](install.md).
## How much battery does the Android app use?
If you use the ntfy.sh server, and you don't use the [instant delivery](subscribe/phone.md#instant-delivery) feature,
the Android/iOS app uses no additional battery, since Firebase Cloud Messaging (FCM) is used. If you use your own server,
or you use *instant delivery* (Android only), the app has to maintain a constant connection to the server, which consumes
about 0-1% of battery in 17h of use (on my phone). There has been a ton of testing and improvement around this. I think it's pretty
decent now.
or you use *instant delivery* (Android only), or install from F-droid ([which does not support FCM](https://f-droid.org/docs/Inclusion_Policy/)),
the app has to maintain a constant connection to the server, which consumes about 0-1% of battery in 17h of use (on my phone).
There has been a ton of testing and improvement around this. I think it's pretty decent now.
## Paid plans? I thought it was open source?
All of ntfy will remain open source, with a free software license (Apache 2.0 and GPLv2). If you'd like to self-host, you

View File

@@ -26,37 +26,37 @@ deb/rpm packages.
=== "x86_64/amd64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_x86_64.tar.gz
tar zxvf ntfy_2.2.0_linux_x86_64.tar.gz
sudo cp -a ntfy_2.2.0_linux_x86_64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.2.0_linux_x86_64/{client,server}/*.yml /etc/ntfy
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_x86_64.tar.gz
tar zxvf ntfy_2.3.1_linux_x86_64.tar.gz
sudo cp -a ntfy_2.3.1_linux_x86_64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.3.1_linux_x86_64/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```
=== "armv6"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_armv6.tar.gz
tar zxvf ntfy_2.2.0_linux_armv6.tar.gz
sudo cp -a ntfy_2.2.0_linux_armv6/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.2.0_linux_armv6/{client,server}/*.yml /etc/ntfy
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv6.tar.gz
tar zxvf ntfy_2.3.1_linux_armv6.tar.gz
sudo cp -a ntfy_2.3.1_linux_armv6/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.3.1_linux_armv6/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```
=== "armv7/armhf"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_armv7.tar.gz
tar zxvf ntfy_2.2.0_linux_armv7.tar.gz
sudo cp -a ntfy_2.2.0_linux_armv7/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.2.0_linux_armv7/{client,server}/*.yml /etc/ntfy
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv7.tar.gz
tar zxvf ntfy_2.3.1_linux_armv7.tar.gz
sudo cp -a ntfy_2.3.1_linux_armv7/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.3.1_linux_armv7/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```
=== "arm64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_arm64.tar.gz
tar zxvf ntfy_2.2.0_linux_arm64.tar.gz
sudo cp -a ntfy_2.2.0_linux_arm64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.2.0_linux_arm64/{client,server}/*.yml /etc/ntfy
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_arm64.tar.gz
tar zxvf ntfy_2.3.1_linux_arm64.tar.gz
sudo cp -a ntfy_2.3.1_linux_arm64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.3.1_linux_arm64/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```
@@ -106,7 +106,7 @@ Manually installing the .deb file:
=== "x86_64/amd64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_amd64.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_amd64.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
@@ -114,7 +114,7 @@ Manually installing the .deb file:
=== "armv6"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_armv6.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv6.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
@@ -122,7 +122,7 @@ Manually installing the .deb file:
=== "armv7/armhf"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_armv7.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv7.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
@@ -130,7 +130,7 @@ Manually installing the .deb file:
=== "arm64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_arm64.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_arm64.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
@@ -140,28 +140,28 @@ Manually installing the .deb file:
=== "x86_64/amd64"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_amd64.rpm
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_amd64.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "armv6"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_armv6.rpm
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv6.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "armv7/armhf"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_armv7.rpm
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv7.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "arm64"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_linux_arm64.rpm
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_arm64.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
@@ -189,18 +189,18 @@ NixOS also supports [declarative setup of the ntfy server](https://search.nixos.
## macOS
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on macOS as well.
To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_macOS_all.tar.gz),
To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_macOS_all.tar.gz),
extract it and place it somewhere in your `PATH` (e.g. `/usr/local/bin/ntfy`).
If run as `root`, ntfy will look for its config at `/etc/ntfy/client.yml`. For all other users, it'll look for it at
`~/Library/Application Support/ntfy/client.yml` (sample included in the tarball).
```bash
curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_macOS_all.tar.gz > ntfy_2.2.0_macOS_all.tar.gz
tar zxvf ntfy_2.2.0_macOS_all.tar.gz
sudo cp -a ntfy_2.2.0_macOS_all/ntfy /usr/local/bin/ntfy
curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_macOS_all.tar.gz > ntfy_2.3.1_macOS_all.tar.gz
tar zxvf ntfy_2.3.1_macOS_all.tar.gz
sudo cp -a ntfy_2.3.1_macOS_all/ntfy /usr/local/bin/ntfy
mkdir ~/Library/Application\ Support/ntfy
cp ntfy_2.2.0_macOS_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml
cp ntfy_2.3.1_macOS_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml
ntfy --help
```
@@ -212,7 +212,7 @@ ntfy --help
## Windows
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on Windows as well.
To install, please [download the latest ZIP](https://github.com/binwiederhier/ntfy/releases/download/v2.2.0/ntfy_2.2.0_windows_x86_64.zip),
To install, please [download the latest ZIP](https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_windows_x86_64.zip),
extract it and place the `ntfy.exe` binary somewhere in your `%Path%`.
The default path for the client config file is at `%AppData%\ntfy\client.yml` (not created automatically, sample in the ZIP file).

View File

@@ -17,6 +17,7 @@ ntfy community. Thanks to everyone running a public server. **You guys rock!**
| [ntfy.adminforge.de](https://ntfy.adminforge.de/) | 🇩🇪 Germany |
| [ntfy.envs.net](https://ntfy.envs.net) | 🇩🇪 Germany |
| [ntfy.mzte.de](https://ntfy.mzte.de/) | 🇩🇪 Germany |
| [ntfy.hostux.net](https://ntfy.hostux.net/) | 🇫🇷 France |
Please be aware that **server operators can log your messages**. The project also cannot guarantee the reliability
and uptime of third party servers, so use of each server is **at your own discretion**.
@@ -116,9 +117,15 @@ and uptime of third party servers, so use of each server is **at your own discre
- [nodebb-plugin-ntfy](https://github.com/NodeBB/nodebb-plugin-ntfy) - Push notifications for NodeBB forums
- [n8n-ntfy](https://github.com/raghavanand98/n8n-ntfy.sh) - n8n community node that lets you use ntfy in your workflows
- [nlog-ntfy](https://github.com/MichelMichels/nlog-ntfy) - Send NLog messages over ntfy (C# / .NET / NLog)
- [helm-charts](https://github.com/sarab97/helm-charts) - Helm charts of some of the selfhosted services, incl. ntfy
- [ntfy_ansible_role](https://github.com/stevenengland/ntfy_ansible_role) (on [Ansible Galaxy](https://galaxy.ansible.com/stevenengland/ntfy)) - Ansible role to install ntfy
## Blog + forum posts
- [ntfy.sh](https://neo-sahara.com/wp/2023/03/25/ntfy-sh/) - neo-sahara.com - 3/2023
- [Using Ntfy to send and receive push notifications - Samuel Rosa de Oliveria - Delphicon 2023](https://www.youtube.com/watch?v=feu0skpI9QI) - youtube.com - 3/2023
- [ntfy: własny darmowy system powiadomień](https://sprawdzone.it/ntfy-wlasny-darmowy-system-powiadomien/) - sprawdzone.it - 3/2023
- [Deploying ntfy on railway](https://www.youtube.com/watch?v=auJICXtxoNA) - youtube.com - 3/2023
- [Start-Job,Variables, and ntfy.sh](https://klingele.dev/2023/03/01/start-jobvariables-and-ntfy-sh/) - klingele.dev - 3/2023
- [enviar notificaciones automáticas usando ntfy.sh](https://osiux.com/2023-02-15-send-automatic-notifications-using-ntfy.html) - osiux.com - 2/2023
- [Carnet IP动态解析以及通过ntfy推送IP信息](https://blog.wslll.cn/index.php/archives/201/) - blog.wslll.cn - 2/2023
@@ -131,6 +138,7 @@ and uptime of third party servers, so use of each server is **at your own discre
- [UnifiedPush: a decentralized, open-source push notification protocol](https://f-droid.org/en/2022/12/18/unifiedpush.html) ⭐ - 12/2022
- [ntfy setup instructions](https://docs.benjamin-altpeter.de/network/vms/1001029-ntfy/) - benjamin-altpeter.de - 12/2022
- [Ntfy Self-Hosted Push Notifications](https://lachlanlife.net/posts/2022-12-ntfy/) - lachlanlife.net - 12/2022
- [NTFY - système de notification hyper simple et complet](https://www.youtube.com/watch?v=UieZYWVVgA4) - youtube.com - 12/2022
- [ntfy.sh](https://paramdeo.com/til/ntfy-sh) - paramdeo.com - 11/2022
- [Using ntfy to warn me when my computer is discharging](https://ulysseszh.github.io/programming/2022/11/28/ntfy-warn-discharge.html) - ulysseszh.github.io - 11/2022
- [ntfy - Push Notification Service](https://dizzytech.de/posts/ntfy/) - dizzytech.de - 11/2022

View File

@@ -8,7 +8,7 @@ For some (many?) users, the iOS app is not refreshing the view when new notifica
swipe down, you do not see the newly arrived messages, even though the popup appeared before.
This is caused by some weirdness between the Notification Service Extension (NSE), SwiftUI and Core Data. I am entirely
clueless on how to fix it, sadly, as it is ephemeral and now clear to me what is causing it.
clueless on how to fix it, sadly, as it is ephemeral and not clear to me what is causing it.
Please send experienced iOS developers my way to help me figure this out.

View File

@@ -2,6 +2,34 @@
Binaries for all releases can be found on the GitHub releases pages for the [ntfy server](https://github.com/binwiederhier/ntfy/releases)
and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/releases).
### ntfy server v2.3.1
Released March 30, 2023
This release disables server-initiated polling of iOS devices entirely, thereby eliminating the thundering herd problem
on ntfy.sh that we observe every 20 minutes. The polling was never strictly necessary, and has actually caused duplicate
delivery issues as well, so disabling it should not have any negative effects. iOS users, please reach out via Discord
or Matrix if there are issues.
**Bug fixes + maintenance:**
* Disable iOS polling entirely ([#677](https://github.com/binwiederhier/ntfy/issues/677)/[#509](https://github.com/binwiederhier/ntfy/issues/509))
## ntfy server v2.3.0
Released March 29, 2023
This release primarily fixes an issue with delayed messages, and it adds support for Go's profiler (if enabled), which
will allow investigating usage spikes in more detail. There will likely be a follow-up release this week to fix the
actual spikes [caused by iOS devices](https://github.com/binwiederhier/ntfy/issues/677).
**Features:**
* ntfy now supports Go's `pprof` profiler, if enabled (relates to [#677](https://github.com/binwiederhier/ntfy/issues/677))
**Bug fixes + maintenance:**
* Fix delayed message sending from authenticated users ([#679](https://github.com/binwiederhier/ntfy/issues/679))
* Fixed plural for Polish and other translations ([#678](https://github.com/binwiederhier/ntfy/pull/678), thanks to [@bmoczulski](https://github.com/bmoczulski))
## ntfy server v2.2.0
Released March 17, 2023
@@ -1125,7 +1153,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
**Features:**
* You can now disable UnifiedPush so ntfy does not act as a UnifiedPush distributor ([#646](https://github.com/binwiederhier/ntfy/issues/646), thanks to [@ollien](https://github.com/ollien) for reporting and to [@wunter8](https://github.com/wunter8) for implementing)
* You can now disable UnifiedPush so ntfy does not act as a UnifiedPush distributor ([#646](https://github.com/binwiederhier/ntfy/issues/646), thanks to [@ollien](https://github.com/ollien) for reporting and to [@wunter8](https://github.com/wunter8) for implementing)
**Bug fixes + maintenance:**

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
docs/static/img/grafana-dashboard.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

BIN
docs/static/img/web-logs.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

131
docs/troubleshooting.md Normal file
View File

@@ -0,0 +1,131 @@
# Troubleshooting
This page lists a few suggestions of what to do when things don't work as expected. This is not a complete list.
If this page does not help, feel free to drop by the [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)
and ask there. We're happy to help.
## ntfy server
If you host your own ntfy server, and you're having issues with any component, it is always helpful to enable debugging/tracing
in the server. You can find detailed instructions in the [Logging & Debugging](config.md#logging-debugging) section, but it ultimately
boils down to setting `log-level: debug` or `log-level: trace` in the `server.yml` file:
=== "server.yml (debug)"
``` yaml
log-level: debug
```
=== "server.yml (trace)"
``` yaml
log-level: trace
```
If you're using environment variables, set `NTFY_LOG_LEVEL=debug` (or `trace`) instead. You can also pass `--debug` or `--trace`
to the `ntfy serve` command, e.g. `ntfy serve --trace`. If you're using systemd (i.e. `systemctl`) to run ntfy, you can look at
the logs using `journalctl -u ntfy -f`. The logs will look something like this:
=== "Example logs (debug)"
```
$ ntfy serve --debug
2023/03/20 14:45:38 INFO Listening on :2586[http] :1025[smtp], ntfy 2.1.2, log level is DEBUG (tag=startup)
2023/03/20 14:45:38 DEBUG Waiting until 2023-03-21 00:00:00 +0000 UTC to reset visitor stats (tag=resetter)
2023/03/20 14:45:39 DEBUG Rate limiters reset for visitor (visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=0, visitor_messages_limit=500, visitor_messages_remaining=500, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=60, visitor_seen=2023-03-20T14:45:39.7-04:00)
2023/03/20 14:45:39 DEBUG HTTP request started (http_method=POST, http_path=/mytopic, tag=http, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=0, visitor_messages_limit=500, visitor_messages_remaining=500, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=60, visitor_seen=2023-03-20T14:45:39.7-04:00)
2023/03/20 14:45:39 DEBUG Received message (http_method=POST, http_path=/mytopic, message_body_size=2, message_delayed=false, message_email=, message_event=message, message_firebase=true, message_id=EZu6i2WZjH0v, message_sender=127.0.0.1, message_time=1679337939, message_unifiedpush=false, tag=publish, topic=mytopic, topic_last_access=2023-03-20T14:45:38.319-04:00, topic_subscribers=0, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.0002132248, visitor_seen=2023-03-20T14:45:39.7-04:00)
2023/03/20 14:45:39 DEBUG Adding message to cache (http_method=POST, http_path=/mytopic, message_body_size=2, message_event=message, message_id=EZu6i2WZjH0v, message_sender=127.0.0.1, message_time=1679337939, tag=publish, topic=mytopic, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.000259165, visitor_seen=2023-03-20T14:45:39.7-04:00)
2023/03/20 14:45:39 DEBUG HTTP request finished (http_method=POST, http_path=/mytopic, tag=http, time_taken_ms=2, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.0004147334, visitor_seen=2023-03-20T14:45:39.7-04:00)
2023/03/20 14:45:39 DEBUG Wrote 1 message(s) in 8.285712ms (tag=message_cache)
...
```
=== "Example logs (trace)"
```
$ ntfy serve --trace
2023/03/20 14:40:42 INFO Listening on :2586[http] :1025[smtp], ntfy 2.1.2, log level is TRACE (tag=startup)
2023/03/20 14:40:42 DEBUG Waiting until 2023-03-21 00:00:00 +0000 UTC to reset visitor stats (tag=resetter)
2023/03/20 14:40:59 DEBUG Rate limiters reset for visitor (visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=0, visitor_messages_limit=500, visitor_messages_remaining=500, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=60, visitor_seen=2023-03-20T14:40:59.893-04:00)
2023/03/20 14:40:59 TRACE HTTP request started (http_method=POST, http_path=/mytopic, http_request=POST /mytopic HTTP/1.1
User-Agent: curl/7.81.0
Accept: */*
Content-Length: 2
Content-Type: application/x-www-form-urlencoded
hi, tag=http, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=0, visitor_messages_limit=500, visitor_messages_remaining=500, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=60, visitor_seen=2023-03-20T14:40:59.893-04:00)
2023/03/20 14:40:59 TRACE Received message (http_method=POST, http_path=/mytopic, message_body={
"id": "Khaup1RVclU3",
"time": 1679337659,
"expires": 1679380859,
"event": "message",
"topic": "mytopic",
"message": "hi"
}, message_body_size=2, message_delayed=false, message_email=, message_event=message, message_firebase=true, message_id=Khaup1RVclU3, message_sender=127.0.0.1, message_time=1679337659, message_unifiedpush=false, tag=publish, topic=mytopic, topic_last_access=2023-03-20T14:40:59.893-04:00, topic_subscribers=0, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.0001785048, visitor_seen=2023-03-20T14:40:59.893-04:00)
2023/03/20 14:40:59 DEBUG Adding message to cache (http_method=POST, http_path=/mytopic, message_body_size=2, message_event=message, message_id=Khaup1RVclU3, message_sender=127.0.0.1, message_time=1679337659, tag=publish, topic=mytopic, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.0002044368, visitor_seen=2023-03-20T14:40:59.893-04:00)
2023/03/20 14:40:59 DEBUG HTTP request finished (http_method=POST, http_path=/mytopic, tag=http, time_taken_ms=1, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.000220502, visitor_seen=2023-03-20T14:40:59.893-04:00)
2023/03/20 14:40:59 TRACE No stream or WebSocket subscribers, not forwarding (message_body_size=2, message_event=message, message_id=Khaup1RVclU3, message_sender=127.0.0.1, message_time=1679337659, tag=publish, topic=mytopic, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.0002369212, visitor_seen=2023-03-20T14:40:59.893-04:00)
2023/03/20 14:41:00 DEBUG Wrote 1 message(s) in 9.529196ms (tag=message_cache)
...
```
## Android app
On Android, you can turn on logging in the settings under **Settings → Record logs**. This will store up to 1,000 log
entries, which you can then copy or upload.
<figure markdown>
![Recording logs on Android](static/img/android-screenshot-logs.jpg){ width=400 }
<figcaption>Recording logs on Android</figcaption>
</figure>
When you copy or upload the logs, you can censor them to make it easier to share them with others. ntfy will replace all
topics and hostnames with fruits. Here's an example:
```
This is a log of the ntfy Android app. The log shows up to 1,000 entries.
Server URLs (aside from ntfy.sh) and topics have been replaced with fruits 🍌🥝🍋🥥🥑🍊🍎🍑.
Device info:
--
ntfy: 1.16.0 (play)
OS: 4.19.157-perf+
Android: 13 (SDK 33)
...
Logs
--
1679339199507 2023-03-20 15:06:39.507 D NtfyMainActivity Battery: ignoring optimizations = true (we want this to be true); instant subscriptions = true; remind time reached = true; banner = false
1679339199507 2023-03-20 15:06:39.507 D NtfySubscriberMgr Enqueuing work to refresh subscriber service
1679339199589 2023-03-20 15:06:39.589 D NtfySubscriberMgr ServiceStartWorker: Starting foreground service with action START (work ID: a7eeeae9-9356-40df-afbd-236e5ed10a0b)
1679339199602 2023-03-20 15:06:39.602 D NtfySubscriberService onStartCommand executed with startId: 262
1679339199602 2023-03-20 15:06:39.602 D NtfySubscriberService using an intent with action START
1679339199629 2023-03-20 15:06:39.629 D NtfySubscriberService Refreshing subscriptions
1679339199629 2023-03-20 15:06:39.629 D NtfySubscriberService - Desired connections: [ConnectionId(baseUrl=https://ntfy.sh, topicsToSubscriptionIds={avocado=23801492, lemon=49013182, banana=1309176509201171073, peach=573300885184666424, pineapple=-5956897229801209316, durian=81453333, starfruit=30489279, fruit12=82532869}), ConnectionId(baseUrl=https://orange.example.com, topicsToSubscriptionIds={apple=4971265, dragonfruit=66809328})]
1679339199629 2023-03-20 15:06:39.629 D NtfySubscriberService - Active connections: [ConnectionId(baseUrl=https://orange.example.com, topicsToSubscriptionIds={apple=4971265, dragonfruit=66809328}), ConnectionId(baseUrl=https://ntfy.sh, topicsToSubscriptionIds={avocado=23801492, lemon=49013182, banana=1309176509201171073, peach=573300885184666424, pineapple=-5956897229801209316, durian=81453333, starfruit=30489279, fruit12=82532869})]
...
```
To get live logs, or to get more advanced access to an Android phone, you can use [adb](https://developer.android.com/studio/command-line/adb).
After you install and [enable adb debugging](https://developer.android.com/studio/command-line/adb#Enabling), you can
get detailed logs like so:
```
# Connect to phone (enable Wireless debugging first)
adb connect 192.168.1.137:39539
# Print all logs; you may have to pass the -s option
adb logcat
adb -s 192.168.1.137:39539 logcat
# Only list ntfy logs
adb logcat --pid=$(adb shell pidof -s io.heckel.ntfy)
adb -s 192.168.1.137:39539 logcat --pid=$(adb -s 192.168.1.137:39539 shell pidof -s io.heckel.ntfy)
```
## Web app
The web app logs everything to the **developer console**, which you can open by **pressing the F12 key** on your
keyboard.
<figure markdown>
![Web app logs](static/img/web-logs.png)
<figcaption>Web app logs in the developer console</figcaption>
</figure>
## iOS app
Sorry, there is no way to debug or get the logs from the iOS app (yet), outside of running the app in Xcode.

File diff suppressed because it is too large Load Diff

12
go.mod
View File

@@ -4,7 +4,7 @@ go 1.18
require (
cloud.google.com/go/firestore v1.9.0 // indirect
cloud.google.com/go/storage v1.30.0 // indirect
cloud.google.com/go/storage v1.30.1 // indirect
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/emersion/go-smtp v0.16.0
@@ -13,7 +13,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.16
github.com/olebedev/when v0.0.0-20221205223600-4d190b02b8d8
github.com/stretchr/testify v1.8.1
github.com/urfave/cli/v2 v2.25.0
github.com/urfave/cli/v2 v2.25.1
golang.org/x/crypto v0.7.0
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sync v0.1.0
@@ -28,12 +28,12 @@ require github.com/pkg/errors v0.9.1 // indirect
require (
firebase.google.com/go/v4 v4.10.0
github.com/prometheus/client_golang v1.14.0
github.com/stripe/stripe-go/v74 v74.12.0
github.com/stripe/stripe-go/v74 v74.14.0
)
require (
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/compute v1.18.0 // indirect
cloud.google.com/go/compute v1.19.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v0.13.0 // indirect
cloud.google.com/go/longrunning v0.4.1 // indirect
@@ -66,8 +66,8 @@ require (
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/appengine/v2 v2.0.2 // indirect
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
google.golang.org/grpc v1.53.0 // indirect
google.golang.org/genproto v0.0.0-20230330200707-38013875ee22 // indirect
google.golang.org/grpc v1.54.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

26
go.sum
View File

@@ -1,8 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=
cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY=
cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ=
cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA=
@@ -11,8 +11,8 @@ cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM=
cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
cloud.google.com/go/storage v1.30.0 h1:g1yrbxAWOrvg/594228pETWkOi00MLTrOWfh56veU5o=
cloud.google.com/go/storage v1.30.0/go.mod h1:xAVretHSROm1BQX4IIsoVgJqw0LqOyX+I/O2GzRAzdE=
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
firebase.google.com/go/v4 v4.10.0 h1:dgK/8uwfJbzc5LZK/GyRRfIkZEDObN9q0kgEXsjlXN4=
firebase.google.com/go/v4 v4.10.0/go.mod h1:m0gLwPY9fxKggizzglgCNWOGnFnVPifLpqZzo5u3e/A=
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
@@ -124,10 +124,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stripe/stripe-go/v74 v74.12.0 h1:uakz8Ubngok3G6Pcwc1ssqI3msONE4tdeyi84UooLQk=
github.com/stripe/stripe-go/v74 v74.12.0/go.mod h1:f9L6LvaXa35ja7eyvP6GQswoaIPaBRvGAimAO+udbBw=
github.com/urfave/cli/v2 v2.25.0 h1:ykdZKuQey2zq0yin/l7JOm9Mh+pg72ngYMeB0ABn6q8=
github.com/urfave/cli/v2 v2.25.0/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/stripe/stripe-go/v74 v74.14.0 h1:hB1Ocu/m3BUZ+PrTePsPSv8TKcXTrleCL5Y5JfB8zCo=
github.com/stripe/stripe-go/v74 v74.14.0/go.mod h1:f9L6LvaXa35ja7eyvP6GQswoaIPaBRvGAimAO+udbBw=
github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
@@ -191,8 +191,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.113.0 h1:3zLZyS9hgne8yoXUFy871yWdQcA2tA6wp59aaCT6Cp4=
google.golang.org/api v0.113.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE=
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -204,15 +202,15 @@ google.golang.org/appengine/v2 v2.0.2/go.mod h1:PkgRUWz4o1XOvbqtWTkBtCitEJ5Tp4Ho
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
google.golang.org/genproto v0.0.0-20230330200707-38013875ee22 h1:n3ThVoQnHbCbnkhZZ1fx3+3fBAisViSwrpbtLV7vydY=
google.golang.org/genproto v0.0.0-20230330200707-38013875ee22/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -93,6 +93,7 @@ nav:
- "Integrations + projects": integrations.md
- "Release notes": releases.md
- "Emojis 🥳 🎉": emojis.md
- "Troubleshooting": troubleshooting.md
- "Known issues": known-issues.md
- "Deprecation notices": deprecations.md
- "Development": develop.md

View File

@@ -107,6 +107,7 @@ type Config struct {
SMTPServerAddrPrefix string
MetricsEnable bool
MetricsListenHTTP string
ProfileListenHTTP string
MessageLimit int
MinDelay time.Duration
MaxDelay time.Duration

View File

@@ -19,6 +19,7 @@ import (
"io"
"net"
"net/http"
"net/http/pprof"
"net/netip"
"net/url"
"os"
@@ -39,6 +40,7 @@ type Server struct {
httpServer *http.Server
httpsServer *http.Server
httpMetricsServer *http.Server
httpProfileServer *http.Server
unixListener net.Listener
smtpServer *smtp.Server
smtpServerBackend *smtpBackend
@@ -217,6 +219,9 @@ func (s *Server) Run() error {
if s.config.MetricsListenHTTP != "" {
listenStr += fmt.Sprintf(" %s[http/metrics]", s.config.MetricsListenHTTP)
}
if s.config.ProfileListenHTTP != "" {
listenStr += fmt.Sprintf(" %s[http/profile]", s.config.ProfileListenHTTP)
}
log.Tag(tagStartup).Info("Listening on%s, ntfy %s, log level is %s", listenStr, s.config.Version, log.CurrentLevel().String())
if log.IsFile() {
fmt.Fprintf(os.Stderr, "Listening on%s, ntfy %s\n", listenStr, s.config.Version)
@@ -273,6 +278,18 @@ func (s *Server) Run() error {
initMetrics()
s.metricsHandler = promhttp.Handler()
}
if s.config.ProfileListenHTTP != "" {
profileMux := http.NewServeMux()
profileMux.HandleFunc("/debug/pprof/", pprof.Index)
profileMux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
profileMux.HandleFunc("/debug/pprof/profile", pprof.Profile)
profileMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
profileMux.HandleFunc("/debug/pprof/trace", pprof.Trace)
s.httpProfileServer = &http.Server{Addr: s.config.ProfileListenHTTP, Handler: profileMux}
go func() {
errChan <- s.httpProfileServer.ListenAndServe()
}()
}
if s.config.SMTPServerListen != "" {
go func() {
errChan <- s.runSMTPServer()
@@ -1512,8 +1529,14 @@ func (s *Server) runFirebaseKeepaliver() {
select {
case <-time.After(s.config.FirebaseKeepaliveInterval):
s.sendToFirebase(v, newKeepaliveMessage(firebaseControlTopic))
case <-time.After(s.config.FirebasePollInterval):
s.sendToFirebase(v, newKeepaliveMessage(firebasePollTopic))
/*
FIXME: Disable iOS polling entirely for now due to thundering herd problem (see #677)
To solve this, we'd have to shard the iOS poll topics to spread out the polling evenly.
Given that it's not really necessary to poll, turning it off for now should not have any impact.
case <-time.After(s.config.FirebasePollInterval):
s.sendToFirebase(v, newKeepaliveMessage(firebasePollTopic))
*/
case <-s.closeChan:
return
}
@@ -1541,7 +1564,7 @@ func (s *Server) sendDelayedMessages() error {
for _, m := range messages {
var u *user.User
if s.userManager != nil && m.User != "" {
u, err = s.userManager.User(m.User)
u, err = s.userManager.UserByID(m.User)
if err != nil {
log.With(m).Err(err).Warn("Error sending delayed message")
continue

View File

@@ -276,6 +276,14 @@
# enable-metrics: false
# metrics-listen-http:
# Profiling
#
# ntfy can expose Go's net/http/pprof endpoints to support profiling of the ntfy server. If enabled, ntfy will listen
# on a dedicated listen IP/port, which can be accessed via the web browser on http://<ip>:<port>/debug/pprof/.
# This can be helpful to expose bottlenecks, and visualize call flows. See https://pkg.go.dev/net/http/pprof for details.
#
# profile-listen-http:
# Logging options
#
# By default, ntfy logs to the console (stderr), with an "info" log level, and in a human-readable text format.

View File

@@ -701,8 +701,7 @@ func TestAccount_Reservation_Delete_Messages_And_Attachments(t *testing.T) {
require.FileExists(t, filepath.Join(s.config.AttachmentCacheDir, m2.ID))
}
func TestAccount_Persist_UserStats_After_Tier_Change(t *testing.T) {
t.Parallel()
/*func TestAccount_Persist_UserStats_After_Tier_Change(t *testing.T) {
conf := newTestConfigWithAuthFile(t)
conf.AuthDefault = user.PermissionReadWrite
conf.AuthStatsQueueWriterInterval = 300 * time.Millisecond
@@ -763,4 +762,4 @@ func TestAccount_Persist_UserStats_After_Tier_Change(t *testing.T) {
require.Equal(t, 200, rr.Code)
account, _ = util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
require.Equal(t, int64(2), account.Stats.Messages) // Is not reset!
}
}*/

View File

@@ -327,13 +327,10 @@ func TestServer_PublishNoCache(t *testing.T) {
func TestServer_PublishAt(t *testing.T) {
t.Parallel()
c := newTestConfig(t)
c.MinDelay = time.Second
c.DelayedSenderInterval = 100 * time.Millisecond
s := newTestServer(t, c)
s := newTestServer(t, newTestConfig(t))
response := request(t, s, "PUT", "/mytopic", "a message", map[string]string{
"In": "1s",
"In": "1h",
})
require.Equal(t, 200, response.Code)
@@ -341,22 +338,62 @@ func TestServer_PublishAt(t *testing.T) {
messages := toMessages(t, response.Body.String())
require.Equal(t, 0, len(messages))
time.Sleep(time.Second)
require.Nil(t, s.sendDelayedMessages())
// Update message time to the past
fakeTime := time.Now().Add(-10 * time.Second).Unix()
_, err := s.messageCache.db.Exec(`UPDATE messages SET time=?`, fakeTime)
require.Nil(t, err)
// Trigger delayed message sending
require.Nil(t, s.sendDelayedMessages())
response = request(t, s, "GET", "/mytopic/json?poll=1", "", nil)
messages = toMessages(t, response.Body.String())
require.Equal(t, 1, len(messages))
require.Equal(t, "a message", messages[0].Message)
require.Equal(t, netip.Addr{}, messages[0].Sender) // Never return the sender!
messages, err := s.messageCache.Messages("mytopic", sinceAllMessages, true)
messages, err = s.messageCache.Messages("mytopic", sinceAllMessages, true)
require.Nil(t, err)
require.Equal(t, 1, len(messages))
require.Equal(t, "a message", messages[0].Message)
require.Equal(t, "9.9.9.9", messages[0].Sender.String()) // It's stored in the DB though!
}
func TestServer_PublishAt_FromUser(t *testing.T) {
t.Parallel()
s := newTestServer(t, newTestConfigWithAuthFile(t))
require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleAdmin))
response := request(t, s, "PUT", "/mytopic", "a message", map[string]string{
"Authorization": util.BasicAuth("phil", "phil"),
"In": "1h",
})
require.Equal(t, 200, response.Code)
// Message doesn't show up immediately
response = request(t, s, "GET", "/mytopic/json?poll=1", "", nil)
messages := toMessages(t, response.Body.String())
require.Equal(t, 0, len(messages))
// Update message time to the past
fakeTime := time.Now().Add(-10 * time.Second).Unix()
_, err := s.messageCache.db.Exec(`UPDATE messages SET time=?`, fakeTime)
require.Nil(t, err)
// Trigger delayed message sending
require.Nil(t, s.sendDelayedMessages())
response = request(t, s, "GET", "/mytopic/json?poll=1", "", nil)
messages = toMessages(t, response.Body.String())
require.Equal(t, 1, len(messages))
require.Equal(t, fakeTime, messages[0].Time)
require.Equal(t, "a message", messages[0].Message)
messages, err = s.messageCache.Messages("mytopic", sinceAllMessages, true)
require.Nil(t, err)
require.Equal(t, 1, len(messages))
require.Equal(t, "a message", messages[0].Message)
require.True(t, strings.HasPrefix(messages[0].User, "u_"))
}
func TestServer_PublishAt_Expires(t *testing.T) {
s := newTestServer(t, newTestConfig(t))

69
tools/loadgen/main.go Normal file
View File

@@ -0,0 +1,69 @@
package main
import (
"bufio"
"context"
"fmt"
"net/http"
"os"
"time"
)
func main() {
baseURL := "https://staging.ntfy.sh"
if len(os.Args) > 1 {
baseURL = os.Args[1]
}
for i := 0; i < 2000; i++ {
go subscribe(i, baseURL)
}
time.Sleep(5 * time.Second)
for i := 0; i < 2000; i++ {
go func(worker int) {
for {
poll(worker, baseURL)
}
}(i)
}
time.Sleep(time.Hour)
}
func subscribe(worker int, baseURL string) {
fmt.Printf("[subscribe] worker=%d STARTING\n", worker)
start := time.Now()
topic, ip := fmt.Sprintf("subtopic%d", worker), fmt.Sprintf("1.2.%d.%d", (worker/255)%255, worker%255)
req, _ := http.NewRequest("GET", fmt.Sprintf("%s/%s/json", baseURL, topic), nil)
req.Header.Set("X-Forwarded-For", ip)
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Printf("[subscribe] worker=%d time=%d error=%s\n", worker, time.Since(start).Milliseconds(), err.Error())
return
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
// Do nothing
}
fmt.Printf("[subscribe] worker=%d status=%d time=%d EXITED\n", worker, resp.StatusCode, time.Since(start).Milliseconds())
}
func poll(worker int, baseURL string) {
fmt.Printf("[poll] worker=%d STARTING\n", worker)
topic, ip := fmt.Sprintf("polltopic%d", worker), fmt.Sprintf("1.2.%d.%d", (worker/255)%255, worker%255)
start := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
//req, _ := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://staging.ntfy.sh/%s/json?poll=1&since=all", topic), nil)
req, _ := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%s/json?poll=1&since=all", baseURL, topic), nil)
req.Header.Set("X-Forwarded-For", ip)
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Printf("[poll] worker=%d time=%d status=- error=%s\n", worker, time.Since(start).Milliseconds(), err.Error())
cancel()
return
}
defer resp.Body.Close()
fmt.Printf("[poll] worker=%d time=%d status=%s\n", worker, time.Since(start).Milliseconds(), resp.Status)
}

487
web/package-lock.json generated
View File

@@ -2123,9 +2123,9 @@
}
},
"node_modules/@csstools/selector-specificity": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.1.1.tgz",
"integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz",
"integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==",
"engines": {
"node": "^14 || ^16 || >=18"
},
@@ -2134,7 +2134,6 @@
"url": "https://opencollective.com/csstools"
},
"peerDependencies": {
"postcss": "^8.4",
"postcss-selector-parser": "^6.0.10"
}
},
@@ -2272,9 +2271,9 @@
"integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg=="
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz",
"integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
"integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
"dependencies": {
"eslint-visitor-keys": "^3.3.0"
},
@@ -2286,21 +2285,21 @@
}
},
"node_modules/@eslint-community/regexpp": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz",
"integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz",
"integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
"node_modules/@eslint/eslintrc": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz",
"integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz",
"integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.5.0",
"espree": "^9.5.1",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
@@ -2357,9 +2356,9 @@
}
},
"node_modules/@eslint/js": {
"version": "8.36.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz",
"integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==",
"version": "8.37.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz",
"integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
@@ -3135,15 +3134,15 @@
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
"node_modules/@mui/base": {
"version": "5.0.0-alpha.121",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.121.tgz",
"integrity": "sha512-8nJRY76UqlJV+q/Yzo0tgGfPWEOa+4N9rjO81fMmcJqP0I6m54hLDXsjvMg4tvelY5eKHXUK6Tb7en+GHfTqZA==",
"version": "5.0.0-alpha.123",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.123.tgz",
"integrity": "sha512-pxzcAfET3I6jvWqS4kijiLMn1OmdMw+mGmDa0SqmDZo3bXXdvLhpCCPqCkULG3UykhvFCOcU5HclOX3JCA+Zhg==",
"dependencies": {
"@babel/runtime": "^7.21.0",
"@emotion/is-prop-valid": "^1.2.0",
"@mui/types": "^7.2.3",
"@mui/utils": "^5.11.13",
"@popperjs/core": "^2.11.6",
"@popperjs/core": "^2.11.7",
"clsx": "^1.2.1",
"prop-types": "^15.8.1",
"react-is": "^18.2.0"
@@ -3167,9 +3166,9 @@
}
},
"node_modules/@mui/core-downloads-tracker": {
"version": "5.11.13",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.13.tgz",
"integrity": "sha512-lx+GXBR9h/ApZsEP728tl0pyZyuajto+VnBgsoAzw1d5+CbmOo8ZWieKwVUGxZlPT1wMYNUYS5NtKzCli0xYjw==",
"version": "5.11.15",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.15.tgz",
"integrity": "sha512-Q0e2oBsjHyIWWj1wLzl14btunvBYC0yl+px7zL9R69tF87uenj6q72ieS369BJ6jxYpJwvXfR6/f+TC+ZUsKKg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui"
@@ -3201,14 +3200,14 @@
}
},
"node_modules/@mui/material": {
"version": "5.11.13",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.13.tgz",
"integrity": "sha512-2CnSj43F+159LbGmTLLQs5xbGYMiYlpTByQhP7c7cMX6opbScctBFE1PuyElpAmwW8Ag9ysfZH1d1MFAmJQkjg==",
"version": "5.11.15",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.15.tgz",
"integrity": "sha512-E5RbLq9/OvRKmGyeZawdnmFBCvhKkI/Zqgr0xFqW27TGwKLxObq/BreJc6Uu5Sbv8Fjj34vEAbRx6otfOyxn5w==",
"dependencies": {
"@babel/runtime": "^7.21.0",
"@mui/base": "5.0.0-alpha.121",
"@mui/core-downloads-tracker": "^5.11.13",
"@mui/system": "^5.11.13",
"@mui/base": "5.0.0-alpha.123",
"@mui/core-downloads-tracker": "^5.11.15",
"@mui/system": "^5.11.15",
"@mui/types": "^7.2.3",
"@mui/utils": "^5.11.13",
"@types/react-transition-group": "^4.4.5",
@@ -3302,9 +3301,9 @@
}
},
"node_modules/@mui/system": {
"version": "5.11.13",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.13.tgz",
"integrity": "sha512-OWP0Alp6C8ufnGm9+CZcl3d+OoRXL2PnrRT5ohaMLxvGL9OfNcL2t4JOjMmA0k1UAGd6E/Ygbu5lEPrZSDlvCg==",
"version": "5.11.15",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.15.tgz",
"integrity": "sha512-vCatoWCTnAPquoNifHbqMCMnOElEbLosVUeW0FQDyjCq+8yMABD9E6iY0s14O7iq1wD+qqU7rFAuDIVvJ/AzzA==",
"dependencies": {
"@babel/runtime": "^7.21.0",
"@mui/private-theming": "^5.11.13",
@@ -3493,18 +3492,18 @@
}
},
"node_modules/@popperjs/core": {
"version": "2.11.6",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
"version": "2.11.7",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
"integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@remix-run/router": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.4.0.tgz",
"integrity": "sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz",
"integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==",
"engines": {
"node": ">=14"
}
@@ -3915,9 +3914,9 @@
}
},
"node_modules/@types/eslint": {
"version": "8.21.2",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.2.tgz",
"integrity": "sha512-EMpxUyystd3uZVByZap1DACsMXvb82ypQnGn89e1Y0a+LYu3JJscUd/gqhRsVFDkaD2MIiWo0MT8EfXr3DGRKw==",
"version": "8.37.0",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz",
"integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==",
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
@@ -4016,9 +4015,9 @@
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
},
"node_modules/@types/node": {
"version": "18.15.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz",
"integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw=="
"version": "18.15.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q=="
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@@ -4051,9 +4050,9 @@
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
},
"node_modules/@types/react": {
"version": "18.0.28",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz",
"integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==",
"version": "18.0.31",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.31.tgz",
"integrity": "sha512-EEG67of7DsvRDU6BLLI0p+k1GojDLz9+lZsnCpCRTa/lOokvyPBvp8S5x+A24hME3yyQuIipcP70KJ6H7Qupww==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -4090,9 +4089,9 @@
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="
},
"node_modules/@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
"version": "0.16.3",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
},
"node_modules/@types/semver": {
"version": "7.3.13",
@@ -4156,14 +4155,14 @@
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz",
"integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz",
"integrity": "sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==",
"dependencies": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.55.0",
"@typescript-eslint/type-utils": "5.55.0",
"@typescript-eslint/utils": "5.55.0",
"@typescript-eslint/scope-manager": "5.57.0",
"@typescript-eslint/type-utils": "5.57.0",
"@typescript-eslint/utils": "5.57.0",
"debug": "^4.3.4",
"grapheme-splitter": "^1.0.4",
"ignore": "^5.2.0",
@@ -4189,11 +4188,11 @@
}
},
"node_modules/@typescript-eslint/experimental-utils": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.55.0.tgz",
"integrity": "sha512-3ZqXIZhdGyGQAIIGATeMtg7prA6VlyxGtcy5hYIR/3qUqp3t18pWWUYhL9mpsDm7y8F9mr3ISMt83TiqCt7OPQ==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.57.0.tgz",
"integrity": "sha512-0RnrwGQ7MmgtOSnzB/rSGYr2iXENi6L+CtPzX3g5ovo0HlruLukSEKcc4s+q0IEc+DLTDc7Edan0Y4WSQ/bFhw==",
"dependencies": {
"@typescript-eslint/utils": "5.55.0"
"@typescript-eslint/utils": "5.57.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4207,13 +4206,13 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz",
"integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz",
"integrity": "sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==",
"dependencies": {
"@typescript-eslint/scope-manager": "5.55.0",
"@typescript-eslint/types": "5.55.0",
"@typescript-eslint/typescript-estree": "5.55.0",
"@typescript-eslint/scope-manager": "5.57.0",
"@typescript-eslint/types": "5.57.0",
"@typescript-eslint/typescript-estree": "5.57.0",
"debug": "^4.3.4"
},
"engines": {
@@ -4233,12 +4232,12 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz",
"integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz",
"integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==",
"dependencies": {
"@typescript-eslint/types": "5.55.0",
"@typescript-eslint/visitor-keys": "5.55.0"
"@typescript-eslint/types": "5.57.0",
"@typescript-eslint/visitor-keys": "5.57.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4249,12 +4248,12 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz",
"integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz",
"integrity": "sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==",
"dependencies": {
"@typescript-eslint/typescript-estree": "5.55.0",
"@typescript-eslint/utils": "5.55.0",
"@typescript-eslint/typescript-estree": "5.57.0",
"@typescript-eslint/utils": "5.57.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@@ -4275,9 +4274,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz",
"integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz",
"integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -4287,12 +4286,12 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz",
"integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz",
"integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==",
"dependencies": {
"@typescript-eslint/types": "5.55.0",
"@typescript-eslint/visitor-keys": "5.55.0",
"@typescript-eslint/types": "5.57.0",
"@typescript-eslint/visitor-keys": "5.57.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -4313,16 +4312,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz",
"integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz",
"integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.55.0",
"@typescript-eslint/types": "5.55.0",
"@typescript-eslint/typescript-estree": "5.55.0",
"@typescript-eslint/scope-manager": "5.57.0",
"@typescript-eslint/types": "5.57.0",
"@typescript-eslint/typescript-estree": "5.57.0",
"eslint-scope": "^5.1.1",
"semver": "^7.3.7"
},
@@ -4358,11 +4357,11 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.55.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz",
"integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==",
"version": "5.57.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz",
"integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==",
"dependencies": {
"@typescript-eslint/types": "5.55.0",
"@typescript-eslint/types": "5.57.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@@ -4578,27 +4577,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/acorn-node": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
"integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
"dependencies": {
"acorn": "^7.0.0",
"acorn-walk": "^7.0.0",
"xtend": "^4.0.2"
}
},
"node_modules/acorn-node/node_modules/acorn": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
@@ -4741,6 +4719,11 @@
"node": ">=4"
}
},
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -5349,9 +5332,9 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/bonjour-service": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz",
"integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz",
"integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==",
"dependencies": {
"array-flatten": "^2.1.2",
"dns-equal": "^1.0.0",
@@ -5508,9 +5491,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001467",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001467.tgz",
"integrity": "sha512-cEdN/5e+RPikvl9AHm4uuLXxeCNq8rFsQ+lPHTfe/OtypP3WwnVVbjn+6uBV7PaFL6xUFzTh+sSCOz1rKhcO+Q==",
"version": "1.0.30001473",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz",
"integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==",
"funding": [
{
"type": "opencollective",
@@ -5519,6 +5502,10 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
]
},
@@ -5952,9 +5939,9 @@
}
},
"node_modules/css-declaration-sorter": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz",
"integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==",
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz",
"integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==",
"engines": {
"node": "^10 || ^12 || >=14"
},
@@ -6164,9 +6151,9 @@
}
},
"node_modules/cssdb": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.4.1.tgz",
"integrity": "sha512-0Q8NOMpXJ3iTDDbUv9grcmQAfdDx4qz+fN/+Md2FGbevT+6+bJNQ2LjB2YIUlLbpBTM32idU1Sb+tb/uGt6/XQ==",
"version": "7.5.2",
"resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.5.2.tgz",
"integrity": "sha512-Xpu7Bf5Vlw+G7ikA2Lg/lVCRTSY8D5M5qFUgGNFyS4pa8ufGLyCBxIX/3if3krHlF1SKSfVPI/YsAWLDVEbocw==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/csstools"
@@ -6460,14 +6447,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/defined": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz",
"integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -6535,22 +6514,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/detective": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
"integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
"dependencies": {
"acorn-node": "^1.8.2",
"defined": "^1.0.0",
"minimist": "^1.2.6"
},
"bin": {
"detective": "bin/detective.js"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/dexie": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/dexie/-/dexie-3.2.3.tgz",
@@ -6604,9 +6567,9 @@
"integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg=="
},
"node_modules/dns-packet": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz",
"integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==",
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.5.0.tgz",
"integrity": "sha512-USawdAUzRkV6xrqTjiAEp6M9YagZEzWcSUaZTcIFAiyQWW1SoI6KyId8y2+/71wbgHKQAKd+iupLv4YvEwYWvA==",
"dependencies": {
"@leichtgewicht/ip-codec": "^2.0.1"
},
@@ -6759,9 +6722,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.4.333",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.333.tgz",
"integrity": "sha512-YyE8+GKyGtPEP1/kpvqsdhD6rA/TP1DUFDN4uiU/YI52NzDxmwHkEb3qjId8hLBa5siJvG0sfC3O66501jMruQ=="
"version": "1.4.347",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.347.tgz",
"integrity": "sha512-LNi3+/9nV0vT6Bz1OsSoZ/w7IgNuWdefZ7mjKNjZxyRlI/ag6uMXxsxAy5Etvuixq3Q26exw2fc4bNYvYQqXSw=="
},
"node_modules/emittery": {
"version": "0.8.1",
@@ -7046,14 +7009,14 @@
}
},
"node_modules/eslint": {
"version": "8.36.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz",
"integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==",
"version": "8.37.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz",
"integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.1",
"@eslint/js": "8.36.0",
"@eslint/eslintrc": "^2.0.2",
"@eslint/js": "8.37.0",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -7064,8 +7027,8 @@
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.1.1",
"eslint-visitor-keys": "^3.3.0",
"espree": "^9.5.0",
"eslint-visitor-keys": "^3.4.0",
"espree": "^9.5.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@@ -7404,11 +7367,14 @@
}
},
"node_modules/eslint-visitor-keys": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
"integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-webpack-plugin": {
@@ -7624,13 +7590,13 @@
}
},
"node_modules/espree": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz",
"integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==",
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
"integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==",
"dependencies": {
"acorn": "^8.8.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.3.0"
"eslint-visitor-keys": "^3.4.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -8978,9 +8944,9 @@
}
},
"node_modules/immer": {
"version": "9.0.19",
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz",
"integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==",
"version": "9.0.21",
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
"integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
@@ -11139,9 +11105,9 @@
}
},
"node_modules/jest-watch-typeahead/node_modules/@types/yargs": {
"version": "17.0.22",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz",
"integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==",
"version": "17.0.24",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
"integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
"dependencies": {
"@types/yargs-parser": "*"
}
@@ -11513,15 +11479,23 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/jiti": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
"integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
"bin": {
"jiti": "bin/jiti.js"
}
},
"node_modules/js-base64": {
"version": "3.7.5",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz",
"integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA=="
},
"node_modules/js-sdsl": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
"integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz",
"integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/js-sdsl"
@@ -12114,10 +12088,26 @@
"multicast-dns": "cli.js"
}
},
"node_modules/mz": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
"dependencies": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
"thenify-all": "^1.0.0"
}
},
"node_modules/nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -14384,11 +14374,11 @@
}
},
"node_modules/react-router": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.9.0.tgz",
"integrity": "sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==",
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz",
"integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==",
"dependencies": {
"@remix-run/router": "1.4.0"
"@remix-run/router": "1.5.0"
},
"engines": {
"node": ">=14"
@@ -14398,12 +14388,12 @@
}
},
"node_modules/react-router-dom": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.9.0.tgz",
"integrity": "sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==",
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz",
"integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==",
"dependencies": {
"@remix-run/router": "1.4.0",
"react-router": "6.9.0"
"@remix-run/router": "1.5.0",
"react-router": "6.10.0"
},
"engines": {
"node": ">=14"
@@ -15648,6 +15638,53 @@
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz",
"integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA=="
},
"node_modules/sucrase": {
"version": "3.31.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.31.0.tgz",
"integrity": "sha512-6QsHnkqyVEzYcaiHsOKkzOtOgdJcb8i54x6AV2hDwyZcY9ZyykGZVw6L/YN98xC0evwTP6utsWWrKRaa8QlfEQ==",
"dependencies": {
"commander": "^4.0.0",
"glob": "7.1.6",
"lines-and-columns": "^1.1.6",
"mz": "^2.7.0",
"pirates": "^4.0.1",
"ts-interface-checker": "^0.1.9"
},
"bin": {
"sucrase": "bin/sucrase",
"sucrase-node": "bin/sucrase-node"
},
"engines": {
"node": ">=8"
}
},
"node_modules/sucrase/node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
"engines": {
"node": ">= 6"
}
},
"node_modules/sucrase/node_modules/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -15792,19 +15829,19 @@
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
},
"node_modules/tailwindcss": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.7.tgz",
"integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz",
"integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==",
"dependencies": {
"arg": "^5.0.2",
"chokidar": "^3.5.3",
"color-name": "^1.1.4",
"detective": "^5.2.1",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
"fast-glob": "^3.2.12",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
"jiti": "^1.17.2",
"lilconfig": "^2.0.6",
"micromatch": "^4.0.5",
"normalize-path": "^3.0.0",
@@ -15818,7 +15855,8 @@
"postcss-selector-parser": "^6.0.11",
"postcss-value-parser": "^4.2.0",
"quick-lru": "^5.1.1",
"resolve": "^1.22.1"
"resolve": "^1.22.1",
"sucrase": "^3.29.0"
},
"bin": {
"tailwind": "lib/cli.js",
@@ -15896,9 +15934,9 @@
}
},
"node_modules/terser": {
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.6.tgz",
"integrity": "sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg==",
"version": "5.16.8",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.8.tgz",
"integrity": "sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==",
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
@@ -15968,6 +16006,25 @@
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="
},
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
"dependencies": {
"any-promise": "^1.0.0"
}
},
"node_modules/thenify-all": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
"dependencies": {
"thenify": ">= 3.1.0 < 4"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/throat": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz",
@@ -16050,6 +16107,11 @@
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
"integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA=="
},
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
},
"node_modules/tsconfig-paths": {
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
@@ -16447,9 +16509,9 @@
}
},
"node_modules/webpack": {
"version": "5.76.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz",
"integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==",
"version": "5.77.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz",
"integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==",
"dependencies": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51",
@@ -16564,9 +16626,9 @@
}
},
"node_modules/webpack-dev-server": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.0.tgz",
"integrity": "sha512-1objTjwG2IaLNz0RjRQd41PjWOxHPc4I+1al4kmZu8J2nWcZcu1N1zlEWIJXTiYIkzhQ1RTrwjX4elnL+2e2GA==",
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.1.tgz",
"integrity": "sha512-5tWg00bnWbYgkN+pd5yISQKDejRBYGEw15RaEEslH+zdbNDxxaZvEAO2WulaSaFKb5n3YG8JXsGaDsut1D0xdA==",
"dependencies": {
"@types/bonjour": "^3.5.9",
"@types/connect-history-api-fallback": "^1.3.5",
@@ -16613,6 +16675,9 @@
"webpack": "^4.37.0 || ^5.0.0"
},
"peerDependenciesMeta": {
"webpack": {
"optional": true
},
"webpack-cli": {
"optional": true
}
@@ -17275,14 +17340,6 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"engines": {
"node": ">=0.4"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@@ -214,8 +214,8 @@
"account_delete_description": "احذف حسابك نهائيا",
"account_delete_dialog_label": "كلمة المرور",
"account_upgrade_dialog_title": "تغيير فئة الحساب",
"account_upgrade_dialog_tier_features_messages": "{{messages}} رسائل يومية",
"account_upgrade_dialog_tier_features_emails": "{{emails}} من رسائل البريد الإلكتروني اليومية",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} رسائل يومية",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} من رسائل البريد الإلكتروني اليومية",
"account_upgrade_dialog_button_cancel": "إلغاء",
"account_upgrade_dialog_button_pay_now": "ادفع الآن واشترك",
"account_upgrade_dialog_button_cancel_subscription": "إلغاء الاشتراك",
@@ -314,7 +314,7 @@
"publish_dialog_progress_uploading_detail": "تحميل {{loaded}}/{{total}} ({{percent}}٪) …",
"account_basics_tier_interval_monthly": "شهريا",
"account_basics_tier_interval_yearly": "سنويا",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} مواضيع محجوزة",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} مواضيع محجوزة",
"account_upgrade_dialog_billing_contact_website": "للأسئلة المتعلقة بالفوترة، يرجى الرجوع إلى <Link>موقعنا على الويب</Link>.",
"prefs_notifications_min_priority_description_x_or_higher": "إظهار الإشعارات إذا كانت الأولوية {{number}} ({{name}}) أو أعلى",
"account_upgrade_dialog_billing_contact_email": "للأسئلة المتعلقة بالفوترة، الرجاء <Link>الاتصال بنا</Link> مباشرة.",

View File

@@ -252,7 +252,7 @@
"account_usage_attachment_storage_title": "Хранилище за прикачени файлове",
"account_delete_dialog_button_cancel": "Отказ",
"account_upgrade_dialog_interval_monthly": "Месечно",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} резервирани теми",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} резервирани теми",
"account_upgrade_dialog_tier_features_no_reservations": "Няма резервирани теми",
"account_tokens_dialog_button_cancel": "Отказ",
"account_delete_title": "Премахване на профила",
@@ -260,5 +260,23 @@
"account_usage_emails_title": "Изпратени съобщения",
"account_usage_reservations_title": "Резервирани теми",
"account_usage_reservations_none": "Няма резервирани теми",
"account_usage_cannot_create_portal_session": "Порталът за разплащане не може да бъде отворен"
"account_usage_cannot_create_portal_session": "Порталът за разплащане не може да бъде отворен",
"account_upgrade_dialog_interval_yearly": "Годишно",
"account_delete_description": "Безвъзвратно премахване на профила",
"account_delete_dialog_button_submit": "Безвъзвратно премахване на профила",
"account_upgrade_dialog_interval_yearly_discount_save": "отстъпка {{discount}}%",
"account_upgrade_dialog_button_cancel": "Отказ",
"account_upgrade_dialog_button_redirect_signup": "Регистриране",
"account_tokens_table_label_header": "Етикет",
"prefs_reservations_edit_button": "Настройки на достъпа",
"prefs_reservations_table_topic_header": "Тема",
"prefs_reservations_table_access_header": "Достъп",
"prefs_reservations_dialog_topic_label": "Тема",
"prefs_reservations_dialog_access_label": "Достъп",
"account_basics_password_dialog_current_password_incorrect": "Грешна парола",
"account_basics_tier_description": "Ниво на профила",
"account_basics_tier_upgrade_button": "Надграждане до Pro",
"account_usage_messages_title": "Публикувани съобщения",
"account_tokens_table_last_access_header": "Последен достъп",
"account_basics_tier_payment_overdue": "Имате просрочено задължение. Обновете начина на плащане, защото в противен случай скоро профилът ви ще загуби предимствата на абонамента."
}

View File

@@ -287,9 +287,9 @@
"account_upgrade_dialog_title": "Změna úrovně účtu",
"account_upgrade_dialog_proration_info": "<strong>Prohlášení</strong>: Při přechodu mezi placenými úrovněmi bude rozdíl v ceně <strong>zaúčtován okamžitě</strong>. Při přechodu na nižší úroveň se zůstatek použije na platbu za budoucí zúčtovací období.",
"account_upgrade_dialog_reservations_warning_one": "Vybraná úroveň umožňuje méně rezervovaných témat než vaše aktuální úroveň. Než změníte svou úroveň, <strong>odstraňte alespoň jednu rezervaci</strong>. Rezervace můžete odstranit v <Link>Nastavení</Link>.",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} rezervovaných témat",
"account_upgrade_dialog_tier_features_messages": "{{messages}} denních zpráv",
"account_upgrade_dialog_tier_features_emails": "{{emails}} denních e-mailů",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} rezervovaných témat",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} denních zpráv",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} denních e-mailů",
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} na soubor",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} celkový úložný prostor",
"account_upgrade_dialog_tier_selected_label": "Vybráno",

View File

@@ -201,18 +201,18 @@
"account_basics_password_dialog_current_password_label": "Nuværende kodeord",
"account_basics_password_dialog_new_password_label": "Nyt kodeord",
"notifications_loading": "Indlæser notifikationer…",
"account_upgrade_dialog_tier_features_emails": "{{emails}} daglige e-mails",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} daglige e-mails",
"account_tokens_table_create_token_button": "Opret adgangstoken",
"account_tokens_dialog_title_delete": "Slet adgangstoken",
"publish_dialog_chip_email_label": "Videresend til e-mail",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} samlet lagerplads",
"subscribe_dialog_subscribe_use_another_label": "Brug en anden server",
"account_basics_tier_upgrade_button": "Opgrader til Pro",
"account_upgrade_dialog_tier_features_messages": "{{messages}} daglige beskeder",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} daglige beskeder",
"account_tokens_table_copy_to_clipboard": "Kopier til udklipsholder",
"prefs_reservations_edit_button": "Rediger emneadgang",
"account_upgrade_dialog_title": "Skift kontoniveau",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} reserverede emner",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} reserverede emner",
"account_tokens_dialog_expires_never": "Token udløber aldrig",
"account_tokens_table_current_session": "Nuværende browsersession",
"account_tokens_dialog_title_edit": "Rediger adgangstoken",

View File

@@ -264,9 +264,9 @@
"account_upgrade_dialog_proration_info": "<strong>Anrechnung</strong>: Wenn Du auf einen höheren kostenpflichtigen Level wechselst wird die Differenz <strong>sofort berechnet</strong>. Beim Wechsel auf ein kleineres Level verwenden wir Dein Guthaben für zukünftige Abrechnungsperioden.",
"account_upgrade_dialog_reservations_warning_one": "Das gewählte Level erlaubt weniger reservierte Themen als Dein aktueller Level. <strong>Bitte löschen vor dem Wechsel Deines Levels mindestens eine Reservierung</strong>. Du kannst Reservierungen in den <Link>Einstellungen</Link> löschen.",
"account_upgrade_dialog_reservations_warning_other": "Das gewählte Level erlaubt weniger reservierte Themen als Dein aktueller Level. <strong>Bitte löschen vor dem Wechsel Deines Levels mindestens {{count}} Reservierungen</strong>. Du kannst Reservierungen in den <Link>Einstellungen</Link> löschen.",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} reservierte Themen",
"account_upgrade_dialog_tier_features_messages": "{{messages}} Nachrichten pro Tag",
"account_upgrade_dialog_tier_features_emails": "{{emails}} Emails pro Tag",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} reservierte Themen",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} Nachrichten pro Tag",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} Emails pro Tag",
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} pro Datei",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} gesamter Speicherplatz",
"account_upgrade_dialog_tier_selected_label": "Ausgewählt",

View File

@@ -225,10 +225,13 @@
"account_upgrade_dialog_proration_info": "<strong>Proration</strong>: When upgrading between paid plans, the price difference will be <strong>charged immediately</strong>. When downgrading to a lower tier, the balance will be used to pay for future billing periods.",
"account_upgrade_dialog_reservations_warning_one": "The selected tier allows fewer reserved topics than your current tier. Before changing your tier, <strong>please delete at least one reservation</strong>. You can remove reservations in the <Link>Settings</Link>.",
"account_upgrade_dialog_reservations_warning_other": "The selected tier allows fewer reserved topics than your current tier. Before changing your tier, <strong>please delete at least {{count}} reservations</strong>. You can remove reservations in the <Link>Settings</Link>.",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} reserved topics",
"account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} reserved topic",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} reserved topics",
"account_upgrade_dialog_tier_features_no_reservations": "No reserved topics",
"account_upgrade_dialog_tier_features_messages": "{{messages}} daily messages",
"account_upgrade_dialog_tier_features_emails": "{{emails}} daily emails",
"account_upgrade_dialog_tier_features_messages_one": "{{messages}} daily message",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} daily messages",
"account_upgrade_dialog_tier_features_emails_one": "{{emails}} daily email",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} daily emails",
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} per file",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} total storage",
"account_upgrade_dialog_tier_price_per_month": "month",

View File

@@ -291,12 +291,12 @@
"account_delete_dialog_description": "Esto borrará permanentemente su cuenta, incluyendo todos los datos almacenados en el servidor. Tras la eliminación, su nombre de usuario no estará disponible durante 7 días. Si realmente desea continuar, por favor confirme su contraseña en la casilla de abajo.",
"account_delete_dialog_label": "Contraseña",
"account_delete_dialog_button_submit": "Eliminar permanentemente la cuenta",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} tópicos reservados",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} tópicos reservados",
"account_upgrade_dialog_cancel_warning": "Esto <strong>cancelará su suscripción</strong> y degradará su cuenta en {{date}}. En esa fecha, sus tópicos reservados y sus mensajes almacenados en caché en el servidor <strong>serán eliminados</strong>.",
"account_upgrade_dialog_proration_info": "<strong>Prorrateo</strong>: al actualizar entre planes pagos, la diferencia de precio se <strong>cobrará de inmediato</strong>. Al cambiar a un nivel inferior, el saldo se utilizará para pagar futuros períodos de facturación.",
"account_upgrade_dialog_reservations_warning_other": "El nivel seleccionado permite menos tópicos reservados que su nivel actual. Antes de cambiar de nivel, <strong>por favor elimine al menos {{count}} reservaciones</strong>. Puede eliminar reservaciones en <Link>Configuración</Link>.",
"account_upgrade_dialog_tier_features_messages": "{{messages}} mensajes diarios",
"account_upgrade_dialog_tier_features_emails": "{{emails}} correos diarios",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} mensajes diarios",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} correos diarios",
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} por archivo",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} almacenamiento total",
"account_upgrade_dialog_tier_current_label": "Actual",

View File

@@ -274,9 +274,9 @@
"account_upgrade_dialog_title": "Changer le tarif du compte",
"account_upgrade_dialog_proration_info": "<strong>Facturation</strong> : Lors d'un changement entre un plan payant et un autre, la différence de prix sera créditée ou remboursée sur la prochaine facture. Vous ne recevrez pas d'autre facture avant la fin de la prochaine période de facturation.",
"account_upgrade_dialog_reservations_warning_other": "Le tarif sélectionné autorise moins de sujets réservés que votre tarif actuel. Avant de changer de tarif, <strong>veuillez supprimer au moins {{count}} sujets réservés</strong>. Vous pouvez supprimer des sujets réservés dans les <Link>Paramètres</Link>.",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} sujets réservés",
"account_upgrade_dialog_tier_features_messages": "{{messages}} messages journaliers",
"account_upgrade_dialog_tier_features_emails": "{{emails}} emails journaliers",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} sujets réservés",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} messages journaliers",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} emails journaliers",
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} par fichier",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} stockage total",
"account_upgrade_dialog_tier_selected_label": "Sélectionné",

View File

@@ -258,9 +258,9 @@
"account_upgrade_dialog_title": "Ubah peringkat akun",
"account_upgrade_dialog_proration_info": "<strong>Prorasi</strong>: Saat melakukan upgrade antar paket berbayar, selisih harga akan <strong>langsung dibebankan ke</strong>. Saat menurunkan ke tingkat yang lebih rendah, saldo akan digunakan untuk membayar periode penagihan di masa mendatang.",
"account_upgrade_dialog_reservations_warning_other": "Peringkat yang dipilih memperbolehkan lebih sedikit reservasi topik daripada peringkat Anda saat ini. Sebelum mengubah peringkat Anda, <strong>silakan menghapus setidaknya {{count}} reservasi</strong>. Anda dapat menghapus reservasi di <Link>Pengaturan</Link>.",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} topik yang telah direservasi",
"account_upgrade_dialog_tier_features_messages": "{{messages}} pesan harian",
"account_upgrade_dialog_tier_features_emails": "{{emails}} surel harian",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} topik yang telah direservasi",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} pesan harian",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} surel harian",
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} per berkas",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} jumlah penyimpanan",
"account_upgrade_dialog_tier_selected_label": "Dipilih",

View File

@@ -187,5 +187,74 @@
"prefs_notifications_delete_after_one_week": "Dopo una settimana",
"prefs_notifications_delete_after_one_month": "Dopo un mese",
"prefs_notifications_delete_after_three_hours_description": "Le notifiche vengono eliminate automaticamente dopo tre ore",
"error_boundary_unsupported_indexeddb_description": "L'app web ntfy ha bisogno di IndexedDB per funzionare e il tuo browser non supporta IndexedDB in modalità di navigazione privata.<br/><br/>Anche se questo è un peccato, non ha molto senso usare il web ntfy app in modalità di navigazione privata comunque, perché tutto è archiviato nella memoria del browser. Puoi leggere di più a riguardo <githubLink>in questo numero di GitHub</githubLink> o parlarci su <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink>."
"error_boundary_unsupported_indexeddb_description": "L'app web ntfy ha bisogno di IndexedDB per funzionare e il tuo browser non supporta IndexedDB in modalità di navigazione privata.<br/><br/>Anche se questo è un peccato, non ha molto senso usare il web ntfy app in modalità di navigazione privata comunque, perché tutto è archiviato nella memoria del browser. Puoi leggere di più a riguardo <githubLink>in questo numero di GitHub</githubLink> o parlarci su <discordLink>Discord</discordLink> o <matrixLink>Matrix</matrixLink>.",
"nav_upgrade_banner_label": "Passa alla versione Pro di ntfy",
"alert_not_supported_context_description": "Le Notificche sono supportate solo tramite HTTPS. Questa è una limitazione delle <mdnLink>Notifications API</mdnLink>.",
"account_basics_password_dialog_new_password_label": "Nuova password",
"action_bar_profile_logout": "Esci",
"account_basics_tier_interval_monthly": "mensile",
"account_basics_tier_interval_yearly": "annuale",
"account_basics_tier_upgrade_button": "Passa alla versione Pro",
"account_basics_tier_change_button": "Cambia",
"account_basics_tier_paid_until": "Abbonamento pagato fino a {{data}}, e si rinnoverà automaticamente",
"account_basics_tier_payment_overdue": "Il pagamento è scaduto. La preghiamo di aggiornare il suo metodo di pagamento, altrimenti il suo account verrà presto declassato.",
"account_basics_tier_canceled_subscription": "L'abbonamento è stato annullato e sarà declassato ad account gratuito a partire dalla {{data}}.",
"account_basics_tier_manage_billing_button": "Gestire la fatturazione",
"account_usage_messages_title": "Messaggi pubblicati",
"account_usage_reservations_title": "Argomenti riservati",
"account_usage_reservations_none": "Non ci sono argomenti riservati per questo account",
"signup_form_toggle_password_visibility": "Imposta la visibilità della password",
"signup_already_have_account": "Hai già un account? Accedi!",
"signup_disabled": "Registrazione disabilitata",
"signup_title": "Crea un account ntfy",
"signup_form_username": "Nome utente",
"signup_form_password": "Password",
"signup_form_confirm_password": "Conferma password",
"signup_form_button_submit": "Registrazione",
"signup_error_username_taken": "Il nome utente {{username}} è già utilizzato",
"signup_error_creation_limit_reached": "Il limite per la creazione di account è stato raggiunto",
"login_title": "Accedi al tuo account ntfy",
"login_form_button_submit": "Accedi",
"login_link_signup": "Registrati",
"login_disabled": "L'accesso è disabilitato",
"action_bar_account": "Account",
"action_bar_change_display_name": "Cambia il nome da visualizzare",
"action_bar_reservation_limit_reached": "Limite raggiunto",
"action_bar_profile_title": "Profilo",
"action_bar_profile_settings": "Impostazioni",
"action_bar_reservation_add": "Riserva un argomento",
"action_bar_reservation_edit": "Modifica l'argomento riservato",
"action_bar_reservation_delete": "Rimuovi l'argomento riservato",
"action_bar_sign_in": "Accedi",
"action_bar_sign_up": "Registrati",
"nav_button_account": "Account",
"nav_upgrade_banner_description": "Riserva argomenti, più messaggi ed e-mail e allegati più grandi",
"display_name_dialog_description": "Imposta un nome alternativo per un argomento che viene visualizzato nell'elenco delle sottoscrizioni. Questo aiuta a identificare più facilmente gli argomenti con nomi complicati.",
"display_name_dialog_title": "Cambia il nome visualizzato",
"display_name_dialog_placeholder": "Nome visualizzato",
"reserve_dialog_checkbox_label": "Riserva un argomento e configura l'accesso",
"subscribe_dialog_subscribe_button_generate_topic_name": "Genera un nome",
"subscribe_dialog_error_topic_already_reserved": "Argomento già in uso",
"account_basics_title": "Account",
"account_basics_username_title": "Nome utente",
"account_basics_username_admin_tooltip": "Sei Amministratore",
"account_basics_password_title": "Password",
"account_basics_password_description": "Cambia la password del tuo account",
"account_basics_password_dialog_title": "Cambia la password",
"account_basics_password_dialog_current_password_label": "Password attuale",
"account_basics_password_dialog_confirm_password_label": "Conferma la password",
"account_basics_password_dialog_button_submit": "Cambia la password",
"account_basics_password_dialog_current_password_incorrect": "Password errata",
"account_usage_title": "Utilizzo",
"account_usage_of_limit": "di {{limit}}",
"account_usage_unlimited": "Illimitato",
"account_usage_limits_reset_daily": "I limiti di utilizzo vengono azzerati ogni giorno a mezzanotte (orario UTC)",
"account_basics_tier_title": "Tipo di account",
"account_basics_tier_description": "Permessi del tuo account",
"account_basics_tier_admin": "Amministratore",
"account_basics_tier_admin_suffix_with_tier": "(con livello {{tier}})",
"account_basics_tier_admin_suffix_no_tier": "(nessun livello)",
"account_basics_tier_basic": "Base",
"account_basics_tier_free": "Gratuito",
"account_usage_emails_title": "Email inviate"
}

View File

@@ -241,9 +241,9 @@
"account_upgrade_dialog_title": "アカウントティアを変更",
"account_upgrade_dialog_cancel_warning": "これにより<strong>サブスクリプションをキャンセルし</strong>{{date}}にアカウントをダウングレードします。同日、トピック予約およびサーバーにキャッシュされたメッセージは<strong>削除されます</strong>。",
"account_upgrade_dialog_proration_info": "<strong>追記</strong>。有料プランをアップグレードする場合、価格差は<strong>即座に請求されます</strong>。ダウングレードする場合、差額は次の請求期間の支払いに利用されます。",
"account_upgrade_dialog_tier_features_reservations": "予約のトピック{{reservations}}件",
"account_upgrade_dialog_tier_features_emails": "日次メール{{emails}}件",
"account_upgrade_dialog_tier_features_messages": "日次メッセージ{{messages}}件",
"account_upgrade_dialog_tier_features_reservations_other": "予約のトピック{{reservations}}件",
"account_upgrade_dialog_tier_features_emails_other": "日次メール{{emails}}件",
"account_upgrade_dialog_tier_features_messages_other": "日次メッセージ{{messages}}件",
"account_upgrade_dialog_tier_selected_label": "選択",
"account_upgrade_dialog_tier_current_label": "現在",
"account_upgrade_dialog_button_cancel": "キャンセル",

View File

@@ -308,5 +308,14 @@
"account_upgrade_dialog_button_pay_now": "Zapłać i aktywuj subskrypcję",
"account_tokens_dialog_button_cancel": "Anuluj",
"account_tokens_dialog_expires_label": "Token dostępowy wygasa po",
"account_tokens_dialog_expires_unchanged": "Pozostaw termin ważności bez zmian"
"account_tokens_dialog_expires_unchanged": "Pozostaw termin ważności bez zmian",
"account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} rezerwacja tematu",
"account_upgrade_dialog_tier_features_reservations_few": "{{reservations}} rezerwacje tematów",
"account_upgrade_dialog_tier_features_reservations_many": "{{reservations}} rezerwacji tematów",
"account_upgrade_dialog_tier_features_emails_one": "{{emails}} mail dziennie",
"account_upgrade_dialog_tier_features_emails_few": "{{emails}} maile dziennie",
"account_upgrade_dialog_tier_features_emails_many": "{{emails}} maili dziennie",
"account_upgrade_dialog_tier_features_messages_one": "{{messages}} wiadomość dziennie",
"account_upgrade_dialog_tier_features_messages_few": "{{messages}} wiadomości dziennie",
"account_upgrade_dialog_tier_features_messages_many": "{{messages}} wiadomości dziennie"
}

View File

@@ -31,7 +31,7 @@
"notifications_attachment_copy_url_title": "Copiar URL do anexo para a área de transferência",
"notifications_attachment_copy_url_button": "Copiar URL",
"notifications_attachment_open_title": "Ir para {{url}}",
"notifications_attachment_link_expired": "a ligação de transferência expirou",
"notifications_attachment_link_expired": "a ligação de descarga expirou",
"notifications_attachment_open_button": "Abrir anexo",
"notifications_attachment_link_expires": "a ligação expira em {{date}}",
"notifications_attachment_file_image": "ficheiro de imagem",

View File

@@ -1,5 +1,5 @@
{
"publish_dialog_priority_min": "Наименьший приоритет",
"publish_dialog_priority_min": "Минимальный приоритет",
"action_bar_settings": "Настройки",
"action_bar_send_test_notification": "Отправить тестовое уведомление",
"action_bar_clear_notifications": "Удалить все уведомления",
@@ -24,7 +24,7 @@
"publish_dialog_priority_low": "Низкий приоритет",
"publish_dialog_priority_default": "Стандартный приоритет",
"publish_dialog_priority_high": "Высокий приоритет",
"publish_dialog_priority_max": "Наивысший приоритет",
"publish_dialog_priority_max": "Максимальный приоритет",
"publish_dialog_base_url_label": "URL-адрес сервиса",
"publish_dialog_base_url_placeholder": "URL-адрес сервиса, например https://example.com",
"publish_dialog_topic_label": "Название темы",
@@ -106,13 +106,13 @@
"prefs_notifications_sound_title": "Звук уведомления",
"prefs_notifications_sound_description_none": "Уведомления не воспроизводят никаких звуков при получении",
"prefs_notifications_sound_no_sound": "Без звука",
"prefs_notifications_min_priority_title": "Наименьший приоритет",
"prefs_notifications_min_priority_description_any": "Показать все уведомления, независимо от приоритета",
"prefs_notifications_min_priority_title": "Минимальный приоритет",
"prefs_notifications_min_priority_description_any": "Показывать все уведомления, независимо от приоритета",
"prefs_notifications_min_priority_description_x_or_higher": "Показывать уведомления, если приоритет {{number}} ({{name}}) или выше",
"prefs_notifications_min_priority_description_max": "Показывать уведомления, если приоритет равен 5 (наивысший)",
"prefs_notifications_min_priority_description_max": "Показывать уведомления, если приоритет равен 5 (максимальный)",
"prefs_notifications_min_priority_any": "Любой приоритет",
"prefs_notifications_min_priority_low_and_higher": "Низкий приоритет и выше",
"prefs_notifications_min_priority_max_only": "Только наивысший приоритет",
"prefs_notifications_min_priority_max_only": "Только максимальный приоритет",
"prefs_notifications_delete_after_title": "Удалить уведомления",
"prefs_notifications_delete_after_never": "Никогда",
"prefs_notifications_delete_after_three_hours": "Через три часа",
@@ -140,11 +140,11 @@
"common_save": "Сохранить",
"prefs_appearance_title": "Внешний вид",
"prefs_appearance_language_title": "Язык",
"priority_min": "наименьший",
"priority_min": "минимальный",
"priority_low": "низкий",
"priority_default": "стандартный",
"priority_high": "высокий",
"priority_max": "наивысший",
"priority_max": "максимальный",
"error_boundary_title": "О нет, ntfy сломался",
"error_boundary_button_copy_stack_trace": "Скопировать трассировку стека",
"error_boundary_stack_trace": "Трассировка стека",
@@ -192,7 +192,7 @@
"account_tokens_dialog_button_create": "Создать токен",
"account_tokens_delete_dialog_submit_button": "Безвозвратно удалить токен",
"account_upgrade_dialog_reservations_warning_other": "Выбранная подписка разрешает меньше зарезервированных тем, чем есть у Вас на данный момент. Перед сменой подписки, <strong>пожалуйста удалите хотя бы {{count}} зарезервированных тем</strong>. Вы можете это сделать в <Link>Настройках</Link>.",
"account_upgrade_dialog_tier_features_messages": "{{messages}} сообщений в день",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} сообщений в день",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} суммарный объем",
"account_upgrade_dialog_tier_selected_label": "Выбранная",
"account_tokens_table_current_session": "Текущий сеанс браузера",
@@ -201,8 +201,8 @@
"account_tokens_dialog_expires_x_hours": "Токен истекает через {{hours}} часов",
"account_tokens_dialog_expires_never": "Токен никогда не истекает",
"prefs_notifications_sound_play": "Воспроизводить выбранный звук",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} зарезервированных тем",
"account_upgrade_dialog_tier_features_emails": "{{emails}} эл. сообщений в день",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} зарезервированных тем",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} эл. сообщений в день",
"account_basics_tier_free": "Бесплатный",
"account_tokens_dialog_title_create": "Создать токен доступа",
"account_tokens_dialog_title_delete": "Удалить токен доступа",
@@ -303,7 +303,7 @@
"account_usage_reservations_title": "Зарезервированные темы",
"account_usage_reservations_none": "Нет зарезервированных тем",
"account_usage_attachment_storage_title": "Хранение вложений",
"account_usage_attachment_storage_description": "{{filesize}} за файл, удаляются после {{expiry}}",
"account_usage_attachment_storage_description": "{{filesize}} за файл, удаляются спустя {{expiry}}",
"account_usage_cannot_create_portal_session": "Невозможно открыть портал оплаты",
"account_delete_title": "Удалить учетную запись",
"account_delete_description": "Безвозвратно удалить Вашу учетную запись",

View File

@@ -253,9 +253,9 @@
"account_upgrade_dialog_title": "Hesap seviyesini değiştir",
"account_upgrade_dialog_proration_info": "<strong>Fiyatlandırma</strong>: Ücretli planlar arasında yükseltme yaparken, fiyat farkı <strong>hemen tahsil edilecektir</strong>. Daha düşük bir seviyeye inildiğinde, bakiye gelecek faturalandırma dönemleri için ödeme yapmak üzere kullanılacaktır.",
"account_upgrade_dialog_reservations_warning_other": "Seçilen seviye, geçerli seviyenizden daha az konu ayırtmaya izin veriyor. Seviyenizi değiştirmeden önce <strong>lütfen en az {{count}} ayırtmayı silin</strong>. Ayırtmaları <Link>Ayarlar</Link> sayfasından kaldırabilirsiniz.",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} konu ayırtıldı",
"account_upgrade_dialog_tier_features_messages": "{{messages}} günlük mesaj",
"account_upgrade_dialog_tier_features_emails": "{{emails}} günlük e-posta",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} konu ayırtıldı",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} günlük mesaj",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} günlük e-posta",
"account_upgrade_dialog_tier_features_attachment_file_size": "dosya başına {{filesize}}",
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} toplam depolama",
"account_upgrade_dialog_tier_selected_label": "Seçilen",

View File

@@ -293,12 +293,12 @@
"account_delete_dialog_billing_warning": "删除您的帐户也会立即取消您的计费订阅。您将无法再访问计费仪表板。",
"account_upgrade_dialog_title": "更改帐户等级",
"account_upgrade_dialog_cancel_warning": "这将<strong>取消您的订阅</strong>,并在 {{date}} 降级您的帐户。在那一天,主题保留以及缓存在服务器上的消息<strong>将被删除</strong>。",
"account_upgrade_dialog_proration_info": "<strong>按比例分配</strong>:在付费计划之间切换时,差价将在下一次计费时收取或退还。在下一个计费周期结束之前,您不会收到另一张收据。",
"account_upgrade_dialog_proration_info": "<strong>按比例分配</strong>:在付费计划之间升级时,差价将被<strong>立刻收取</strong>。在降级到较低级别时,余额将被用于支付未来的账单周期。",
"account_upgrade_dialog_reservations_warning_one": "所选等级允许的保留主题少于当前等级。在更改您的等级之前,<strong>请至少删除 1 项保留</strong>。您可以在<Link>设置</Link>中删除保留。",
"account_upgrade_dialog_reservations_warning_other": "所选等级允许的保留主题少于当前等级。在更改您的等级之前,<strong>请至少删除 {{count}} 项保留</strong>。您可以在<Link>设置</Link>中删除保留。",
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} 条保留主题",
"account_upgrade_dialog_tier_features_messages": "{{messages}} 条每日消息",
"account_upgrade_dialog_tier_features_emails": "{{emails}} 条每日邮件",
"account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} 条保留主题",
"account_upgrade_dialog_tier_features_messages_other": "{{messages}} 条每日消息",
"account_upgrade_dialog_tier_features_emails_other": "{{emails}} 条每日邮件",
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} 每个文件",
"signup_form_confirm_password": "确认密码",
"signup_form_button_submit": "注册",
@@ -340,5 +340,17 @@
"account_tokens_table_last_origin_tooltip": "于IP地址 {{ip}},点击查找",
"account_tokens_dialog_label": "标签例如Radarr 通知",
"account_tokens_dialog_button_create": "创建令牌",
"account_tokens_dialog_button_update": "更新令牌"
"account_tokens_dialog_button_update": "更新令牌",
"account_basics_tier_interval_monthly": "每月",
"account_basics_tier_interval_yearly": "每年",
"account_upgrade_dialog_interval_monthly": "每月",
"account_upgrade_dialog_interval_yearly": "每年",
"account_upgrade_dialog_interval_yearly_discount_save": "节省 {{discount}}%",
"account_upgrade_dialog_interval_yearly_discount_save_up_to": "节省高达 {{discount}}%",
"account_upgrade_dialog_tier_features_no_reservations": "无保留主题",
"account_upgrade_dialog_tier_price_per_month": "月",
"account_upgrade_dialog_tier_price_billed_monthly": "{{price}} 每年。按月计费。",
"account_upgrade_dialog_tier_price_billed_yearly": "{{价格}} 按年计费。节省 {{save}}。",
"account_upgrade_dialog_billing_contact_email": "有关账单问题,请直接<Link>联系我们 </Link>。",
"account_upgrade_dialog_billing_contact_website": "有关账单问题,请参考我们的<Link>网站 </Link>。"
}

View File

@@ -297,10 +297,10 @@ const TierCard = (props) => {
{monthlyPrice > 0 && <>/ {t("account_upgrade_dialog_tier_price_per_month")}</>}
</div>
<List dense>
{tier.limits.reservations > 0 && <Feature>{t("account_upgrade_dialog_tier_features_reservations", { reservations: tier.limits.reservations })}</Feature>}
{tier.limits.reservations > 0 && <Feature>{t("account_upgrade_dialog_tier_features_reservations", { reservations: tier.limits.reservations, count: tier.limits.reservations })}</Feature>}
{tier.limits.reservations === 0 && <NoFeature>{t("account_upgrade_dialog_tier_features_no_reservations")}</NoFeature>}
<Feature>{t("account_upgrade_dialog_tier_features_messages", { messages: formatNumber(tier.limits.messages) })}</Feature>
<Feature>{t("account_upgrade_dialog_tier_features_emails", { emails: formatNumber(tier.limits.emails) })}</Feature>
<Feature>{t("account_upgrade_dialog_tier_features_messages", { messages: formatNumber(tier.limits.messages), count: tier.limits.messages })}</Feature>
<Feature>{t("account_upgrade_dialog_tier_features_emails", { emails: formatNumber(tier.limits.emails), count: tier.limits.emails })}</Feature>
<Feature>{t("account_upgrade_dialog_tier_features_attachment_file_size", { filesize: formatBytes(tier.limits.attachment_file_size, 0) })}</Feature>
<Feature>{t("account_upgrade_dialog_tier_features_attachment_total_size", { totalsize: formatBytes(tier.limits.attachment_total_size, 0) })}</Feature>
</List>