mirror of
https://github.com/binwiederhier/ntfy.git
synced 2026-01-19 00:27:25 +01:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85fc16b016 | ||
|
|
5287fa1c94 | ||
|
|
1c54be3581 | ||
|
|
484fd91452 | ||
|
|
9ff3bb0c87 | ||
|
|
38e7801b41 | ||
|
|
7fb6f794e5 | ||
|
|
df68b0cb43 | ||
|
|
ca49fd1161 | ||
|
|
bb3f17ada2 | ||
|
|
d18c61f0da | ||
|
|
92cfc04024 | ||
|
|
2d0ce79011 | ||
|
|
c6e091a754 | ||
|
|
c8c16eb8e6 | ||
|
|
0e1082b09c | ||
|
|
c815b183d4 | ||
|
|
a95d1f9200 | ||
|
|
6451762508 |
@@ -13,11 +13,9 @@
|
||||
[](https://ntfy.statuspage.io/)
|
||||
[](https://gitpod.io/#https://github.com/binwiederhier/ntfy)
|
||||
|
||||
**ntfy** (pronounce: *notify*) is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) notification service.
|
||||
It allows you to **send notifications to your phone or desktop via scripts** from any computer, entirely **without signup or cost**.
|
||||
It's also open source (as you can plainly see) if you want to run your own.
|
||||
**ntfy** (pronounced "*notify*") is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) notification service. With ntfy, you can **send notifications to your phone or desktop via scripts** from any computer, **without having to sign up or pay any fees**. If you'd like to run your own instance of the service, you can easily do so since ntfy is open source.
|
||||
|
||||
I run a free version of it at **[ntfy.sh](https://ntfy.sh)**. There's also an [open source Android app](https://github.com/binwiederhier/ntfy-android) (see [Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) or [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/)), and an [open source iOS app](https://github.com/binwiederhier/ntfy-ios) (see [App Store](https://apps.apple.com/us/app/ntfy/id1625396347)).
|
||||
You can access the free version of ntfy at **[ntfy.sh](https://ntfy.sh)**. There is also an [open source Android app](https://github.com/binwiederhier/ntfy-android) available on [Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) or [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/), as well as an [open source iOS app](https://github.com/binwiederhier/ntfy-ios) available on the [App Store](https://apps.apple.com/us/app/ntfy/id1625396347).
|
||||
|
||||
<p>
|
||||
<img src="web/public/static/img/screenshot-curl.png" height="180">
|
||||
|
||||
@@ -1179,9 +1179,9 @@ variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
|
||||
| `visitor-request-limit-exempt-hosts` | `NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS` | *comma-separated host/IP list* | - | Rate limiting: List of hostnames and IPs to be exempt from request rate limiting |
|
||||
| `visitor-subscription-limit` | `NTFY_VISITOR_SUBSCRIPTION_LIMIT` | *number* | 30 | Rate limiting: Number of subscriptions per visitor (IP address) |
|
||||
| `web-root` | `NTFY_WEB_ROOT` | `app`, `home` or `disable` | `app` | Sets web root to landing page (home), web app (app) or disables the web app entirely (disable) |
|
||||
| `enable-signup` | `NTFY_SIGNUP` | *boolean* (`true` or `false`) | `false` | Allows users to sign up via the web app, or API |
|
||||
| `enable-login` | `NTFY_LOGIN` | *boolean* (`true` or `false`) | `false` | Allows users to log in via the web app, or API |
|
||||
| `enable-reservations` | `NTFY_RESERVATIONS` | *boolean* (`true` or `false`) | `false` | Allows users to reserve topics (if their tier allows it) |
|
||||
| `enable-signup` | `NTFY_ENABLE_SIGNUP` | *boolean* (`true` or `false`) | `false` | Allows users to sign up via the web app, or API |
|
||||
| `enable-login` | `NTFY_ENABLE_LOGIN` | *boolean* (`true` or `false`) | `false` | Allows users to log in via the web app, or API |
|
||||
| `enable-reservations` | `NTFY_ENABLE_RESERVATIONS` | *boolean* (`true` or `false`) | `false` | Allows users to reserve topics (if their tier allows it) |
|
||||
| `stripe-secret-key` | `NTFY_STRIPE_SECRET_KEY` | *string* | - | Payments: Key used for the Stripe API communication, this enables payments |
|
||||
| `stripe-webhook-key` | `NTFY_STRIPE_WEBHOOK_KEY` | *string* | - | Payments: Key required to validate the authenticity of incoming webhooks from Stripe |
|
||||
|
||||
|
||||
@@ -26,37 +26,37 @@ deb/rpm packages.
|
||||
|
||||
=== "x86_64/amd64"
|
||||
```bash
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.0/ntfy_2.0.0_linux_x86_64.tar.gz
|
||||
tar zxvf ntfy_2.0.0_linux_x86_64.tar.gz
|
||||
sudo cp -a ntfy_2.0.0_linux_x86_64/ntfy /usr/bin/ntfy
|
||||
sudo mkdir /etc/ntfy && sudo cp ntfy_2.0.0_linux_x86_64/{client,server}/*.yml /etc/ntfy
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.1_linux_x86_64.tar.gz
|
||||
tar zxvf ntfy_2.0.1_linux_x86_64.tar.gz
|
||||
sudo cp -a ntfy_2.0.1_linux_x86_64/ntfy /usr/bin/ntfy
|
||||
sudo mkdir /etc/ntfy && sudo cp ntfy_2.0.1_linux_x86_64/{client,server}/*.yml /etc/ntfy
|
||||
sudo ntfy serve
|
||||
```
|
||||
|
||||
=== "armv6"
|
||||
```bash
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.0/ntfy_2.0.0_linux_armv6.tar.gz
|
||||
tar zxvf ntfy_2.0.0_linux_armv6.tar.gz
|
||||
sudo cp -a ntfy_2.0.0_linux_armv6/ntfy /usr/bin/ntfy
|
||||
sudo mkdir /etc/ntfy && sudo cp ntfy_2.0.0_linux_armv6/{client,server}/*.yml /etc/ntfy
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.1_linux_armv6.tar.gz
|
||||
tar zxvf ntfy_2.0.1_linux_armv6.tar.gz
|
||||
sudo cp -a ntfy_2.0.1_linux_armv6/ntfy /usr/bin/ntfy
|
||||
sudo mkdir /etc/ntfy && sudo cp ntfy_2.0.1_linux_armv6/{client,server}/*.yml /etc/ntfy
|
||||
sudo ntfy serve
|
||||
```
|
||||
|
||||
=== "armv7/armhf"
|
||||
```bash
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.0/ntfy_2.0.0_linux_armv7.tar.gz
|
||||
tar zxvf ntfy_2.0.0_linux_armv7.tar.gz
|
||||
sudo cp -a ntfy_2.0.0_linux_armv7/ntfy /usr/bin/ntfy
|
||||
sudo mkdir /etc/ntfy && sudo cp ntfy_2.0.0_linux_armv7/{client,server}/*.yml /etc/ntfy
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.1_linux_armv7.tar.gz
|
||||
tar zxvf ntfy_2.0.1_linux_armv7.tar.gz
|
||||
sudo cp -a ntfy_2.0.1_linux_armv7/ntfy /usr/bin/ntfy
|
||||
sudo mkdir /etc/ntfy && sudo cp ntfy_2.0.1_linux_armv7/{client,server}/*.yml /etc/ntfy
|
||||
sudo ntfy serve
|
||||
```
|
||||
|
||||
=== "arm64"
|
||||
```bash
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.0/ntfy_2.0.0_linux_arm64.tar.gz
|
||||
tar zxvf ntfy_2.0.0_linux_arm64.tar.gz
|
||||
sudo cp -a ntfy_2.0.0_linux_arm64/ntfy /usr/bin/ntfy
|
||||
sudo mkdir /etc/ntfy && sudo cp ntfy_2.0.0_linux_arm64/{client,server}/*.yml /etc/ntfy
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.1_linux_arm64.tar.gz
|
||||
tar zxvf ntfy_2.0.1_linux_arm64.tar.gz
|
||||
sudo cp -a ntfy_2.0.1_linux_arm64/ntfy /usr/bin/ntfy
|
||||
sudo mkdir /etc/ntfy && sudo cp ntfy_2.0.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.0.0/ntfy_2.0.0_linux_amd64.deb
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_linux_armv6.deb
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_linux_armv7.deb
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_linux_arm64.deb
|
||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_linux_amd64.rpm
|
||||
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_linux_armv6.rpm
|
||||
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_linux_armv7.rpm
|
||||
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_linux_arm64.rpm
|
||||
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_macOS_all.tar.gz),
|
||||
To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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.0.0/ntfy_2.0.0_macOS_all.tar.gz > ntfy_2.0.0_macOS_all.tar.gz
|
||||
tar zxvf ntfy_2.0.0_macOS_all.tar.gz
|
||||
sudo cp -a ntfy_2.0.0_macOS_all/ntfy /usr/local/bin/ntfy
|
||||
curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.1_macOS_all.tar.gz > ntfy_2.0.1_macOS_all.tar.gz
|
||||
tar zxvf ntfy_2.0.1_macOS_all.tar.gz
|
||||
sudo cp -a ntfy_2.0.1_macOS_all/ntfy /usr/local/bin/ntfy
|
||||
mkdir ~/Library/Application\ Support/ntfy
|
||||
cp ntfy_2.0.0_macOS_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml
|
||||
cp ntfy_2.0.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.0.0/ntfy_2.0.0_windows_x86_64.zip),
|
||||
To install, please [download the latest ZIP](https://github.com/binwiederhier/ntfy/releases/download/v2.0.1/ntfy_2.0.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).
|
||||
|
||||
@@ -72,6 +72,7 @@ and uptime of third party servers, so use of each server is **at your own discre
|
||||
## Projects + scripts
|
||||
|
||||
- [Grafana-to-ntfy](https://github.com/kittyandrew/grafana-to-ntfy) - Grafana-to-ntfy alerts channel (Rust)
|
||||
- [Grafana-ntfy-webhook-integration](https://github.com/academo/grafana-alerting-ntfy-webhook-integration) - Integrates Grafana alerts webhooks (Go)
|
||||
- [ntfy-long-zsh-command](https://github.com/robfox92/ntfy-long-zsh-command) - Notifies you once a long-running command completes (zsh)
|
||||
- [ntfy-shellscripts](https://github.com/nickexyz/ntfy-shellscripts) - A few scripts for the ntfy project (Shell)
|
||||
- [QuickStatus](https://github.com/corneliusroot/QuickStatus) - A shell script to alert to any immediate problems upon login (Shell)
|
||||
@@ -114,6 +115,7 @@ and uptime of third party servers, so use of each server is **at your own discre
|
||||
## Blog + forum posts
|
||||
|
||||
- [Video: Simple Push Notifications ntfy](https://www.youtube.com/watch?v=u9EcWrsjE20) ⭐ - youtube.com - 2/2023
|
||||
- [Use ntfy.sh with Home Assistant](https://diecknet.de/en/2023/02/12/ntfy-sh-with-homeassistant/) - diecknet.de - 2/2023
|
||||
- [On installe Ntfy sur Synology Docker](https://www.maison-et-domotique.com/140356-serveur-notification-jeedom-ntfy-synology-docker/) - maison-et-domotique.co - 1/2023
|
||||
- [January 2023 Developer Update](https://community.nodebb.org/topic/16908/january-2023-developer-update) - nodebb.org - 1/2023
|
||||
- [Comment envoyer des notifications push sur votre téléphone facilement et gratuitement?](https://korben.info/notifications-push-telephone.html) - 1/2023
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
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.0.0 (UNRELEASED)
|
||||
## ntfy server v2.0.1
|
||||
Released February 17, 2023
|
||||
|
||||
This is a quick bugfix release to address a panic that happens when `attachment-cache-dir` is not set.
|
||||
|
||||
**Bug fixes + maintenance:**
|
||||
|
||||
* Avoid panic in manager when `attachment-cache-dir` is not set ([#617](https://github.com/binwiederhier/ntfy/issues/617), thanks to [@ksurl](https://github.com/ksurl))
|
||||
* Ensure that calls to standard logger `log.Println` also output JSON (no ticket)
|
||||
|
||||
## ntfy server v2.0.0
|
||||
Released February 16, 2023
|
||||
|
||||
This is the biggest ntfy server release I've ever done 🥳 . Lots of new and exciting features.
|
||||
@@ -64,6 +74,11 @@ going. It'll only make ntfy better.
|
||||
* User account signup, login, topic reservations, access tokens, tiers etc. ([#522](https://github.com/binwiederhier/ntfy/issues/522))
|
||||
* `OPTIONS` method calls are not serviced when the UI is disabled ([#598](https://github.com/binwiederhier/ntfy/issues/598), thanks to [@enticedwanderer](https://github.com/enticedwanderer) for reporting)
|
||||
|
||||
**Special thanks:**
|
||||
|
||||
A big Thank-you goes to everyone who tested the user account and payments work. I very much appreciate all the feedback,
|
||||
suggestions, and bug reports. Thank you, @nwithan8, @deadcade, @xenrox, @cmeis, and the others who I forgot.
|
||||
|
||||
## ntfy server v1.31.0
|
||||
Released February 14, 2023
|
||||
|
||||
@@ -95,11 +110,6 @@ breaking-change upgrade, which required some work to get working again.
|
||||
|
||||
* Portuguese (thanks to [@ssantos](https://hosted.weblate.org/user/ssantos/))
|
||||
|
||||
**Special thanks:**
|
||||
|
||||
A big Thank-you goes to everyone who tested the user account and payments work. I very much appreciate all the feedback,
|
||||
suggestions, and bug reports. Thank you, @nwithan8, @deadcade, and @xenrox.
|
||||
|
||||
## ntfy server v1.30.1
|
||||
Released December 23, 2022 🎅
|
||||
|
||||
|
||||
6
go.mod
6
go.mod
@@ -27,14 +27,14 @@ require github.com/pkg/errors v0.9.1 // indirect
|
||||
|
||||
require (
|
||||
firebase.google.com/go/v4 v4.10.0
|
||||
github.com/stripe/stripe-go/v74 v74.7.0
|
||||
github.com/stripe/stripe-go/v74 v74.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.0 // indirect
|
||||
cloud.google.com/go/compute v1.18.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v0.10.0 // indirect
|
||||
cloud.google.com/go/iam v0.12.0 // indirect
|
||||
cloud.google.com/go/longrunning v0.4.1 // indirect
|
||||
github.com/AlekSi/pointer v1.2.0 // indirect
|
||||
github.com/MicahParks/keyfunc v1.9.0 // indirect
|
||||
@@ -58,7 +58,7 @@ 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-20230209215440-0dfe4f8abfcc // indirect
|
||||
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 // indirect
|
||||
google.golang.org/grpc v1.53.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -7,8 +7,8 @@ cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGB
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA=
|
||||
cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE=
|
||||
cloud.google.com/go/iam v0.10.0 h1:fpP/gByFs6US1ma53v7VxhvbJpO2Aapng6wabJ99MuI=
|
||||
cloud.google.com/go/iam v0.10.0/go.mod h1:nXAECrMt2qHpF6RZUZseteD6QyanL68reN4OXPw0UWM=
|
||||
cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE=
|
||||
cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY=
|
||||
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.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
|
||||
@@ -101,8 +101,8 @@ 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.7.0 h1:KHlyslQj9YOv62b1sycQ31LFj7KlqR+seHsSowAWrjc=
|
||||
github.com/stripe/stripe-go/v74 v74.7.0/go.mod h1:5PoXNp30AJ3tGq57ZcFuaMylzNi8KpwlrYAFmO1fHZw=
|
||||
github.com/stripe/stripe-go/v74 v74.8.0 h1:0+3EfQSBhMg8SQ1+w+AP6Gxyko2crWbUG2uXbzYs8SU=
|
||||
github.com/stripe/stripe-go/v74 v74.8.0/go.mod h1:5PoXNp30AJ3tGq57ZcFuaMylzNi8KpwlrYAFmO1fHZw=
|
||||
github.com/urfave/cli/v2 v2.24.4 h1:0gyJJEBYtCV87zI/x2nZCPyDxD51K6xM8SkwjHFCNEU=
|
||||
github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
@@ -176,8 +176,8 @@ 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-20230209215440-0dfe4f8abfcc h1:ijGwO+0vL2hJt5gaygqP2j6PfflOBrRot0IczKbmtio=
|
||||
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 h1:EfLuoKW5WfkgVdDy7dTK8qSbH37AX5mj/MFh+bGPz14=
|
||||
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=
|
||||
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=
|
||||
|
||||
37
log/event.go
37
log/event.go
@@ -11,10 +11,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
tagField = "tag"
|
||||
errorField = "error"
|
||||
timeTakenField = "time_taken_ms"
|
||||
exitCodeField = "exit_code"
|
||||
fieldTag = "tag"
|
||||
fieldError = "error"
|
||||
fieldTimeTaken = "time_taken_ms"
|
||||
fieldExitCode = "exit_code"
|
||||
tagStdLog = "stdlog"
|
||||
timestampFormat = "2006-01-02T15:04:05.999Z07:00"
|
||||
)
|
||||
|
||||
@@ -40,7 +41,7 @@ func newEvent() *Event {
|
||||
|
||||
// Fatal logs the event as FATAL, and exits the program with exit code 1
|
||||
func (e *Event) Fatal(message string, v ...any) {
|
||||
e.Field(exitCodeField, 1).maybeLog(FatalLevel, message, v...)
|
||||
e.Field(fieldExitCode, 1).maybeLog(FatalLevel, message, v...)
|
||||
fmt.Fprintf(os.Stderr, message+"\n", v...) // Always output error to stderr
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -72,7 +73,7 @@ func (e *Event) Trace(message string, v ...any) {
|
||||
|
||||
// Tag adds a "tag" field to the log event
|
||||
func (e *Event) Tag(tag string) *Event {
|
||||
return e.Field(tagField, tag)
|
||||
return e.Field(fieldTag, tag)
|
||||
}
|
||||
|
||||
// Time sets the time field
|
||||
@@ -85,7 +86,7 @@ func (e *Event) Time(t time.Time) *Event {
|
||||
func (e *Event) Timing(f func()) *Event {
|
||||
start := time.Now()
|
||||
f()
|
||||
return e.Field(timeTakenField, time.Since(start).Milliseconds())
|
||||
return e.Field(fieldTimeTaken, time.Since(start).Milliseconds())
|
||||
}
|
||||
|
||||
// Err adds an "error" field to the log event
|
||||
@@ -95,7 +96,7 @@ func (e *Event) Err(err error) *Event {
|
||||
} else if c, ok := err.(Contexter); ok {
|
||||
return e.With(c)
|
||||
}
|
||||
return e.Field(errorField, err.Error())
|
||||
return e.Field(fieldError, err.Error())
|
||||
}
|
||||
|
||||
// Field adds a custom field and value to the log event
|
||||
@@ -128,17 +129,17 @@ func (e *Event) With(contexts ...Contexter) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// maybeLog logs the event to the defined output. The event is only logged, if
|
||||
// either the global log level is >= l, or if the log level in one of the overrides matches
|
||||
// Render returns the rendered log event as a string, or an empty string. The event is only rendered,
|
||||
// if either the global log level is >= l, or if the log level in one of the overrides matches
|
||||
// the level.
|
||||
//
|
||||
// If no overrides are defined (default), the Contexter array is not applied unless the event
|
||||
// is actually logged. If overrides are defined, then Contexters have to be applied in any case
|
||||
// to determine if they match. This is super complicated, but required for efficiency.
|
||||
func (e *Event) maybeLog(l Level, message string, v ...any) {
|
||||
func (e *Event) Render(l Level, message string, v ...any) string {
|
||||
appliedContexters := e.maybeApplyContexters()
|
||||
if !e.shouldLog(l) {
|
||||
return
|
||||
return ""
|
||||
}
|
||||
e.Message = fmt.Sprintf(message, v...)
|
||||
e.Level = l
|
||||
@@ -147,9 +148,15 @@ func (e *Event) maybeLog(l Level, message string, v ...any) {
|
||||
e.applyContexters()
|
||||
}
|
||||
if CurrentFormat() == JSONFormat {
|
||||
log.Println(e.JSON())
|
||||
} else {
|
||||
log.Println(e.String())
|
||||
return e.JSON()
|
||||
}
|
||||
return e.String()
|
||||
}
|
||||
|
||||
// maybeLog logs the event to the defined output, or does nothing if Render returns an empty string
|
||||
func (e *Event) maybeLog(l Level, message string, v ...any) {
|
||||
if m := e.Render(l, message, v...); m != "" {
|
||||
log.Println(m)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
48
log/log.go
48
log/log.go
@@ -4,6 +4,7 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -12,7 +13,7 @@ import (
|
||||
var (
|
||||
DefaultLevel = InfoLevel
|
||||
DefaultFormat = TextFormat
|
||||
DefaultOutput = os.Stderr
|
||||
DefaultOutput = &peekLogWriter{os.Stderr}
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -20,9 +21,18 @@ var (
|
||||
format = DefaultFormat
|
||||
overrides = make(map[string]*levelOverride)
|
||||
output io.Writer = DefaultOutput
|
||||
filename = ""
|
||||
mu = &sync.RWMutex{}
|
||||
)
|
||||
|
||||
// init sets the default log output (including log.SetOutput)
|
||||
//
|
||||
// This has to be explicitly called, because DefaultOutput is a peekLogWriter,
|
||||
// which wraps os.Stderr.
|
||||
func init() {
|
||||
SetOutput(DefaultOutput)
|
||||
}
|
||||
|
||||
// Fatal prints the given message, and exits the program
|
||||
func Fatal(message string, v ...any) {
|
||||
newEvent().Fatal(message, v...)
|
||||
@@ -132,28 +142,27 @@ func SetFormat(newFormat Format) {
|
||||
func SetOutput(w io.Writer) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
log.SetOutput(w)
|
||||
output = w
|
||||
output = &peekLogWriter{w}
|
||||
if f, ok := w.(*os.File); ok {
|
||||
filename = f.Name()
|
||||
} else {
|
||||
filename = ""
|
||||
}
|
||||
log.SetOutput(output)
|
||||
}
|
||||
|
||||
// File returns the log file, if any, or an empty string otherwise
|
||||
func File() string {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
if f, ok := output.(*os.File); ok {
|
||||
return f.Name()
|
||||
}
|
||||
return ""
|
||||
return filename
|
||||
}
|
||||
|
||||
// IsFile returns true if the output is a non-default file
|
||||
func IsFile() bool {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
if _, ok := output.(*os.File); ok && output != DefaultOutput {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return filename != ""
|
||||
}
|
||||
|
||||
// DisableDates disables the date/time prefix
|
||||
@@ -175,3 +184,20 @@ func IsTrace() bool {
|
||||
func IsDebug() bool {
|
||||
return Loggable(DebugLevel)
|
||||
}
|
||||
|
||||
// peekLogWriter is an io.Writer which will peek at the rendered log event,
|
||||
// and ensure that the rendered output is valid JSON. This is a hack!
|
||||
type peekLogWriter struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (w *peekLogWriter) Write(p []byte) (n int, err error) {
|
||||
if len(p) == 0 || p[0] == '{' || CurrentFormat() == TextFormat {
|
||||
return w.w.Write(p)
|
||||
}
|
||||
m := newEvent().Tag(tagStdLog).Render(InfoLevel, strings.TrimSpace(string(p)))
|
||||
if m == "" {
|
||||
return 0, nil
|
||||
}
|
||||
return w.w.Write([]byte(m + "\n"))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/stretchr/testify/require"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -170,6 +173,51 @@ func TestLog_LevelOverrideAny(t *testing.T) {
|
||||
{"time":"1970-01-01T00:00:14Z","level":"INFO","message":"this is also logged","time_taken_ms":0}
|
||||
`
|
||||
require.Equal(t, expected, out.String())
|
||||
require.False(t, IsFile())
|
||||
require.Equal(t, "", File())
|
||||
}
|
||||
|
||||
func TestLog_UsingStdLogger_JSON(t *testing.T) {
|
||||
t.Cleanup(resetState)
|
||||
|
||||
var out bytes.Buffer
|
||||
SetOutput(&out)
|
||||
SetFormat(JSONFormat)
|
||||
|
||||
log.Println("Some other library is using the standard Go logger")
|
||||
require.Contains(t, out.String(), `,"level":"INFO","message":"Some other library is using the standard Go logger","tag":"stdlog"}`+"\n")
|
||||
}
|
||||
|
||||
func TestLog_UsingStdLogger_Text(t *testing.T) {
|
||||
t.Cleanup(resetState)
|
||||
|
||||
var out bytes.Buffer
|
||||
SetOutput(&out)
|
||||
|
||||
log.Println("Some other library is using the standard Go logger")
|
||||
require.Contains(t, out.String(), `Some other library is using the standard Go logger`+"\n")
|
||||
require.NotContains(t, out.String(), `{`)
|
||||
}
|
||||
|
||||
func TestLog_File(t *testing.T) {
|
||||
t.Cleanup(resetState)
|
||||
|
||||
logfile := filepath.Join(t.TempDir(), "ntfy.log")
|
||||
f, err := os.OpenFile(logfile, os.O_CREATE|os.O_WRONLY, 0600)
|
||||
require.Nil(t, err)
|
||||
SetOutput(f)
|
||||
SetFormat(JSONFormat)
|
||||
require.True(t, IsFile())
|
||||
require.Equal(t, logfile, File())
|
||||
|
||||
Time(time.Unix(11, 0).UTC()).Field("this_one", "11").Info("this is logged")
|
||||
require.Nil(t, f.Close())
|
||||
|
||||
f, err = os.Open(logfile)
|
||||
require.Nil(t, err)
|
||||
contents, err := io.ReadAll(f)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, `{"time":"1970-01-01T00:00:11Z","level":"INFO","message":"this is logged","this_one":"11"}`+"\n", string(contents))
|
||||
}
|
||||
|
||||
type fakeError struct {
|
||||
|
||||
@@ -536,7 +536,7 @@ func (c *messageCache) ExpireMessages(topics ...string) error {
|
||||
}
|
||||
defer tx.Rollback()
|
||||
for _, t := range topics {
|
||||
if _, err := tx.Exec(updateMessagesForTopicExpiryQuery, time.Now().Unix(), t); err != nil {
|
||||
if _, err := tx.Exec(updateMessagesForTopicExpiryQuery, time.Now().Unix()-1, t); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,9 +333,9 @@ func (s *Server) handleError(w http.ResponseWriter, r *http.Request, v *visitor,
|
||||
return
|
||||
}
|
||||
if isNormalError {
|
||||
logvr(v, r).Err(httpErr).Debug("Connection closed with HTTP %d (ntfy error %d)", httpErr.HTTPCode, httpErr.Code)
|
||||
logvr(v, r).Err(err).Debug("Connection closed with HTTP %d (ntfy error %d)", httpErr.HTTPCode, httpErr.Code)
|
||||
} else {
|
||||
logvr(v, r).Err(httpErr).Info("Connection closed with HTTP %d (ntfy error %d)", httpErr.HTTPCode, httpErr.Code)
|
||||
logvr(v, r).Err(err).Info("Connection closed with HTTP %d (ntfy error %d)", httpErr.HTTPCode, httpErr.Code)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Access-Control-Allow-Origin", s.config.AccessControlAllowOrigin) // CORS, allow cross-origin requests
|
||||
|
||||
@@ -506,6 +506,7 @@ func (s *Server) maybeRemoveMessagesAndExcessReservations(r *http.Request, v *vi
|
||||
if err := s.messageCache.ExpireMessages(topics...); err != nil {
|
||||
return err
|
||||
}
|
||||
go s.pruneMessages()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -116,29 +116,30 @@ func (s *Server) pruneTokens() {
|
||||
}
|
||||
|
||||
func (s *Server) pruneAttachments() {
|
||||
if s.fileCache != nil {
|
||||
log.
|
||||
Tag(tagManager).
|
||||
Timing(func() {
|
||||
ids, err := s.messageCache.AttachmentsExpired()
|
||||
if err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error retrieving expired attachments")
|
||||
} else if len(ids) > 0 {
|
||||
if log.Tag(tagManager).IsDebug() {
|
||||
log.Tag(tagManager).Debug("Deleting attachments %s", strings.Join(ids, ", "))
|
||||
}
|
||||
if err := s.fileCache.Remove(ids...); err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error deleting attachments")
|
||||
}
|
||||
if err := s.messageCache.MarkAttachmentsDeleted(ids...); err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error marking attachments deleted")
|
||||
}
|
||||
} else {
|
||||
log.Tag(tagManager).Debug("No expired attachments to delete")
|
||||
}
|
||||
}).
|
||||
Debug("Deleted expired attachments")
|
||||
if s.fileCache == nil {
|
||||
return
|
||||
}
|
||||
log.
|
||||
Tag(tagManager).
|
||||
Timing(func() {
|
||||
ids, err := s.messageCache.AttachmentsExpired()
|
||||
if err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error retrieving expired attachments")
|
||||
} else if len(ids) > 0 {
|
||||
if log.Tag(tagManager).IsDebug() {
|
||||
log.Tag(tagManager).Debug("Deleting attachments %s", strings.Join(ids, ", "))
|
||||
}
|
||||
if err := s.fileCache.Remove(ids...); err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error deleting attachments")
|
||||
}
|
||||
if err := s.messageCache.MarkAttachmentsDeleted(ids...); err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error marking attachments deleted")
|
||||
}
|
||||
} else {
|
||||
log.Tag(tagManager).Debug("No expired attachments to delete")
|
||||
}
|
||||
}).
|
||||
Debug("Deleted expired attachments")
|
||||
}
|
||||
|
||||
func (s *Server) pruneMessages() {
|
||||
@@ -149,8 +150,10 @@ func (s *Server) pruneMessages() {
|
||||
if err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error retrieving expired messages")
|
||||
} else if len(expiredMessageIDs) > 0 {
|
||||
if err := s.fileCache.Remove(expiredMessageIDs...); err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error deleting attachments for expired messages")
|
||||
if s.fileCache != nil {
|
||||
if err := s.fileCache.Remove(expiredMessageIDs...); err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error deleting attachments for expired messages")
|
||||
}
|
||||
}
|
||||
if err := s.messageCache.DeleteMessages(expiredMessageIDs...); err != nil {
|
||||
log.Tag(tagManager).Err(err).Warn("Error marking attachments deleted")
|
||||
|
||||
28
server/server_manager_test.go
Normal file
28
server/server_manager_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServer_Manager_Prune_Messages_Without_Attachments_DoesNotPanic(t *testing.T) {
|
||||
// Tests that the manager runs without attachment-cache-dir set, see #617
|
||||
c := newTestConfig(t)
|
||||
c.AttachmentCacheDir = ""
|
||||
s := newTestServer(t, c)
|
||||
|
||||
// Publish a message
|
||||
rr := request(t, s, "POST", "/mytopic", "hi", nil)
|
||||
require.Equal(t, 200, rr.Code)
|
||||
m := toMessage(t, rr.Body.String())
|
||||
|
||||
// Expire message
|
||||
require.Nil(t, s.messageCache.ExpireMessages("mytopic"))
|
||||
|
||||
// Does not panic
|
||||
s.pruneMessages()
|
||||
|
||||
// Actually deleted
|
||||
_, err := s.messageCache.Message(m.ID)
|
||||
require.Equal(t, errMessageNotFound, err)
|
||||
}
|
||||
@@ -1498,7 +1498,7 @@ func TestServer_PublishAttachmentTooLargeBodyVisitorAttachmentTotalSizeLimit(t *
|
||||
c.VisitorAttachmentTotalSizeLimit = 10000
|
||||
s := newTestServer(t, c)
|
||||
|
||||
response := request(t, s, "PUT", "/mytopic", util.RandomString(5000), nil)
|
||||
response := request(t, s, "PUT", "/mytopic", "text file!"+util.RandomString(4990), nil)
|
||||
msg := toMessage(t, response.Body.String())
|
||||
require.Equal(t, 200, response.Code)
|
||||
require.Equal(t, "You received a file: attachment.txt", msg.Message)
|
||||
|
||||
428
web/package-lock.json
generated
428
web/package-lock.json
generated
@@ -89,6 +89,14 @@
|
||||
"url": "https://opencollective.com/babel"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/eslint-parser": {
|
||||
"version": "7.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz",
|
||||
@@ -114,6 +122,14 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/eslint-parser/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.20.14",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz",
|
||||
@@ -181,6 +197,14 @@
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-class-features-plugin": {
|
||||
"version": "7.20.12",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz",
|
||||
@@ -233,6 +257,14 @@
|
||||
"@babel/core": "^7.4.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.18.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
|
||||
@@ -1496,6 +1528,14 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-runtime/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-shorthand-properties": {
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz",
|
||||
@@ -1700,6 +1740,14 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-modules": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
|
||||
@@ -2089,12 +2137,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/babel-plugin": {
|
||||
"version": "11.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz",
|
||||
"integrity": "sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==",
|
||||
"version": "11.10.6",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz",
|
||||
"integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/plugin-syntax-jsx": "^7.17.12",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/hash": "^0.9.0",
|
||||
"@emotion/memoize": "^0.8.0",
|
||||
@@ -2105,9 +2152,6 @@
|
||||
"find-root": "^1.1.0",
|
||||
"source-map": "^0.5.7",
|
||||
"stylis": "4.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/cache": {
|
||||
@@ -2141,12 +2185,12 @@
|
||||
"integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
|
||||
},
|
||||
"node_modules/@emotion/react": {
|
||||
"version": "11.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.5.tgz",
|
||||
"integrity": "sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==",
|
||||
"version": "11.10.6",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz",
|
||||
"integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.10.5",
|
||||
"@emotion/babel-plugin": "^11.10.6",
|
||||
"@emotion/cache": "^11.10.5",
|
||||
"@emotion/serialize": "^1.1.1",
|
||||
"@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
|
||||
@@ -2155,13 +2199,9 @@
|
||||
"hoist-non-react-statics": "^3.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@babel/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
@@ -2185,26 +2225,22 @@
|
||||
"integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA=="
|
||||
},
|
||||
"node_modules/@emotion/styled": {
|
||||
"version": "11.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.5.tgz",
|
||||
"integrity": "sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==",
|
||||
"version": "11.10.6",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz",
|
||||
"integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.10.5",
|
||||
"@emotion/babel-plugin": "^11.10.6",
|
||||
"@emotion/is-prop-valid": "^1.2.0",
|
||||
"@emotion/serialize": "^1.1.1",
|
||||
"@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
|
||||
"@emotion/utils": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"@emotion/react": "^11.0.0-rc.0",
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@babel/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
@@ -3948,9 +3984,9 @@
|
||||
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz",
|
||||
"integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg=="
|
||||
"version": "18.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz",
|
||||
"integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A=="
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
@@ -4120,36 +4156,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/experimental-utils": {
|
||||
"version": "5.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.52.0.tgz",
|
||||
@@ -4274,36 +4280,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz",
|
||||
@@ -4349,36 +4325,6 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz",
|
||||
@@ -5162,6 +5108,14 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs3": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz",
|
||||
@@ -5510,9 +5464,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001453",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001453.tgz",
|
||||
"integrity": "sha512-R9o/uySW38VViaTrOtwfbFEiBFUh7ST3uIG4OEymIG3/uKdHDO4xk/FaqfUw0d+irSUyFPy3dZszf9VvSTPnsA==",
|
||||
"version": "1.0.30001456",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001456.tgz",
|
||||
"integrity": "sha512-XFHJY5dUgmpMV25UqaD4kVq2LsiaU5rS8fb0f17pCoXQiQslzmFgnfOxfvo1bTpTqf7dwG/N/05CnLCnOEKmzA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -6006,36 +5960,6 @@
|
||||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/css-loader/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/css-loader/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/css-loader/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/css-minimizer-webpack-plugin": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz",
|
||||
@@ -6791,9 +6715,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.300",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.300.tgz",
|
||||
"integrity": "sha512-tHLIBkKaxvG6NnDWuLgeYrz+LTwAnApHm2R3KBNcRrFn0qLmTrqQeB4X4atfN6YJbkOOOSdRBeQ89OfFUelnEQ=="
|
||||
"version": "1.4.302",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.302.tgz",
|
||||
"integrity": "sha512-Uk7C+7aPBryUR1Fwvk9VmipBcN9fVsqBO57jV2ZjTm+IZ6BMNqu7EDVEg2HxCNufk6QcWlFsBkhQyQroB2VWKw=="
|
||||
},
|
||||
"node_modules/emittery": {
|
||||
"version": "0.8.1",
|
||||
@@ -7264,6 +7188,14 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest": {
|
||||
"version": "25.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz",
|
||||
@@ -7316,6 +7248,14 @@
|
||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react": {
|
||||
"version": "7.32.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz",
|
||||
@@ -7382,6 +7322,14 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-testing-library": {
|
||||
"version": "5.10.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.2.tgz",
|
||||
@@ -8223,17 +8171,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
|
||||
@@ -8251,20 +8188,6 @@
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@@ -8284,11 +8207,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
@@ -9548,6 +9466,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/istanbul-lib-instrument/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/istanbul-lib-report": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
|
||||
@@ -10946,31 +10872,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-snapshot/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-snapshot/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-snapshot/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@@ -10982,11 +10883,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-snapshot/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/jest-util": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
|
||||
@@ -11953,6 +11849,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/makeerror": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
|
||||
@@ -13343,36 +13247,6 @@
|
||||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-loader/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-loader/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-loader/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/postcss-logical": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz",
|
||||
@@ -14581,36 +14455,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-scripts/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/react-scripts/node_modules/semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/react-scripts/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
@@ -15172,13 +15016,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/semver/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/semver/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
@@ -15891,9 +15757,9 @@
|
||||
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.6.tgz",
|
||||
"integrity": "sha512-BfgQWZrtqowOQMC2bwaSNe7xcIjdDEgixWGYOd6AL0CbKHJlvhfdbINeAW76l1sO+1ov/MJ93ODJ9yluRituIw==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.7.tgz",
|
||||
"integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==",
|
||||
"dependencies": {
|
||||
"arg": "^5.0.2",
|
||||
"chokidar": "^3.5.3",
|
||||
@@ -15995,9 +15861,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.16.3",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.3.tgz",
|
||||
"integrity": "sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==",
|
||||
"version": "5.16.4",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.4.tgz",
|
||||
"integrity": "sha512-5yEGuZ3DZradbogeYQ1NaGz7rXVBDWujWlx1PT8efXO6Txn+eWbfKqB2bTDVmFXmePFkoLU6XI8UektMIEA0ug==",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
"acorn": "^8.5.0",
|
||||
|
||||
45
web/public/static/langs/ar.json
Normal file
45
web/public/static/langs/ar.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"action_bar_logo_alt": "شعار ntfy",
|
||||
"action_bar_settings": "اﻹعدادات",
|
||||
"action_bar_clear_notifications": "محو كافة الإشعارات",
|
||||
"action_bar_unsubscribe": "إلغاء الاشتراك",
|
||||
"message_bar_show_dialog": "إظهار مربع حوار النشر",
|
||||
"message_bar_publish": "نشر الرسالة",
|
||||
"nav_topics_title": "المواضيع التي تم الاشتراك فيها",
|
||||
"nav_button_all_notifications": "كافة الإشعارات",
|
||||
"nav_button_settings": "اﻹعدادات",
|
||||
"nav_button_documentation": "الدليل",
|
||||
"nav_button_publish_message": "نشر الإشعار",
|
||||
"nav_button_subscribe": "اشترك في الموضوع",
|
||||
"nav_button_connecting": "جارٍ الاتصال",
|
||||
"alert_grant_title": "تم تعطيل الإشعارات",
|
||||
"alert_grant_description": "امنح متصفحك الإذن لعرض إشعارات سطح المكتب.",
|
||||
"notifications_list": "قائمة الإشعارات",
|
||||
"notifications_list_item": "إشعار",
|
||||
"notifications_mark_read": "وضع علامة كمقروء",
|
||||
"notifications_tags": "الوسوم",
|
||||
"notifications_priority_x": "الأولوية {{priority}}",
|
||||
"notifications_new_indicator": "إشعار جديد",
|
||||
"notifications_attachment_image": "صورة مرفقة",
|
||||
"notifications_attachment_copy_url_button": "نسخ عنوان URL",
|
||||
"notifications_attachment_open_title": "انتقل إلى {{url}}",
|
||||
"notifications_attachment_link_expires": "تنتهي صلاحية الرابط {{date}}",
|
||||
"notifications_attachment_link_expired": "انتهت صلاحية رابط التنزيل",
|
||||
"notifications_attachment_file_image": "ملف الصورة",
|
||||
"notifications_attachment_file_video": "ملف فيديو",
|
||||
"notifications_attachment_file_audio": "ملف صوتي",
|
||||
"notifications_attachment_file_app": "ملف تطبيق Android",
|
||||
"notifications_attachment_file_document": "وثيقة أخرى",
|
||||
"notifications_click_copy_url_button": "نسخ الرابط",
|
||||
"notifications_click_open_button": "فتح الرابط",
|
||||
"notifications_actions_open_url_title": "انتقل إلى {{url}}",
|
||||
"notifications_actions_not_supported": "هذا الإجراء غير مدعوم في تطبيق الويب",
|
||||
"action_bar_send_test_notification": "إرسال إشعار للاختبار",
|
||||
"action_bar_show_menu": "عرض القائمة",
|
||||
"message_bar_type_message": "اكتب رسالة هنا",
|
||||
"alert_not_supported_title": "الإشعارات غير مدعومة",
|
||||
"alert_not_supported_description": "الإشعارات غير مدعومة في متصفحك.",
|
||||
"message_bar_error_publishing": "خطأ أثناء نشر الإشعار",
|
||||
"notifications_delete": "حذف",
|
||||
"notifications_copied_to_clipboard": "تم نسخه إلى الحافظة"
|
||||
}
|
||||
Reference in New Issue
Block a user