diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fef08e1..900fdbf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ jobs: test: strategy: matrix: - go-version: [1.18.x] + go-version: [1.21.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1142339..f0be530 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ Notable changes to Mailpit will be documented in this file. +## [v1.9.0] + +### API +- Remove redundant `Read` status from message (always true) +- Delete by search filter +- Add endpoint to return all tags in use + +### Feature +- Improved search parser +- New search filter `[!]is:tagged` + +### Fix +- Correctly escape certain characters in search (eg: `'`) + +### Libs +- Update minimum Go version to 1.20 +- Update Go modules +- Update node modules + +### Tests +- Bump Go version to 1.21 + +### UI +- Rewrite web UI, add URL routing and components + + ## [v1.8.4] ### Fix diff --git a/config/config.go b/config/config.go index fe18ea9..1ccc231 100644 --- a/config/config.go +++ b/config/config.go @@ -12,7 +12,6 @@ import ( "github.com/axllent/mailpit/utils/logger" "github.com/axllent/mailpit/utils/tools" - "github.com/mattn/go-shellwords" "github.com/tg123/go-htpasswd" "gopkg.in/yaml.v3" ) @@ -228,13 +227,8 @@ func VerifyConfig() error { SMTPTags = []AutoTag{} - p := shellwords.NewParser() - if SMTPCLITags != "" { - args, err := p.Parse(SMTPCLITags) - if err != nil { - return fmt.Errorf("Error parsing tags (%s)", err) - } + args := tools.ArgsParser(SMTPCLITags) for _, a := range args { t := strings.Split(a, "=") diff --git a/go.mod b/go.mod index 75c663d..3360cb0 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,19 @@ module github.com/axllent/mailpit -go 1.18 +go 1.20 require ( github.com/GuiaBolso/darwin v0.0.0-20191218124601-fd6d2aa3d244 github.com/PuerkitoBio/goquery v1.8.1 github.com/axllent/semver v0.0.1 github.com/disintegration/imaging v1.6.2 - github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 + github.com/gomarkdown/markdown v0.0.0-20230916125811-7478c230c7cd github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 - github.com/jhillyerd/enmime v1.0.0 + github.com/jhillyerd/enmime v1.0.1 github.com/k3a/html2text v1.2.1 - github.com/klauspost/compress v1.16.7 + github.com/klauspost/compress v1.17.0 github.com/leporo/sqlf v1.4.0 - github.com/mattn/go-shellwords v1.0.12 github.com/mhale/smtpd v0.8.0 github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e github.com/satori/go.uuid v1.2.0 @@ -23,8 +22,8 @@ require ( github.com/spf13/pflag v1.0.5 github.com/tg123/go-htpasswd v1.2.1 github.com/vanng822/go-premailer v1.20.2 - golang.org/x/net v0.14.0 - golang.org/x/text v0.12.0 + golang.org/x/net v0.15.0 + golang.org/x/text v0.13.0 gopkg.in/yaml.v3 v3.0.1 modernc.org/sqlite v1.25.0 ) @@ -37,7 +36,7 @@ require ( github.com/cznic/ql v1.2.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect @@ -53,18 +52,18 @@ require ( github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/vanng822/css v1.0.1 // indirect - golang.org/x/crypto v0.12.0 // indirect - golang.org/x/image v0.11.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/image v0.12.0 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/tools v0.12.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/tools v0.13.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect lukechampine.com/uint128 v1.3.0 // indirect modernc.org/cc/v3 v3.41.0 // indirect modernc.org/ccgo/v3 v3.16.15 // indirect modernc.org/libc v1.24.1 // indirect modernc.org/mathutil v1.6.0 // indirect - modernc.org/memory v1.7.0 // indirect + modernc.org/memory v1.7.1 // indirect modernc.org/opt v0.1.3 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect diff --git a/go.sum b/go.sum index 0d54902..93056e0 100644 --- a/go.sum +++ b/go.sum @@ -47,16 +47,16 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E= -github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/gomarkdown/markdown v0.0.0-20230916125811-7478c230c7cd h1:laCEzrtkKEkT2424vMTGl6N1m0xN8kq371hksD5Be+8= +github.com/gomarkdown/markdown v0.0.0-20230916125811-7478c230c7cd/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= @@ -69,16 +69,16 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA= github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= -github.com/jhillyerd/enmime v1.0.0 h1:8swYgO1fm68PllCKz5jiLzgD3axNUS388jr6BtRSsl8= -github.com/jhillyerd/enmime v1.0.0/go.mod h1:EktNOa/V6ka9yCrfoB2uxgefp1lno6OVdszW0iQ5LnM= +github.com/jhillyerd/enmime v1.0.1 h1:y6RyqIgBOI2hIinOXIzmeB+ITRVls0zTJIm5GwgXnjE= +github.com/jhillyerd/enmime v1.0.1/go.mod h1:LMMbm6oTlzWHghPavqHtOrP/NosVv3l42CUrZjn03/Q= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/k3a/html2text v1.2.1 h1:nvnKgBvBR/myqrwfLuiqecUtaK1lB9hGziIJKatNFVY= github.com/k3a/html2text v1.2.1/go.mod h1:ieEXykM67iT8lTvEWBh6fhpH4B23kB9OMKPdIBmgUqA= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -93,8 +93,6 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= -github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mhale/smtpd v0.8.0 h1:5JvdsehCg33PQrZBvFyDMMUDQmvbzVpZgKob7eYBJc0= @@ -138,8 +136,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/tg123/go-htpasswd v1.2.1 h1:i4wfsX1KvvkyoMiHZzjS0VzbAPWfxzI8INcZAKtutoU= github.com/tg123/go-htpasswd v1.2.1/go.mod h1:erHp1B86KXdwQf1X5ZrLb7erXZnWueEQezb2dql4q58= github.com/unrolled/render v1.0.3/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM= @@ -154,11 +152,11 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo= -golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= +golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ= +golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= @@ -175,8 +173,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -193,8 +191,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -205,15 +203,15 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -235,8 +233,8 @@ modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.7.0 h1:2pXdbgdP5hIyDp2JqIwkHNZ1sAjEbh8GnRpcqFWBf7E= -modernc.org/memory v1.7.0/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/memory v1.7.1 h1:9J+2/GKTlV503mk3yv8QJ6oEpRCUrRy0ad8TXEPoV8M= +modernc.org/memory v1.7.1/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= diff --git a/package-lock.json b/package-lock.json index 12ddbdb..e437011 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,12 +19,15 @@ "rapidoc": "^9.3.4", "tinycon": "^0.6.8", "vue": "^3.2.13", - "vue-css-donut-chart": "^2.0.0" + "vue-css-donut-chart": "^2.0.0", + "vue-router": "^4.2.4" }, "devDependencies": { "@popperjs/core": "^2.11.5", + "@types/bootstrap": "^5.2.7", + "@types/tinycon": "^0.6.3", "@vue/compiler-sfc": "^3.2.37", - "esbuild": "^0.18.10", + "esbuild": "^0.19.1", "esbuild-plugin-vue-next": "^0.1.4", "esbuild-sass-plugin": "^2.3.2" } @@ -38,9 +41,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -49,21 +52,21 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.22.6.tgz", - "integrity": "sha512-M+37LLIRBTEVjktoJjbw4KVhupF0U/3PYUCbBwgAd9k17hoKhRu1n935QiG7Tuxv0LJOMrb2vuKEeYUlv0iyiw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.22.15.tgz", + "integrity": "sha512-SAj8oKi8UogVi6eXQXKNPu8qZ78Yzy7zawrlTr0M+IuW/g8Qe9gVDhGcF9h1S69OyACpYoLxEzpjs1M15sI5wQ==", "dependencies": { "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.3.tgz", + "integrity": "sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==", "cpu": [ "arm" ], @@ -77,9 +80,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.3.tgz", + "integrity": "sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==", "cpu": [ "arm64" ], @@ -93,9 +96,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.3.tgz", + "integrity": "sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==", "cpu": [ "x64" ], @@ -109,9 +112,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.3.tgz", + "integrity": "sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==", "cpu": [ "arm64" ], @@ -125,9 +128,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.3.tgz", + "integrity": "sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==", "cpu": [ "x64" ], @@ -141,9 +144,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.3.tgz", + "integrity": "sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==", "cpu": [ "arm64" ], @@ -157,9 +160,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.3.tgz", + "integrity": "sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==", "cpu": [ "x64" ], @@ -173,9 +176,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.3.tgz", + "integrity": "sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==", "cpu": [ "arm" ], @@ -189,9 +192,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.3.tgz", + "integrity": "sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==", "cpu": [ "arm64" ], @@ -205,9 +208,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.3.tgz", + "integrity": "sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==", "cpu": [ "ia32" ], @@ -221,9 +224,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.3.tgz", + "integrity": "sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==", "cpu": [ "loong64" ], @@ -237,9 +240,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.3.tgz", + "integrity": "sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==", "cpu": [ "mips64el" ], @@ -253,9 +256,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.3.tgz", + "integrity": "sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==", "cpu": [ "ppc64" ], @@ -269,9 +272,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.3.tgz", + "integrity": "sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==", "cpu": [ "riscv64" ], @@ -285,9 +288,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.3.tgz", + "integrity": "sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA==", "cpu": [ "s390x" ], @@ -301,9 +304,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.3.tgz", + "integrity": "sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==", "cpu": [ "x64" ], @@ -317,9 +320,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.3.tgz", + "integrity": "sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==", "cpu": [ "x64" ], @@ -333,9 +336,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.3.tgz", + "integrity": "sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==", "cpu": [ "x64" ], @@ -349,9 +352,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.3.tgz", + "integrity": "sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==", "cpu": [ "x64" ], @@ -365,9 +368,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.3.tgz", + "integrity": "sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==", "cpu": [ "arm64" ], @@ -381,9 +384,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.3.tgz", + "integrity": "sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==", "cpu": [ "ia32" ], @@ -397,9 +400,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.3.tgz", + "integrity": "sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==", "cpu": [ "x64" ], @@ -440,220 +443,238 @@ } }, "node_modules/@swagger-api/apidom-ast": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ast/-/apidom-ast-0.74.1.tgz", - "integrity": "sha512-EoHyaRBeZmNYFNlDNZGeI45zRLfcVW0o4uZ8Fs/+HN1UIyDoZdr+ObElj5PEkCmdDx7ADlNmoGK4B+4AQA2LeA==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ast/-/apidom-ast-0.76.2.tgz", + "integrity": "sha512-yLSeI3KtfpR7tI/misqTeasFonssj9GGhCOJfSHBuRAZkrPCJf0eU8vh3pL7YPa8lqFWcPT+z/arZoMcC9VLnQ==", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", + "@swagger-api/apidom-error": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2", "unraw": "^3.0.0" } }, "node_modules/@swagger-api/apidom-core": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-core/-/apidom-core-0.74.1.tgz", - "integrity": "sha512-y70oo/CrNMSi7TtUkATXkSWd+Q/4BjchwCuLpWbhSJuIpJM+W9yGyzWOFTFLZQpDbwK0yzocMk8iPClq/rWNPw==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-core/-/apidom-core-0.76.2.tgz", + "integrity": "sha512-366dJJM7DFONlO3nUQfQRMJpJzZjPpWZldbHJZCcvy+aCyrNYI3Waauas7fm29UXRliPirGrd9e/ZsnW3Jimag==", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^0.74.1", + "@swagger-api/apidom-ast": "^0.76.2", + "@swagger-api/apidom-error": "^0.76.2", "@types/ramda": "~0.29.3", "minim": "~0.23.8", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", - "short-unique-id": "^4.4.4", + "ramda-adjunct": "^4.1.1", + "short-unique-id": "^5.0.2", "stampit": "^4.3.2" } }, - "node_modules/@swagger-api/apidom-json-pointer": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-0.74.1.tgz", - "integrity": "sha512-UusZdVY2AbYSyMK0aPSNvCiCtgn6NcGnS9fbAPVFsV+ALEtWYdMs/ZjfqYhbuzd+nRY34J9GCF7m+kVysZ9EWw==", + "node_modules/@swagger-api/apidom-error": { + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-error/-/apidom-error-0.76.2.tgz", + "integrity": "sha512-QxoWL+qGzwftqXSJaYLZ1Nrdtro+U1zX5Q4OLK+Ggg8Hi6Kn1SGXcHhn4JZ9J1rwrP85XCabilL3z9mhdebqWg==", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", + "@types/ramda": "~0.29.3", + "ramda": "~0.29.0", + "ramda-adjunct": "^4.0.0" + } + }, + "node_modules/@swagger-api/apidom-json-pointer": { + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-0.76.2.tgz", + "integrity": "sha512-2XCgA4bn8vB1VMDbSiP+6SHUTiBxx1EVLW2pgqFolhLPMdiI/QBVmoW+jEkvTPo4d5gwj/vP5WDs5QnnC9VwEA==", + "dependencies": { + "@babel/runtime-corejs3": "^7.20.7", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-error": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-ns-api-design-systems": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-api-design-systems/-/apidom-ns-api-design-systems-0.74.1.tgz", - "integrity": "sha512-eJxd3B4lQbVCi+g9ZXSM0IeCbqPEH5o7WdLdfrSowFLQqc7jQur/29UhbAh2PDvPSI/l7oaNzwgPTp4Zm8SaTw==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-api-design-systems/-/apidom-ns-api-design-systems-0.76.2.tgz", + "integrity": "sha512-ct83R5Pvc08jeOuGShO4N0ty7VO8f46WedTDCbzT4edMRhd9Xdr5UFxkwWDuliy4uLzl9ZayHygSxfnyZKQb8g==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-openapi-3-1": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-error": "^0.76.2", + "@swagger-api/apidom-ns-openapi-3-1": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2" } }, "node_modules/@swagger-api/apidom-ns-asyncapi-2": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-2/-/apidom-ns-asyncapi-2-0.74.1.tgz", - "integrity": "sha512-xH6ilO8jJpZOWzWwbse3xi8zIbe3Iho+AMwwMFtkCnjUqmv81TGhlA6VPXpLCKgFsnZqJVyCKn/VaTW8N6379w==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-2/-/apidom-ns-asyncapi-2-0.76.2.tgz", + "integrity": "sha512-ffV2AhF7jTBbYl2vX0nYSDufs70CmC/kNMWHkgwR2Vq86lgadUc6S/NK/djpWY8+oAU3EYmHwTqu07hpSOUb4A==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-json-schema-draft-7": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-json-schema-draft-7": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2" } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-4": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-0.74.1.tgz", - "integrity": "sha512-zUQvrxoRQpvdYymHko1nxNeVWwqdGDYNYWUFW/EGZbP0sigKmuSZkh6LdseB9Pxt1WQD/6MkW3zN4JMXt/qFUA==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-0.76.2.tgz", + "integrity": "sha512-0Y32CQE6tIt4IPsoCzWAUskZSyGkfw87IIsH5Bcm3D1qIlAhPAokQbe1212MmZoLVUvqrXDqZHXnOxxMaHZvYw==", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^0.74.1", - "@swagger-api/apidom-core": "^0.74.1", + "@swagger-api/apidom-ast": "^0.76.2", + "@swagger-api/apidom-core": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2" } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-6": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-0.74.1.tgz", - "integrity": "sha512-8GFH6bR5ERyuS+4u7CnLirBPYkYWostk31WDj7YeY5b0BRNtI3omH4rV24KECu99ZAg/unZY688VwmN25Dut/A==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-0.76.2.tgz", + "integrity": "sha512-i6nZtj3ie6SP1LhRtBeZNJuBppWkuC/+AsVfUzXkH5pM+3B7Puklc77hHdLtmvUTpd/iRBdlfsklvBVXJYPtUA==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-json-schema-draft-4": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-error": "^0.76.2", + "@swagger-api/apidom-ns-json-schema-draft-4": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2" } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-7": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-0.74.1.tgz", - "integrity": "sha512-4ttxnBuRcegp1ooKtwoOqXDUNCWH4GuQlMBOUlHfKPR35qbMf0LCYU+ROvTk05ycoVkc2x6+AJQ4He684EXwfw==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-0.76.2.tgz", + "integrity": "sha512-Klyfi/1XkJVUZa1nJP87HPMjklmB3IxE+TSD27aZIEi7GKASu96euan0gflZaegexUBA9hsAngk98USbdpHpgQ==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-json-schema-draft-6": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-error": "^0.76.2", + "@swagger-api/apidom-ns-json-schema-draft-6": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2" } }, "node_modules/@swagger-api/apidom-ns-openapi-3-0": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-0/-/apidom-ns-openapi-3-0-0.74.1.tgz", - "integrity": "sha512-n5jccxnbiNjHiID0uTV1UXdt47WxyduQRKK9ILo7N2yXqkwI1ygqQNBVEUC/YZnHT4ZvFsifYAqbT0hO1h54ig==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-0/-/apidom-ns-openapi-3-0-0.76.2.tgz", + "integrity": "sha512-tV7dfbAZjX4HHul6JzmWsipMIVHCX5fAsBwLTltq8qmF9X9m6kZwg7fb4pD+cGK2KVlZl/ucDDDIQLDRWpOAog==", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-json-schema-draft-4": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-json-schema-draft-4": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2" } }, "node_modules/@swagger-api/apidom-ns-openapi-3-1": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-0.74.1.tgz", - "integrity": "sha512-8ZqQBjMfiCEwePUbwdKIAStl7nIPIiyKGrON4Sy+PWTwvCQiam3haKeT5r6TDiTFyrS3idSplfXijuWfZF//Ag==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-0.76.2.tgz", + "integrity": "sha512-Mb9VhVacoWvQcBqxO4j0eweyM6PGupAOt7XcOL5CzID0dOU+P4BbAv6kHD++0bTqRgXk1O31HkS/yPJmPaTCrw==", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^0.74.1", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-openapi-3-0": "^0.74.1", + "@swagger-api/apidom-ast": "^0.76.2", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-openapi-3-0": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2" } }, "node_modules/@swagger-api/apidom-parser-adapter-api-design-systems-json": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-json/-/apidom-parser-adapter-api-design-systems-json-0.74.1.tgz", - "integrity": "sha512-RFwnL2u3OzKVkE4jQ4zGNHA83BnXM3EjpTNRbCzcmsP78RGr7H9HebPaiRPpLMyC3GuzBwPXe8WbOdYsReuFww==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-json/-/apidom-parser-adapter-api-design-systems-json-0.76.2.tgz", + "integrity": "sha512-mJ4HLVIR9YHgWu0SiHykFQ9Sz1f3eV5Wqhrff8sH2Qll+4QSSdOOs0tW4Gp56F0HIcrU66uvrrTy1tpkO943aw==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-api-design-systems": "^0.74.1", - "@swagger-api/apidom-parser-adapter-json": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-api-design-systems": "^0.76.2", + "@swagger-api/apidom-parser-adapter-json": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-api-design-systems-yaml": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-yaml/-/apidom-parser-adapter-api-design-systems-yaml-0.74.1.tgz", - "integrity": "sha512-3r5lxhP/glOhQVFRVRf/Ps2F5V2oMowG6+YBkajV2jCW9XPIrIuVef+KcjbQQlm06J3QnD+Tg/ZiLXcxziAvoQ==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-yaml/-/apidom-parser-adapter-api-design-systems-yaml-0.76.2.tgz", + "integrity": "sha512-ot0F8Pw9/oWce6daDK+3srhNad/Iva/OlkVtN0S9cR58Zcn8p1F3s6RcN7ZG97i8EdBuyQj6Bm0jzXnOX+lvtQ==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-api-design-systems": "^0.74.1", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-api-design-systems": "^0.76.2", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-asyncapi-json-2": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-2/-/apidom-parser-adapter-asyncapi-json-2-0.74.1.tgz", - "integrity": "sha512-jPp5n0aKtqZrQrz+Lh1B5LNocuMliA3OvNWGGTD14T54qNDJ+a2B6a31SXZqzjqfseWr7SeE2Z/RM5ljqviLWA==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-2/-/apidom-parser-adapter-asyncapi-json-2-0.76.2.tgz", + "integrity": "sha512-FK06pb4w5E8RQ65Nh1FHHM8aWzPL7fHr2HeuXZkbSeKu4j0xyzwYkxZVGwZJOT6YPJR0Yrkb/2rD89CNXsLctA==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-asyncapi-2": "^0.74.1", - "@swagger-api/apidom-parser-adapter-json": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-asyncapi-2": "^0.76.2", + "@swagger-api/apidom-parser-adapter-json": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2/-/apidom-parser-adapter-asyncapi-yaml-2-0.74.1.tgz", - "integrity": "sha512-em8o7bu0XEMac6cJvSi9WjMpTEny39gn+1UrANnICpvsMoiRjlfE5yEG4eueewV1nsukO4qTiUjTf32BGNgHYg==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2/-/apidom-parser-adapter-asyncapi-yaml-2-0.76.2.tgz", + "integrity": "sha512-7TGhZgHZ9nmBJnFA7YhDWbNDbKoUOGVkBqx563ExHr2FewaohiQ/wagXAhKZzOK+HS+KHvob09uROtqOWGdIew==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-asyncapi-2": "^0.74.1", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-asyncapi-2": "^0.76.2", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-json": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-json/-/apidom-parser-adapter-json-0.74.1.tgz", - "integrity": "sha512-CtJxt/o0ZyW/GkvETuTUUlCjTJ/wH0S7jr3CBnZR/vVVVlVfIYkGw2fEo8HUBAr+EnJNFfWOzOAjXQHul71wUw==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-json/-/apidom-parser-adapter-json-0.76.2.tgz", + "integrity": "sha512-vbH7EcldZ/gSK9FnGUW1cpibM5+hiJPQcoyLmzLZe8YBxX73qzd2WAd77v+uI56eO9Z0G4KMCRCF9PDZT/tz5Q==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^0.74.1", - "@swagger-api/apidom-core": "^0.74.1", + "@swagger-api/apidom-ast": "^0.76.2", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-error": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2", "tree-sitter": "=0.20.4", "tree-sitter-json": "=0.20.0", @@ -661,77 +682,78 @@ } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-3-0": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-0/-/apidom-parser-adapter-openapi-json-3-0-0.74.1.tgz", - "integrity": "sha512-k8zOeb2aCyEVUdW1sUUBmawyqHmx7C7WB9eXFM1yEzwy3Y589cVygiy6AG1yOaPU8WWzR80+xPEqHw0VmqkBRg==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-0/-/apidom-parser-adapter-openapi-json-3-0-0.76.2.tgz", + "integrity": "sha512-Kqcq5QUgz1TcCuPaL+zU+wmdAEo7YM0LR5jyWQo3FAT3BhAsmeVv2wRZMiz9RMDrPyxzHzbJhjMZxCqL8r2G0g==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-openapi-3-0": "^0.74.1", - "@swagger-api/apidom-parser-adapter-json": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-openapi-3-0": "^0.76.2", + "@swagger-api/apidom-parser-adapter-json": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-3-1": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-1/-/apidom-parser-adapter-openapi-json-3-1-0.74.1.tgz", - "integrity": "sha512-x70fOeBiavi9siSq2Hr07cBcIXdTEDpi87OpaQIGTk5tjN8wQfnQF1MWxdHpe4p/cJN7LiYw5Dx6uIAhp/RuGg==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-1/-/apidom-parser-adapter-openapi-json-3-1-0.76.2.tgz", + "integrity": "sha512-kfZ4BBxww5afiIIeFT6l0/Kuob72dnYAP+Qnmp2zQB3GQUTilKqv+ddj4blCF19n8RGNERVv2RDHLTZhjg+1AA==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-openapi-3-1": "^0.74.1", - "@swagger-api/apidom-parser-adapter-json": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-openapi-3-1": "^0.76.2", + "@swagger-api/apidom-parser-adapter-json": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0/-/apidom-parser-adapter-openapi-yaml-3-0-0.74.1.tgz", - "integrity": "sha512-MdZrzR+9AbunoP9OyETqZabhCllUiu5lu59uG7exo7jR1GfC28A4wVolNhi0C01wOcS+55t+1qvzi+i+9Kz3ew==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0/-/apidom-parser-adapter-openapi-yaml-3-0-0.76.2.tgz", + "integrity": "sha512-spXabhd0sgX87QaYUDou22KduSL5GHCmLNuPDpPykYelB/zZnE8aPsrjBMIgK9CPZoQCDoWYYmtRTPfJjKwf3Q==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-openapi-3-0": "^0.74.1", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-openapi-3-0": "^0.76.2", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1/-/apidom-parser-adapter-openapi-yaml-3-1-0.74.1.tgz", - "integrity": "sha512-OaDAhZm38chXyc0P0yHQSD4fCmUmEUWTTLgHntJDmvAZ7nSkV4NddDP7cgZ07z8dLEwMokI//9u+I/s0G0BO0Q==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1/-/apidom-parser-adapter-openapi-yaml-3-1-0.76.2.tgz", + "integrity": "sha512-KIEg9QWeiMMKQ9VtftK+1Rc7irKQjj0VTsoEtraun9N2MWLVt7g+xZKqbqtQ4/ovv5J8JBHE+hFGLdm2qZalsg==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", - "@swagger-api/apidom-ns-openapi-3-1": "^0.74.1", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-ns-openapi-3-1": "^0.76.2", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", "ramda-adjunct": "^4.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-yaml-1-2": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-0.74.1.tgz", - "integrity": "sha512-QHxx3ZJ12FAF8yserAR1qL863/eOdi78HgdDFqVeg5tOfUUDXLnvEYbtCWejIjudBFD6s88ctffzN7+DEDFOPg==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-0.76.2.tgz", + "integrity": "sha512-nmEDYOfqeB8yCHbQ5yEQkJ09zIDOeX61KXTUktP4yErm96WVjIUk5YTTAkO7QbAEND9JHE+BAnS25cBC8BxFFA==", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^0.74.1", - "@swagger-api/apidom-core": "^0.74.1", + "@swagger-api/apidom-ast": "^0.76.2", + "@swagger-api/apidom-core": "^0.76.2", + "@swagger-api/apidom-error": "^0.76.2", "@types/ramda": "~0.29.3", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2", "tree-sitter": "=0.20.4", "tree-sitter-yaml": "=0.5.0", @@ -739,49 +761,65 @@ } }, "node_modules/@swagger-api/apidom-reference": { - "version": "0.74.1", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-0.74.1.tgz", - "integrity": "sha512-DwMGmTA2VkiPf8CLDnhhR4PObqzrGGOKydxd3uWWFFI0/itU8mZcBZssMHseW1dV2fC9hvkva672Gt2W/wSJng==", + "version": "0.76.2", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-0.76.2.tgz", + "integrity": "sha512-O1qX6Tql+B18Em/ERyqCzuhcvOG3JeRq4QIHfebzS3lNxpxX6si/z0DrL5K1azBldmnXx7UGqt/fvwq8GQJmIA==", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^0.74.1", + "@swagger-api/apidom-core": "^0.76.2", "@types/ramda": "~0.29.3", "axios": "^1.4.0", "minimatch": "^7.4.3", "process": "^0.11.10", "ramda": "~0.29.0", - "ramda-adjunct": "^4.0.0", + "ramda-adjunct": "^4.1.1", "stampit": "^4.3.2" }, "optionalDependencies": { - "@swagger-api/apidom-json-pointer": "^0.74.1", - "@swagger-api/apidom-ns-asyncapi-2": "^0.74.1", - "@swagger-api/apidom-ns-openapi-3-0": "^0.74.1", - "@swagger-api/apidom-ns-openapi-3-1": "^0.74.1", - "@swagger-api/apidom-parser-adapter-api-design-systems-json": "^0.74.1", - "@swagger-api/apidom-parser-adapter-api-design-systems-yaml": "^0.74.1", - "@swagger-api/apidom-parser-adapter-asyncapi-json-2": "^0.74.1", - "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": "^0.74.1", - "@swagger-api/apidom-parser-adapter-json": "^0.74.1", - "@swagger-api/apidom-parser-adapter-openapi-json-3-0": "^0.74.1", - "@swagger-api/apidom-parser-adapter-openapi-json-3-1": "^0.74.1", - "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": "^0.74.1", - "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": "^0.74.1", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.74.1" + "@swagger-api/apidom-error": "^0.76.2", + "@swagger-api/apidom-json-pointer": "^0.76.2", + "@swagger-api/apidom-ns-asyncapi-2": "^0.76.2", + "@swagger-api/apidom-ns-openapi-3-0": "^0.76.2", + "@swagger-api/apidom-ns-openapi-3-1": "^0.76.2", + "@swagger-api/apidom-parser-adapter-api-design-systems-json": "^0.76.2", + "@swagger-api/apidom-parser-adapter-api-design-systems-yaml": "^0.76.2", + "@swagger-api/apidom-parser-adapter-asyncapi-json-2": "^0.76.2", + "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": "^0.76.2", + "@swagger-api/apidom-parser-adapter-json": "^0.76.2", + "@swagger-api/apidom-parser-adapter-openapi-json-3-0": "^0.76.2", + "@swagger-api/apidom-parser-adapter-openapi-json-3-1": "^0.76.2", + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": "^0.76.2", + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": "^0.76.2", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^0.76.2" + } + }, + "node_modules/@types/bootstrap": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.7.tgz", + "integrity": "sha512-vWs0HzobIB8Af2F0B1GXpaVLSVn1NWULDYgTIWp08Et/r2B3aAwwhFBeOs/rRFWJA38EZTXkWP3tepIjpQkpLg==", + "dev": true, + "dependencies": { + "@popperjs/core": "^2.9.2" } }, "node_modules/@types/ramda": { - "version": "0.29.3", - "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.29.3.tgz", - "integrity": "sha512-Yh/RHkjN0ru6LVhSQtTkCRo6HXkfL9trot/2elzM/yXLJmbLm2v6kJc8yftTnwv1zvUob6TEtqI2cYjdqG3U0Q==", + "version": "0.29.4", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.29.4.tgz", + "integrity": "sha512-bd3nyfkZd5EVxuBf1kW6wvFz61SvAEfXXISIEIePJOj2XRjCHyro1ikvDXTXIlpRtuC6lwTMfYdkXCD+oiXQfw==", "dependencies": { "types-ramda": "^0.29.4" } }, + "node_modules/@types/tinycon": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@types/tinycon/-/tinycon-0.6.3.tgz", + "integrity": "sha512-TC42m8KAyp3AqyZKRXVkk5Qy+oIU8zo2U3362i16Qan0JgZNzLawO7oYnin4BJOy8FSZfOadYYvUWQnpaXoZwg==", + "dev": true + }, "node_modules/@types/trusted-types": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", - "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz", + "integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==" }, "node_modules/@vue/compiler-core": { "version": "3.3.4", @@ -829,6 +867,11 @@ "@vue/shared": "3.3.4" } }, + "node_modules/@vue/devtools-api": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", + "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + }, "node_modules/@vue/reactivity": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz", @@ -995,9 +1038,9 @@ } }, "node_modules/bootstrap": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.1.tgz", - "integrity": "sha512-jzwza3Yagduci2x0rr9MeFSORjcHpt0lRZukZPZQJT1Dth5qzV7XcgGqYzi39KGAVYR8QEDVoO0ubFKOxzMG+g==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", + "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", "funding": [ { "type": "github", @@ -1013,9 +1056,9 @@ } }, "node_modules/bootstrap-icons": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.5.tgz", - "integrity": "sha512-oSX26F37V7QV7NCE53PPEL45d7EGXmBgHG3pDpZvcRaKVzWMqIRL9wcqJUyEha1esFtM3NJzvmxFXDxjJYD0jQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.1.tgz", + "integrity": "sha512-F0DDp7nKUX+x/QtpfRZ+XHFya60ng9nfdpdS59vDDfs4Uhuxp7zym/QavMsu/xx51txkoM9eVmpE7D08N35blw==", "funding": [ { "type": "github", @@ -1028,9 +1071,9 @@ ] }, "node_modules/bootstrap5-tags": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/bootstrap5-tags/-/bootstrap5-tags-1.6.7.tgz", - "integrity": "sha512-9EZT3o4BqGGG/IzyHMVH+MX4JS0hSMu/7Zubp8Mlh/NX4MeNLPCXgV0xW3aUpR4JaKk+NOlojgBPTMX5aa9ywQ==" + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/bootstrap5-tags/-/bootstrap5-tags-1.6.9.tgz", + "integrity": "sha512-4gxjYaLX9iLWCxabxUNexAaCcxpjgd7Ix1eYRWyRm/doIpID1aeKOI+sQG885ANmmExr0YTu73NE/hFfsuQb2w==" }, "node_modules/brace-expansion": { "version": "2.0.1", @@ -1075,6 +1118,17 @@ "ieee754": "^1.2.1" } }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -1151,23 +1205,15 @@ } }, "node_modules/core-js-pure": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.32.0.tgz", - "integrity": "sha512-qsev1H+dTNYpDUEURRuOXMvpdtAnNEvQWS/FMJ2Vb5AY8ZP4rAPQldkE27joykZPJTe0+IVgHZYh1P5Xu1/i1g==", + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.32.2.tgz", + "integrity": "sha512-Y2rxThOuNywTjnX/PgA5vWM6CZ9QB9sz9oGeCixV8MqXZO70z/5SHzf9EeBrEBK0PN36DnEBBu9O/aGWzKuMZQ==", "hasInstallScript": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, - "node_modules/cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", @@ -1232,9 +1278,9 @@ } }, "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.3.tgz", + "integrity": "sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==", "dev": true, "hasInstallScript": true, "bin": { @@ -1244,28 +1290,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/android-arm": "0.19.3", + "@esbuild/android-arm64": "0.19.3", + "@esbuild/android-x64": "0.19.3", + "@esbuild/darwin-arm64": "0.19.3", + "@esbuild/darwin-x64": "0.19.3", + "@esbuild/freebsd-arm64": "0.19.3", + "@esbuild/freebsd-x64": "0.19.3", + "@esbuild/linux-arm": "0.19.3", + "@esbuild/linux-arm64": "0.19.3", + "@esbuild/linux-ia32": "0.19.3", + "@esbuild/linux-loong64": "0.19.3", + "@esbuild/linux-mips64el": "0.19.3", + "@esbuild/linux-ppc64": "0.19.3", + "@esbuild/linux-riscv64": "0.19.3", + "@esbuild/linux-s390x": "0.19.3", + "@esbuild/linux-x64": "0.19.3", + "@esbuild/netbsd-x64": "0.19.3", + "@esbuild/openbsd-x64": "0.19.3", + "@esbuild/sunos-x64": "0.19.3", + "@esbuild/win32-arm64": "0.19.3", + "@esbuild/win32-ia32": "0.19.3", + "@esbuild/win32-x64": "0.19.3" } }, "node_modules/esbuild-plugin-vue-next": { @@ -1282,16 +1328,16 @@ } }, "node_modules/esbuild-sass-plugin": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-2.10.0.tgz", - "integrity": "sha512-STv849QGT8g77RRFmroSt4VBVKjv+dypKcO4aWz8IP4G5JbRH0KC0+B8ODuzlUNu9R5MbkGcev/62RDP/JcZ2Q==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-2.15.0.tgz", + "integrity": "sha512-T0GCHVfeuGBBgY5k19RbExd7vVuC3lzrK8IZbXOqZftw6N9lTBnZuqKhnhdAJBcu6wek7K/fXJ2zzY6KrcNtAg==", "dev": true, "dependencies": { "resolve": "^1.22.2", - "sass": "^1.63.0" + "sass": "^1.65.1" }, "peerDependencies": { - "esbuild": "^0.18.0" + "esbuild": "^0.19.1" } }, "node_modules/estree-walker": { @@ -1326,9 +1372,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "funding": [ { "type": "individual", @@ -1357,23 +1403,6 @@ "node": ">= 6" } }, - "node_modules/form-data-encoder": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.9.0.tgz", - "integrity": "sha512-rahaRMkN8P8d/tgK/BLPX+WBVM27NbvdXBxqQujBtkDAIFspaRqN7Od7lfdGQA6KAD+f82fYCLBq1ipvcu8qLw==" - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -1381,9 +1410,9 @@ "optional": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1490,9 +1519,9 @@ ] }, "node_modules/immutable": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.2.tgz", - "integrity": "sha512-oGXzbEDem9OOpDWZu88jGiYCvIsLHMvGw+8OXlpsvTFvIQplQbjg1B1cvKg8f7Hoch6+NGjpPsH1Fr+Mc2D1aA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", "dev": true }, "node_modules/inherits": { @@ -1626,9 +1655,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", + "version": "0.30.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz", + "integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, @@ -1719,9 +1748,9 @@ "optional": true }, "node_modules/modern-screenshot": { - "version": "4.4.30", - "resolved": "https://registry.npmjs.org/modern-screenshot/-/modern-screenshot-4.4.30.tgz", - "integrity": "sha512-rC6SC40NEP04qZqthKM+W3xttz3NuNOpyMFMZ+P//zoBxsSrQbrBGYL/Sp1h6U9TKmIzyj3vEymVwdcwl7EEiA==" + "version": "4.4.31", + "resolved": "https://registry.npmjs.org/modern-screenshot/-/modern-screenshot-4.4.31.tgz", + "integrity": "sha512-qBK9XduvgkfdmtjHnxX2GHq1pYYhylNEyP/xqxN2g1VCzqKwL2QIOgmMSCmpWHemETXDW8LKckdJzWUAoD3D+Q==" }, "node_modules/moment": { "version": "2.29.4", @@ -1732,9 +1761,9 @@ } }, "node_modules/nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", "optional": true }, "node_modules/nanoid": { @@ -1761,9 +1790,9 @@ "optional": true }, "node_modules/node-abi": { - "version": "3.45.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz", - "integrity": "sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==", + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.47.0.tgz", + "integrity": "sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==", "optional": true, "dependencies": { "semver": "^7.3.5" @@ -1772,6 +1801,11 @@ "node": ">=10" } }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -1790,23 +1824,20 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "node_modules/node-fetch-commonjs": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch-commonjs/-/node-fetch-commonjs-3.3.2.tgz", + "integrity": "sha512-VBlAiynj3VMLrotgwOS3OyECFxas5y7ltLcK4t41lMUZeaK15Ym4QRkqN0EQKAFL42q9i21EPKjzLUPfltR72A==", "dependencies": { - "whatwg-url": "^5.0.0" + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" }, "engines": { - "node": "4.x || >=6.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/normalize-path": { @@ -1859,9 +1890,9 @@ } }, "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.30", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz", + "integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==", "funding": [ { "type": "opencollective", @@ -1942,11 +1973,6 @@ "once": "^1.3.1" } }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, "node_modules/qs": { "version": "6.11.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", @@ -1971,9 +1997,9 @@ } }, "node_modules/ramda-adjunct": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ramda-adjunct/-/ramda-adjunct-4.0.0.tgz", - "integrity": "sha512-W/NiJAlZdwZ/iUkWEQQgRdH5Szqqet1WoVH9cdqDVjFbVaZHuJfJRvsxqHhvq6tZse+yVbFatLDLdVa30wBlGQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ramda-adjunct/-/ramda-adjunct-4.1.1.tgz", + "integrity": "sha512-BnCGsZybQZMDGram9y7RiryoRHS5uwx8YeGuUeDKuZuvK38XO6JJfmK85BwRWAKFA6pZ5nZBO/HBFtExVaf31w==", "engines": { "node": ">=0.10.3" }, @@ -2044,9 +2070,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/repeat-string": { "version": "1.6.1", @@ -2057,9 +2083,9 @@ } }, "node_modules/resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -2094,9 +2120,9 @@ "optional": true }, "node_modules/sass": { - "version": "1.64.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.2.tgz", - "integrity": "sha512-TnDlfc+CRnUAgLO9D8cQLFu/GIjJIzJCGkE7o4ekIGQOH7T3GetiRR/PsTWJUHhkzcSPrARkPI+gNWn5alCzDg==", + "version": "1.68.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz", + "integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -2126,9 +2152,9 @@ } }, "node_modules/short-unique-id": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/short-unique-id/-/short-unique-id-4.4.4.tgz", - "integrity": "sha512-oLF1NCmtbiTWl2SqdXZQbo5KM1b7axdp0RgQLq8qCBBLoq+o3A5wmLrNM6bZIh54/a8BJ3l69kTXuxwZ+XCYuw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/short-unique-id/-/short-unique-id-5.0.2.tgz", + "integrity": "sha512-4wZq1VLV4hsEx8guP5bN7XnY8UDsVXtdUDWFMP1gvEieAXolq5fWGKpuua21PRXaLn3OybTKFQNm7JGcHSWu/Q==", "bin": { "short-unique-id": "bin/short-unique-id", "suid": "bin/short-unique-id" @@ -2205,6 +2231,14 @@ "resolved": "https://registry.npmjs.org/stampit/-/stampit-4.3.2.tgz", "integrity": "sha512-pE2org1+ZWQBnIxRPrBM2gVupkuDD0TTNIo1H6GdT/vO82NXli2z8lRE8cu/nBIHrcOCXFBAHpb9ZldrB2/qOA==" }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -2236,27 +2270,25 @@ } }, "node_modules/swagger-client": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.20.0.tgz", - "integrity": "sha512-5RLge2NIE1UppIT/AjUPEceT05hcBAzjiQkrXJYjpxsbFV/UDH3pp+fsrWbAeuZtgRdhNB9KDo+szLoUpzkydQ==", + "version": "3.22.3", + "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.22.3.tgz", + "integrity": "sha512-9I3BGD/6LItBzvJoKaRZ+QQ7IcEKq+iVlvvvcfZz65WgnXkORM1uj5+M+Oa5d8Tu5qABuOXd1UnlClBPuTITBA==", "dependencies": { - "@babel/runtime-corejs3": "^7.20.13", - "@swagger-api/apidom-core": ">=0.74.1 <1.0.0", - "@swagger-api/apidom-json-pointer": ">=0.74.1 <1.0.0", - "@swagger-api/apidom-ns-openapi-3-1": ">=0.74.1 <1.0.0", - "@swagger-api/apidom-reference": ">=0.74.1 <1.0.0", + "@babel/runtime-corejs3": "^7.22.15", + "@swagger-api/apidom-core": ">=0.76.2 <1.0.0", + "@swagger-api/apidom-json-pointer": ">=0.76.2 <1.0.0", + "@swagger-api/apidom-ns-openapi-3-1": ">=0.76.2 <1.0.0", + "@swagger-api/apidom-reference": ">=0.76.2 <1.0.0", "cookie": "~0.5.0", - "cross-fetch": "^3.1.5", "deepmerge": "~4.3.0", "fast-json-patch": "^3.0.0-1", - "form-data-encoder": "^1.4.3", - "formdata-node": "^4.0.0", "is-plain-object": "^5.0.0", "js-yaml": "^4.1.0", - "lodash": "^4.17.21", + "node-abort-controller": "^3.1.1", + "node-fetch-commonjs": "^3.3.1", "qs": "^6.10.2", "traverse": "~0.6.6", - "url": "~0.11.0" + "undici": "^5.24.0" } }, "node_modules/tar-fs": { @@ -2304,11 +2336,6 @@ "node": ">=8.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, "node_modules/traverse": { "version": "0.6.7", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", @@ -2373,20 +2400,22 @@ "ts-toolbelt": "^9.6.0" } }, + "node_modules/undici": { + "version": "5.25.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.25.1.tgz", + "integrity": "sha512-nTw6b2G2OqP6btYPyghCgV4hSwjJlL/78FMJatVLCa3otj6PCOQSt6dVtYt82OtNqFz8XsnJ+vsXLADPXjPhqw==", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/unraw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unraw/-/unraw-3.0.0.tgz", "integrity": "sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==" }, - "node_modules/url": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.1.tgz", - "integrity": "sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==", - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.11.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2413,12 +2442,26 @@ "vue": "^3" } }, + "node_modules/vue-router": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz", + "integrity": "sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, "node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", "engines": { - "node": ">= 14" + "node": ">= 8" } }, "node_modules/web-tree-sitter": { @@ -2427,20 +2470,6 @@ "integrity": "sha512-zKGJW9r23y3BcJusbgvnOH2OYAW40MXAOi9bi3Gcc7T4Gms9WWgXF8m6adsJWpGJEhgOzCrfiz1IzKowJWrtYw==", "optional": true }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 7ebd43b..53836f5 100644 --- a/package.json +++ b/package.json @@ -20,12 +20,15 @@ "rapidoc": "^9.3.4", "tinycon": "^0.6.8", "vue": "^3.2.13", - "vue-css-donut-chart": "^2.0.0" + "vue-css-donut-chart": "^2.0.0", + "vue-router": "^4.2.4" }, "devDependencies": { "@popperjs/core": "^2.11.5", + "@types/bootstrap": "^5.2.7", + "@types/tinycon": "^0.6.3", "@vue/compiler-sfc": "^3.2.37", - "esbuild": "^0.18.10", + "esbuild": "^0.19.1", "esbuild-plugin-vue-next": "^0.1.4", "esbuild-sass-plugin": "^2.3.2" } diff --git a/server/apiv1/api.go b/server/apiv1/api.go index 59d564e..07834c9 100644 --- a/server/apiv1/api.go +++ b/server/apiv1/api.go @@ -131,8 +131,8 @@ func Search(w http.ResponseWriter, r *http.Request) { res.Start = start res.Messages = messages - res.Count = results // legacy - now undocumented in API specs - res.Total = stats.Total + res.Count = len(messages) // legacy - now undocumented in API specs + res.Total = stats.Total // total messages in mailbox res.MessagesCount = results res.Unread = stats.Unread res.Tags = stats.Tags @@ -142,6 +142,44 @@ func Search(w http.ResponseWriter, r *http.Request) { _, _ = w.Write(bytes) } +// DeleteSearch will delete all messages matching a search +func DeleteSearch(w http.ResponseWriter, r *http.Request) { + // swagger:route DELETE /api/v1/search messages MessagesSummary + // + // # Delete messages by search + // + // Deletes messages matching a search. + // + // Produces: + // - application/json + // + // Schemes: http, https + // + // Parameters: + // + name: query + // in: query + // description: Search query + // required: true + // type: string + // + // Responses: + // 200: OKResponse + // default: ErrorResponse + search := strings.TrimSpace(r.URL.Query().Get("query")) + if search == "" { + httpError(w, "Error: no search query") + return + } + + if err := storage.DeleteSearch(search); err != nil { + httpError(w, err.Error()) + return + } + + w.Header().Add("Content-Type", "text/plain") + _, _ = w.Write([]byte("ok")) +} + // GetMessage (method: GET) returns the Message as JSON func GetMessage(w http.ResponseWriter, r *http.Request) { // swagger:route GET /api/v1/message/{ID} message Message @@ -368,7 +406,7 @@ func DeleteMessages(w http.ResponseWriter, r *http.Request) { } } - w.Header().Add("Content-Type", "text/plain") + w.Header().Add("Content-Type", "application/json") _, _ = w.Write([]byte("ok")) } @@ -451,6 +489,35 @@ func SetReadStatus(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("ok")) } +// GetTags (method: GET) will get all tags currently in use +func GetTags(w http.ResponseWriter, _ *http.Request) { + // swagger:route GET /api/v1/tags tags SetTags + // + // # Get all current tags + // + // Returns a JSON array of all unique message tags. + // + // Produces: + // - application/json + // + // Schemes: http, https + // + // Responses: + // 200: ArrayResponse + // default: ErrorResponse + + tags := storage.GetAllTags() + + data, err := json.Marshal(tags) + if err != nil { + httpError(w, err.Error()) + return + } + + w.Header().Add("Content-Type", "application/json") + _, _ = w.Write(data) +} + // SetTags (method: PUT) will set the tags for all provided IDs func SetTags(w http.ResponseWriter, r *http.Request) { // swagger:route PUT /api/v1/tags tags SetTags @@ -778,7 +845,7 @@ func getStartLimit(req *http.Request) (start int, limit int) { } // GetOptions returns a blank response -func GetOptions(w http.ResponseWriter, r *http.Request) { +func GetOptions(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/plain") _, _ = w.Write([]byte("")) diff --git a/server/apiv1/swagger.go b/server/apiv1/swagger.go index 4c259cd..ee83f01 100644 --- a/server/apiv1/swagger.go +++ b/server/apiv1/swagger.go @@ -96,3 +96,7 @@ type okResponse struct { // in: body Body string } + +// Plain JSON array response +// swagger:response ArrayResponse +type arrayResponse []string diff --git a/server/server.go b/server/server.go index 3841365..6e683fb 100644 --- a/server/server.go +++ b/server/server.go @@ -12,11 +12,13 @@ import ( "os" "strings" "sync/atomic" + "text/template" "github.com/axllent/mailpit/config" "github.com/axllent/mailpit/server/apiv1" "github.com/axllent/mailpit/server/handlers" "github.com/axllent/mailpit/server/websockets" + "github.com/axllent/mailpit/storage" "github.com/axllent/mailpit/utils/logger" "github.com/gorilla/mux" ) @@ -42,7 +44,7 @@ func Listen() { go websockets.MessageHub.Run() - r := defaultRoutes() + r := apiRoutes() // kubernetes probes r.HandleFunc(config.Webroot+"livez", handlers.HealthzHandler) @@ -51,18 +53,24 @@ func Listen() { // proxy handler for screenshots r.HandleFunc(config.Webroot+"proxy", middleWareFunc(handlers.ProxyHandler)).Methods("GET") - // web UI websocket - r.HandleFunc(config.Webroot+"api/events", apiWebsocket).Methods("GET") - - // virtual filesystem for others - r.PathPrefix(config.Webroot).Handler(middlewareHandler(http.StripPrefix(config.Webroot, http.FileServer(http.FS(serverRoot))))) + // virtual filesystem for /dist/ & some individual files + r.PathPrefix(config.Webroot + "dist/").Handler(middlewareHandler(http.StripPrefix(config.Webroot, http.FileServer(http.FS(serverRoot))))) + r.PathPrefix(config.Webroot + "api/").Handler(middlewareHandler(http.StripPrefix(config.Webroot, http.FileServer(http.FS(serverRoot))))) + r.Path(config.Webroot + "favicon.ico").Handler(middlewareHandler(http.StripPrefix(config.Webroot, http.FileServer(http.FS(serverRoot))))) + r.Path(config.Webroot + "favicon.svg").Handler(middlewareHandler(http.StripPrefix(config.Webroot, http.FileServer(http.FS(serverRoot))))) + r.Path(config.Webroot + "mailpit.svg").Handler(middlewareHandler(http.StripPrefix(config.Webroot, http.FileServer(http.FS(serverRoot))))) + r.Path(config.Webroot + "notification.png").Handler(middlewareHandler(http.StripPrefix(config.Webroot, http.FileServer(http.FS(serverRoot))))) // redirect to webroot if no trailing slash if config.Webroot != "/" { - redir := strings.TrimRight(config.Webroot, "/") - r.HandleFunc(redir, middleWareFunc(addSlashToWebroot)).Methods("GET") + redirect := strings.TrimRight(config.Webroot, "/") + r.HandleFunc(redirect, middleWareFunc(addSlashToWebroot)).Methods("GET") } + // handle everything else with the virtual index.html + r.PathPrefix(config.Webroot).Handler(middleWareFunc(index)).Methods("GET") + + // put it all together http.Handle("/", r) if config.UIAuthFile != "" { @@ -81,15 +89,17 @@ func Listen() { } } -func defaultRoutes() *mux.Router { +func apiRoutes() *mux.Router { r := mux.NewRouter() // API V1 r.HandleFunc(config.Webroot+"api/v1/messages", middleWareFunc(apiv1.GetMessages)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/messages", middleWareFunc(apiv1.SetReadStatus)).Methods("PUT") r.HandleFunc(config.Webroot+"api/v1/messages", middleWareFunc(apiv1.DeleteMessages)).Methods("DELETE") + r.HandleFunc(config.Webroot+"api/v1/tags", middleWareFunc(apiv1.GetTags)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/tags", middleWareFunc(apiv1.SetTags)).Methods("PUT") r.HandleFunc(config.Webroot+"api/v1/search", middleWareFunc(apiv1.Search)).Methods("GET") + r.HandleFunc(config.Webroot+"api/v1/search", middleWareFunc(apiv1.DeleteSearch)).Methods("DELETE") r.HandleFunc(config.Webroot+"api/v1/message/{id}/part/{partID}", middleWareFunc(apiv1.DownloadAttachment)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/message/{id}/part/{partID}/thumb", middleWareFunc(apiv1.Thumbnail)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/message/{id}/headers", middleWareFunc(apiv1.GetHeaders)).Methods("GET") @@ -104,6 +114,9 @@ func defaultRoutes() *mux.Router { r.HandleFunc(config.Webroot+"api/v1/webui", middleWareFunc(apiv1.WebUIConfig)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/swagger.json", middleWareFunc(swaggerBasePath)).Methods("GET") + // web UI websocket + r.HandleFunc(config.Webroot+"api/events", apiWebsocket).Methods("GET") + // return blank 200 response for OPTIONS requests for CORS r.PathPrefix(config.Webroot + "api/v1/").Handler(middleWareFunc(apiv1.GetOptions)).Methods("OPTIONS") @@ -211,6 +224,7 @@ func addSlashToWebroot(w http.ResponseWriter, r *http.Request) { // Websocket to broadcast changes func apiWebsocket(w http.ResponseWriter, r *http.Request) { websockets.ServeWs(websockets.MessageHub, w, r) + storage.BroadcastMailboxStats() } // Wrapper to artificially inject a basePath to the swagger.json if a webroot has been specified @@ -230,3 +244,59 @@ func swaggerBasePath(w http.ResponseWriter, _ *http.Request) { w.Header().Add("Content-Type", "application/json") _, _ = w.Write(f) } + +// Just returns the default HTML template +func index(w http.ResponseWriter, _ *http.Request) { + + var h = ` + + + + + + + + + Mailpit + + + + +
+ +
+ + + + +` + + t, err := template.New("index").Parse(h) + if err != nil { + panic(err) + } + + data := struct { + Webroot string + Version string + }{ + Webroot: config.Webroot, + Version: config.Version, + } + + buff := new(bytes.Buffer) + + err = t.Execute(buff, data) + if err != nil { + panic(err) + } + + buff.Bytes() + + // f, err := embeddedFS.ReadFile("public/index.html") + // if err != nil { + // panic(err) + // } + w.Header().Add("Content-Type", "text/html") + _, _ = w.Write(buff.Bytes()) +} diff --git a/server/server_test.go b/server/server_test.go index fc41dd1..96499d8 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "net/url" @@ -29,7 +29,7 @@ func Test_APIv1(t *testing.T) { setup() defer storage.Close() - r := defaultRoutes() + r := apiRoutes() ts := httptest.NewServer(r) defer ts.Close() @@ -57,8 +57,8 @@ func Test_APIv1(t *testing.T) { // read first 10 t.Log("Read first 10 messages including raw & headers") putIDS := []string{} - for indx, msg := range m.Messages { - if indx == 10 { + for idx, msg := range m.Messages { + if idx == 10 { break } @@ -253,7 +253,7 @@ func clientGet(url string) ([]byte, error) { defer resp.Body.Close() - data, err := ioutil.ReadAll(resp.Body) + data, err := io.ReadAll(resp.Body) return data, err } @@ -278,7 +278,7 @@ func clientDelete(url, body string) ([]byte, error) { return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode) } - data, err := ioutil.ReadAll(resp.Body) + data, err := io.ReadAll(resp.Body) return data, err } @@ -303,7 +303,7 @@ func clientPut(url, body string) ([]byte, error) { return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode) } - data, err := ioutil.ReadAll(resp.Body) + data, err := io.ReadAll(resp.Body) return data, err } diff --git a/server/ui-src/App.vue b/server/ui-src/App.vue index c194040..79a9bca 100644 --- a/server/ui-src/App.vue +++ b/server/ui-src/App.vue @@ -1,1227 +1,37 @@ diff --git a/server/ui-src/app.js b/server/ui-src/app.js index 4861314..614f92d 100644 --- a/server/ui-src/app.js +++ b/server/ui-src/app.js @@ -1,7 +1,11 @@ -import { createApp } from 'vue'; -import App from './App.vue'; -import "./assets/styles.scss"; -import "bootstrap-icons/font/bootstrap-icons.scss"; -import "bootstrap"; +import App from './App.vue' +import router from './router' +import { createApp } from 'vue' -createApp(App).mount('#app'); +import './assets/styles.scss' +import 'bootstrap-icons/font/bootstrap-icons.scss' +import 'bootstrap' + +const app = createApp(App) +app.use(router) +app.mount('#app') diff --git a/server/ui-src/assets/bootstrap.scss b/server/ui-src/assets/_bootstrap.scss similarity index 97% rename from server/ui-src/assets/bootstrap.scss rename to server/ui-src/assets/_bootstrap.scss index 8621b02..91c2bfa 100644 --- a/server/ui-src/assets/bootstrap.scss +++ b/server/ui-src/assets/_bootstrap.scss @@ -39,7 +39,7 @@ // @import "bootstrap/scss/popover"; // @import "bootstrap/scss/carousel"; @import "bootstrap/scss/spinners"; -// @import "bootstrap/scss/offcanvas"; +@import "bootstrap/scss/offcanvas"; // @import "bootstrap/scss/popover"; @import "bootstrap/scss/progress"; diff --git a/server/ui-src/assets/_bootstrap_variables.scss b/server/ui-src/assets/_bootstrap_variables.scss index f4ac6df..2197cc9 100644 --- a/server/ui-src/assets/_bootstrap_variables.scss +++ b/server/ui-src/assets/_bootstrap_variables.scss @@ -1,9 +1,21 @@ // Removed "Noto Color Emoji" from list re: https://github.com/axllent/mailpit/issues/92 -$font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", - Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; +$font-family-sans-serif: + system-ui, + -apple-system, + "Segoe UI", + Roboto, + "Helvetica Neue", + "Noto Sans", + "Liberation Sans", + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol"; $link-decoration: none; $primary: #2c3e50; $list-group-disabled-color: #adb5bd; $enable-negative-margins: true; $body-color-dark: #e7eaed; +$offcanvas-border-width: 0; diff --git a/server/ui-src/assets/styles.scss b/server/ui-src/assets/styles.scss index 93df3c7..d2f500d 100644 --- a/server/ui-src/assets/styles.scss +++ b/server/ui-src/assets/styles.scss @@ -1,373 +1,376 @@ @import "./bootstrap"; [v-cloak] { - display: none !important; + display: none !important; } .navbar { - z-index: 99; + z-index: 99; - .navbar-brand { - color: #2d4a5d; - transition: all 0.2s; + .navbar-brand { + color: #2d4a5d; + transition: all 0.2s; - img { - width: 40px; - } + img { + width: 40px; + } - @include media-breakpoint-down(md) { - padding: 0; + @include media-breakpoint-down(md) { + padding: 0; - img { - width: 35px; - } - } - } + img { + width: 35px; + } + } + } } .navbar-brand { - span { - opacity: 0.8; - transition: all 0.5s; - } + span { + opacity: 0.8; + transition: all 0.5s; + } - &:hover { - span { - opacity: 1; - } - } + &:hover { + span { + opacity: 1; + } + } } .nav-tabs .nav-link { - @include media-breakpoint-down(xl) { - padding-left: 10px; - padding-right: 10px; - } + @include media-breakpoint-down(xl) { + padding-left: 10px; + padding-right: 10px; + } } :not(.text-view) > a:not(.no-icon) { - &[href^="http://"], - &[href^="https://"] - { - &:after { - content: "\f1c5"; - display: inline-block; - font-family: "bootstrap-icons" !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -0.125em; - margin-left: 4px; - } - } + &[href^="http://"], + &[href^="https://"] + { + &:after { + content: "\f1c5"; + display: inline-block; + font-family: "bootstrap-icons" !important; + font-style: normal; + font-weight: normal !important; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: -0.125em; + margin-left: 4px; + } + } } -#loading { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background: rgba(255, 255, 255, 0.4); - z-index: 1500; +.loader { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(255, 255, 255, 0.4); + z-index: 1500; } // dark mode adjustments @include color-mode(dark) { - #loading { - background: rgba(0, 0, 0, 0.4); - } + .loader { + background: rgba(0, 0, 0, 0.4); + } - .token.tag, - .token.property { - color: #ee6969; - } + .token.tag, + .token.property { + color: #ee6969; + } +} + +.about-mailpit { + @include media-breakpoint-down(md) { + width: var(--bs-offcanvas-width); + margin-left: -1rem !important; + } } .message { - &.read { - color: $text-muted; + &.read { + color: $text-muted; - b { - font-weight: normal; - } - } - &.selected { - background: var(--bs-primary-bg-subtle); - } + b { + font-weight: normal; + } + } + &.selected { + background: var(--bs-primary-bg-subtle); + } } #nav-plain-text .text-view, #nav-source { - white-space: pre; - font-family: - Courier New, - Courier, - System, - fixed-width; - font-size: 0.85em; + white-space: pre; + font-family: "Courier New", Courier, System, fixed-width; + font-size: 0.85em; } #nav-html-source pre[class*="language-"] code { - white-space: pre-wrap; + white-space: pre-wrap; } #nav-plain-text .text-view { - white-space: pre-wrap; + white-space: pre-wrap; } .messageHeaders { - margin: 15px 0 0; + margin: 15px 0 0; - th { - padding-right: 1.5rem; - font-weight: normal; - vertical-align: top; - } + th { + padding-right: 1.5rem; + font-weight: normal; + vertical-align: top; + } - td { - vertical-align: top; - } + td { + vertical-align: top; + } } #nav-html { - @include media-breakpoint-up(md) { - padding-right: 1.5rem; - } + @include media-breakpoint-up(md) { + padding-right: 1.5rem; + } } #preview-html { - min-height: 300px; + min-height: 300px; - &.tablet, - &.phone { - border: solid $gray-300 1px; - } + &.tablet, + &.phone { + border: solid $gray-300 1px; + } } #responsive-view { - margin: auto; - transition: width 0.5s; - position: relative; + margin: auto; + transition: width 0.5s; + position: relative; - &.tablet, - &.phone { - border-radius: 35px; - box-sizing: content-box; - padding-bottom: 76px; - padding-top: 54px; - padding-left: 10px; - padding-right: 10px; - background: $gray-800; + &.tablet, + &.phone { + border-radius: 35px; + box-sizing: content-box; + padding-bottom: 76px; + padding-top: 54px; + padding-left: 10px; + padding-right: 10px; + background: $gray-800; - iframe { - height: 100% !important; - background: #fff; - } - } + iframe { + height: 100% !important; + background: #fff; + } + } - &.phone { - &::before { - border-radius: 5px; - background: $gray-600; - top: 22px; - content: ""; - display: block; - height: 10px; - left: 50%; - position: absolute; - transform: translateX(-50%); - width: 80px; - } + &.phone { + &::before { + border-radius: 5px; + background: $gray-600; + top: 22px; + content: ""; + display: block; + height: 10px; + left: 50%; + position: absolute; + transform: translateX(-50%); + width: 80px; + } - &::after { - border-radius: 20px; - background: $gray-900; - bottom: 20px; - content: ""; - display: block; - width: 65px; - height: 40px; - left: 50%; - position: absolute; - transform: translateX(-50%); - } - } + &::after { + border-radius: 20px; + background: $gray-900; + bottom: 20px; + content: ""; + display: block; + width: 65px; + height: 40px; + left: 50%; + position: absolute; + transform: translateX(-50%); + } + } - &.tablet { - &::before { - border-radius: 50%; - border: solid #b5b0b0 2px; - top: 22px; - content: ""; - display: block; - width: 10px; - height: 10px; - left: 50%; - position: absolute; - transform: translateX(-50%); - } + &.tablet { + &::before { + border-radius: 50%; + border: solid #b5b0b0 2px; + top: 22px; + content: ""; + display: block; + width: 10px; + height: 10px; + left: 50%; + position: absolute; + transform: translateX(-50%); + } - &::after { - border-radius: 50%; - border: solid #b5b0b0 2px; - bottom: 23px; - content: ""; - display: block; - width: 30px; - height: 30px; - left: 50%; - position: absolute; - transform: translateX(-50%); - } - } + &::after { + border-radius: 50%; + border: solid #b5b0b0 2px; + bottom: 23px; + content: ""; + display: block; + width: 30px; + height: 30px; + left: 50%; + position: absolute; + transform: translateX(-50%); + } + } } .list-group-item.message:first-child { - border-top: 0; + border-top: 0; } body.blur { - .privacy { - filter: blur(3px); - } + .privacy { + filter: blur(3px); + } } .card.attachment { - color: $gray-800; + color: $gray-800; - .icon { - position: absolute; - top: 18px; - left: 0; - right: 0; - font-size: 3.5rem; - text-align: center; - color: $gray-300; - } + .icon { + position: absolute; + top: 18px; + left: 0; + right: 0; + font-size: 3.5rem; + text-align: center; + color: $gray-300; + } - .card-body { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - overflow: hidden; - opacity: 0; - } + .card-body { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: hidden; + opacity: 0; + } - .card-footer { - background: $gray-300; + .card-footer { + background: $gray-300; - .bi { - font-size: 1.3em; - margin-left: -10px; - } - } + .bi { + font-size: 1.3em; + margin-left: -10px; + } + } - &:hover { - .card-body { - opacity: 1; - background: $gray-300; - } - } + &:hover { + .card-body { + opacity: 1; + background: $gray-300; + } + } } .form-select.tag-selector { - display: none; + display: none; } .form-control.dropdown { - padding: 0; - border: 0; + padding: 0; + border: 0; - input { - font-size: 0.875em; - } + input { + font-size: 0.875em; + } - div { - cursor: text; // html5-tags - } + div { + cursor: text; // html5-tags + } } // bootstrap5-tags .tags-badge { - display: flex; + display: flex; } #DownloadBtn { - @include media-breakpoint-down(sm) { - position: static; + @include media-breakpoint-down(sm) { + position: static; - .dropdown-menu { - left: 0; - right: 0; - } - } + .dropdown-menu { + left: 0; + right: 0; + } + } } #ReleaseModal { - .form-control.dropdown { - div { - @extend .form-control; - } - } + .form-control.dropdown { + div { + @extend .form-control; + } + } } /* PrismJS 1.29.0 - modified! https://prismjs.com/download.html#themes=prism-coy&languages=markup+css */ code[class*="language-"], pre[class*="language-"] { - // color: #000; - // background: 0 0; - font-size: 0.85em; - text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; - word-wrap: normal; - line-height: 1.5; - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; + // color: #000; + // background: 0 0; + font-size: 0.85em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; } pre[class*="language-"] { - position: relative; - overflow: visible; + position: relative; + overflow: visible; } pre[class*="language-"] > code { - position: relative; - z-index: 1; + position: relative; + z-index: 1; } code[class*="language-"] { - max-height: inherit; - height: inherit; - padding: 0 1em; - display: block; - overflow: auto; + max-height: inherit; + height: inherit; + padding: 0 1em; + display: block; + overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { - // background-color: #fdfdfd; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - margin-bottom: 1em; + // background-color: #fdfdfd; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + margin-bottom: 1em; } :not(pre) > code[class*="language-"] { - position: relative; - padding: 0.2em; - border-radius: 0.3em; - color: #c92c2c; - border: 1px solid rgba(0, 0, 0, 0.1); - display: inline; - white-space: normal; + position: relative; + padding: 0.2em; + border-radius: 0.3em; + color: #c92c2c; + border: 1px solid rgba(0, 0, 0, 0.1); + display: inline; + white-space: normal; } .token.block-comment, @@ -375,10 +378,10 @@ pre[class*="language-"] { .token.comment, .token.doctype, .token.prolog { - color: #7d8b99; + color: #7d8b99; } .token.punctuation { - color: #5f6364; + color: #5f6364; } .token.boolean, .token.constant, @@ -388,7 +391,7 @@ pre[class*="language-"] { .token.property, .token.symbol, .token.tag { - color: #c92c2c; + color: #c92c2c; } .token.attr-name, .token.builtin, @@ -397,70 +400,70 @@ pre[class*="language-"] { .token.inserted, .token.selector, .token.string { - color: #2f9c0a; + color: #2f9c0a; } .token.entity, .token.operator, .token.url, .token.variable { - color: #a67f59; - // background: rgba(255, 255, 255, 0.5); + color: #a67f59; + // background: rgba(255, 255, 255, 0.5); } .token.atrule, .token.attr-value, .token.class-name, .token.keyword { - color: #1990b8; + color: #1990b8; } .token.important, .token.regex { - color: #e90; + color: #e90; } .language-css .token.string, .style .token.string { - color: #a67f59; - // background: rgba(255, 255, 255, 0.5); + color: #a67f59; + // background: rgba(255, 255, 255, 0.5); } .token.important { - font-weight: 400; + font-weight: 400; } .token.bold { - font-weight: 700; + font-weight: 700; } .token.italic { - font-style: italic; + font-style: italic; } // .token.entity { // cursor: help; // } .token.namespace { - opacity: 0.7; + opacity: 0.7; } @media screen and (max-width: 767px) { - pre[class*="language-"]::after, - pre[class*="language-"]::before { - bottom: 14px; - box-shadow: none; - } + pre[class*="language-"]::after, + pre[class*="language-"]::before { + bottom: 14px; + box-shadow: none; + } } pre[class*="language-"].line-numbers.line-numbers { - padding-left: 0; + padding-left: 0; } pre[class*="language-"].line-numbers.line-numbers code { - padding-left: 3.8em; + padding-left: 3.8em; } pre[class*="language-"].line-numbers.line-numbers .line-numbers-rows { - left: 0; + left: 0; } pre[class*="language-"][data-line] { - padding-top: 0; - padding-bottom: 0; - padding-left: 0; + padding-top: 0; + padding-bottom: 0; + padding-left: 0; } pre[data-line] code { - position: relative; - padding-left: 4em; + position: relative; + padding-left: 4em; } pre .line-highlight { - margin-top: 0; + margin-top: 0; } diff --git a/server/ui-src/components/AboutMailpit.vue b/server/ui-src/components/AboutMailpit.vue new file mode 100644 index 0000000..e0f6702 --- /dev/null +++ b/server/ui-src/components/AboutMailpit.vue @@ -0,0 +1,239 @@ + + + diff --git a/server/ui-src/components/AjaxLoader.vue b/server/ui-src/components/AjaxLoader.vue new file mode 100644 index 0000000..237a4d5 --- /dev/null +++ b/server/ui-src/components/AjaxLoader.vue @@ -0,0 +1,17 @@ + + + diff --git a/server/ui-src/components/ListMessages.vue b/server/ui-src/components/ListMessages.vue new file mode 100644 index 0000000..5d26f04 --- /dev/null +++ b/server/ui-src/components/ListMessages.vue @@ -0,0 +1,166 @@ + + + diff --git a/server/ui-src/components/NavMailbox.vue b/server/ui-src/components/NavMailbox.vue new file mode 100644 index 0000000..e3cd1a8 --- /dev/null +++ b/server/ui-src/components/NavMailbox.vue @@ -0,0 +1,139 @@ + + + diff --git a/server/ui-src/components/NavSearch.vue b/server/ui-src/components/NavSearch.vue new file mode 100644 index 0000000..c75f3ba --- /dev/null +++ b/server/ui-src/components/NavSearch.vue @@ -0,0 +1,115 @@ + + + diff --git a/server/ui-src/components/NavSelected.vue b/server/ui-src/components/NavSelected.vue new file mode 100644 index 0000000..b41e8f6 --- /dev/null +++ b/server/ui-src/components/NavSelected.vue @@ -0,0 +1,120 @@ + + + diff --git a/server/ui-src/components/NavTags.vue b/server/ui-src/components/NavTags.vue new file mode 100644 index 0000000..d106b3a --- /dev/null +++ b/server/ui-src/components/NavTags.vue @@ -0,0 +1,55 @@ + + + diff --git a/server/ui-src/components/Notifications.vue b/server/ui-src/components/Notifications.vue new file mode 100644 index 0000000..d10aa17 --- /dev/null +++ b/server/ui-src/components/Notifications.vue @@ -0,0 +1,176 @@ + + + diff --git a/server/ui-src/components/Pagination.vue b/server/ui-src/components/Pagination.vue new file mode 100644 index 0000000..a106ae9 --- /dev/null +++ b/server/ui-src/components/Pagination.vue @@ -0,0 +1,92 @@ + + diff --git a/server/ui-src/components/SearchForm.vue b/server/ui-src/components/SearchForm.vue new file mode 100644 index 0000000..f27343a --- /dev/null +++ b/server/ui-src/components/SearchForm.vue @@ -0,0 +1,64 @@ + + + diff --git a/server/ui-src/templates/Attachments.vue b/server/ui-src/components/message/Attachments.vue similarity index 79% rename from server/ui-src/templates/Attachments.vue rename to server/ui-src/components/message/Attachments.vue index c4457ee..db2e4f8 100644 --- a/server/ui-src/templates/Attachments.vue +++ b/server/ui-src/components/message/Attachments.vue @@ -1,6 +1,6 @@ + + diff --git a/server/ui-src/templates/MessageScreenshot.vue b/server/ui-src/components/message/Screenshot.vue similarity index 82% rename from server/ui-src/templates/MessageScreenshot.vue rename to server/ui-src/components/message/Screenshot.vue index c6a37fc..5c00611 100644 --- a/server/ui-src/templates/MessageScreenshot.vue +++ b/server/ui-src/components/message/Screenshot.vue @@ -1,5 +1,7 @@ - - diff --git a/server/ui-src/templates/MessageSummary.vue b/server/ui-src/templates/MessageSummary.vue deleted file mode 100644 index 8da74f3..0000000 --- a/server/ui-src/templates/MessageSummary.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - diff --git a/server/ui-src/templates/MessageToast.vue b/server/ui-src/templates/MessageToast.vue deleted file mode 100644 index e68cd66..0000000 --- a/server/ui-src/templates/MessageToast.vue +++ /dev/null @@ -1,44 +0,0 @@ - - - diff --git a/server/ui-src/templates/ThemeToggle.vue b/server/ui-src/templates/ThemeToggle.vue deleted file mode 100644 index 123ea7e..0000000 --- a/server/ui-src/templates/ThemeToggle.vue +++ /dev/null @@ -1,123 +0,0 @@ - - - diff --git a/server/ui-src/views/MailboxView.vue b/server/ui-src/views/MailboxView.vue new file mode 100644 index 0000000..de1e503 --- /dev/null +++ b/server/ui-src/views/MailboxView.vue @@ -0,0 +1,94 @@ + + + diff --git a/server/ui-src/views/MessageView.vue b/server/ui-src/views/MessageView.vue new file mode 100644 index 0000000..9d8dbf7 --- /dev/null +++ b/server/ui-src/views/MessageView.vue @@ -0,0 +1,323 @@ + + + diff --git a/server/ui-src/views/NotFoundView.vue b/server/ui-src/views/NotFoundView.vue new file mode 100644 index 0000000..3e086ca --- /dev/null +++ b/server/ui-src/views/NotFoundView.vue @@ -0,0 +1,29 @@ + + + diff --git a/server/ui-src/views/SearchView.vue b/server/ui-src/views/SearchView.vue new file mode 100644 index 0000000..a431c5b --- /dev/null +++ b/server/ui-src/views/SearchView.vue @@ -0,0 +1,122 @@ + + + diff --git a/server/ui/api/v1/swagger.json b/server/ui/api/v1/swagger.json index f6b0ff0..40366de 100644 --- a/server/ui/api/v1/swagger.json +++ b/server/ui/api/v1/swagger.json @@ -532,9 +532,64 @@ "$ref": "#/responses/ErrorResponse" } } + }, + "delete": { + "description": "Deletes messages matching a search.", + "produces": [ + "application/json" + ], + "schemes": [ + "http", + "https" + ], + "tags": [ + "messages" + ], + "summary": "Delete messages by search", + "operationId": "MessagesSummary", + "parameters": [ + { + "type": "string", + "description": "Search query", + "name": "query", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/OKResponse" + }, + "default": { + "$ref": "#/responses/ErrorResponse" + } + } } }, "/api/v1/tags": { + "get": { + "description": "Returns a JSON array of all unique message tags.", + "produces": [ + "application/json" + ], + "schemes": [ + "http", + "https" + ], + "tags": [ + "tags" + ], + "summary": "Get all current tags", + "operationId": "SetTags", + "responses": { + "200": { + "$ref": "#/responses/ArrayResponse" + }, + "default": { + "$ref": "#/responses/ErrorResponse" + } + } + }, "put": { "description": "To remove all tags from a message, pass an empty tags array.", "consumes": [ @@ -964,10 +1019,6 @@ "description": "Message ID", "type": "string" }, - "Read": { - "description": "Read status", - "type": "boolean" - }, "ReplyTo": { "description": "ReplyTo addresses", "type": "array", @@ -1234,6 +1285,15 @@ } }, "responses": { + "ArrayResponse": { + "description": "Plain JSON array response", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, "BinaryResponse": { "description": "Binary data response inherits the attachment's content type" }, diff --git a/server/ui/index.html b/server/ui/index.html deleted file mode 100644 index c5065cd..0000000 --- a/server/ui/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - Mailpit - - - - -
- -
- - - - - diff --git a/server/websockets/hub.go b/server/websockets/hub.go index 0df4c66..c1a47dc 100644 --- a/server/websockets/hub.go +++ b/server/websockets/hub.go @@ -79,7 +79,7 @@ func Broadcast(t string, msg interface{}) { b, err := json.Marshal(w) if err != nil { - logger.Log().Errorf("[http] broadcast received invalid data: %s", err) + logger.Log().Errorf("[websocket] broadcast received invalid data: %s", err) } go func() { MessageHub.Broadcast <- b }() diff --git a/storage/database.go b/storage/database.go index d366fab..1fc4ba1 100644 --- a/storage/database.go +++ b/storage/database.go @@ -25,7 +25,6 @@ import ( "github.com/jhillyerd/enmime" "github.com/klauspost/compress/zstd" "github.com/leporo/sqlf" - "github.com/mattn/go-shellwords" uuid "github.com/satori/go.uuid" // sqlite (native) - https://gitlab.com/cznic/sqlite @@ -317,6 +316,8 @@ func Store(body []byte) (string, error) { dbLastAction = time.Now() + BroadcastMailboxStats() + return id, nil } @@ -367,9 +368,6 @@ func List(start, limit int) ([]MessageSummary, error) { em.Read = read == 1 results = append(results, em) - - // logger.PrettyPrint(em) - }); err != nil { return results, err } @@ -379,96 +377,6 @@ func List(start, limit int) ([]MessageSummary, error) { return results, nil } -// Search will search a mailbox for search terms. -// The search is broken up by segments (exact phrases can be quoted), and interprets specific terms such as: -// is:read, is:unread, has:attachment, to:, from: & subject: -// Negative searches also also included by prefixing the search term with a `-` or `!` -func Search(search string, start, limit int) ([]MessageSummary, int, error) { - results := []MessageSummary{} - allResults := []MessageSummary{} - tsStart := time.Now() - nrResults := 0 - if limit < 0 { - limit = 50 - } - - s := strings.ToLower(search) - // add another quote if missing closing quote - quotes := strings.Count(s, `"`) - if quotes%2 != 0 { - s += `"` - } - - p := shellwords.NewParser() - args, err := p.Parse(s) - if err != nil { - return results, nrResults, errors.New("Your search contains invalid characters") - } - - // generate the SQL based on arguments - q := searchParser(args) - - if err := q.QueryAndClose(nil, db, func(row *sql.Rows) { - var created int64 - var id string - var messageID string - var subject string - var metadata string - var size int - var attachments int - var tags string - var read int - var ignore string - em := MessageSummary{} - - if err := row.Scan(&created, &id, &messageID, &subject, &metadata, &size, &attachments, &read, &tags, &ignore, &ignore, &ignore, &ignore); err != nil { - logger.Log().Error(err) - return - } - - if err := json.Unmarshal([]byte(metadata), &em); err != nil { - logger.Log().Error(err) - return - } - - if err := json.Unmarshal([]byte(tags), &em.Tags); err != nil { - logger.Log().Error(err) - return - } - - em.Created = time.UnixMilli(created) - em.ID = id - em.MessageID = messageID - em.Subject = subject - em.Size = size - em.Attachments = attachments - em.Read = read == 1 - - allResults = append(allResults, em) - }); err != nil { - return results, nrResults, err - } - - dbLastAction = time.Now() - - nrResults = len(allResults) - - if nrResults > start { - end := nrResults - if nrResults >= start+limit { - end = start + limit - } - - results = allResults[start:end] - } - - elapsed := time.Since(tsStart) - - logger.Log().Debugf("[db] search for \"%s\" in %s", search, elapsed) - - return results, nrResults, err -} - // GetMessage returns a Message generated from the mailbox_data collection. // If the message lacks a date header, then the received datetime is used. func GetMessage(id string) (*Message, error) { @@ -525,7 +433,6 @@ func GetMessage(id string) (*Message, error) { obj := Message{ ID: id, MessageID: messageID, - Read: true, From: from, Date: date, To: addressToSlice(env, "To"), @@ -651,6 +558,8 @@ func MarkRead(id string) error { logger.Log().Debugf("[db] marked message %s as read", id) } + BroadcastMailboxStats() + return err } @@ -672,6 +581,8 @@ func MarkAllRead() error { elapsed := time.Since(start) logger.Log().Debugf("[db] marked %d messages as read in %s", total, elapsed) + BroadcastMailboxStats() + dbLastAction = time.Now() return nil @@ -695,6 +606,8 @@ func MarkAllUnread() error { elapsed := time.Since(start) logger.Log().Debugf("[db] marked %d messages as unread in %s", total, elapsed) + BroadcastMailboxStats() + dbLastAction = time.Now() return nil @@ -717,6 +630,8 @@ func MarkUnread(id string) error { dbLastAction = time.Now() + BroadcastMailboxStats() + return err } @@ -751,6 +666,8 @@ func DeleteOneMessage(id string) error { dbLastAction = time.Now() dbDataDeleted = true + BroadcastMailboxStats() + return err } @@ -799,19 +716,13 @@ func DeleteAllMessages() error { dbDataDeleted = false websockets.Broadcast("prune", nil) + BroadcastMailboxStats() return err } -// StatsGet returns the total/unread statistics for a mailbox -func StatsGet() MailboxStats { - var ( - total = CountTotal() - unread = CountUnread() - ) - - dbLastAction = time.Now() - +// GetAllTags returns all used tags +func GetAllTags() []string { q := sqlf.From("mailbox"). Select(`DISTINCT Tags`). Where("Tags != ?", "[]") @@ -844,6 +755,19 @@ func StatsGet() MailboxStats { sort.Strings(tags) + return tags +} + +// StatsGet returns the total/unread statistics for a mailbox +func StatsGet() MailboxStats { + var ( + total = CountTotal() + unread = CountUnread() + tags = GetAllTags() + ) + + dbLastAction = time.Now() + return MailboxStats{ Total: total, Unread: unread, diff --git a/storage/notifications.go b/storage/notifications.go new file mode 100644 index 0000000..8b8ccbb --- /dev/null +++ b/storage/notifications.go @@ -0,0 +1,35 @@ +package storage + +import ( + "time" + + "github.com/axllent/mailpit/server/websockets" +) + +var bcStatsDelay = false + +// BroadcastMailboxStats broadcasts the total number of messages +// displayed to the web UI, as well as the total unread messages. +// The lookup is very fast (< 10ms / 100k messages under load). +// Rate limited to 4x per second. +func BroadcastMailboxStats() { + if bcStatsDelay { + return + } + + bcStatsDelay = true + + go func() { + time.Sleep(250 * time.Millisecond) + bcStatsDelay = false + b := struct { + Total int + Unread int + }{ + Total: CountTotal(), + Unread: CountUnread(), + } + + websockets.Broadcast("stats", b) + }() +} diff --git a/storage/search.go b/storage/search.go index 519bd78..c4398f7 100644 --- a/storage/search.go +++ b/storage/search.go @@ -1,14 +1,193 @@ package storage import ( + "context" + "database/sql" + "encoding/json" "regexp" "strings" + "time" + "github.com/axllent/mailpit/utils/logger" + "github.com/axllent/mailpit/utils/tools" "github.com/leporo/sqlf" ) +// Search will search a mailbox for search terms. +// The search is broken up by segments (exact phrases can be quoted), and interprets specific terms such as: +// is:read, is:unread, has:attachment, to:, from: & subject: +// Negative searches also also included by prefixing the search term with a `-` or `!` +func Search(search string, start, limit int) ([]MessageSummary, int, error) { + results := []MessageSummary{} + allResults := []MessageSummary{} + tsStart := time.Now() + nrResults := 0 + if limit < 0 { + limit = 50 + } + + q := searchParser(search) + var err error + + if err := q.QueryAndClose(nil, db, func(row *sql.Rows) { + var created int64 + var id string + var messageID string + var subject string + var metadata string + var size int + var attachments int + var tags string + var read int + var ignore string + em := MessageSummary{} + + if err := row.Scan(&created, &id, &messageID, &subject, &metadata, &size, &attachments, &read, &tags, &ignore, &ignore, &ignore, &ignore); err != nil { + logger.Log().Error(err) + return + } + + if err := json.Unmarshal([]byte(metadata), &em); err != nil { + logger.Log().Error(err) + return + } + + if err := json.Unmarshal([]byte(tags), &em.Tags); err != nil { + logger.Log().Error(err) + return + } + + em.Created = time.UnixMilli(created) + em.ID = id + em.MessageID = messageID + em.Subject = subject + em.Size = size + em.Attachments = attachments + em.Read = read == 1 + + allResults = append(allResults, em) + }); err != nil { + return results, nrResults, err + } + + dbLastAction = time.Now() + + nrResults = len(allResults) + + if nrResults > start { + end := nrResults + if nrResults >= start+limit { + end = start + limit + } + + results = allResults[start:end] + } + + elapsed := time.Since(tsStart) + + logger.Log().Debugf("[db] search for \"%s\" in %s", search, elapsed) + + return results, nrResults, err +} + +// DeleteSearch will delete all messages for search terms. +// The search is broken up by segments (exact phrases can be quoted), and interprets specific terms such as: +// is:read, is:unread, has:attachment, to:, from: & subject: +// Negative searches also also included by prefixing the search term with a `-` or `!` +func DeleteSearch(search string) error { + q := searchParser(search) + + ids := []string{} + + if err := q.QueryAndClose(nil, db, func(row *sql.Rows) { + var created int64 + var id string + var messageID string + var subject string + var metadata string + var size int + var attachments int + var tags string + var read int + var ignore string + + if err := row.Scan(&created, &id, &messageID, &subject, &metadata, &size, &attachments, &read, &tags, &ignore, &ignore, &ignore, &ignore); err != nil { + logger.Log().Error(err) + return + } + + ids = append(ids, id) + }); err != nil { + return err + } + + if len(ids) > 0 { + total := len(ids) + + // split ids into chunks + var chunks [][]string + if total > 1000 { + chunkSize := 1000 + chunks = make([][]string, 0, (len(ids)+chunkSize-1)/chunkSize) + for chunkSize < len(ids) { + ids, chunks = ids[chunkSize:], append(chunks, ids[0:chunkSize:chunkSize]) + } + } else { + chunks = append(chunks, ids) + } + + // begin a transaction to ensure both the message + // and data are deleted successfully + tx, err := db.BeginTx(context.Background(), nil) + if err != nil { + return err + } + + // roll back if it fails + defer tx.Rollback() + + for _, ids := range chunks { + delIDs := make([]interface{}, len(ids)) + for i, id := range ids { + delIDs[i] = id + } + + sqlDelete1 := `DELETE FROM mailbox WHERE ID IN (?` + strings.Repeat(",?", len(ids)-1) + `)` + + _, err = tx.Exec(sqlDelete1, delIDs...) + if err != nil { + return err + } + + sqlDelete2 := `DELETE FROM mailbox_data WHERE ID IN (?` + strings.Repeat(",?", len(ids)-1) + `)` + + _, err = tx.Exec(sqlDelete2, delIDs...) + if err != nil { + return err + } + } + + err = tx.Commit() + + if err == nil { + logger.Log().Debugf("[db] deleted %d messages matching %s", total, search) + } + + dbLastAction = time.Now() + dbDataDeleted = true + + BroadcastMailboxStats() + } + + return nil +} + // SearchParser returns the SQL syntax for the database search based on the search arguments -func searchParser(args []string) *sqlf.Stmt { +func searchParser(searchString string) *sqlf.Stmt { + searchString = strings.ToLower(searchString) + // group strings with quotes as a single argument and remove quotes + args := tools.ArgsParser(searchString) + q := sqlf.From("mailbox"). Select(`Created, ID, MessageID, Subject, Metadata, Size, Attachments, Read, Tags, IFNULL(json_extract(Metadata, '$.To'), '{}') as ToJSON, @@ -71,7 +250,7 @@ func searchParser(args []string) *sqlf.Stmt { } } } else if strings.HasPrefix(w, "subject:") { - w = cleanString(w[8:]) + w = w[8:] if w != "" { if exclude { q.Where("Subject NOT LIKE ?", "%"+escPercentChar(w)+"%") @@ -109,6 +288,12 @@ func searchParser(args []string) *sqlf.Stmt { } else { q.Where("Read = 0") } + } else if w == "is:tagged" { + if exclude { + q.Where("Tags = ?", "[]") + } else { + q.Where("Tags != ?", "[]") + } } else if w == "has:attachment" || w == "has:attachments" { if exclude { q.Where("Attachments = 0") diff --git a/storage/structs.go b/storage/structs.go index 2f01e91..e3e05df 100644 --- a/storage/structs.go +++ b/storage/structs.go @@ -15,8 +15,6 @@ type Message struct { ID string // Message ID MessageID string - // Read status - Read bool // From address From *mail.Address // To addresses diff --git a/storage/utils.go b/storage/utils.go index 2cff91e..9fccba4 100644 --- a/storage/utils.go +++ b/storage/utils.go @@ -61,7 +61,7 @@ func createSearchText(env *enmime.Envelope) string { // CleanString removes unwanted characters from stored search text and search queries func cleanString(str string) string { // remove/replace new lines - re := regexp.MustCompile(`(\r?\n|\t|>|<|"|\,|;)`) + re := regexp.MustCompile(`(\r?\n|\t|>|<|"|\,|;|\(|\))`) str = re.ReplaceAllString(str, " ") // remove duplicate whitespace and trim @@ -183,3 +183,42 @@ func inArray(k string, arr []string) bool { func escPercentChar(s string) string { return strings.ReplaceAll(s, "%", "%%") } + +// Escape certain characters in search phrases +func escSearch(str string) string { + dest := make([]byte, 0, 2*len(str)) + var escape byte + for i := 0; i < len(str); i++ { + c := str[i] + + escape = 0 + + switch c { + case 0: /* Must be escaped for 'mysql' */ + escape = '0' + break + case '\n': /* Must be escaped for logs */ + escape = 'n' + break + case '\r': + escape = 'r' + break + case '\\': + escape = '\\' + break + case '\'': + escape = '\'' + break + case '\032': //十进制26,八进制32,十六进制1a, /* This gives problems on Win32 */ + escape = 'Z' + } + + if escape != 0 { + dest = append(dest, '\\', escape) + } else { + dest = append(dest, c) + } + } + + return string(dest) +} diff --git a/utils/tools/args.go b/utils/tools/args.go new file mode 100644 index 0000000..a2cf1fa --- /dev/null +++ b/utils/tools/args.go @@ -0,0 +1,32 @@ +package tools + +import "strings" + +// ArgsParser will split a string by new words and quotes phrases +func ArgsParser(s string) []string { + args := []string{} + sb := &strings.Builder{} + quoted := false + for _, r := range s { + if r == '"' { + quoted = !quoted + sb.WriteRune(r) // keep '"' otherwise comment this line + } else if !quoted && r == ' ' { + v := strings.TrimSpace(strings.ReplaceAll(sb.String(), "\"", "")) + if v != "" { + args = append(args, v) + } + sb.Reset() + } else { + sb.WriteRune(r) + } + } + if sb.Len() > 0 { + v := strings.TrimSpace(strings.ReplaceAll(sb.String(), "\"", "")) + if v != "" { + args = append(args, v) + } + } + + return args +}