From e18c45d0b3ac7bf50a8b63545e147d810714bd88 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Thu, 14 Sep 2023 22:30:10 +1200 Subject: [PATCH 01/17] Fix: Correctly escape certain characters in search (eg: `'`) --- storage/database.go | 2 +- storage/utils.go | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/storage/database.go b/storage/database.go index d366fab..40aa219 100644 --- a/storage/database.go +++ b/storage/database.go @@ -392,7 +392,7 @@ func Search(search string, start, limit int) ([]MessageSummary, int, error) { limit = 50 } - s := strings.ToLower(search) + s := escSearch(strings.ToLower(search)) // add another quote if missing closing quote quotes := strings.Count(s, `"`) if quotes%2 != 0 { diff --git a/storage/utils.go b/storage/utils.go index 2cff91e..220aaab 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,44 @@ 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 { + str = strings.ReplaceAll(str, "(", " ") + str = strings.ReplaceAll(str, ")", " ") + 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) +} From ee49149df948f6b3969800f99980a6081e075c0f Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Thu, 14 Sep 2023 22:30:20 +1200 Subject: [PATCH 02/17] Feature: New search filter `[!]is:tagged` See #164 --- package-lock.json | 22 +- package.json | 3 +- server/server.go | 84 +- server/server_test.go | 14 +- server/ui-src/App.vue | 1226 +---------------- server/ui-src/app.js | 12 +- server/ui-src/assets/styles.scss | 568 ++++---- server/ui-src/components/AboutMailpit.vue | 210 +++ server/ui-src/components/AjaxLoader.vue | 16 + server/ui-src/components/ListMessages.vue | 119 ++ server/ui-src/components/MailboxActions.vue | 112 ++ server/ui-src/components/MailboxTags.vue | 56 + server/ui-src/components/Notifications.vue | 163 +++ server/ui-src/components/Pagination.vue | 90 ++ server/ui-src/components/SearchActions.vue | 47 + server/ui-src/components/SearchForm.vue | 65 + .../{mixins.js => mixins/CommonMixins.js} | 44 +- server/ui-src/mixins/MessagesMixins.js | 77 ++ server/ui-src/router/index.js | 42 + server/ui-src/stores/mailbox.js | 48 + server/ui-src/stores/pagination.js | 12 + server/ui-src/templates/Attachments.vue | 41 - server/ui-src/templates/Headers.vue | 38 - server/ui-src/templates/Message.vue | 461 ------- server/ui-src/templates/MessageHTMLCheck.vue | 670 --------- server/ui-src/templates/MessageLinkCheck.vue | 398 ------ server/ui-src/templates/MessageRelease.vue | 116 -- server/ui-src/templates/MessageScreenshot.vue | 144 -- server/ui-src/templates/MessageSummary.vue | 28 - server/ui-src/templates/MessageToast.vue | 44 - server/ui-src/templates/ThemeToggle.vue | 123 -- server/ui-src/views/MailboxView.vue | 84 ++ server/ui-src/views/NotFoundView.vue | 7 + server/ui-src/views/SearchView.vue | 100 ++ server/ui/index.html | 22 - storage/search.go | 6 + 36 files changed, 1697 insertions(+), 3615 deletions(-) create mode 100644 server/ui-src/components/AboutMailpit.vue create mode 100644 server/ui-src/components/AjaxLoader.vue create mode 100644 server/ui-src/components/ListMessages.vue create mode 100644 server/ui-src/components/MailboxActions.vue create mode 100644 server/ui-src/components/MailboxTags.vue create mode 100644 server/ui-src/components/Notifications.vue create mode 100644 server/ui-src/components/Pagination.vue create mode 100644 server/ui-src/components/SearchActions.vue create mode 100644 server/ui-src/components/SearchForm.vue rename server/ui-src/{mixins.js => mixins/CommonMixins.js} (89%) create mode 100644 server/ui-src/mixins/MessagesMixins.js create mode 100644 server/ui-src/router/index.js create mode 100644 server/ui-src/stores/mailbox.js create mode 100644 server/ui-src/stores/pagination.js delete mode 100644 server/ui-src/templates/Attachments.vue delete mode 100644 server/ui-src/templates/Headers.vue delete mode 100644 server/ui-src/templates/Message.vue delete mode 100644 server/ui-src/templates/MessageHTMLCheck.vue delete mode 100644 server/ui-src/templates/MessageLinkCheck.vue delete mode 100644 server/ui-src/templates/MessageRelease.vue delete mode 100644 server/ui-src/templates/MessageScreenshot.vue delete mode 100644 server/ui-src/templates/MessageSummary.vue delete mode 100644 server/ui-src/templates/MessageToast.vue delete mode 100644 server/ui-src/templates/ThemeToggle.vue create mode 100644 server/ui-src/views/MailboxView.vue create mode 100644 server/ui-src/views/NotFoundView.vue create mode 100644 server/ui-src/views/SearchView.vue delete mode 100644 server/ui/index.html diff --git a/package-lock.json b/package-lock.json index 12ddbdb..d3eddfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,8 @@ "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", @@ -829,6 +830,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", @@ -2413,6 +2419,20 @@ "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", diff --git a/package.json b/package.json index 7ebd43b..2b89247 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "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", diff --git a/server/server.go b/server/server.go index 3841365..876a444 100644 --- a/server/server.go +++ b/server/server.go @@ -12,6 +12,7 @@ import ( "os" "strings" "sync/atomic" + "text/template" "github.com/axllent/mailpit/config" "github.com/axllent/mailpit/server/apiv1" @@ -42,7 +43,7 @@ func Listen() { go websockets.MessageHub.Run() - r := defaultRoutes() + r := apiRoutes() // kubernetes probes r.HandleFunc(config.Webroot+"livez", handlers.HealthzHandler) @@ -51,18 +52,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,7 +88,7 @@ func Listen() { } } -func defaultRoutes() *mux.Router { +func apiRoutes() *mux.Router { r := mux.NewRouter() // API V1 @@ -104,6 +111,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") @@ -230,3 +240,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..6fd7e0b 100644 --- a/server/ui-src/App.vue +++ b/server/ui-src/App.vue @@ -1,1227 +1,33 @@ diff --git a/server/ui-src/app.js b/server/ui-src/app.js index 4861314..85c7f7b 100644 --- a/server/ui-src/app.js +++ b/server/ui-src/app.js @@ -1,7 +1,13 @@ -import { createApp } from 'vue'; -import App from './App.vue'; +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' + import "./assets/styles.scss"; import "bootstrap-icons/font/bootstrap-icons.scss"; import "bootstrap"; -createApp(App).mount('#app'); +const app = createApp(App) + +app.use(router) + +app.mount('#app') diff --git a/server/ui-src/assets/styles.scss b/server/ui-src/assets/styles.scss index 93df3c7..0068ac0 100644 --- a/server/ui-src/assets/styles.scss +++ b/server/ui-src/assets/styles.scss @@ -1,373 +1,369 @@ @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; + } } .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 +371,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 +384,7 @@ pre[class*="language-"] { .token.property, .token.symbol, .token.tag { - color: #c92c2c; + color: #c92c2c; } .token.attr-name, .token.builtin, @@ -397,70 +393,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..8536ce8 --- /dev/null +++ b/server/ui-src/components/AboutMailpit.vue @@ -0,0 +1,210 @@ + + + diff --git a/server/ui-src/components/AjaxLoader.vue b/server/ui-src/components/AjaxLoader.vue new file mode 100644 index 0000000..9012046 --- /dev/null +++ b/server/ui-src/components/AjaxLoader.vue @@ -0,0 +1,16 @@ + + diff --git a/server/ui-src/components/ListMessages.vue b/server/ui-src/components/ListMessages.vue new file mode 100644 index 0000000..2dd2612 --- /dev/null +++ b/server/ui-src/components/ListMessages.vue @@ -0,0 +1,119 @@ + + + diff --git a/server/ui-src/components/MailboxActions.vue b/server/ui-src/components/MailboxActions.vue new file mode 100644 index 0000000..633f820 --- /dev/null +++ b/server/ui-src/components/MailboxActions.vue @@ -0,0 +1,112 @@ + + + diff --git a/server/ui-src/components/MailboxTags.vue b/server/ui-src/components/MailboxTags.vue new file mode 100644 index 0000000..e9b3547 --- /dev/null +++ b/server/ui-src/components/MailboxTags.vue @@ -0,0 +1,56 @@ + + + diff --git a/server/ui-src/components/Notifications.vue b/server/ui-src/components/Notifications.vue new file mode 100644 index 0000000..1b3dabb --- /dev/null +++ b/server/ui-src/components/Notifications.vue @@ -0,0 +1,163 @@ + + + diff --git a/server/ui-src/components/Pagination.vue b/server/ui-src/components/Pagination.vue new file mode 100644 index 0000000..35c94ad --- /dev/null +++ b/server/ui-src/components/Pagination.vue @@ -0,0 +1,90 @@ + + diff --git a/server/ui-src/components/SearchActions.vue b/server/ui-src/components/SearchActions.vue new file mode 100644 index 0000000..0a63060 --- /dev/null +++ b/server/ui-src/components/SearchActions.vue @@ -0,0 +1,47 @@ + + + diff --git a/server/ui-src/components/SearchForm.vue b/server/ui-src/components/SearchForm.vue new file mode 100644 index 0000000..a1e4b5b --- /dev/null +++ b/server/ui-src/components/SearchForm.vue @@ -0,0 +1,65 @@ + + + diff --git a/server/ui-src/mixins.js b/server/ui-src/mixins/CommonMixins.js similarity index 89% rename from server/ui-src/mixins.js rename to server/ui-src/mixins/CommonMixins.js index 07c6fb1..f24fee0 100644 --- a/server/ui-src/mixins.js +++ b/server/ui-src/mixins/CommonMixins.js @@ -14,17 +14,27 @@ FakeModal.prototype.show = function () { } const colorHash = new ColorHash({ lightness: 0.3, saturation: [0.35, 0.5, 0.65] }); /* Common mixin functions used in apps */ -const commonMixins = { +export default { data() { return { loading: 0, tagColorCache: {}, - showTagColors: true + // showTagColors: true, } }, + beforeMount() { + // this.baseURL = this.$router.resolve(`/`).href + }, + mounted() { - this.showTagColors = localStorage.getItem('showTagsColors') + // this.showTagColors = localStorage.getItem('showTagsColors') + }, + + computed: { + baseURL() { + return window.baseURL + } }, methods: { @@ -41,6 +51,14 @@ const commonMixins = { return moment(d).format('ddd, D MMM YYYY, h:mm a'); }, + tagEncodeURI: function (tag) { + if (tag.match(/ /)) { + tag = `"${tag}"` + } + + return 'tag:' + encodeURIComponent(`${tag}`) + }, + // Ajax error message handleError: function (error) { // handle error @@ -224,17 +242,17 @@ const commonMixins = { return this.tagColorCache[s] }, - toggleTagColors: function () { - if (this.showTagColors) { - localStorage.removeItem('showTagsColors') - this.showTagColors = false - } else { - localStorage.setItem('showTagsColors', '1') - this.showTagColors = true - } - } + // toggleTagColors: function () { + // if (this.showTagColors) { + // localStorage.removeItem('showTagsColors') + // this.showTagColors = false + // } else { + // localStorage.setItem('showTagsColors', '1') + // this.showTagColors = true + // } + // } } } -export default commonMixins; +// export default commonMixins; diff --git a/server/ui-src/mixins/MessagesMixins.js b/server/ui-src/mixins/MessagesMixins.js new file mode 100644 index 0000000..3e104a6 --- /dev/null +++ b/server/ui-src/mixins/MessagesMixins.js @@ -0,0 +1,77 @@ +import CommonMixins from './CommonMixins.js' +import { mailbox } from "../stores/mailbox.js" +import { pagination } from "../stores/pagination.js" + +export default { + mixins: [CommonMixins], + + data() { + return { + apiURI: false, + pagination, + mailbox, + } + }, + + watch: { + 'mailbox.refresh': function (v) { + if (v) { + // trigger a refresh + this.loadMessages() + } + + mailbox.refresh = false + } + }, + + methods: { + reloadMailbox: function () { + pagination.start = 0; + this.loadMessages() + }, + + loadMessages: function () { + if (!this.apiURI) { + alert('apiURL not set!') + return + } + + let self = this + let params = {} + mailbox.selected = [] + + params['limit'] = pagination.limit + if (pagination.start > 0) { + params['start'] = pagination.start + } + + self.get(this.apiURI, params, function (response) { + mailbox.total = response.data.total // all messages + mailbox.unread = response.data.unread // all unread messages + mailbox.tags = response.data.tags // all tags + mailbox.messages = response.data.messages // current messages + mailbox.count = response.data.messages_count // total results for this mailbox/search + // ensure the pagination remains consistent + pagination.start = response.data.start + + // pagination.total = response.data.messages_count + // self.existingTags = JSON.parse(JSON.stringify(self.tags)) + + // if pagination > 0 && results == 0 reload first page (prune) + if (response.data.count == 0 && response.data.start > 0) { + pagination.start = 0 + return self.loadMessages() + } + + if (!window.scrollInPlace) { + let mp = document.getElementById('message-page') + if (mp) { + mp.scrollTop = 0 + } + } + + window.scrollInPlace = false + }) + }, + } +} diff --git a/server/ui-src/router/index.js b/server/ui-src/router/index.js new file mode 100644 index 0000000..45b0b69 --- /dev/null +++ b/server/ui-src/router/index.js @@ -0,0 +1,42 @@ +import { createRouter, createWebHistory } from 'vue-router' +import MailboxView from '../views/MailboxView.vue' +import SearchView from '../views/SearchView.vue' +import NotFoundView from '../views/NotFoundView.vue' +// import EditView from '../views/EditView.vue' +// import StatsView from '../views/StatsView.vue' +// import NotFound from '../views/NotFound.vue' + +let d = document.getElementById('app') +let webroot = '/' +if (d) { + webroot = d.dataset.webroot +} + +// paths are relative to webroot +const router = createRouter({ + history: createWebHistory(webroot), + routes: [ + { + path: '/', + // name: 'home', + component: MailboxView + }, + { + path: '/search', + // name: 'edit', + component: SearchView + }, + // { + // path: '/view/:id', + // name: 'view', + // component: StatsView + // }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: NotFoundView + } + ] +}) + +export default router diff --git a/server/ui-src/stores/mailbox.js b/server/ui-src/stores/mailbox.js new file mode 100644 index 0000000..50a2dfa --- /dev/null +++ b/server/ui-src/stores/mailbox.js @@ -0,0 +1,48 @@ +// State Management + +import { reactive, watch } from 'vue' +import Tinycon from 'tinycon' + +Tinycon.setOptions({ + height: 11, + background: '#dd0000', + fallback: false +}) + +// global mailbox info +export const mailbox = reactive({ + total: 0, // total number of messages + unread: 0, // total unread + count: 0, // total in mailbox or search + messages: [], // current messages + tags: [], // all tags + showTagColors: false, // show tag colors? + selected: [], // currently selected + connected: false, // websocket connection + searching: false, // whether we are currently searching + refresh: false, // to listen from MessagesMixin + notificationsSupported: false, + notificationsEnabled: false, +}) + +watch( + () => mailbox.total, + (v) => { + if (v == 0) { + Tinycon.reset() + } else { + Tinycon.setBubble(v) + } + } +) + +watch( + () => mailbox.showTagColors, + (v) => { + if (v) { + localStorage.setItem('showTagsColors', '1') + } else { + localStorage.removeItem('showTagsColors') + } + } +) diff --git a/server/ui-src/stores/pagination.js b/server/ui-src/stores/pagination.js new file mode 100644 index 0000000..1f0291c --- /dev/null +++ b/server/ui-src/stores/pagination.js @@ -0,0 +1,12 @@ +import { reactive } from 'vue' + +export const pagination = reactive({ + start: 0, // pagination offset + limit: 50, // per page + total: 0, // total results of current view / filter + count: 0, // number of messages currently displayed + + // increment() { + // this.count++ + // } +}) diff --git a/server/ui-src/templates/Attachments.vue b/server/ui-src/templates/Attachments.vue deleted file mode 100644 index c4457ee..0000000 --- a/server/ui-src/templates/Attachments.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - - diff --git a/server/ui-src/templates/Headers.vue b/server/ui-src/templates/Headers.vue deleted file mode 100644 index 5dad9c5..0000000 --- a/server/ui-src/templates/Headers.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - - diff --git a/server/ui-src/templates/Message.vue b/server/ui-src/templates/Message.vue deleted file mode 100644 index f33c011..0000000 --- a/server/ui-src/templates/Message.vue +++ /dev/null @@ -1,461 +0,0 @@ - - - - diff --git a/server/ui-src/templates/MessageHTMLCheck.vue b/server/ui-src/templates/MessageHTMLCheck.vue deleted file mode 100644 index 376f67c..0000000 --- a/server/ui-src/templates/MessageHTMLCheck.vue +++ /dev/null @@ -1,670 +0,0 @@ - - - diff --git a/server/ui-src/templates/MessageLinkCheck.vue b/server/ui-src/templates/MessageLinkCheck.vue deleted file mode 100644 index 608b277..0000000 --- a/server/ui-src/templates/MessageLinkCheck.vue +++ /dev/null @@ -1,398 +0,0 @@ - - - diff --git a/server/ui-src/templates/MessageRelease.vue b/server/ui-src/templates/MessageRelease.vue deleted file mode 100644 index 425f02f..0000000 --- a/server/ui-src/templates/MessageRelease.vue +++ /dev/null @@ -1,116 +0,0 @@ - - - - diff --git a/server/ui-src/templates/MessageScreenshot.vue b/server/ui-src/templates/MessageScreenshot.vue deleted file mode 100644 index c6a37fc..0000000 --- a/server/ui-src/templates/MessageScreenshot.vue +++ /dev/null @@ -1,144 +0,0 @@ - - - - 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..89d989e --- /dev/null +++ b/server/ui-src/views/MailboxView.vue @@ -0,0 +1,84 @@ + + + diff --git a/server/ui-src/views/NotFoundView.vue b/server/ui-src/views/NotFoundView.vue new file mode 100644 index 0000000..1f81d75 --- /dev/null +++ b/server/ui-src/views/NotFoundView.vue @@ -0,0 +1,7 @@ + + + diff --git a/server/ui-src/views/SearchView.vue b/server/ui-src/views/SearchView.vue new file mode 100644 index 0000000..9cd59f7 --- /dev/null +++ b/server/ui-src/views/SearchView.vue @@ -0,0 +1,100 @@ + + + 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/storage/search.go b/storage/search.go index 519bd78..c65e20c 100644 --- a/storage/search.go +++ b/storage/search.go @@ -109,6 +109,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") From aa0af5de32a0e90db8d676878109481c73bff2d6 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 15 Sep 2023 19:08:53 +1200 Subject: [PATCH 03/17] Update api search docs --- server/apiv1/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/apiv1/api.go b/server/apiv1/api.go index 59d564e..2914d01 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 From 0d084cfa1d09705c0621cc1a9109b01cd5060690 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 06:46:23 +1200 Subject: [PATCH 04/17] Feature: Improved search parser --- go.mod | 1 - go.sum | 2 - storage/database.go | 94 ----------------------- storage/search.go | 183 +++++++++++++++++++++++++++++++++++++++++++- storage/utils.go | 2 - utils/tools/args.go | 32 ++++++++ 6 files changed, 213 insertions(+), 101 deletions(-) create mode 100644 utils/tools/args.go diff --git a/go.mod b/go.mod index 75c663d..d9ac94b 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/k3a/html2text v1.2.1 github.com/klauspost/compress v1.16.7 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 diff --git a/go.sum b/go.sum index 0d54902..03667ce 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/storage/database.go b/storage/database.go index 40aa219..88bd5b2 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 @@ -367,9 +366,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 +375,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 := escSearch(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) { diff --git a/storage/search.go b/storage/search.go index c65e20c..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)+"%") diff --git a/storage/utils.go b/storage/utils.go index 220aaab..6ca394e 100644 --- a/storage/utils.go +++ b/storage/utils.go @@ -186,8 +186,6 @@ func escPercentChar(s string) string { // Escape certain characters in search phrases func escSearch(str string) string { - str = strings.ReplaceAll(str, "(", " ") - str = strings.ReplaceAll(str, ")", " ") dest := make([]byte, 0, 2*len(str)) var escape byte for i := 0; i < len(str); i++ { 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 +} From 582f1f88b250553fa4c4b00255e20ccbcccebf95 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 06:55:20 +1200 Subject: [PATCH 05/17] API: Add endpoint to return all tags in use --- server/apiv1/api.go | 27 +++++++++++++++++++++++++++ server/apiv1/swagger.go | 4 ++++ server/server.go | 1 + storage/database.go | 24 +++++++++++++++--------- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/server/apiv1/api.go b/server/apiv1/api.go index 2914d01..55789ab 100644 --- a/server/apiv1/api.go +++ b/server/apiv1/api.go @@ -451,6 +451,33 @@ 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 + // + // 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 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 876a444..4003d63 100644 --- a/server/server.go +++ b/server/server.go @@ -95,6 +95,7 @@ func apiRoutes() *mux.Router { 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/message/{id}/part/{partID}", middleWareFunc(apiv1.DownloadAttachment)).Methods("GET") diff --git a/storage/database.go b/storage/database.go index 88bd5b2..4a13460 100644 --- a/storage/database.go +++ b/storage/database.go @@ -709,15 +709,8 @@ func DeleteAllMessages() error { 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 != ?", "[]") @@ -750,6 +743,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, From 95e346f8afd0c474781c6b8752d33b0645959195 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 06:55:51 +1200 Subject: [PATCH 06/17] Improved search parser --- config/config.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) 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, "=") From b193851269d0450fc343958884bbc381b928ed44 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 07:00:02 +1200 Subject: [PATCH 07/17] API: Delete by search filter See #164 --- server/apiv1/api.go | 38 ++++++++++++++++++++++++++++++++++++++ server/server.go | 1 + 2 files changed, 39 insertions(+) diff --git a/server/apiv1/api.go b/server/apiv1/api.go index 55789ab..3123358 100644 --- a/server/apiv1/api.go +++ b/server/apiv1/api.go @@ -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 diff --git a/server/server.go b/server/server.go index 4003d63..2e20833 100644 --- a/server/server.go +++ b/server/server.go @@ -98,6 +98,7 @@ func apiRoutes() *mux.Router { 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") From 8e0c174bf39a88a72dbd313035c8acb577c20aca Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 07:02:15 +1200 Subject: [PATCH 08/17] Code cleanup --- server/apiv1/api.go | 4 ++-- server/websockets/hub.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/apiv1/api.go b/server/apiv1/api.go index 3123358..8d5477a 100644 --- a/server/apiv1/api.go +++ b/server/apiv1/api.go @@ -406,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")) } @@ -843,7 +843,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/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 }() From 9af04f83a3f6aa55a051861efbfedd5490c0b1cd Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 07:07:40 +1200 Subject: [PATCH 09/17] API: Remove redundant `Read` status from message (always true) --- storage/database.go | 1 - storage/structs.go | 2 -- 2 files changed, 3 deletions(-) diff --git a/storage/database.go b/storage/database.go index 4a13460..c3e3245 100644 --- a/storage/database.go +++ b/storage/database.go @@ -431,7 +431,6 @@ func GetMessage(id string) (*Message, error) { obj := Message{ ID: id, MessageID: messageID, - Read: true, From: from, Date: date, To: addressToSlice(env, "To"), 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 From 4a762c502eea586cded460905fae3eb55236e214 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 07:11:13 +1200 Subject: [PATCH 10/17] Add Swagger note --- server/apiv1/api.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/apiv1/api.go b/server/apiv1/api.go index 8d5477a..07834c9 100644 --- a/server/apiv1/api.go +++ b/server/apiv1/api.go @@ -495,6 +495,8 @@ func GetTags(w http.ResponseWriter, _ *http.Request) { // // # Get all current tags // + // Returns a JSON array of all unique message tags. + // // Produces: // - application/json // From 8f0549c5964e1cbb010125666ed8967e85b30716 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 15:01:33 +1200 Subject: [PATCH 11/17] Libs: Update node modules --- package-lock.json | 781 +++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 398 insertions(+), 387 deletions(-) diff --git a/package-lock.json b/package-lock.json index d3eddfa..e437011 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,8 +24,10 @@ }, "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" } @@ -39,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" }, @@ -50,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" ], @@ -78,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" ], @@ -94,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" ], @@ -110,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" ], @@ -126,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" ], @@ -142,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" ], @@ -158,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" ], @@ -174,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" ], @@ -190,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" ], @@ -206,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" ], @@ -222,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" ], @@ -238,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" ], @@ -254,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" ], @@ -270,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" ], @@ -286,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" ], @@ -302,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" ], @@ -318,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" ], @@ -334,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" ], @@ -350,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" ], @@ -366,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" ], @@ -382,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" ], @@ -398,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" ], @@ -441,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", @@ -662,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", @@ -740,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", @@ -1001,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", @@ -1019,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", @@ -1034,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", @@ -1081,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", @@ -1157,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", @@ -1238,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": { @@ -1250,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": { @@ -1288,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": { @@ -1332,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", @@ -1363,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", @@ -1387,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, @@ -1496,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": { @@ -1632,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" }, @@ -1725,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", @@ -1738,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": { @@ -1767,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" @@ -1778,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", @@ -1796,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": { @@ -1865,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", @@ -1948,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", @@ -1977,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" }, @@ -2050,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", @@ -2063,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", @@ -2100,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", @@ -2132,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" @@ -2211,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", @@ -2242,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": { @@ -2310,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", @@ -2379,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", @@ -2434,11 +2457,11 @@ } }, "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": { @@ -2447,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 2b89247..53836f5 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,10 @@ }, "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" } From 6a4e5fb03cb8d66e12328508b61dad3691c81d7a Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 22 Sep 2023 15:06:03 +1200 Subject: [PATCH 12/17] UI: Rewrite web UI, add URL routing and components See #156 --- server/server.go | 2 + server/ui-src/App.vue | 22 +- server/ui-src/app.js | 10 +- .../{bootstrap.scss => _bootstrap.scss} | 2 +- .../ui-src/assets/_bootstrap_variables.scss | 16 +- server/ui-src/assets/styles.scss | 7 + server/ui-src/components/AboutMailpit.vue | 283 ++++---- server/ui-src/components/AjaxLoader.vue | 1 + server/ui-src/components/ListMessages.vue | 65 +- server/ui-src/components/MailboxActions.vue | 112 --- server/ui-src/components/NavMailbox.vue | 139 ++++ server/ui-src/components/NavSearch.vue | 115 +++ server/ui-src/components/NavSelected.vue | 120 ++++ .../{MailboxTags.vue => NavTags.vue} | 13 +- server/ui-src/components/Notifications.vue | 45 +- server/ui-src/components/Pagination.vue | 36 +- server/ui-src/components/SearchActions.vue | 47 -- server/ui-src/components/SearchForm.vue | 17 +- .../ui-src/components/message/Attachments.vue | 41 ++ .../ui-src/components/message/HTMLCheck.vue | 670 ++++++++++++++++++ server/ui-src/components/message/Headers.vue | 38 + .../ui-src/components/message/LinkCheck.vue | 398 +++++++++++ server/ui-src/components/message/Message.vue | 458 ++++++++++++ server/ui-src/components/message/Release.vue | 135 ++++ .../ui-src/components/message/Screenshot.vue | 147 ++++ server/ui-src/mixins/CommonMixins.js | 161 +++-- server/ui-src/mixins/MessagesMixins.js | 29 +- server/ui-src/router/index.js | 17 +- server/ui-src/stores/mailbox.js | 21 +- server/ui-src/stores/pagination.js | 4 - server/ui-src/views/MailboxView.vue | 82 ++- server/ui-src/views/MessageView.vue | 323 +++++++++ server/ui-src/views/NotFoundView.vue | 26 +- server/ui-src/views/SearchView.vue | 76 +- server/ui/api/v1/swagger.json | 68 +- storage/database.go | 13 + storage/notifications.go | 35 + 37 files changed, 3254 insertions(+), 540 deletions(-) rename server/ui-src/assets/{bootstrap.scss => _bootstrap.scss} (97%) delete mode 100644 server/ui-src/components/MailboxActions.vue create mode 100644 server/ui-src/components/NavMailbox.vue create mode 100644 server/ui-src/components/NavSearch.vue create mode 100644 server/ui-src/components/NavSelected.vue rename server/ui-src/components/{MailboxTags.vue => NavTags.vue} (85%) delete mode 100644 server/ui-src/components/SearchActions.vue create mode 100644 server/ui-src/components/message/Attachments.vue create mode 100644 server/ui-src/components/message/HTMLCheck.vue create mode 100644 server/ui-src/components/message/Headers.vue create mode 100644 server/ui-src/components/message/LinkCheck.vue create mode 100644 server/ui-src/components/message/Message.vue create mode 100644 server/ui-src/components/message/Release.vue create mode 100644 server/ui-src/components/message/Screenshot.vue create mode 100644 server/ui-src/views/MessageView.vue create mode 100644 storage/notifications.go diff --git a/server/server.go b/server/server.go index 2e20833..6e683fb 100644 --- a/server/server.go +++ b/server/server.go @@ -18,6 +18,7 @@ import ( "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" ) @@ -223,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 diff --git a/server/ui-src/App.vue b/server/ui-src/App.vue index 6fd7e0b..79a9bca 100644 --- a/server/ui-src/App.vue +++ b/server/ui-src/App.vue @@ -1,12 +1,8 @@ diff --git a/server/ui-src/components/AjaxLoader.vue b/server/ui-src/components/AjaxLoader.vue index 9012046..237a4d5 100644 --- a/server/ui-src/components/AjaxLoader.vue +++ b/server/ui-src/components/AjaxLoader.vue @@ -5,6 +5,7 @@ export default { }, } +