From d840178cc0e878c3f35753054534c733897c9ef9 Mon Sep 17 00:00:00 2001 From: TOomaAh Date: Wed, 7 Aug 2024 23:59:02 +0200 Subject: [PATCH 01/19] change hub file structure --- hub/.goreleaser.yml => .goreleaser.yml | 17 + agent/.goreleaser.yml | 42 - agent/docker-compose.yml | 12 - agent/go.mod | 30 - agent/go.sum | 100 - cmd/agent/agent.go | 1 + .../hub}/1722186612_collections_snapshot.go | 2 +- cmd/hub/hub.go | 33 + .../hub}/initial-settings.go | 2 +- agent/dockerfile => dockerfile_Agent | 0 hub/dockerfile => dockerfile_Hub | 0 hub/go.mod => go.mod | 41 +- hub/go.sum => go.sum | 154 +- hub/docker-compose.yml | 9 - hub/types.go | 60 - {hub => internal/alerts}/alerts.go | 85 +- internal/entities/container/stats.go | 9 + internal/entities/email/email.go | 27 + internal/entities/server/server.go | 17 + internal/entities/system/stats.go | 18 + internal/entities/system/system.go | 20 + hub/main.go => internal/hub/hub.go | 233 +- {hub => internal/records}/records.go | 53 +- {hub => internal/update}/update.go | 7 +- {hub/site => site}/.gitignore | 0 {hub/site => site}/bun.lockb | Bin {hub/site => site}/components.json | 0 {hub/site => site}/embed.go | 0 {hub/site => site}/index.html | 0 site/package-lock.json | 4597 +++++++++++++++++ {hub/site => site}/package.json | 0 {hub/site => site}/postcss.config.js | 0 {hub/site => site}/public/static/apple.svg | 0 .../site => site}/public/static/bitbucket.svg | 0 {hub/site => site}/public/static/discord.svg | 0 {hub/site => site}/public/static/facebook.svg | 0 .../public/static/favicon-green.svg | 0 .../public/static/favicon-red.svg | 0 {hub/site => site}/public/static/favicon.svg | 0 {hub/site => site}/public/static/gitea.svg | 0 {hub/site => site}/public/static/gitee.svg | 0 {hub/site => site}/public/static/github.svg | 0 {hub/site => site}/public/static/gitlab.svg | 0 {hub/site => site}/public/static/google.svg | 0 .../site => site}/public/static/instagram.svg | 0 {hub/site => site}/public/static/lock.svg | 0 {hub/site => site}/public/static/oidc.svg | 0 {hub/site => site}/public/static/patreon.svg | 0 {hub/site => site}/public/static/spotify.svg | 0 {hub/site => site}/public/static/strava.svg | 0 {hub/site => site}/public/static/twitch.svg | 0 {hub/site => site}/public/static/twitter.svg | 0 .../src/components/add-system.tsx | 0 .../src/components/charts/bandwidth-chart.tsx | 0 .../components/charts/chart-time-select.tsx | 0 .../components/charts/container-cpu-chart.tsx | 0 .../components/charts/container-mem-chart.tsx | 0 .../components/charts/container-net-chart.tsx | 0 .../src/components/charts/cpu-chart.tsx | 0 .../src/components/charts/disk-chart.tsx | 0 .../src/components/charts/disk-io-chart.tsx | 0 .../src/components/charts/mem-chart.tsx | 0 .../src/components/charts/swap-chart.tsx | 0 .../src/components/command-palette.tsx | 0 .../src/components/login/auth-form.tsx | 0 .../src/components/login/forgot-pass-form.tsx | 0 .../src/components/login/login.tsx | 0 {hub/site => site}/src/components/logo.tsx | 0 .../src/components/mode-toggle.tsx | 0 {hub/site => site}/src/components/router.tsx | 0 .../src/components/routes/home.tsx | 0 .../src/components/routes/system.tsx | 0 {hub/site => site}/src/components/spinner.tsx | 0 .../src/components/systems-table/columns.tsx | 0 .../systems-table/systems-table.tsx | 0 .../src/components/table-alerts.tsx | 0 .../src/components/theme-provider.tsx | 0 .../src/components/ui/alert-dialog.tsx | 0 .../src/components/ui/button.tsx | 0 {hub/site => site}/src/components/ui/card.tsx | 0 .../site => site}/src/components/ui/chart.tsx | 0 .../src/components/ui/command.tsx | 0 .../src/components/ui/dialog.tsx | 0 .../src/components/ui/dropdown-menu.tsx | 0 .../site => site}/src/components/ui/input.tsx | 0 .../site => site}/src/components/ui/label.tsx | 0 .../src/components/ui/select.tsx | 0 .../src/components/ui/separator.tsx | 0 .../src/components/ui/slider.tsx | 0 .../src/components/ui/switch.tsx | 0 .../site => site}/src/components/ui/table.tsx | 0 .../site => site}/src/components/ui/toast.tsx | 0 .../src/components/ui/toaster.tsx | 0 .../src/components/ui/tooltip.tsx | 0 .../src/components/ui/use-toast.ts | 0 {hub/site => site}/src/index.css | 0 {hub/site => site}/src/lib/stores.ts | 0 {hub/site => site}/src/lib/utils.ts | 0 {hub/site => site}/src/main.tsx | 0 {hub/site => site}/src/types.d.ts | 0 {hub/site => site}/src/vite-env.d.ts | 0 {hub/site => site}/tailwind.config.js | 0 {hub/site => site}/tsconfig.app.json | 0 {hub/site => site}/tsconfig.json | 0 {hub/site => site}/tsconfig.node.json | 0 {hub/site => site}/vite.config.ts | 0 version.go | 6 + 107 files changed, 5025 insertions(+), 550 deletions(-) rename hub/.goreleaser.yml => .goreleaser.yml (66%) delete mode 100644 agent/.goreleaser.yml delete mode 100644 agent/docker-compose.yml delete mode 100644 agent/go.mod delete mode 100644 agent/go.sum create mode 100644 cmd/agent/agent.go rename {hub/migrations => cmd/hub}/1722186612_collections_snapshot.go (99%) create mode 100644 cmd/hub/hub.go rename {hub/migrations => cmd/hub}/initial-settings.go (95%) rename agent/dockerfile => dockerfile_Agent (100%) rename hub/dockerfile => dockerfile_Hub (100%) rename hub/go.mod => go.mod (74%) rename hub/go.sum => go.sum (76%) delete mode 100644 hub/docker-compose.yml delete mode 100644 hub/types.go rename {hub => internal/alerts}/alerts.go (53%) create mode 100644 internal/entities/container/stats.go create mode 100644 internal/entities/email/email.go create mode 100644 internal/entities/server/server.go create mode 100644 internal/entities/system/stats.go create mode 100644 internal/entities/system/system.go rename hub/main.go => internal/hub/hub.go (58%) rename {hub => internal/records}/records.go (71%) rename {hub => internal/update}/update.go (90%) rename {hub/site => site}/.gitignore (100%) rename {hub/site => site}/bun.lockb (100%) mode change 100755 => 100644 rename {hub/site => site}/components.json (100%) rename {hub/site => site}/embed.go (100%) rename {hub/site => site}/index.html (100%) create mode 100644 site/package-lock.json rename {hub/site => site}/package.json (100%) rename {hub/site => site}/postcss.config.js (100%) rename {hub/site => site}/public/static/apple.svg (100%) rename {hub/site => site}/public/static/bitbucket.svg (100%) rename {hub/site => site}/public/static/discord.svg (100%) rename {hub/site => site}/public/static/facebook.svg (100%) rename {hub/site => site}/public/static/favicon-green.svg (100%) rename {hub/site => site}/public/static/favicon-red.svg (100%) rename {hub/site => site}/public/static/favicon.svg (100%) rename {hub/site => site}/public/static/gitea.svg (100%) rename {hub/site => site}/public/static/gitee.svg (100%) rename {hub/site => site}/public/static/github.svg (100%) rename {hub/site => site}/public/static/gitlab.svg (100%) rename {hub/site => site}/public/static/google.svg (100%) rename {hub/site => site}/public/static/instagram.svg (100%) rename {hub/site => site}/public/static/lock.svg (100%) rename {hub/site => site}/public/static/oidc.svg (100%) rename {hub/site => site}/public/static/patreon.svg (100%) rename {hub/site => site}/public/static/spotify.svg (100%) rename {hub/site => site}/public/static/strava.svg (100%) rename {hub/site => site}/public/static/twitch.svg (100%) rename {hub/site => site}/public/static/twitter.svg (100%) rename {hub/site => site}/src/components/add-system.tsx (100%) rename {hub/site => site}/src/components/charts/bandwidth-chart.tsx (100%) rename {hub/site => site}/src/components/charts/chart-time-select.tsx (100%) rename {hub/site => site}/src/components/charts/container-cpu-chart.tsx (100%) rename {hub/site => site}/src/components/charts/container-mem-chart.tsx (100%) rename {hub/site => site}/src/components/charts/container-net-chart.tsx (100%) rename {hub/site => site}/src/components/charts/cpu-chart.tsx (100%) rename {hub/site => site}/src/components/charts/disk-chart.tsx (100%) rename {hub/site => site}/src/components/charts/disk-io-chart.tsx (100%) rename {hub/site => site}/src/components/charts/mem-chart.tsx (100%) rename {hub/site => site}/src/components/charts/swap-chart.tsx (100%) rename {hub/site => site}/src/components/command-palette.tsx (100%) rename {hub/site => site}/src/components/login/auth-form.tsx (100%) rename {hub/site => site}/src/components/login/forgot-pass-form.tsx (100%) rename {hub/site => site}/src/components/login/login.tsx (100%) rename {hub/site => site}/src/components/logo.tsx (100%) rename {hub/site => site}/src/components/mode-toggle.tsx (100%) rename {hub/site => site}/src/components/router.tsx (100%) rename {hub/site => site}/src/components/routes/home.tsx (100%) rename {hub/site => site}/src/components/routes/system.tsx (100%) rename {hub/site => site}/src/components/spinner.tsx (100%) rename {hub/site => site}/src/components/systems-table/columns.tsx (100%) rename {hub/site => site}/src/components/systems-table/systems-table.tsx (100%) rename {hub/site => site}/src/components/table-alerts.tsx (100%) rename {hub/site => site}/src/components/theme-provider.tsx (100%) rename {hub/site => site}/src/components/ui/alert-dialog.tsx (100%) rename {hub/site => site}/src/components/ui/button.tsx (100%) rename {hub/site => site}/src/components/ui/card.tsx (100%) rename {hub/site => site}/src/components/ui/chart.tsx (100%) rename {hub/site => site}/src/components/ui/command.tsx (100%) rename {hub/site => site}/src/components/ui/dialog.tsx (100%) rename {hub/site => site}/src/components/ui/dropdown-menu.tsx (100%) rename {hub/site => site}/src/components/ui/input.tsx (100%) rename {hub/site => site}/src/components/ui/label.tsx (100%) rename {hub/site => site}/src/components/ui/select.tsx (100%) rename {hub/site => site}/src/components/ui/separator.tsx (100%) rename {hub/site => site}/src/components/ui/slider.tsx (100%) rename {hub/site => site}/src/components/ui/switch.tsx (100%) rename {hub/site => site}/src/components/ui/table.tsx (100%) rename {hub/site => site}/src/components/ui/toast.tsx (100%) rename {hub/site => site}/src/components/ui/toaster.tsx (100%) rename {hub/site => site}/src/components/ui/tooltip.tsx (100%) rename {hub/site => site}/src/components/ui/use-toast.ts (100%) rename {hub/site => site}/src/index.css (100%) rename {hub/site => site}/src/lib/stores.ts (100%) rename {hub/site => site}/src/lib/utils.ts (100%) rename {hub/site => site}/src/main.tsx (100%) rename {hub/site => site}/src/types.d.ts (100%) rename {hub/site => site}/src/vite-env.d.ts (100%) rename {hub/site => site}/tailwind.config.js (100%) rename {hub/site => site}/tsconfig.app.json (100%) rename {hub/site => site}/tsconfig.json (100%) rename {hub/site => site}/tsconfig.node.json (100%) rename {hub/site => site}/vite.config.ts (100%) create mode 100644 version.go diff --git a/hub/.goreleaser.yml b/.goreleaser.yml similarity index 66% rename from hub/.goreleaser.yml rename to .goreleaser.yml index 2624440..bf0cb67 100644 --- a/hub/.goreleaser.yml +++ b/.goreleaser.yml @@ -16,6 +16,23 @@ builds: - amd64 - arm64 - arm + main: cmd/hub/hub.go + + - env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - freebsd + goarch: + - amd64 + - arm64 + - arm + - mips64 + ignore: + - goos: freebsd + goarch: arm + main: cmd/agent/agent.go archives: - format: tar.gz diff --git a/agent/.goreleaser.yml b/agent/.goreleaser.yml deleted file mode 100644 index de017f2..0000000 --- a/agent/.goreleaser.yml +++ /dev/null @@ -1,42 +0,0 @@ -# version: 1 - -project_name: beszel-agent - -before: - hooks: - - go mod tidy - -builds: - - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - - freebsd - goarch: - - amd64 - - arm64 - - arm - - mips64 - ignore: - - goos: freebsd - goarch: arm - -archives: - - format: tar.gz - name_template: >- - {{ .ProjectName }}_ - {{- .Os }}_ - {{- .Arch }} - # use zip for windows archives - format_overrides: - - goos: windows - format: zip - -changelog: - disable: true - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' diff --git a/agent/docker-compose.yml b/agent/docker-compose.yml deleted file mode 100644 index 687b8f9..0000000 --- a/agent/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -services: - beszel-agent: - image: 'henrygd/beszel-agent' - container_name: 'beszel-agent' - restart: unless-stopped - network_mode: host - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - environment: - PORT: 45876 - KEY: 'ssh-ed25519 YOUR_PUBLIC_KEY' - # FILESYSTEM: /dev/sda1 # set to the correct filesystem for disk I/O stats diff --git a/agent/go.mod b/agent/go.mod deleted file mode 100644 index 1121e8c..0000000 --- a/agent/go.mod +++ /dev/null @@ -1,30 +0,0 @@ -module beszel-agent - -go 1.22.4 - -require ( - github.com/blang/semver v3.5.1+incompatible - github.com/gliderlabs/ssh v0.3.7 - github.com/rhysd/go-github-selfupdate v1.2.3 - github.com/shirou/gopsutil/v4 v4.24.7 -) - -require ( - github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect - github.com/go-ole/go-ole v1.3.0 // indirect - github.com/google/go-github/v30 v30.1.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect - github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect - github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect - github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/tcnksm/go-gitconfig v0.1.2 // indirect - github.com/tklauser/go-sysconf v0.3.14 // indirect - github.com/tklauser/numcpus v0.8.0 // indirect - github.com/ulikunitz/xz v0.5.12 // indirect - github.com/yusufpapurcu/wmi v1.2.4 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sys v0.23.0 // indirect -) diff --git a/agent/go.sum b/agent/go.sum deleted file mode 100644 index 73190d7..0000000 --- a/agent/go.sum +++ /dev/null @@ -1,100 +0,0 @@ -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= -github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= -github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8= -github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI= -github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I= -github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= -github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag= -github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg= -github.com/shirou/gopsutil/v4 v4.24.7 h1:V9UGTK4gQ8HvcnPKf6Zt3XHyQq/peaekfxpJ2HSocJk= -github.com/shirou/gopsutil/v4 v4.24.7/go.mod h1:0uW/073rP7FYLOkvxolUQM5rMOLTNmRXnFKafpb71rw= -github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= -github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw= -github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE= -github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= -github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= -github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= -github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= -github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= -github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/cmd/agent/agent.go @@ -0,0 +1 @@ +package main diff --git a/hub/migrations/1722186612_collections_snapshot.go b/cmd/hub/1722186612_collections_snapshot.go similarity index 99% rename from hub/migrations/1722186612_collections_snapshot.go rename to cmd/hub/1722186612_collections_snapshot.go index 6cf10b5..e6fcadb 100644 --- a/hub/migrations/1722186612_collections_snapshot.go +++ b/cmd/hub/1722186612_collections_snapshot.go @@ -1,4 +1,4 @@ -package migrations +package main import ( "encoding/json" diff --git a/cmd/hub/hub.go b/cmd/hub/hub.go new file mode 100644 index 0000000..c9c182b --- /dev/null +++ b/cmd/hub/hub.go @@ -0,0 +1,33 @@ +package main + +import ( + "beszel" + "beszel/internal/hub" + "beszel/internal/update" + + "github.com/pocketbase/pocketbase" + "github.com/spf13/cobra" +) + +func main() { + var app *pocketbase.PocketBase + + app = pocketbase.NewWithConfig(pocketbase.Config{ + DefaultDataDir: beszel.AppName + "_data", + }) + app.RootCmd.Version = beszel.Version + app.RootCmd.Use = beszel.AppName + app.RootCmd.Short = "" + + // add update command + app.RootCmd.AddCommand(&cobra.Command{ + Use: "update", + Short: "Update " + beszel.AppName + " to the latest version", + Run: update.UpdateBeszel, + }) + + hubApp := hub.NewHub(app) + + hubApp.Run() + +} diff --git a/hub/migrations/initial-settings.go b/cmd/hub/initial-settings.go similarity index 95% rename from hub/migrations/initial-settings.go rename to cmd/hub/initial-settings.go index c528245..22907f7 100644 --- a/hub/migrations/initial-settings.go +++ b/cmd/hub/initial-settings.go @@ -1,4 +1,4 @@ -package migrations +package main import ( "github.com/pocketbase/dbx" diff --git a/agent/dockerfile b/dockerfile_Agent similarity index 100% rename from agent/dockerfile rename to dockerfile_Agent diff --git a/hub/dockerfile b/dockerfile_Hub similarity index 100% rename from hub/dockerfile rename to dockerfile_Hub diff --git a/hub/go.mod b/go.mod similarity index 74% rename from hub/go.mod rename to go.mod index d8c1859..27fc7ca 100644 --- a/hub/go.mod +++ b/go.mod @@ -4,23 +4,21 @@ go 1.22.4 require ( github.com/blang/semver v3.5.1+incompatible - github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 - github.com/pocketbase/dbx v1.10.1 - github.com/pocketbase/pocketbase v0.22.18 + github.com/gliderlabs/ssh v0.3.7 github.com/rhysd/go-github-selfupdate v1.2.3 - github.com/spf13/cobra v1.8.1 - golang.org/x/crypto v0.25.0 + github.com/shirou/gopsutil/v4 v4.24.7 ) require ( github.com/AlecAivazis/survey/v2 v2.3.7 // indirect + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.9 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect @@ -38,8 +36,9 @@ require ( github.com/domodwyer/mailyak/v3 v3.6.2 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.17.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/gabriel-vasile/mimetype v1.4.4 // indirect github.com/ganigeorgiev/fexpr v0.4.1 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect @@ -52,36 +51,46 @@ require ( github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 // indirect + github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/pocketbase/dbx v1.10.1 // indirect + github.com/pocketbase/pocketbase v0.22.18 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tcnksm/go-gitconfig v0.1.2 // indirect + github.com/tklauser/go-sysconf v0.3.14 // indirect + github.com/tklauser/numcpus v0.8.0 // indirect github.com/ulikunitz/xz v0.5.12 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opencensus.io v0.24.0 // indirect - gocloud.dev v0.38.0 // indirect + gocloud.dev v0.37.0 // indirect + golang.org/x/crypto v0.26.0 // indirect golang.org/x/image v0.18.0 // indirect golang.org/x/net v0.27.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect google.golang.org/api v0.189.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v2 v2.2.8 // indirect modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e // indirect - modernc.org/libc v1.55.5 // indirect + modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect modernc.org/sqlite v1.31.1 // indirect diff --git a/hub/go.sum b/go.sum similarity index 76% rename from hub/go.sum rename to go.sum index f21a876..0d494cf 100644 --- a/hub/go.sum +++ b/go.sum @@ -1,28 +1,13 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= -cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= -cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE= -cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs= -cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI= -cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= -cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= -cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= -cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= -cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= -cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= -cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.51.30 h1:RVFkjn9P0JMwnuZCVH0TlV5k9zepHzlbc4943eZMhGw= -github.com/aws/aws-sdk-go v1.51.30/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= @@ -33,8 +18,8 @@ github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVO github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.9 h1:TC2vjvaAv1VNl9A0rm+SeuBjrzXnrlwk6Yop+gKRi38= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.9/go.mod h1:WPv2FRnkIOoDv/8j2gSUsI4qDc7392w5anFB/I89GZ8= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8 h1:u1KOU1S15ufyZqmH/rA3POkiRH6EcDANHj2xHRzq+zc= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8/go.mod h1:WPv2FRnkIOoDv/8j2gSUsI4qDc7392w5anFB/I89GZ8= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= @@ -67,7 +52,6 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -84,24 +68,19 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= +github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k= github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -121,8 +100,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -137,41 +114,28 @@ github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQF github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 h1:e+8XbKB6IMn8A4OAyZccO4pYfB3s7bt6azNIPE7AnPg= -github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= -github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 h1:FwuzbVh87iLiUQj1+uQUsuw9x5t9m5n5g7rG7o4svW4= github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61/go.mod h1:paQfF1YtHe+GrGg5fOgjsjoCX/UKDr9bc1DoWpZfns8= +github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI= +github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -195,14 +159,20 @@ github.com/pocketbase/dbx v1.10.1 h1:cw+vsyfCJD8YObOVeqb93YErnlxwYMkNZ4rwN0G0AaA github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs= github.com/pocketbase/pocketbase v0.22.18 h1:yVckUhi5GDORqCb0BbtlvRB1CVxHY9HO9btEaeZHVJU= github.com/pocketbase/pocketbase v0.22.18/go.mod h1:0QFvDOOW7ANId78ChZSagyHbmP6CgMxDQrQFXzeaDpA= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag= github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil/v4 v4.24.7 h1:V9UGTK4gQ8HvcnPKf6Zt3XHyQq/peaekfxpJ2HSocJk= +github.com/shirou/gopsutil/v4 v4.24.7/go.mod h1:0uW/073rP7FYLOkvxolUQM5rMOLTNmRXnFKafpb71rw= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= @@ -217,10 +187,14 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw= github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE= +github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= +github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= +github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= +github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -229,26 +203,18 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 h1:A3SayB3rNyt+1S6qpI9mHPkeHTZbD7XILEqWnYZb2l0= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0/go.mod h1:27iA5uvhuRNmalO+iEUdVn5ZMj2qy10Mm+XRIpRmyuU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc= -go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= -go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= -go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= -go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= -go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= -go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= -gocloud.dev v0.38.0 h1:SpxfaOc/Fp4PeO8ui7wRcCZV0EgXZ+IWcVSLn6ZMSw0= -gocloud.dev v0.38.0/go.mod h1:3XjKvd2E5iVNu/xFImRzjN0d/fkNHe4s0RiKidpEUMQ= +gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= +gocloud.dev v0.37.0/go.mod h1:7/O4kqdInCNsc6LqgmuFnS0GRew4XNNYWpA44yQnwco= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= @@ -257,8 +223,6 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -274,42 +238,45 @@ golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -319,8 +286,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk= @@ -334,12 +299,8 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg= -google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= -google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY= -google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f h1:RARaIm8pxYuxyNPbBQf5igT7XdOyCNtat1qAT2ZxjU4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -362,35 +323,22 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= -modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.20.5 h1:s04akhT2dysD0DFOlv9fkQ6oUTLPYgMnnDk9oaqjszM= -modernc.org/ccgo/v4 v4.20.5/go.mod h1:fYXClPUMWxWaz1Xj5sHbzW/ZENEFeuHLToqBxUk41nE= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.4.3 h1:Ik4ZcMbC7aY4ZDPUhzXVXi7GMub9QcXLTfXn3mWpNw8= -modernc.org/gc/v2 v2.4.3/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e h1:WPC4v0rNIFb2PY+nBBEEKyugPPRHPzUgyN3xZPpGK58= modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.55.5 h1:7duW01NsK0fIJ1xctdujeNDO46yPC89t0TZwDC5fE5k= -modernc.org/libc v1.55.5/go.mod h1:JXguUpMkbw1gknxspNE9XaG+kk9hDAAnBxpA6KGLiyA= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= -modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs= modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= diff --git a/hub/docker-compose.yml b/hub/docker-compose.yml deleted file mode 100644 index a5bf3ec..0000000 --- a/hub/docker-compose.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - beszel: - image: 'henrygd/beszel' - container_name: 'beszel' - restart: unless-stopped - ports: - - '8090:8090' - volumes: - - ./beszel_data:/beszel_data diff --git a/hub/types.go b/hub/types.go deleted file mode 100644 index 376daf2..0000000 --- a/hub/types.go +++ /dev/null @@ -1,60 +0,0 @@ -package main - -import ( - "golang.org/x/crypto/ssh" -) - -type Server struct { - Host string - Port string - Status string - Client *ssh.Client -} - -type SystemData struct { - Stats SystemStats `json:"stats"` - Info SystemInfo `json:"info"` - Containers []ContainerStats `json:"container"` -} - -type SystemInfo struct { - Cores int `json:"c"` - Threads int `json:"t"` - CpuModel string `json:"m"` - // Os string `json:"o"` - Uptime uint64 `json:"u"` - Cpu float64 `json:"cpu"` - MemPct float64 `json:"mp"` - DiskPct float64 `json:"dp"` -} - -type SystemStats struct { - Cpu float64 `json:"cpu"` - Mem float64 `json:"m"` - MemUsed float64 `json:"mu"` - MemPct float64 `json:"mp"` - MemBuffCache float64 `json:"mb"` - Swap float64 `json:"s"` - SwapUsed float64 `json:"su"` - Disk float64 `json:"d"` - DiskUsed float64 `json:"du"` - DiskPct float64 `json:"dp"` - DiskRead float64 `json:"dr"` - DiskWrite float64 `json:"dw"` - NetworkSent float64 `json:"ns"` - NetworkRecv float64 `json:"nr"` -} - -type ContainerStats struct { - Name string `json:"n"` - Cpu float64 `json:"c"` - Mem float64 `json:"m"` - NetworkSent float64 `json:"ns"` - NetworkRecv float64 `json:"nr"` -} - -type EmailData struct { - to string - subj string - body string -} diff --git a/hub/alerts.go b/internal/alerts/alerts.go similarity index 53% rename from hub/alerts.go rename to internal/alerts/alerts.go index ec82c27..6ffbbd5 100644 --- a/hub/alerts.go +++ b/internal/alerts/alerts.go @@ -1,16 +1,31 @@ -package main +package alerts import ( + "beszel/internal/entities/email" + "beszel/internal/entities/system" "fmt" "net/mail" "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/tools/mailer" ) -func handleSystemAlerts(newStatus string, newRecord *models.Record, oldRecord *models.Record) { - alertRecords, err := app.Dao().FindRecordsByExpr("alerts", +type AlertManager struct { + app *pocketbase.PocketBase + mailClient mailer.Mailer +} + +func NewAlertManager(app *pocketbase.PocketBase) *AlertManager { + return &AlertManager{ + app: app, + mailClient: app.NewMailClient(), + } +} + +func (am *AlertManager) HandleSystemAlerts(newStatus string, newRecord *models.Record, oldRecord *models.Record) { + alertRecords, err := am.app.Dao().FindRecordsByExpr("alerts", dbx.NewExp("system = {:system}", dbx.Params{"system": oldRecord.GetId()}), ) if err != nil || len(alertRecords) == 0 { @@ -18,12 +33,12 @@ func handleSystemAlerts(newStatus string, newRecord *models.Record, oldRecord *m return } // log.Println("found alerts", len(alertRecords)) - var systemInfo *SystemInfo + var systemInfo *system.SystemInfo for _, alertRecord := range alertRecords { name := alertRecord.GetString("name") switch name { case "Status": - handleStatusAlerts(newStatus, oldRecord, alertRecord) + am.handleStatusAlerts(newStatus, oldRecord, alertRecord) case "CPU", "Memory", "Disk": if newStatus != "up" { continue @@ -32,23 +47,23 @@ func handleSystemAlerts(newStatus string, newRecord *models.Record, oldRecord *m systemInfo = getSystemInfo(newRecord) } if name == "CPU" { - handleSlidingValueAlert(newRecord, alertRecord, name, systemInfo.Cpu) + am.handleSlidingValueAlert(newRecord, alertRecord, name, systemInfo.Cpu) } else if name == "Memory" { - handleSlidingValueAlert(newRecord, alertRecord, name, systemInfo.MemPct) + am.handleSlidingValueAlert(newRecord, alertRecord, name, systemInfo.MemPct) } else if name == "Disk" { - handleSlidingValueAlert(newRecord, alertRecord, name, systemInfo.DiskPct) + am.handleSlidingValueAlert(newRecord, alertRecord, name, systemInfo.DiskPct) } } } } -func getSystemInfo(record *models.Record) *SystemInfo { - var SystemInfo SystemInfo +func getSystemInfo(record *models.Record) *system.SystemInfo { + var SystemInfo system.SystemInfo record.UnmarshalJSONField("info", &SystemInfo) return &SystemInfo } -func handleSlidingValueAlert(newRecord *models.Record, alertRecord *models.Record, name string, curValue float64) { +func (am *AlertManager) handleSlidingValueAlert(newRecord *models.Record, alertRecord *models.Record, name string, curValue float64) { triggered := alertRecord.GetBool("triggered") threshold := alertRecord.GetFloat("value") // fmt.Println(name, curValue, "threshold", threshold, "triggered", triggered) @@ -58,35 +73,35 @@ func handleSlidingValueAlert(newRecord *models.Record, alertRecord *models.Recor alertRecord.Set("triggered", true) systemName := newRecord.GetString("name") subject = fmt.Sprintf("%s usage threshold exceeded on %s", name, systemName) - body = fmt.Sprintf("%s usage on %s is %.1f%%.\n\n%s\n\n- Beszel", name, systemName, curValue, app.Settings().Meta.AppUrl+"/system/"+systemName) + body = fmt.Sprintf("%s usage on %s is %.1f%%.\n\n%s\n\n- Beszel", name, systemName, curValue, am.app.Settings().Meta.AppUrl+"/system/"+systemName) } else if triggered && curValue <= threshold { alertRecord.Set("triggered", false) systemName := newRecord.GetString("name") subject = fmt.Sprintf("%s usage returned below threshold on %s", name, systemName) - body = fmt.Sprintf("%s usage on %s is below threshold at %.1f%%.\n\n%s\n\n- Beszel", name, systemName, curValue, app.Settings().Meta.AppUrl+"/system/"+systemName) + body = fmt.Sprintf("%s usage on %s is below threshold at %.1f%%.\n\n%s\n\n- Beszel", name, systemName, curValue, am.app.Settings().Meta.AppUrl+"/system/"+systemName) } else { // fmt.Println(name, "not triggered") return } - if err := app.Dao().SaveRecord(alertRecord); err != nil { + if err := am.app.Dao().SaveRecord(alertRecord); err != nil { // app.Logger().Error("failed to save alert record", "err", err.Error()) return } // expand the user relation and send the alert - if errs := app.Dao().ExpandRecord(alertRecord, []string{"user"}, nil); len(errs) > 0 { + if errs := am.app.Dao().ExpandRecord(alertRecord, []string{"user"}, nil); len(errs) > 0 { // app.Logger().Error("failed to expand user relation", "errs", errs) return } if user := alertRecord.ExpandedOne("user"); user != nil { - sendAlert(EmailData{ - to: user.GetString("email"), - subj: subject, - body: body, - }) + am.sendAlert(email.NewEmailData( + user.GetString("email"), + subject, + body, + )) } } -func handleStatusAlerts(newStatus string, oldRecord *models.Record, alertRecord *models.Record) error { +func (am *AlertManager) handleStatusAlerts(newStatus string, oldRecord *models.Record, alertRecord *models.Record) error { var alertStatus string switch newStatus { case "up": @@ -102,7 +117,7 @@ func handleStatusAlerts(newStatus string, oldRecord *models.Record, alertRecord return nil } // expand the user relation - if errs := app.Dao().ExpandRecord(alertRecord, []string{"user"}, nil); len(errs) > 0 { + if errs := am.app.Dao().ExpandRecord(alertRecord, []string{"user"}, nil); len(errs) > 0 { return fmt.Errorf("failed to expand: %v", errs) } user := alertRecord.ExpandedOne("user") @@ -115,26 +130,26 @@ func handleStatusAlerts(newStatus string, oldRecord *models.Record, alertRecord } // send alert systemName := oldRecord.GetString("name") - sendAlert(EmailData{ - to: user.GetString("email"), - subj: fmt.Sprintf("Connection to %s is %s %v", systemName, alertStatus, emoji), - body: fmt.Sprintf("Connection to %s is %s\n\n- Beszel", systemName, alertStatus), - }) + am.sendAlert(email.NewEmailData( + user.GetString("email"), + fmt.Sprintf("Connection to %s is %s %v", systemName, alertStatus, emoji), + fmt.Sprintf("Connection to %s is %s\n\n- Beszel", systemName, alertStatus), + )) return nil } -func sendAlert(data EmailData) { +func (am *AlertManager) sendAlert(data *email.EmailData) { // fmt.Println("sending alert", "to", data.to, "subj", data.subj, "body", data.body) message := &mailer.Message{ From: mail.Address{ - Address: app.Settings().Meta.SenderAddress, - Name: app.Settings().Meta.SenderName, + Address: am.app.Settings().Meta.SenderAddress, + Name: am.app.Settings().Meta.SenderName, }, - To: []mail.Address{{Address: data.to}}, - Subject: data.subj, - Text: data.body, + To: []mail.Address{{Address: data.To()}}, + Subject: data.Subject(), + Text: data.Body(), } - if err := app.NewMailClient().Send(message); err != nil { - app.Logger().Error("Failed to send alert: ", "err", err.Error()) + if err := am.mailClient.Send(message); err != nil { + am.app.Logger().Error("Failed to send alert: ", "err", err.Error()) } } diff --git a/internal/entities/container/stats.go b/internal/entities/container/stats.go new file mode 100644 index 0000000..e99a9f4 --- /dev/null +++ b/internal/entities/container/stats.go @@ -0,0 +1,9 @@ +package container + +type ContainerStats struct { + Name string `json:"n"` + Cpu float64 `json:"c"` + Mem float64 `json:"m"` + NetworkSent float64 `json:"ns"` + NetworkRecv float64 `json:"nr"` +} diff --git a/internal/entities/email/email.go b/internal/entities/email/email.go new file mode 100644 index 0000000..a1d3321 --- /dev/null +++ b/internal/entities/email/email.go @@ -0,0 +1,27 @@ +package email + +type EmailData struct { + to string + subj string + body string +} + +func NewEmailData(to, subj, body string) *EmailData { + return &EmailData{ + to: to, + subj: subj, + body: body, + } +} + +func (e *EmailData) To() string { + return e.to +} + +func (e *EmailData) Subject() string { + return e.subj +} + +func (e *EmailData) Body() string { + return e.body +} diff --git a/internal/entities/server/server.go b/internal/entities/server/server.go new file mode 100644 index 0000000..282ce21 --- /dev/null +++ b/internal/entities/server/server.go @@ -0,0 +1,17 @@ +package server + +import "golang.org/x/crypto/ssh" + +type Server struct { + Host string + Port string + Status string + Client *ssh.Client +} + +func NewServer(host, port string) *Server { + return &Server{ + Host: host, + Port: port, + } +} diff --git a/internal/entities/system/stats.go b/internal/entities/system/stats.go new file mode 100644 index 0000000..43f591c --- /dev/null +++ b/internal/entities/system/stats.go @@ -0,0 +1,18 @@ +package system + +type SystemStats struct { + Cpu float64 `json:"cpu"` + Mem float64 `json:"m"` + MemUsed float64 `json:"mu"` + MemPct float64 `json:"mp"` + MemBuffCache float64 `json:"mb"` + Swap float64 `json:"s"` + SwapUsed float64 `json:"su"` + Disk float64 `json:"d"` + DiskUsed float64 `json:"du"` + DiskPct float64 `json:"dp"` + DiskRead float64 `json:"dr"` + DiskWrite float64 `json:"dw"` + NetworkSent float64 `json:"ns"` + NetworkRecv float64 `json:"nr"` +} diff --git a/internal/entities/system/system.go b/internal/entities/system/system.go new file mode 100644 index 0000000..39a60b7 --- /dev/null +++ b/internal/entities/system/system.go @@ -0,0 +1,20 @@ +package system + +import "beszel/internal/entities/container" + +type SystemInfo struct { + Cores int `json:"c"` + Threads int `json:"t"` + CpuModel string `json:"m"` + // Os string `json:"o"` + Uptime uint64 `json:"u"` + Cpu float64 `json:"cpu"` + MemPct float64 `json:"mp"` + DiskPct float64 `json:"dp"` +} + +type SystemData struct { + Stats SystemStats `json:"stats"` + Info SystemInfo `json:"info"` + Containers []container.ContainerStats `json:"container"` +} diff --git a/hub/main.go b/internal/hub/hub.go similarity index 58% rename from hub/main.go rename to internal/hub/hub.go index 3751ec2..d78de0c 100644 --- a/hub/main.go +++ b/internal/hub/hub.go @@ -1,7 +1,10 @@ -package main +package hub import ( - _ "beszel/migrations" + "beszel/internal/alerts" + "beszel/internal/entities/server" + "beszel/internal/entities/system" + "beszel/internal/records" "beszel/site" "bytes" "crypto/ed25519" @@ -25,43 +28,40 @@ import ( "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/plugins/migratecmd" "github.com/pocketbase/pocketbase/tools/cron" - "github.com/spf13/cobra" "golang.org/x/crypto/ssh" ) -var Version = "0.1.2" +type Hub struct { + app *pocketbase.PocketBase + serverConnectionsLock *sync.Mutex + serverConnections map[string]*server.Server +} -var app *pocketbase.PocketBase -var serverConnections = make(map[string]*Server) -var serverConnectionsLock = sync.Mutex{} +func NewHub(app *pocketbase.PocketBase) *Hub { + return &Hub{ + app: app, + serverConnectionsLock: &sync.Mutex{}, + serverConnections: make(map[string]*server.Server), + } +} -func main() { - app = pocketbase.NewWithConfig(pocketbase.Config{ - DefaultDataDir: "beszel_data", - }) - app.RootCmd.Version = Version - app.RootCmd.Use = "beszel" - app.RootCmd.Short = "" +func (h *Hub) Run() { - // add update command - app.RootCmd.AddCommand(&cobra.Command{ - Use: "update", - Short: "Update beszel to the latest version", - Run: updateBeszel, - }) + rm := records.NewRecordManager(h.app) + am := alerts.NewAlertManager(h.app) // loosely check if it was executed using "go run" isGoRun := strings.HasPrefix(os.Args[0], os.TempDir()) // // enable auto creation of migration files when making collection changes in the Admin UI - migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{ + migratecmd.MustRegister(h.app, h.app.RootCmd, migratecmd.Config{ // (the isGoRun check is to enable it only during development) Automigrate: isGoRun, }) // set auth settings - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { - usersCollection, err := app.Dao().FindCollectionByNameOrId("users") + h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + usersCollection, err := h.app.Dao().FindCollectionByNameOrId("users") if err != nil { return err } @@ -73,14 +73,14 @@ func main() { usersAuthOptions.AllowEmailAuth = true } usersCollection.SetOptions(usersAuthOptions) - if err := app.Dao().SaveCollection(usersCollection); err != nil { + if err := h.app.Dao().SaveCollection(usersCollection); err != nil { return err } return nil }) // serve site - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { switch isGoRun { case true: proxy := httputil.NewSingleHostReverseProxy(&url.URL{ @@ -98,34 +98,34 @@ func main() { }) // set up cron jobs / ticker for system updates - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { // 15 second ticker for system updates - go startSystemUpdateTicker() + go h.startSystemUpdateTicker() // cron job to delete old records scheduler := cron.New() scheduler.MustAdd("delete old records", "8 * * * *", func() { collections := []string{"system_stats", "container_stats"} - deleteOldRecords(collections, "1m", time.Hour) - deleteOldRecords(collections, "10m", 12*time.Hour) - deleteOldRecords(collections, "20m", 24*time.Hour) - deleteOldRecords(collections, "120m", 7*24*time.Hour) - deleteOldRecords(collections, "480m", 30*24*time.Hour) + rm.DeleteOldRecords(collections, "1m", time.Hour) + rm.DeleteOldRecords(collections, "10m", 12*time.Hour) + rm.DeleteOldRecords(collections, "20m", 24*time.Hour) + rm.DeleteOldRecords(collections, "120m", 7*24*time.Hour) + rm.DeleteOldRecords(collections, "480m", 30*24*time.Hour) }) scheduler.Start() return nil }) // ssh key setup - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { // create ssh key if it doesn't exist - getSSHKey() + h.getSSHKey() // api route to return public key e.Router.GET("/api/beszel/getkey", func(c echo.Context) error { requestData := apis.RequestInfo(c) if requestData.AuthRecord == nil { return apis.NewForbiddenError("Forbidden", nil) } - key, err := os.ReadFile(app.DataDir() + "/id_ed25519.pub") + key, err := os.ReadFile(h.app.DataDir() + "/id_ed25519.pub") if err != nil { return err } @@ -135,10 +135,10 @@ func main() { }) // other api routes - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { // check if first time setup on login page e.Router.GET("/api/beszel/first-run", func(c echo.Context) error { - adminNum, err := app.Dao().TotalAdmins() + adminNum, err := h.app.Dao().TotalAdmins() if err != nil { return err } @@ -148,7 +148,7 @@ func main() { }) // user creation - set default role to user if unset - app.OnModelBeforeCreate("users").Add(func(e *core.ModelEvent) error { + h.app.OnModelBeforeCreate("users").Add(func(e *core.ModelEvent) error { user := e.Model.(*models.Record) if user.GetString("role") == "" { user.Set("role", "user") @@ -157,71 +157,71 @@ func main() { }) // system creation defaults - app.OnModelBeforeCreate("systems").Add(func(e *core.ModelEvent) error { + h.app.OnModelBeforeCreate("systems").Add(func(e *core.ModelEvent) error { record := e.Model.(*models.Record) - record.Set("info", SystemInfo{}) + record.Set("info", system.SystemInfo{}) record.Set("status", "pending") return nil }) // immediately create connection for new servers - app.OnModelAfterCreate("systems").Add(func(e *core.ModelEvent) error { - go updateSystem(e.Model.(*models.Record)) + h.app.OnModelAfterCreate("systems").Add(func(e *core.ModelEvent) error { + go h.updateSystem(e.Model.(*models.Record)) return nil }) // do things after a systems record is updated - app.OnModelAfterUpdate("systems").Add(func(e *core.ModelEvent) error { + h.app.OnModelAfterUpdate("systems").Add(func(e *core.ModelEvent) error { newRecord := e.Model.(*models.Record) oldRecord := newRecord.OriginalCopy() newStatus := newRecord.GetString("status") // if server is disconnected and connection exists, remove it if newStatus == "down" || newStatus == "paused" { - deleteServerConnection(newRecord) + h.deleteServerConnection(newRecord) } // if server is set to pending (unpause), try to connect immediately if newStatus == "pending" { - go updateSystem(newRecord) + go h.updateSystem(newRecord) } // alerts - handleSystemAlerts(newStatus, newRecord, oldRecord) + am.HandleSystemAlerts(newStatus, newRecord, oldRecord) return nil }) // do things after a systems record is deleted - app.OnModelAfterDelete("systems").Add(func(e *core.ModelEvent) error { + h.app.OnModelAfterDelete("systems").Add(func(e *core.ModelEvent) error { // if server connection exists, close it - deleteServerConnection(e.Model.(*models.Record)) + h.deleteServerConnection(e.Model.(*models.Record)) return nil }) - app.OnModelAfterCreate("system_stats").Add(func(e *core.ModelEvent) error { - createLongerRecords("system_stats", e.Model.(*models.Record)) + h.app.OnModelAfterCreate("system_stats").Add(func(e *core.ModelEvent) error { + rm.CreateLongerRecords("system_stats", e.Model.(*models.Record)) return nil }) - app.OnModelAfterCreate("container_stats").Add(func(e *core.ModelEvent) error { - createLongerRecords("container_stats", e.Model.(*models.Record)) + h.app.OnModelAfterCreate("container_stats").Add(func(e *core.ModelEvent) error { + rm.CreateLongerRecords("container_stats", e.Model.(*models.Record)) return nil }) - if err := app.Start(); err != nil { + if err := h.app.Start(); err != nil { log.Fatal(err) } } -func startSystemUpdateTicker() { +func (h *Hub) startSystemUpdateTicker() { ticker := time.NewTicker(15 * time.Second) for range ticker.C { - updateSystems() + h.updateSystems() } } -func updateSystems() { - records, err := app.Dao().FindRecordsByFilter( +func (h *Hub) updateSystems() { + records, err := h.app.Dao().FindRecordsByFilter( "2hz5ncl8tizk5nx", // collection "status != 'paused'", // filter "updated", // sort @@ -230,7 +230,7 @@ func updateSystems() { ) // log.Println("records", len(records)) if err != nil || len(records) == 0 { - // app.Logger().Error("Failed to query systems") + // h.app.Logger().Error("Failed to query systems") return } fiftySecondsAgo := time.Now().UTC().Add(-50 * time.Second) @@ -246,76 +246,75 @@ func updateSystems() { if record.GetString("status") != "down" { done++ } - go updateSystem(record) + go h.updateSystem(record) } } -func updateSystem(record *models.Record) { - var server *Server +func (h *Hub) updateSystem(record *models.Record) { + var s *server.Server // check if server connection data exists - if _, ok := serverConnections[record.Id]; ok { - server = serverConnections[record.Id] + if _, ok := h.serverConnections[record.Id]; ok { + s = h.serverConnections[record.Id] } else { // create server connection struct - server = &Server{ - Host: record.GetString("host"), - Port: record.GetString("port"), - } - client, err := getServerConnection(server) + s = server.NewServer( + record.GetString("host"), + record.GetString("port")) + client, err := h.getServerConnection(s) if err != nil { - app.Logger().Error("Failed to connect:", "err", err.Error(), "server", server.Host, "port", server.Port) - updateServerStatus(record, "down") + h.app.Logger().Error("Failed to connect:", "err", err.Error(), "server", s.Host, "port", s.Port) + h.updateServerStatus(record, "down") return } - server.Client = client - serverConnectionsLock.Lock() - serverConnections[record.Id] = server - serverConnectionsLock.Unlock() + s.Client = client + h.serverConnectionsLock.Lock() + h.serverConnections[record.Id] = s + h.serverConnectionsLock.Unlock() } // get server stats from agent - systemData, err := requestJson(server) + systemData, err := requestJson(s) if err != nil { if err.Error() == "retry" { // if previous connection was closed, try again - app.Logger().Error("Existing SSH connection closed. Retrying...", "host", server.Host, "port", server.Port) - deleteServerConnection(record) - updateSystem(record) + h.app.Logger().Error("Existing SSH connection closed. Retrying...", "host", s.Host, "port", s.Port) + h.deleteServerConnection(record) + h.updateSystem(record) return } - app.Logger().Error("Failed to get server stats: ", "err", err.Error()) - updateServerStatus(record, "down") + h.app.Logger().Error("Failed to get server stats: ", "err", err.Error()) + h.updateServerStatus(record, "down") return } // update system record record.Set("status", "up") record.Set("info", systemData.Info) - if err := app.Dao().SaveRecord(record); err != nil { - app.Logger().Error("Failed to update record: ", "err", err.Error()) + if err := h.app.Dao().SaveRecord(record); err != nil { + h.app.Logger().Error("Failed to update record: ", "err", err.Error()) } // add new system_stats record - system_stats, _ := app.Dao().FindCollectionByNameOrId("system_stats") + system_stats, _ := h.app.Dao().FindCollectionByNameOrId("system_stats") system_stats_record := models.NewRecord(system_stats) system_stats_record.Set("system", record.Id) system_stats_record.Set("stats", systemData.Stats) system_stats_record.Set("type", "1m") - if err := app.Dao().SaveRecord(system_stats_record); err != nil { - app.Logger().Error("Failed to save record: ", "err", err.Error()) + if err := h.app.Dao().SaveRecord(system_stats_record); err != nil { + h.app.Logger().Error("Failed to save record: ", "err", err.Error()) } // add new container_stats record if len(systemData.Containers) > 0 { - container_stats, _ := app.Dao().FindCollectionByNameOrId("container_stats") + container_stats, _ := h.app.Dao().FindCollectionByNameOrId("container_stats") container_stats_record := models.NewRecord(container_stats) container_stats_record.Set("system", record.Id) container_stats_record.Set("stats", systemData.Containers) container_stats_record.Set("type", "1m") - if err := app.Dao().SaveRecord(container_stats_record); err != nil { - app.Logger().Error("Failed to save record: ", "err", err.Error()) + if err := h.app.Dao().SaveRecord(container_stats_record); err != nil { + h.app.Logger().Error("Failed to save record: ", "err", err.Error()) } } } // set server to status down and close connection -func updateServerStatus(record *models.Record, status string) { +func (h *Hub) updateServerStatus(record *models.Record, status string) { // if in map, close connection and remove from map // this is now down automatically in an after update hook // if status == "down" || status == "paused" { @@ -323,28 +322,28 @@ func updateServerStatus(record *models.Record, status string) { // } if record.GetString("status") != status { record.Set("status", status) - if err := app.Dao().SaveRecord(record); err != nil { - app.Logger().Error("Failed to update record: ", "err", err.Error()) + if err := h.app.Dao().SaveRecord(record); err != nil { + h.app.Logger().Error("Failed to update record: ", "err", err.Error()) } } } -func deleteServerConnection(record *models.Record) { - if _, ok := serverConnections[record.Id]; ok { - if serverConnections[record.Id].Client != nil { - serverConnections[record.Id].Client.Close() +func (h *Hub) deleteServerConnection(record *models.Record) { + if _, ok := h.serverConnections[record.Id]; ok { + if h.serverConnections[record.Id].Client != nil { + h.serverConnections[record.Id].Client.Close() } - serverConnectionsLock.Lock() - defer serverConnectionsLock.Unlock() - delete(serverConnections, record.Id) + h.serverConnectionsLock.Lock() + defer h.serverConnectionsLock.Unlock() + delete(h.serverConnections, record.Id) } } -func getServerConnection(server *Server) (*ssh.Client, error) { - // app.Logger().Debug("new ssh connection", "server", server.Host) - key, err := getSSHKey() +func (h *Hub) getServerConnection(server *server.Server) (*ssh.Client, error) { + // h.app.Logger().Debug("new ssh connection", "server", server.Host) + key, err := h.getSSHKey() if err != nil { - app.Logger().Error("Failed to get SSH key: ", "err", err.Error()) + h.app.Logger().Error("Failed to get SSH key: ", "err", err.Error()) return nil, err } @@ -371,10 +370,10 @@ func getServerConnection(server *Server) (*ssh.Client, error) { return client, nil } -func requestJson(server *Server) (SystemData, error) { +func requestJson(server *server.Server) (system.SystemData, error) { session, err := server.Client.NewSession() if err != nil { - return SystemData{}, errors.New("retry") + return system.SystemData{}, errors.New("retry") } defer session.Close() @@ -383,26 +382,26 @@ func requestJson(server *Server) (SystemData, error) { session.Stdout = &outputBuffer if err := session.Shell(); err != nil { - return SystemData{}, err + return system.SystemData{}, err } err = session.Wait() if err != nil { - return SystemData{}, err + return system.SystemData{}, err } // Unmarshal the output into our struct - var systemData SystemData + var systemData system.SystemData err = json.Unmarshal(outputBuffer.Bytes(), &systemData) if err != nil { - return SystemData{}, err + return system.SystemData{}, err } return systemData, nil } -func getSSHKey() ([]byte, error) { - dataDir := app.DataDir() +func (h *Hub) getSSHKey() ([]byte, error) { + dataDir := h.app.DataDir() // check if the key pair already exists existingKey, err := os.ReadFile(dataDir + "/id_ed25519") if err == nil { @@ -412,27 +411,27 @@ func getSSHKey() ([]byte, error) { // Generate the Ed25519 key pair pubKey, privKey, err := ed25519.GenerateKey(nil) if err != nil { - // app.Logger().Error("Error generating key pair:", "err", err.Error()) + // h.app.Logger().Error("Error generating key pair:", "err", err.Error()) return nil, err } // Get the private key in OpenSSH format privKeyBytes, err := ssh.MarshalPrivateKey(privKey, "") if err != nil { - // app.Logger().Error("Error marshaling private key:", "err", err.Error()) + // h.app.Logger().Error("Error marshaling private key:", "err", err.Error()) return nil, err } // Save the private key to a file privateFile, err := os.Create(dataDir + "/id_ed25519") if err != nil { - // app.Logger().Error("Error creating private key file:", "err", err.Error()) + // h.app.Logger().Error("Error creating private key file:", "err", err.Error()) return nil, err } defer privateFile.Close() if err := pem.Encode(privateFile, privKeyBytes); err != nil { - // app.Logger().Error("Error writing private key to file:", "err", err.Error()) + // h.app.Logger().Error("Error writing private key to file:", "err", err.Error()) return nil, err } @@ -455,9 +454,9 @@ func getSSHKey() ([]byte, error) { return nil, err } - app.Logger().Info("ed25519 SSH key pair generated successfully.") - app.Logger().Info("Private key saved to: " + dataDir + "/id_ed25519") - app.Logger().Info("Public key saved to: " + dataDir + "/id_ed25519.pub") + h.app.Logger().Info("ed25519 SSH key pair generated successfully.") + h.app.Logger().Info("Private key saved to: " + dataDir + "/id_ed25519") + h.app.Logger().Info("Public key saved to: " + dataDir + "/id_ed25519.pub") existingKey, err = os.ReadFile(dataDir + "/id_ed25519") if err == nil { diff --git a/hub/records.go b/internal/records/records.go similarity index 71% rename from hub/records.go rename to internal/records/records.go index 1ec2563..be8d028 100644 --- a/hub/records.go +++ b/internal/records/records.go @@ -1,17 +1,28 @@ -package main +package records import ( + "beszel/internal/entities/container" + "beszel/internal/entities/system" "fmt" "math" "reflect" "time" "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/daos" "github.com/pocketbase/pocketbase/models" ) -func createLongerRecords(collectionName string, shorterRecord *models.Record) { +type RecordManager struct { + app *pocketbase.PocketBase +} + +func NewRecordManager(app *pocketbase.PocketBase) *RecordManager { + return &RecordManager{app: app} +} + +func (rm *RecordManager) CreateLongerRecords(collectionName string, shorterRecord *models.Record) { shorterRecordType := shorterRecord.GetString("type") systemId := shorterRecord.GetString("system") // fmt.Println("create longer records", "recordType", shorterRecordType, "systemId", systemId) @@ -39,7 +50,7 @@ func createLongerRecords(collectionName string, shorterRecord *models.Record) { longerRecordPeriod := time.Now().UTC().Add(timeAgo + 10*time.Second).Format("2006-01-02 15:04:05") // check creation time of last 10m record - lastLongerRecord, err := app.Dao().FindFirstRecordByFilter( + lastLongerRecord, err := rm.app.Dao().FindFirstRecordByFilter( collectionName, "type = {:type} && system = {:system} && created > {:created}", dbx.Params{"type": longerRecordType, "system": systemId, "created": longerRecordPeriod}, @@ -51,7 +62,7 @@ func createLongerRecords(collectionName string, shorterRecord *models.Record) { } // get shorter records from the past x minutes // shorterRecordPeriod := time.Now().UTC().Add(timeAgo + time.Second).Format("2006-01-02 15:04:05") - allShorterRecords, err := app.Dao().FindRecordsByFilter( + allShorterRecords, err := rm.app.Dao().FindRecordsByFilter( collectionName, "type = {:type} && system = {:system} && created > {:created}", "-created", @@ -68,28 +79,28 @@ func createLongerRecords(collectionName string, shorterRecord *models.Record) { var stats interface{} switch collectionName { case "system_stats": - stats = averageSystemStats(allShorterRecords) + stats = rm.AverageSystemStats(allShorterRecords) case "container_stats": - stats = averageContainerStats(allShorterRecords) + stats = rm.AverageContainerStats(allShorterRecords) } - collection, _ := app.Dao().FindCollectionByNameOrId(collectionName) + collection, _ := rm.app.Dao().FindCollectionByNameOrId(collectionName) longerRecord := models.NewRecord(collection) longerRecord.Set("system", systemId) longerRecord.Set("stats", stats) longerRecord.Set("type", longerRecordType) - if err := app.Dao().SaveRecord(longerRecord); err != nil { + if err := rm.app.Dao().SaveRecord(longerRecord); err != nil { fmt.Println("failed to save longer record", "err", err.Error()) } } // calculate the average stats of a list of system_stats records -func averageSystemStats(records []*models.Record) SystemStats { +func (rm *RecordManager) AverageSystemStats(records []*models.Record) system.SystemStats { count := float64(len(records)) - sum := reflect.New(reflect.TypeOf(SystemStats{})).Elem() + sum := reflect.New(reflect.TypeOf(system.SystemStats{})).Elem() for _, record := range records { - var stats SystemStats + var stats system.SystemStats record.UnmarshalJSONField("stats", &stats) statValue := reflect.ValueOf(stats) for i := 0; i < statValue.NumField(); i++ { @@ -98,24 +109,24 @@ func averageSystemStats(records []*models.Record) SystemStats { } } - average := reflect.New(reflect.TypeOf(SystemStats{})).Elem() + average := reflect.New(reflect.TypeOf(system.SystemStats{})).Elem() for i := 0; i < sum.NumField(); i++ { average.Field(i).SetFloat(twoDecimals(sum.Field(i).Float() / count)) } - return average.Interface().(SystemStats) + return average.Interface().(system.SystemStats) } // calculate the average stats of a list of container_stats records -func averageContainerStats(records []*models.Record) (stats []ContainerStats) { - sums := make(map[string]*ContainerStats) +func (rm *RecordManager) AverageContainerStats(records []*models.Record) (stats []container.ContainerStats) { + sums := make(map[string]*container.ContainerStats) count := float64(len(records)) for _, record := range records { - var stats []ContainerStats + var stats []container.ContainerStats record.UnmarshalJSONField("stats", &stats) for _, stat := range stats { if _, ok := sums[stat.Name]; !ok { - sums[stat.Name] = &ContainerStats{Name: stat.Name, Cpu: 0, Mem: 0} + sums[stat.Name] = &container.ContainerStats{Name: stat.Name, Cpu: 0, Mem: 0} } sums[stat.Name].Cpu += stat.Cpu sums[stat.Name].Mem += stat.Mem @@ -124,7 +135,7 @@ func averageContainerStats(records []*models.Record) (stats []ContainerStats) { } } for _, value := range sums { - stats = append(stats, ContainerStats{ + stats = append(stats, container.ContainerStats{ Name: value.Name, Cpu: twoDecimals(value.Cpu / count), Mem: twoDecimals(value.Mem / count), @@ -141,7 +152,7 @@ func twoDecimals(value float64) float64 { } /* Delete records of specified collections and type that are older than timeLimit */ -func deleteOldRecords(collections []string, recordType string, timeLimit time.Duration) { +func (rm *RecordManager) DeleteOldRecords(collections []string, recordType string, timeLimit time.Duration) { timeLimitStamp := time.Now().UTC().Add(-timeLimit).Format("2006-01-02 15:04:05") // db query @@ -150,12 +161,12 @@ func deleteOldRecords(collections []string, recordType string, timeLimit time.Du var records []*models.Record for _, collection := range collections { - if collectionRecords, err := app.Dao().FindRecordsByExpr(collection, expType, expCreated); err == nil { + if collectionRecords, err := rm.app.Dao().FindRecordsByExpr(collection, expType, expCreated); err == nil { records = append(records, collectionRecords...) } } - app.Dao().RunInTransaction(func(txDao *daos.Dao) error { + rm.app.Dao().RunInTransaction(func(txDao *daos.Dao) error { for _, record := range records { err := txDao.DeleteRecord(record) if err != nil { diff --git a/hub/update.go b/internal/update/update.go similarity index 90% rename from hub/update.go rename to internal/update/update.go index 5e36284..e4721d1 100644 --- a/hub/update.go +++ b/internal/update/update.go @@ -1,6 +1,7 @@ -package main +package update import ( + "beszel" "fmt" "os" "strings" @@ -10,11 +11,11 @@ import ( "github.com/spf13/cobra" ) -func updateBeszel(cmd *cobra.Command, args []string) { +func UpdateBeszel(cmd *cobra.Command, args []string) { var latest *selfupdate.Release var found bool var err error - currentVersion := semver.MustParse(Version) + currentVersion := semver.MustParse(beszel.Version) fmt.Println("beszel", currentVersion) fmt.Println("Checking for updates...") updater, _ := selfupdate.NewUpdater(selfupdate.Config{ diff --git a/hub/site/.gitignore b/site/.gitignore similarity index 100% rename from hub/site/.gitignore rename to site/.gitignore diff --git a/hub/site/bun.lockb b/site/bun.lockb old mode 100755 new mode 100644 similarity index 100% rename from hub/site/bun.lockb rename to site/bun.lockb diff --git a/hub/site/components.json b/site/components.json similarity index 100% rename from hub/site/components.json rename to site/components.json diff --git a/hub/site/embed.go b/site/embed.go similarity index 100% rename from hub/site/embed.go rename to site/embed.go diff --git a/hub/site/index.html b/site/index.html similarity index 100% rename from hub/site/index.html rename to site/index.html diff --git a/site/package-lock.json b/site/package-lock.json new file mode 100644 index 0000000..256dee1 --- /dev/null +++ b/site/package-lock.json @@ -0,0 +1,4597 @@ +{ + "name": "site", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "site", + "version": "0.0.0", + "dependencies": { + "@nanostores/react": "^0.7.3", + "@nanostores/router": "^0.15.1", + "@radix-ui/react-alert-dialog": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dropdown-menu": "^2.1.1", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slider": "^1.2.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.0", + "@radix-ui/react-toast": "^1.2.1", + "@radix-ui/react-tooltip": "^1.1.2", + "@tanstack/react-table": "^8.20.1", + "@vitejs/plugin-react": "^4.3.1", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^1.0.0", + "d3-scale": "^4.0.2", + "d3-time": "^3.1.0", + "lucide-react": "^0.407.0", + "nanostores": "^0.10.3", + "pocketbase": "^0.21.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "recharts": "^2.13.0-alpha.4", + "tailwind-merge": "^2.4.0", + "tailwindcss-animate": "^1.0.7", + "use-is-in-viewport": "^1.0.9", + "valibot": "^0.36.0" + }, + "devDependencies": { + "@types/bun": "^1.1.6", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.40", + "tailwindcss": "^3.4.7", + "typescript": "^5.5.4", + "vite": "^5.3.5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "dependencies": { + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "dependencies": { + "@babel/types": "^7.25.2" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz", + "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz", + "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", + "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", + "dependencies": { + "@floating-ui/utils": "^0.2.7" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", + "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.7" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", + "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nanostores/react": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@nanostores/react/-/react-0.7.3.tgz", + "integrity": "sha512-/XuLAMENRu/Q71biW4AZ4qmU070vkZgiQ28gaTSNRPm2SZF5zGAR81zPE1MaMB4SeOp6ZTst92NBaG75XSspNg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "nanostores": "^0.9.0 || ^0.10.0 || ^0.11.0", + "react": ">=18.0.0" + } + }, + "node_modules/@nanostores/router": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@nanostores/router/-/router-0.15.1.tgz", + "integrity": "sha512-uEDiHPjkHGSrqEE4NRuqOLepR6lFmfLQ90c4sLLvwSNiWTY3MxejkD7tALmpj9cN4fmLnqt54r51tCNEHJL+mw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "nanostores": "^0.9.0 || ^0.10.0 || ^0.11.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", + "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.1.tgz", + "integrity": "sha512-wmCoJwj7byuVuiLKqDLlX7ClSUU0vd9sdCeM+2Ls+uf13+cpSJoMgwysHq1SGVVkJj5Xn0XWi1NoRCdkMpr6Mw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dialog": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", + "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", + "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz", + "integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-menu": "2.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", + "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", + "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz", + "integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", + "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", + "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", + "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz", + "integrity": "sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.0.tgz", + "integrity": "sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.2.0.tgz", + "integrity": "sha512-dAHCDA4/ySXROEPaRtaMV5WHL8+JB/DbtyTbJjYkY0RXmKMO2Ln8DFZhywG5/mVQ4WqHDBc8smc14yPXPqZHYA==", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.0.tgz", + "integrity": "sha512-OBzy5WAj641k0AOSpKQtreDMe+isX0MQJ1IVyF03ucdF3DunOnROVrjWs8zsXUxC3zfZ6JL9HFVCUlMghz9dJw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.1.tgz", + "integrity": "sha512-5trl7piMXcZiCq7MW6r8YYmu0bK5qDpTWz+FdEPdKyft2UixkspheYbjbrLXVN5NGKHFbOP7lm8eD0biiSqZqg==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.2.tgz", + "integrity": "sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", + "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", + "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", + "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", + "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", + "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", + "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", + "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", + "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", + "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", + "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", + "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", + "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", + "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/react-table": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.1.tgz", + "integrity": "sha512-PJK+07qbengObe5l7c8vCdtefXm8cyR4i078acWrHbdm8JKw1ES7YpmOtVt9ALUVEEFAHscdVpGRhRgikgFMbQ==", + "dependencies": { + "@tanstack/table-core": "8.20.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.1.tgz", + "integrity": "sha512-5Ly5TIRHnWH7vSDell9B/OVyV380qqIJVg7H7R7jU4fPEmOD4smqAX7VRflpYI09srWR8aj5OLD2Ccs1pI5mTg==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/bun": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.1.6.tgz", + "integrity": "sha512-uJgKjTdX0GkWEHZzQzFsJkWp5+43ZS7HC8sZPFnOwnSo1AsNl2q9o2bFeS23disNDqbggEgyFkKCHl/w8iZsMA==", + "dev": true, + "dependencies": { + "bun-types": "1.1.17" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/node": { + "version": "20.12.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.14.tgz", + "integrity": "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==", + "devOptional": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "devOptional": true + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "devOptional": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "devOptional": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", + "integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==", + "dependencies": { + "@babel/core": "^7.24.5", + "@babel/plugin-transform-react-jsx-self": "^7.24.5", + "@babel/plugin-transform-react-jsx-source": "^7.24.1", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bun-types": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.1.17.tgz", + "integrity": "sha512-Z4+OplcSd/YZq7ZsrfD00DKJeCwuNY96a1IDJyR73+cTBaFIS7SC6LhpY/W3AMEXO9iYq5NJ58WAwnwL1p5vKg==", + "dev": true, + "dependencies": { + "@types/node": "~20.12.8", + "@types/ws": "~8.5.10" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001650", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001650.tgz", + "integrity": "sha512-fgEc7hP/LB7iicdXHUI9VsBsMZmUmlVJeQP2qqQW+3lkqVhbmjEU8zp+h5stWeilX+G7uXuIUIIlWlDw9jdt8g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", + "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "dependencies": { + "clsx": "2.0.0" + }, + "funding": { + "url": "https://joebell.co.uk" + } + }, + "node_modules/class-variance-authority/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cmdk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz", + "integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==", + "dependencies": { + "@radix-ui/react-dialog": "1.0.5", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", + "integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz", + "integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-context": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz", + "integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-dialog": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz", + "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz", + "integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-escape-keydown": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-focus-guards": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz", + "integrity": "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz", + "integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-id": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz", + "integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-portal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz", + "integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-presence": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz", + "integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-primitive": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz", + "integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", + "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", + "integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz", + "integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz", + "integrity": "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz", + "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/cmdk/node_modules/react-remove-scroll": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", + "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.3", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", + "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.407.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.407.0.tgz", + "integrity": "sha512-+dRIu9Sry+E8wPF9+sY5eKld2omrU4X5IKXxrgqBt+o11IIHVU0QOfNoVWFuj0ZRDrxr4Wci26o2mKZqLGE0lA==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanostores": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.10.3.tgz", + "integrity": "sha512-Nii8O1XqmawqSCf9o2aWqVxhKRN01+iue9/VEd1TiJCr9VT5XxgPFbF1Edl1XN6pwJcZRsl8Ki+z01yb/T/C2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/observe-element-in-viewport": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/observe-element-in-viewport/-/observe-element-in-viewport-0.0.15.tgz", + "integrity": "sha512-BaJGtCHp8XXxe8zFOnsbv93f4SRLb0W5P3okGJkLLKC9IM9aXvpKF4C8lFxivcS5eROlNkhOCnUOSk4tUnJnKQ==" + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pocketbase": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.21.4.tgz", + "integrity": "sha512-WJHyaqdAt95JgZ1OCRD099+DST4IIG0M/jMrCckWYDSN/6ocp61qsz7m6h0xI0J2N79ScBljceEC0fFAaQrrAw==" + }, + "node_modules/postcss": { + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", + "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.4", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", + "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "dependencies": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", + "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recharts": { + "version": "2.13.0-alpha.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.13.0-alpha.4.tgz", + "integrity": "sha512-K9naL6F7pEcDYJE6yFQASSCQecSLPP0JagnvQ9hPtA/aHgsxsnIOjouLP5yrFZehxzfCkV5TEORr7/uNtSr7Qw==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", + "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.20.0", + "@rollup/rollup-android-arm64": "4.20.0", + "@rollup/rollup-darwin-arm64": "4.20.0", + "@rollup/rollup-darwin-x64": "4.20.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", + "@rollup/rollup-linux-arm-musleabihf": "4.20.0", + "@rollup/rollup-linux-arm64-gnu": "4.20.0", + "@rollup/rollup-linux-arm64-musl": "4.20.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", + "@rollup/rollup-linux-riscv64-gnu": "4.20.0", + "@rollup/rollup-linux-s390x-gnu": "4.20.0", + "@rollup/rollup-linux-x64-gnu": "4.20.0", + "@rollup/rollup-linux-x64-musl": "4.20.0", + "@rollup/rollup-win32-arm64-msvc": "4.20.0", + "@rollup/rollup-win32-ia32-msvc": "4.20.0", + "@rollup/rollup-win32-x64-msvc": "4.20.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.4.0.tgz", + "integrity": "sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.8.tgz", + "integrity": "sha512-GkP17r9GQkxgZ9FKHJQEnjJuKBcbFhMFzKu5slmN6NjlCuFnYJMQ8N4AZ6VrUyiRXlDtPKHkesuQ/MS913Nvdg==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "devOptional": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", + "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-is-in-viewport": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/use-is-in-viewport/-/use-is-in-viewport-1.0.9.tgz", + "integrity": "sha512-Dgi0z/X9eTk3ziI+b28mZVoYtCtyoUFQ+9VBq6fR5EdjqmmsSlbr8ysXAwmEl89OUNBQwVGLGdI9nqwiu3168g==", + "dependencies": { + "observe-element-in-viewport": "0.0.15" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.6" + } + }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/valibot": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.36.0.tgz", + "integrity": "sha512-CjF1XN4sUce8sBK9TixrDqFM7RwNkuXdJu174/AwmQUB62QbCQADg5lLe8ldBalFgtj1uKj+pKwDJiNo4Mn+eQ==" + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", + "integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.40", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/hub/site/package.json b/site/package.json similarity index 100% rename from hub/site/package.json rename to site/package.json diff --git a/hub/site/postcss.config.js b/site/postcss.config.js similarity index 100% rename from hub/site/postcss.config.js rename to site/postcss.config.js diff --git a/hub/site/public/static/apple.svg b/site/public/static/apple.svg similarity index 100% rename from hub/site/public/static/apple.svg rename to site/public/static/apple.svg diff --git a/hub/site/public/static/bitbucket.svg b/site/public/static/bitbucket.svg similarity index 100% rename from hub/site/public/static/bitbucket.svg rename to site/public/static/bitbucket.svg diff --git a/hub/site/public/static/discord.svg b/site/public/static/discord.svg similarity index 100% rename from hub/site/public/static/discord.svg rename to site/public/static/discord.svg diff --git a/hub/site/public/static/facebook.svg b/site/public/static/facebook.svg similarity index 100% rename from hub/site/public/static/facebook.svg rename to site/public/static/facebook.svg diff --git a/hub/site/public/static/favicon-green.svg b/site/public/static/favicon-green.svg similarity index 100% rename from hub/site/public/static/favicon-green.svg rename to site/public/static/favicon-green.svg diff --git a/hub/site/public/static/favicon-red.svg b/site/public/static/favicon-red.svg similarity index 100% rename from hub/site/public/static/favicon-red.svg rename to site/public/static/favicon-red.svg diff --git a/hub/site/public/static/favicon.svg b/site/public/static/favicon.svg similarity index 100% rename from hub/site/public/static/favicon.svg rename to site/public/static/favicon.svg diff --git a/hub/site/public/static/gitea.svg b/site/public/static/gitea.svg similarity index 100% rename from hub/site/public/static/gitea.svg rename to site/public/static/gitea.svg diff --git a/hub/site/public/static/gitee.svg b/site/public/static/gitee.svg similarity index 100% rename from hub/site/public/static/gitee.svg rename to site/public/static/gitee.svg diff --git a/hub/site/public/static/github.svg b/site/public/static/github.svg similarity index 100% rename from hub/site/public/static/github.svg rename to site/public/static/github.svg diff --git a/hub/site/public/static/gitlab.svg b/site/public/static/gitlab.svg similarity index 100% rename from hub/site/public/static/gitlab.svg rename to site/public/static/gitlab.svg diff --git a/hub/site/public/static/google.svg b/site/public/static/google.svg similarity index 100% rename from hub/site/public/static/google.svg rename to site/public/static/google.svg diff --git a/hub/site/public/static/instagram.svg b/site/public/static/instagram.svg similarity index 100% rename from hub/site/public/static/instagram.svg rename to site/public/static/instagram.svg diff --git a/hub/site/public/static/lock.svg b/site/public/static/lock.svg similarity index 100% rename from hub/site/public/static/lock.svg rename to site/public/static/lock.svg diff --git a/hub/site/public/static/oidc.svg b/site/public/static/oidc.svg similarity index 100% rename from hub/site/public/static/oidc.svg rename to site/public/static/oidc.svg diff --git a/hub/site/public/static/patreon.svg b/site/public/static/patreon.svg similarity index 100% rename from hub/site/public/static/patreon.svg rename to site/public/static/patreon.svg diff --git a/hub/site/public/static/spotify.svg b/site/public/static/spotify.svg similarity index 100% rename from hub/site/public/static/spotify.svg rename to site/public/static/spotify.svg diff --git a/hub/site/public/static/strava.svg b/site/public/static/strava.svg similarity index 100% rename from hub/site/public/static/strava.svg rename to site/public/static/strava.svg diff --git a/hub/site/public/static/twitch.svg b/site/public/static/twitch.svg similarity index 100% rename from hub/site/public/static/twitch.svg rename to site/public/static/twitch.svg diff --git a/hub/site/public/static/twitter.svg b/site/public/static/twitter.svg similarity index 100% rename from hub/site/public/static/twitter.svg rename to site/public/static/twitter.svg diff --git a/hub/site/src/components/add-system.tsx b/site/src/components/add-system.tsx similarity index 100% rename from hub/site/src/components/add-system.tsx rename to site/src/components/add-system.tsx diff --git a/hub/site/src/components/charts/bandwidth-chart.tsx b/site/src/components/charts/bandwidth-chart.tsx similarity index 100% rename from hub/site/src/components/charts/bandwidth-chart.tsx rename to site/src/components/charts/bandwidth-chart.tsx diff --git a/hub/site/src/components/charts/chart-time-select.tsx b/site/src/components/charts/chart-time-select.tsx similarity index 100% rename from hub/site/src/components/charts/chart-time-select.tsx rename to site/src/components/charts/chart-time-select.tsx diff --git a/hub/site/src/components/charts/container-cpu-chart.tsx b/site/src/components/charts/container-cpu-chart.tsx similarity index 100% rename from hub/site/src/components/charts/container-cpu-chart.tsx rename to site/src/components/charts/container-cpu-chart.tsx diff --git a/hub/site/src/components/charts/container-mem-chart.tsx b/site/src/components/charts/container-mem-chart.tsx similarity index 100% rename from hub/site/src/components/charts/container-mem-chart.tsx rename to site/src/components/charts/container-mem-chart.tsx diff --git a/hub/site/src/components/charts/container-net-chart.tsx b/site/src/components/charts/container-net-chart.tsx similarity index 100% rename from hub/site/src/components/charts/container-net-chart.tsx rename to site/src/components/charts/container-net-chart.tsx diff --git a/hub/site/src/components/charts/cpu-chart.tsx b/site/src/components/charts/cpu-chart.tsx similarity index 100% rename from hub/site/src/components/charts/cpu-chart.tsx rename to site/src/components/charts/cpu-chart.tsx diff --git a/hub/site/src/components/charts/disk-chart.tsx b/site/src/components/charts/disk-chart.tsx similarity index 100% rename from hub/site/src/components/charts/disk-chart.tsx rename to site/src/components/charts/disk-chart.tsx diff --git a/hub/site/src/components/charts/disk-io-chart.tsx b/site/src/components/charts/disk-io-chart.tsx similarity index 100% rename from hub/site/src/components/charts/disk-io-chart.tsx rename to site/src/components/charts/disk-io-chart.tsx diff --git a/hub/site/src/components/charts/mem-chart.tsx b/site/src/components/charts/mem-chart.tsx similarity index 100% rename from hub/site/src/components/charts/mem-chart.tsx rename to site/src/components/charts/mem-chart.tsx diff --git a/hub/site/src/components/charts/swap-chart.tsx b/site/src/components/charts/swap-chart.tsx similarity index 100% rename from hub/site/src/components/charts/swap-chart.tsx rename to site/src/components/charts/swap-chart.tsx diff --git a/hub/site/src/components/command-palette.tsx b/site/src/components/command-palette.tsx similarity index 100% rename from hub/site/src/components/command-palette.tsx rename to site/src/components/command-palette.tsx diff --git a/hub/site/src/components/login/auth-form.tsx b/site/src/components/login/auth-form.tsx similarity index 100% rename from hub/site/src/components/login/auth-form.tsx rename to site/src/components/login/auth-form.tsx diff --git a/hub/site/src/components/login/forgot-pass-form.tsx b/site/src/components/login/forgot-pass-form.tsx similarity index 100% rename from hub/site/src/components/login/forgot-pass-form.tsx rename to site/src/components/login/forgot-pass-form.tsx diff --git a/hub/site/src/components/login/login.tsx b/site/src/components/login/login.tsx similarity index 100% rename from hub/site/src/components/login/login.tsx rename to site/src/components/login/login.tsx diff --git a/hub/site/src/components/logo.tsx b/site/src/components/logo.tsx similarity index 100% rename from hub/site/src/components/logo.tsx rename to site/src/components/logo.tsx diff --git a/hub/site/src/components/mode-toggle.tsx b/site/src/components/mode-toggle.tsx similarity index 100% rename from hub/site/src/components/mode-toggle.tsx rename to site/src/components/mode-toggle.tsx diff --git a/hub/site/src/components/router.tsx b/site/src/components/router.tsx similarity index 100% rename from hub/site/src/components/router.tsx rename to site/src/components/router.tsx diff --git a/hub/site/src/components/routes/home.tsx b/site/src/components/routes/home.tsx similarity index 100% rename from hub/site/src/components/routes/home.tsx rename to site/src/components/routes/home.tsx diff --git a/hub/site/src/components/routes/system.tsx b/site/src/components/routes/system.tsx similarity index 100% rename from hub/site/src/components/routes/system.tsx rename to site/src/components/routes/system.tsx diff --git a/hub/site/src/components/spinner.tsx b/site/src/components/spinner.tsx similarity index 100% rename from hub/site/src/components/spinner.tsx rename to site/src/components/spinner.tsx diff --git a/hub/site/src/components/systems-table/columns.tsx b/site/src/components/systems-table/columns.tsx similarity index 100% rename from hub/site/src/components/systems-table/columns.tsx rename to site/src/components/systems-table/columns.tsx diff --git a/hub/site/src/components/systems-table/systems-table.tsx b/site/src/components/systems-table/systems-table.tsx similarity index 100% rename from hub/site/src/components/systems-table/systems-table.tsx rename to site/src/components/systems-table/systems-table.tsx diff --git a/hub/site/src/components/table-alerts.tsx b/site/src/components/table-alerts.tsx similarity index 100% rename from hub/site/src/components/table-alerts.tsx rename to site/src/components/table-alerts.tsx diff --git a/hub/site/src/components/theme-provider.tsx b/site/src/components/theme-provider.tsx similarity index 100% rename from hub/site/src/components/theme-provider.tsx rename to site/src/components/theme-provider.tsx diff --git a/hub/site/src/components/ui/alert-dialog.tsx b/site/src/components/ui/alert-dialog.tsx similarity index 100% rename from hub/site/src/components/ui/alert-dialog.tsx rename to site/src/components/ui/alert-dialog.tsx diff --git a/hub/site/src/components/ui/button.tsx b/site/src/components/ui/button.tsx similarity index 100% rename from hub/site/src/components/ui/button.tsx rename to site/src/components/ui/button.tsx diff --git a/hub/site/src/components/ui/card.tsx b/site/src/components/ui/card.tsx similarity index 100% rename from hub/site/src/components/ui/card.tsx rename to site/src/components/ui/card.tsx diff --git a/hub/site/src/components/ui/chart.tsx b/site/src/components/ui/chart.tsx similarity index 100% rename from hub/site/src/components/ui/chart.tsx rename to site/src/components/ui/chart.tsx diff --git a/hub/site/src/components/ui/command.tsx b/site/src/components/ui/command.tsx similarity index 100% rename from hub/site/src/components/ui/command.tsx rename to site/src/components/ui/command.tsx diff --git a/hub/site/src/components/ui/dialog.tsx b/site/src/components/ui/dialog.tsx similarity index 100% rename from hub/site/src/components/ui/dialog.tsx rename to site/src/components/ui/dialog.tsx diff --git a/hub/site/src/components/ui/dropdown-menu.tsx b/site/src/components/ui/dropdown-menu.tsx similarity index 100% rename from hub/site/src/components/ui/dropdown-menu.tsx rename to site/src/components/ui/dropdown-menu.tsx diff --git a/hub/site/src/components/ui/input.tsx b/site/src/components/ui/input.tsx similarity index 100% rename from hub/site/src/components/ui/input.tsx rename to site/src/components/ui/input.tsx diff --git a/hub/site/src/components/ui/label.tsx b/site/src/components/ui/label.tsx similarity index 100% rename from hub/site/src/components/ui/label.tsx rename to site/src/components/ui/label.tsx diff --git a/hub/site/src/components/ui/select.tsx b/site/src/components/ui/select.tsx similarity index 100% rename from hub/site/src/components/ui/select.tsx rename to site/src/components/ui/select.tsx diff --git a/hub/site/src/components/ui/separator.tsx b/site/src/components/ui/separator.tsx similarity index 100% rename from hub/site/src/components/ui/separator.tsx rename to site/src/components/ui/separator.tsx diff --git a/hub/site/src/components/ui/slider.tsx b/site/src/components/ui/slider.tsx similarity index 100% rename from hub/site/src/components/ui/slider.tsx rename to site/src/components/ui/slider.tsx diff --git a/hub/site/src/components/ui/switch.tsx b/site/src/components/ui/switch.tsx similarity index 100% rename from hub/site/src/components/ui/switch.tsx rename to site/src/components/ui/switch.tsx diff --git a/hub/site/src/components/ui/table.tsx b/site/src/components/ui/table.tsx similarity index 100% rename from hub/site/src/components/ui/table.tsx rename to site/src/components/ui/table.tsx diff --git a/hub/site/src/components/ui/toast.tsx b/site/src/components/ui/toast.tsx similarity index 100% rename from hub/site/src/components/ui/toast.tsx rename to site/src/components/ui/toast.tsx diff --git a/hub/site/src/components/ui/toaster.tsx b/site/src/components/ui/toaster.tsx similarity index 100% rename from hub/site/src/components/ui/toaster.tsx rename to site/src/components/ui/toaster.tsx diff --git a/hub/site/src/components/ui/tooltip.tsx b/site/src/components/ui/tooltip.tsx similarity index 100% rename from hub/site/src/components/ui/tooltip.tsx rename to site/src/components/ui/tooltip.tsx diff --git a/hub/site/src/components/ui/use-toast.ts b/site/src/components/ui/use-toast.ts similarity index 100% rename from hub/site/src/components/ui/use-toast.ts rename to site/src/components/ui/use-toast.ts diff --git a/hub/site/src/index.css b/site/src/index.css similarity index 100% rename from hub/site/src/index.css rename to site/src/index.css diff --git a/hub/site/src/lib/stores.ts b/site/src/lib/stores.ts similarity index 100% rename from hub/site/src/lib/stores.ts rename to site/src/lib/stores.ts diff --git a/hub/site/src/lib/utils.ts b/site/src/lib/utils.ts similarity index 100% rename from hub/site/src/lib/utils.ts rename to site/src/lib/utils.ts diff --git a/hub/site/src/main.tsx b/site/src/main.tsx similarity index 100% rename from hub/site/src/main.tsx rename to site/src/main.tsx diff --git a/hub/site/src/types.d.ts b/site/src/types.d.ts similarity index 100% rename from hub/site/src/types.d.ts rename to site/src/types.d.ts diff --git a/hub/site/src/vite-env.d.ts b/site/src/vite-env.d.ts similarity index 100% rename from hub/site/src/vite-env.d.ts rename to site/src/vite-env.d.ts diff --git a/hub/site/tailwind.config.js b/site/tailwind.config.js similarity index 100% rename from hub/site/tailwind.config.js rename to site/tailwind.config.js diff --git a/hub/site/tsconfig.app.json b/site/tsconfig.app.json similarity index 100% rename from hub/site/tsconfig.app.json rename to site/tsconfig.app.json diff --git a/hub/site/tsconfig.json b/site/tsconfig.json similarity index 100% rename from hub/site/tsconfig.json rename to site/tsconfig.json diff --git a/hub/site/tsconfig.node.json b/site/tsconfig.node.json similarity index 100% rename from hub/site/tsconfig.node.json rename to site/tsconfig.node.json diff --git a/hub/site/vite.config.ts b/site/vite.config.ts similarity index 100% rename from hub/site/vite.config.ts rename to site/vite.config.ts diff --git a/version.go b/version.go new file mode 100644 index 0000000..28d474c --- /dev/null +++ b/version.go @@ -0,0 +1,6 @@ +package beszel + +const ( + Version = "0.1.2" + AppName = "beszel" +) From 034a5c21ebb887f3798eb722e1d0b26dd9d71e6a Mon Sep 17 00:00:00 2001 From: TOomaAh Date: Fri, 9 Aug 2024 17:52:02 +0200 Subject: [PATCH 02/19] change agent file structure --- agent/types.go | 177 ----------------------- agent/update.go | 54 ------- cmd/agent/agent.go | 47 ++++++ agent/main.go => internal/agent/agent.go | 114 +++++++-------- internal/entities/container/stats.go | 33 +++++ internal/entities/system/stats.go | 103 +++++++++++++ internal/entities/system/system.go | 6 +- internal/update/update.go | 44 ++++++ 8 files changed, 281 insertions(+), 297 deletions(-) delete mode 100644 agent/types.go delete mode 100644 agent/update.go rename agent/main.go => internal/agent/agent.go (86%) diff --git a/agent/types.go b/agent/types.go deleted file mode 100644 index 1d48eb0..0000000 --- a/agent/types.go +++ /dev/null @@ -1,177 +0,0 @@ -package main - -import "time" - -type SystemData struct { - Stats *SystemStats `json:"stats"` - Info *SystemInfo `json:"info"` - Containers []*ContainerStats `json:"container"` -} - -type SystemInfo struct { - Cores int `json:"c"` - Threads int `json:"t"` - CpuModel string `json:"m"` - // Os string `json:"o"` - Uptime uint64 `json:"u"` - Cpu float64 `json:"cpu"` - MemPct float64 `json:"mp"` - DiskPct float64 `json:"dp"` -} - -type SystemStats struct { - Cpu float64 `json:"cpu"` - Mem float64 `json:"m"` - MemUsed float64 `json:"mu"` - MemPct float64 `json:"mp"` - MemBuffCache float64 `json:"mb"` - Swap float64 `json:"s"` - SwapUsed float64 `json:"su"` - Disk float64 `json:"d"` - DiskUsed float64 `json:"du"` - DiskPct float64 `json:"dp"` - DiskRead float64 `json:"dr"` - DiskWrite float64 `json:"dw"` - NetworkSent float64 `json:"ns"` - NetworkRecv float64 `json:"nr"` -} - -type ContainerStats struct { - Name string `json:"n"` - Cpu float64 `json:"c"` - Mem float64 `json:"m"` - NetworkSent float64 `json:"ns"` - NetworkRecv float64 `json:"nr"` -} - -type Container struct { - Id string - IdShort string - Names []string - Status string - // Image string - // ImageID string - // Command string - // Created int64 - // Ports []Port - // SizeRw int64 `json:",omitempty"` - // SizeRootFs int64 `json:",omitempty"` - // Labels map[string]string - // State string - // HostConfig struct { - // NetworkMode string `json:",omitempty"` - // Annotations map[string]string `json:",omitempty"` - // } - // NetworkSettings *SummaryNetworkSettings - // Mounts []MountPoint -} - -type CStats struct { - // Common stats - // Read time.Time `json:"read"` - // PreRead time.Time `json:"preread"` - - // Linux specific stats, not populated on Windows. - // PidsStats PidsStats `json:"pids_stats,omitempty"` - // BlkioStats BlkioStats `json:"blkio_stats,omitempty"` - - // Windows specific stats, not populated on Linux. - // NumProcs uint32 `json:"num_procs"` - // StorageStats StorageStats `json:"storage_stats,omitempty"` - // Networks request version >=1.21 - Networks map[string]NetworkStats - - // Shared stats - CPUStats CPUStats `json:"cpu_stats,omitempty"` - // PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" - MemoryStats MemoryStats `json:"memory_stats,omitempty"` -} - -type CPUStats struct { - // CPU Usage. Linux and Windows. - CPUUsage CPUUsage `json:"cpu_usage"` - - // System Usage. Linux only. - SystemUsage uint64 `json:"system_cpu_usage,omitempty"` - - // Online CPUs. Linux only. - // OnlineCPUs uint32 `json:"online_cpus,omitempty"` - - // Throttling Data. Linux only. - // ThrottlingData ThrottlingData `json:"throttling_data,omitempty"` -} - -type CPUUsage struct { - // Total CPU time consumed. - // Units: nanoseconds (Linux) - // Units: 100's of nanoseconds (Windows) - TotalUsage uint64 `json:"total_usage"` - - // Total CPU time consumed per core (Linux). Not used on Windows. - // Units: nanoseconds. - // PercpuUsage []uint64 `json:"percpu_usage,omitempty"` - - // Time spent by tasks of the cgroup in kernel mode (Linux). - // Time spent by all container processes in kernel mode (Windows). - // Units: nanoseconds (Linux). - // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers. - // UsageInKernelmode uint64 `json:"usage_in_kernelmode"` - - // Time spent by tasks of the cgroup in user mode (Linux). - // Time spent by all container processes in user mode (Windows). - // Units: nanoseconds (Linux). - // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers - // UsageInUsermode uint64 `json:"usage_in_usermode"` -} - -type MemoryStats struct { - - // current res_counter usage for memory - Usage uint64 `json:"usage,omitempty"` - Cache uint64 `json:"cache,omitempty"` - // maximum usage ever recorded. - // MaxUsage uint64 `json:"max_usage,omitempty"` - // TODO(vishh): Export these as stronger types. - // all the stats exported via memory.stat. - Stats map[string]uint64 `json:"stats,omitempty"` - // number of times memory usage hits limits. - // Failcnt uint64 `json:"failcnt,omitempty"` - // Limit uint64 `json:"limit,omitempty"` - - // // committed bytes - // Commit uint64 `json:"commitbytes,omitempty"` - // // peak committed bytes - // CommitPeak uint64 `json:"commitpeakbytes,omitempty"` - // // private working set - // PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"` -} - -type NetworkStats struct { - // Bytes received. Windows and Linux. - RxBytes uint64 `json:"rx_bytes"` - // Bytes sent. Windows and Linux. - TxBytes uint64 `json:"tx_bytes"` -} - -type DiskIoStats struct { - Read uint64 - Write uint64 - Time time.Time - Filesystem string -} - -type NetIoStats struct { - BytesRecv uint64 - BytesSent uint64 - Time time.Time - Name string -} - -type PrevContainerStats struct { - Cpu [2]uint64 - Net struct { - Sent uint64 - Recv uint64 - Time time.Time - } -} diff --git a/agent/update.go b/agent/update.go deleted file mode 100644 index fef463a..0000000 --- a/agent/update.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strings" - - "github.com/blang/semver" - "github.com/rhysd/go-github-selfupdate/selfupdate" -) - -func updateBeszel() { - var latest *selfupdate.Release - var found bool - var err error - currentVersion := semver.MustParse(Version) - fmt.Println("beszel-agent", currentVersion) - fmt.Println("Checking for updates...") - updater, _ := selfupdate.NewUpdater(selfupdate.Config{ - Filters: []string{"beszel-agent"}, - }) - latest, found, err = updater.DetectLatest("henrygd/beszel") - - if err != nil { - fmt.Println("Error checking for updates:", err) - os.Exit(1) - } - - if !found { - fmt.Println("No updates found") - os.Exit(0) - } - - fmt.Println("Latest version:", latest.Version) - - if latest.Version.LTE(currentVersion) { - fmt.Println("You are up to date") - return - } - - var binaryPath string - fmt.Printf("Updating from %s to %s...\n", currentVersion, latest.Version) - binaryPath, err = os.Executable() - if err != nil { - fmt.Println("Error getting binary path:", err) - os.Exit(1) - } - err = selfupdate.UpdateTo(latest.AssetURL, binaryPath) - if err != nil { - fmt.Println("Please try rerunning with sudo. Error:", err) - os.Exit(1) - } - fmt.Printf("Successfully updated to %s\n\n%s\n", latest.Version, strings.TrimSpace(latest.ReleaseNotes)) -} diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go index 06ab7d0..2918644 100644 --- a/cmd/agent/agent.go +++ b/cmd/agent/agent.go @@ -1 +1,48 @@ package main + +import ( + "beszel" + "beszel/internal/agent" + "beszel/internal/update" + "fmt" + "log" + "os" + "strings" +) + +func main() { + // handle flags / subcommands + if len(os.Args) > 1 { + switch os.Args[1] { + case "-v": + fmt.Println(beszel.AppName+"-agent", beszel.Version) + case "update": + update.UpdateBeszelAgent() + } + os.Exit(0) + } + + var pubKey []byte + if pubKeyEnv, exists := os.LookupEnv("KEY"); exists { + pubKey = []byte(pubKeyEnv) + } else { + log.Fatal("KEY environment variable is not set") + } + + var port string + + if p, exists := os.LookupEnv("PORT"); exists { + // allow passing an address in the form of "127.0.0.1:45876" + if !strings.Contains(port, ":") { + port = ":" + port + } + port = p + } else { + port = ":45876" + } + + a := agent.NewAgent(pubKey, port) + + a.Run() + +} diff --git a/agent/main.go b/internal/agent/agent.go similarity index 86% rename from agent/main.go rename to internal/agent/agent.go index 9134dae..5b44e53 100644 --- a/agent/main.go +++ b/internal/agent/agent.go @@ -1,6 +1,8 @@ -package main +package agent import ( + "beszel/internal/entities/container" + "beszel/internal/entities/system" "context" "encoding/json" "fmt" @@ -15,38 +17,49 @@ import ( "sync" "time" - sshServer "github.com/gliderlabs/ssh" - "github.com/shirou/gopsutil/v4/cpu" "github.com/shirou/gopsutil/v4/disk" "github.com/shirou/gopsutil/v4/host" "github.com/shirou/gopsutil/v4/mem" + + sshServer "github.com/gliderlabs/ssh" psutilNet "github.com/shirou/gopsutil/v4/net" ) var Version = "0.1.2" -var containerStatsMap = make(map[string]*PrevContainerStats) +var containerStatsMap = make(map[string]*container.PrevContainerStats) var containerStatsMutex = &sync.Mutex{} -var sem = make(chan struct{}, 15) - -func acquireSemaphore() { - sem <- struct{}{} +type Agent struct { + port string + pubKey []byte + sem chan struct{} } -func releaseSemaphore() { - <-sem +func NewAgent(pubKey []byte, port string) *Agent { + return &Agent{ + pubKey: pubKey, + sem: make(chan struct{}, 15), + } } -var diskIoStats = DiskIoStats{ +func (a *Agent) acquireSemaphore() { + a.sem <- struct{}{} +} + +func (a *Agent) releaseSemaphore() { + <-a.sem +} + +var diskIoStats = system.DiskIoStats{ Read: 0, Write: 0, Time: time.Now(), Filesystem: "", } -var netIoStats = NetIoStats{ +var netIoStats = system.NetIoStats{ BytesRecv: 0, BytesSent: 0, Time: time.Now(), @@ -56,8 +69,8 @@ var netIoStats = NetIoStats{ // client for docker engine api var dockerClient = newDockerClient() -func getSystemStats() (*SystemInfo, *SystemStats) { - systemStats := &SystemStats{} +func getSystemStats() (*system.SystemInfo, *system.SystemStats) { + systemStats := &system.SystemStats{} // cpu percent cpuPct, err := cpu.Percent(0, false) @@ -124,7 +137,7 @@ func getSystemStats() (*SystemInfo, *SystemStats) { netIoStats.Time = time.Now() } - systemInfo := &SystemInfo{ + systemInfo := &system.SystemInfo{ Cpu: systemStats.Cpu, MemPct: systemStats.MemPct, DiskPct: systemStats.DiskPct, @@ -150,21 +163,21 @@ func getSystemStats() (*SystemInfo, *SystemStats) { } -func getDockerStats() ([]*ContainerStats, error) { +func (a *Agent) getDockerStats() ([]*container.ContainerStats, error) { resp, err := dockerClient.Get("http://localhost/containers/json") if err != nil { closeIdleConnections(err) - return []*ContainerStats{}, err + return []*container.ContainerStats{}, err } defer resp.Body.Close() - var containers []*Container + var containers []*container.Container if err := json.NewDecoder(resp.Body).Decode(&containers); err != nil { log.Printf("Error decoding containers: %+v\n", err) - return []*ContainerStats{}, err + return []*container.ContainerStats{}, err } - containerStats := make([]*ContainerStats, 0, len(containers)) + containerStats := make([]*container.ContainerStats, 0, len(containers)) // store valid ids to clean up old container ids from map validIds := make(map[string]struct{}, len(containers)) @@ -183,7 +196,7 @@ func getDockerStats() ([]*ContainerStats, error) { wg.Add(1) go func() { defer wg.Done() - cstats, err := getContainerStats(ctr) + cstats, err := a.getContainerStats(ctr) if err != nil { // Check if the error is a network timeout if netErr, ok := err.(net.Error); ok && netErr.Timeout() { @@ -194,7 +207,7 @@ func getDockerStats() ([]*ContainerStats, error) { deleteContainerStatsSync(ctr.IdShort) } // retry once - cstats, err = getContainerStats(ctr) + cstats, err = a.getContainerStats(ctr) if err != nil { log.Printf("Error getting container stats: %+v\n", err) return @@ -216,17 +229,17 @@ func getDockerStats() ([]*ContainerStats, error) { return containerStats, nil } -func getContainerStats(ctr *Container) (*ContainerStats, error) { +func (a *Agent) getContainerStats(ctr *container.Container) (*container.ContainerStats, error) { // use semaphore to limit concurrency - acquireSemaphore() - defer releaseSemaphore() + a.acquireSemaphore() + defer a.releaseSemaphore() resp, err := dockerClient.Get("http://localhost/containers/" + ctr.IdShort + "/stats?stream=0&one-shot=1") if err != nil { - return &ContainerStats{}, err + return &container.ContainerStats{}, err } defer resp.Body.Close() - var statsJson CStats + var statsJson system.CStats if err := json.NewDecoder(resp.Body).Decode(&statsJson); err != nil { panic(err) } @@ -246,7 +259,7 @@ func getContainerStats(ctr *Container) (*ContainerStats, error) { // add empty values if they doesn't exist in map stats, initialized := containerStatsMap[ctr.IdShort] if !initialized { - stats = &PrevContainerStats{} + stats = &container.PrevContainerStats{} containerStatsMap[ctr.IdShort] = stats } @@ -255,7 +268,7 @@ func getContainerStats(ctr *Container) (*ContainerStats, error) { systemDelta := statsJson.CPUStats.SystemUsage - stats.Cpu[1] cpuPct := float64(cpuDelta) / float64(systemDelta) * 100 if cpuPct > 100 { - return &ContainerStats{}, fmt.Errorf("%s cpu pct greater than 100: %+v", name, cpuPct) + return &container.ContainerStats{}, fmt.Errorf("%s cpu pct greater than 100: %+v", name, cpuPct) } stats.Cpu = [2]uint64{statsJson.CPUStats.CPUUsage.TotalUsage, statsJson.CPUStats.SystemUsage} @@ -277,7 +290,7 @@ func getContainerStats(ctr *Container) (*ContainerStats, error) { stats.Net.Recv = total_recv stats.Net.Time = time.Now() - cStats := &ContainerStats{ + cStats := &container.ContainerStats{ Name: name, Cpu: twoDecimals(cpuPct), Mem: bytesToMegabytes(float64(usedMemory)), @@ -294,14 +307,14 @@ func deleteContainerStatsSync(id string) { delete(containerStatsMap, id) } -func gatherStats() *SystemData { +func (a *Agent) gatherStats() *system.SystemData { systemInfo, systemStats := getSystemStats() - stats := &SystemData{ + stats := &system.SystemData{ Stats: systemStats, Info: systemInfo, - Containers: []*ContainerStats{}, + Containers: []*container.ContainerStats{}, } - containerStats, err := getDockerStats() + containerStats, err := a.getDockerStats() if err == nil { stats.Containers = containerStats } @@ -309,9 +322,9 @@ func gatherStats() *SystemData { return stats } -func startServer(addr string, pubKey []byte) { +func (a *Agent) startServer(addr string, pubKey []byte) { sshServer.Handle(func(s sshServer.Session) { - stats := gatherStats() + stats := a.gatherStats() var jsonStats []byte jsonStats, _ = json.Marshal(stats) io.WriteString(s, string(jsonStats)) @@ -330,24 +343,7 @@ func startServer(addr string, pubKey []byte) { } } -func main() { - // handle flags / subcommands - if len(os.Args) > 1 { - switch os.Args[1] { - case "-v": - fmt.Println("beszel-agent", Version) - case "update": - updateBeszel() - } - os.Exit(0) - } - - var pubKey []byte - if pubKeyEnv, exists := os.LookupEnv("KEY"); exists { - pubKey = []byte(pubKeyEnv) - } else { - log.Fatal("KEY environment variable is not set") - } +func (a *Agent) Run() { if filesystem, exists := os.LookupEnv("FILESYSTEM"); exists { diskIoStats.Filesystem = filesystem @@ -358,15 +354,7 @@ func main() { initializeDiskIoStats() initializeNetIoStats() - if port, exists := os.LookupEnv("PORT"); exists { - // allow passing an address in the form of "127.0.0.1:45876" - if !strings.Contains(port, ":") { - port = ":" + port - } - startServer(port, pubKey) - } else { - startServer(":45876", pubKey) - } + a.startServer(a.port, a.pubKey) } func bytesToMegabytes(b float64) float64 { diff --git a/internal/entities/container/stats.go b/internal/entities/container/stats.go index e99a9f4..80aab5e 100644 --- a/internal/entities/container/stats.go +++ b/internal/entities/container/stats.go @@ -1,5 +1,29 @@ package container +import "time" + +type Container struct { + Id string + IdShort string + Names []string + Status string + // Image string + // ImageID string + // Command string + // Created int64 + // Ports []Port + // SizeRw int64 `json:",omitempty"` + // SizeRootFs int64 `json:",omitempty"` + // Labels map[string]string + // State string + // HostConfig struct { + // NetworkMode string `json:",omitempty"` + // Annotations map[string]string `json:",omitempty"` + // } + // NetworkSettings *SummaryNetworkSettings + // Mounts []MountPoint +} + type ContainerStats struct { Name string `json:"n"` Cpu float64 `json:"c"` @@ -7,3 +31,12 @@ type ContainerStats struct { NetworkSent float64 `json:"ns"` NetworkRecv float64 `json:"nr"` } + +type PrevContainerStats struct { + Cpu [2]uint64 + Net struct { + Sent uint64 + Recv uint64 + Time time.Time + } +} diff --git a/internal/entities/system/stats.go b/internal/entities/system/stats.go index 43f591c..caafcc8 100644 --- a/internal/entities/system/stats.go +++ b/internal/entities/system/stats.go @@ -1,5 +1,7 @@ package system +import "time" + type SystemStats struct { Cpu float64 `json:"cpu"` Mem float64 `json:"m"` @@ -16,3 +18,104 @@ type SystemStats struct { NetworkSent float64 `json:"ns"` NetworkRecv float64 `json:"nr"` } + +type DiskIoStats struct { + Read uint64 + Write uint64 + Time time.Time + Filesystem string +} + +type NetIoStats struct { + BytesRecv uint64 + BytesSent uint64 + Time time.Time + Name string +} + +type CPUStats struct { + // CPU Usage. Linux and Windows. + CPUUsage CPUUsage `json:"cpu_usage"` + + // System Usage. Linux only. + SystemUsage uint64 `json:"system_cpu_usage,omitempty"` + + // Online CPUs. Linux only. + // OnlineCPUs uint32 `json:"online_cpus,omitempty"` + + // Throttling Data. Linux only. + // ThrottlingData ThrottlingData `json:"throttling_data,omitempty"` +} + +type CPUUsage struct { + // Total CPU time consumed. + // Units: nanoseconds (Linux) + // Units: 100's of nanoseconds (Windows) + TotalUsage uint64 `json:"total_usage"` + + // Total CPU time consumed per core (Linux). Not used on Windows. + // Units: nanoseconds. + // PercpuUsage []uint64 `json:"percpu_usage,omitempty"` + + // Time spent by tasks of the cgroup in kernel mode (Linux). + // Time spent by all container processes in kernel mode (Windows). + // Units: nanoseconds (Linux). + // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers. + // UsageInKernelmode uint64 `json:"usage_in_kernelmode"` + + // Time spent by tasks of the cgroup in user mode (Linux). + // Time spent by all container processes in user mode (Windows). + // Units: nanoseconds (Linux). + // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers + // UsageInUsermode uint64 `json:"usage_in_usermode"` +} + +type CStats struct { + // Common stats + // Read time.Time `json:"read"` + // PreRead time.Time `json:"preread"` + + // Linux specific stats, not populated on Windows. + // PidsStats PidsStats `json:"pids_stats,omitempty"` + // BlkioStats BlkioStats `json:"blkio_stats,omitempty"` + + // Windows specific stats, not populated on Linux. + // NumProcs uint32 `json:"num_procs"` + // StorageStats StorageStats `json:"storage_stats,omitempty"` + // Networks request version >=1.21 + Networks map[string]NetworkStats + + // Shared stats + CPUStats CPUStats `json:"cpu_stats,omitempty"` + // PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" + MemoryStats MemoryStats `json:"memory_stats,omitempty"` +} + +type MemoryStats struct { + + // current res_counter usage for memory + Usage uint64 `json:"usage,omitempty"` + Cache uint64 `json:"cache,omitempty"` + // maximum usage ever recorded. + // MaxUsage uint64 `json:"max_usage,omitempty"` + // TODO(vishh): Export these as stronger types. + // all the stats exported via memory.stat. + Stats map[string]uint64 `json:"stats,omitempty"` + // number of times memory usage hits limits. + // Failcnt uint64 `json:"failcnt,omitempty"` + // Limit uint64 `json:"limit,omitempty"` + + // // committed bytes + // Commit uint64 `json:"commitbytes,omitempty"` + // // peak committed bytes + // CommitPeak uint64 `json:"commitpeakbytes,omitempty"` + // // private working set + // PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"` +} + +type NetworkStats struct { + // Bytes received. Windows and Linux. + RxBytes uint64 `json:"rx_bytes"` + // Bytes sent. Windows and Linux. + TxBytes uint64 `json:"tx_bytes"` +} diff --git a/internal/entities/system/system.go b/internal/entities/system/system.go index 39a60b7..941ce7f 100644 --- a/internal/entities/system/system.go +++ b/internal/entities/system/system.go @@ -14,7 +14,7 @@ type SystemInfo struct { } type SystemData struct { - Stats SystemStats `json:"stats"` - Info SystemInfo `json:"info"` - Containers []container.ContainerStats `json:"container"` + Stats *SystemStats `json:"stats"` + Info *SystemInfo `json:"info"` + Containers []*container.ContainerStats `json:"container"` } diff --git a/internal/update/update.go b/internal/update/update.go index e4721d1..9ad5c82 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -54,3 +54,47 @@ func UpdateBeszel(cmd *cobra.Command, args []string) { } fmt.Printf("Successfully updated to %s\n\n%s\n", latest.Version, strings.TrimSpace(latest.ReleaseNotes)) } + +func UpdateBeszelAgent() { + var latest *selfupdate.Release + var found bool + var err error + currentVersion := semver.MustParse(beszel.Version) + fmt.Println("beszel-agent", currentVersion) + fmt.Println("Checking for updates...") + updater, _ := selfupdate.NewUpdater(selfupdate.Config{ + Filters: []string{"beszel-agent"}, + }) + latest, found, err = updater.DetectLatest("henrygd/beszel") + + if err != nil { + fmt.Println("Error checking for updates:", err) + os.Exit(1) + } + + if !found { + fmt.Println("No updates found") + os.Exit(0) + } + + fmt.Println("Latest version:", latest.Version) + + if latest.Version.LTE(currentVersion) { + fmt.Println("You are up to date") + return + } + + var binaryPath string + fmt.Printf("Updating from %s to %s...\n", currentVersion, latest.Version) + binaryPath, err = os.Executable() + if err != nil { + fmt.Println("Error getting binary path:", err) + os.Exit(1) + } + err = selfupdate.UpdateTo(latest.AssetURL, binaryPath) + if err != nil { + fmt.Println("Please try rerunning with sudo. Error:", err) + os.Exit(1) + } + fmt.Printf("Successfully updated to %s\n\n%s\n", latest.Version, strings.TrimSpace(latest.ReleaseNotes)) +} From 932d1261173e448154849c458e1e1bea91e28ff6 Mon Sep 17 00:00:00 2001 From: TOomaAh Date: Fri, 9 Aug 2024 17:58:09 +0200 Subject: [PATCH 03/19] remove global variable --- internal/agent/agent.go | 104 ++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 57 deletions(-) diff --git a/internal/agent/agent.go b/internal/agent/agent.go index 5b44e53..0392280 100644 --- a/internal/agent/agent.go +++ b/internal/agent/agent.go @@ -26,21 +26,25 @@ import ( psutilNet "github.com/shirou/gopsutil/v4/net" ) -var Version = "0.1.2" - var containerStatsMap = make(map[string]*container.PrevContainerStats) -var containerStatsMutex = &sync.Mutex{} type Agent struct { - port string - pubKey []byte - sem chan struct{} + port string + pubKey []byte + sem chan struct{} + containerStatsMutex *sync.Mutex + diskIoStats system.DiskIoStats + netIoStats system.NetIoStats } func NewAgent(pubKey []byte, port string) *Agent { return &Agent{ - pubKey: pubKey, - sem: make(chan struct{}, 15), + pubKey: pubKey, + sem: make(chan struct{}, 15), + port: port, + containerStatsMutex: &sync.Mutex{}, + diskIoStats: system.DiskIoStats{}, + netIoStats: system.NetIoStats{}, } } @@ -52,24 +56,10 @@ func (a *Agent) releaseSemaphore() { <-a.sem } -var diskIoStats = system.DiskIoStats{ - Read: 0, - Write: 0, - Time: time.Now(), - Filesystem: "", -} - -var netIoStats = system.NetIoStats{ - BytesRecv: 0, - BytesSent: 0, - Time: time.Now(), - Name: "", -} - // client for docker engine api var dockerClient = newDockerClient() -func getSystemStats() (*system.SystemInfo, *system.SystemStats) { +func (a *Agent) getSystemStats() (*system.SystemInfo, *system.SystemStats) { systemStats := &system.SystemStats{} // cpu percent @@ -98,18 +88,18 @@ func getSystemStats() (*system.SystemInfo, *system.SystemStats) { } // disk i/o - if io, err := disk.IOCounters(diskIoStats.Filesystem); err == nil { + if io, err := disk.IOCounters(a.diskIoStats.Filesystem); err == nil { for _, d := range io { // add to systemStats - secondsElapsed := time.Since(diskIoStats.Time).Seconds() - readPerSecond := float64(d.ReadBytes-diskIoStats.Read) / secondsElapsed + secondsElapsed := time.Since(a.diskIoStats.Time).Seconds() + readPerSecond := float64(d.ReadBytes-a.diskIoStats.Read) / secondsElapsed systemStats.DiskRead = bytesToMegabytes(readPerSecond) - writePerSecond := float64(d.WriteBytes-diskIoStats.Write) / secondsElapsed + writePerSecond := float64(d.WriteBytes-a.diskIoStats.Write) / secondsElapsed systemStats.DiskWrite = bytesToMegabytes(writePerSecond) // update diskIoStats - diskIoStats.Time = time.Now() - diskIoStats.Read = d.ReadBytes - diskIoStats.Write = d.WriteBytes + a.diskIoStats.Time = time.Now() + a.diskIoStats.Read = d.ReadBytes + a.diskIoStats.Write = d.WriteBytes } } @@ -126,15 +116,15 @@ func getSystemStats() (*system.SystemInfo, *system.SystemStats) { bytesRecv += v.BytesRecv } // add to systemStats - secondsElapsed := time.Since(netIoStats.Time).Seconds() - sentPerSecond := float64(bytesSent-netIoStats.BytesSent) / secondsElapsed - recvPerSecond := float64(bytesRecv-netIoStats.BytesRecv) / secondsElapsed + secondsElapsed := time.Since(a.netIoStats.Time).Seconds() + sentPerSecond := float64(bytesSent-a.netIoStats.BytesSent) / secondsElapsed + recvPerSecond := float64(bytesRecv-a.netIoStats.BytesRecv) / secondsElapsed systemStats.NetworkSent = bytesToMegabytes(sentPerSecond) systemStats.NetworkRecv = bytesToMegabytes(recvPerSecond) // update netIoStats - netIoStats.BytesSent = bytesSent - netIoStats.BytesRecv = bytesRecv - netIoStats.Time = time.Now() + a.netIoStats.BytesSent = bytesSent + a.netIoStats.BytesRecv = bytesRecv + a.netIoStats.Time = time.Now() } systemInfo := &system.SystemInfo{ @@ -191,7 +181,7 @@ func (a *Agent) getDockerStats() ([]*container.ContainerStats, error) { // note: can't use Created field because it's not updated on restart if strings.HasSuffix(ctr.Status, "seconds") { // if so, remove old container data - deleteContainerStatsSync(ctr.IdShort) + a.deleteContainerStatsSync(ctr.IdShort) } wg.Add(1) go func() { @@ -204,7 +194,7 @@ func (a *Agent) getDockerStats() ([]*container.ContainerStats, error) { closeIdleConnections(err) } else { // otherwise delete container from map - deleteContainerStatsSync(ctr.IdShort) + a.deleteContainerStatsSync(ctr.IdShort) } // retry once cstats, err = a.getContainerStats(ctr) @@ -253,8 +243,8 @@ func (a *Agent) getContainerStats(ctr *container.Container) (*container.Containe } usedMemory := statsJson.MemoryStats.Usage - memCache - containerStatsMutex.Lock() - defer containerStatsMutex.Unlock() + a.containerStatsMutex.Lock() + defer a.containerStatsMutex.Unlock() // add empty values if they doesn't exist in map stats, initialized := containerStatsMap[ctr.IdShort] @@ -301,14 +291,14 @@ func (a *Agent) getContainerStats(ctr *container.Container) (*container.Containe } // delete container stats from map using mutex -func deleteContainerStatsSync(id string) { - containerStatsMutex.Lock() - defer containerStatsMutex.Unlock() +func (a *Agent) deleteContainerStatsSync(id string) { + a.containerStatsMutex.Lock() + defer a.containerStatsMutex.Unlock() delete(containerStatsMap, id) } func (a *Agent) gatherStats() *system.SystemData { - systemInfo, systemStats := getSystemStats() + systemInfo, systemStats := a.getSystemStats() stats := &system.SystemData{ Stats: systemStats, Info: systemInfo, @@ -346,13 +336,13 @@ func (a *Agent) startServer(addr string, pubKey []byte) { func (a *Agent) Run() { if filesystem, exists := os.LookupEnv("FILESYSTEM"); exists { - diskIoStats.Filesystem = filesystem + a.diskIoStats.Filesystem = filesystem } else { - diskIoStats.Filesystem = findDefaultFilesystem() + a.diskIoStats.Filesystem = findDefaultFilesystem() } - initializeDiskIoStats() - initializeNetIoStats() + a.initializeDiskIoStats() + a.initializeNetIoStats() a.startServer(a.port, a.pubKey) } @@ -395,17 +385,17 @@ func skipNetworkInterface(v *psutilNet.IOCountersStat) bool { } } -func initializeDiskIoStats() { - if io, err := disk.IOCounters(diskIoStats.Filesystem); err == nil { +func (a *Agent) initializeDiskIoStats() { + if io, err := disk.IOCounters(a.diskIoStats.Filesystem); err == nil { for _, d := range io { - diskIoStats.Time = time.Now() - diskIoStats.Read = d.ReadBytes - diskIoStats.Write = d.WriteBytes + a.diskIoStats.Time = time.Now() + a.diskIoStats.Read = d.ReadBytes + a.diskIoStats.Write = d.WriteBytes } } } -func initializeNetIoStats() { +func (a *Agent) initializeNetIoStats() { if netIO, err := psutilNet.IOCounters(true); err == nil { bytesSent := uint64(0) bytesRecv := uint64(0) @@ -417,9 +407,9 @@ func initializeNetIoStats() { bytesSent += v.BytesSent bytesRecv += v.BytesRecv } - netIoStats.BytesSent = bytesSent - netIoStats.BytesRecv = bytesRecv - netIoStats.Time = time.Now() + a.netIoStats.BytesSent = bytesSent + a.netIoStats.BytesRecv = bytesRecv + a.netIoStats.Time = time.Now() } } From ea71492d131bd670bbf75d629da3420ee106f1ac Mon Sep 17 00:00:00 2001 From: TOomaAh Date: Sun, 11 Aug 2024 02:18:24 +0200 Subject: [PATCH 04/19] fix migrations --- .gitignore | 3 ++- cmd/hub/hub.go | 4 +--- {cmd/hub => migrations}/1722186612_collections_snapshot.go | 0 {cmd/hub => migrations}/initial-settings.go | 0 4 files changed, 3 insertions(+), 4 deletions(-) rename {cmd/hub => migrations}/1722186612_collections_snapshot.go (100%) rename {cmd/hub => migrations}/initial-settings.go (100%) diff --git a/.gitignore b/.gitignore index 8b08a68..fcad27b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ beszel beszel-agent beszel_data beszel_data* -dist \ No newline at end of file +dist +*.exe \ No newline at end of file diff --git a/cmd/hub/hub.go b/cmd/hub/hub.go index c9c182b..428db4e 100644 --- a/cmd/hub/hub.go +++ b/cmd/hub/hub.go @@ -10,9 +10,7 @@ import ( ) func main() { - var app *pocketbase.PocketBase - - app = pocketbase.NewWithConfig(pocketbase.Config{ + app := pocketbase.NewWithConfig(pocketbase.Config{ DefaultDataDir: beszel.AppName + "_data", }) app.RootCmd.Version = beszel.Version diff --git a/cmd/hub/1722186612_collections_snapshot.go b/migrations/1722186612_collections_snapshot.go similarity index 100% rename from cmd/hub/1722186612_collections_snapshot.go rename to migrations/1722186612_collections_snapshot.go diff --git a/cmd/hub/initial-settings.go b/migrations/initial-settings.go similarity index 100% rename from cmd/hub/initial-settings.go rename to migrations/initial-settings.go From 9da1e5751a1e377209fa44e9b9e853541abc8e6f Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 11 Aug 2024 13:41:57 -0400 Subject: [PATCH 05/19] move application code into beszel folder --- .gitignore | 1 - .goreleaser.yml => beszel/.goreleaser.yml | 0 {cmd => beszel/cmd}/agent/agent.go | 0 {cmd => beszel/cmd}/hub/hub.go | 0 dockerfile_Agent => beszel/dockerfile_Agent | 0 dockerfile_Hub => beszel/dockerfile_Hub | 0 go.mod => beszel/go.mod | 10 +-- go.sum => beszel/go.sum | 80 +++++++++++++++++- {internal => beszel/internal}/agent/agent.go | 0 .../internal}/alerts/alerts.go | 0 .../internal}/entities/container/stats.go | 0 .../internal}/entities/email/email.go | 0 .../internal}/entities/server/server.go | 0 .../internal}/entities/system/stats.go | 0 .../internal}/entities/system/system.go | 0 {internal => beszel/internal}/hub/hub.go | 0 .../internal}/records/records.go | 0 .../internal}/update/update.go | 0 .../1722186612_collections_snapshot.go | 0 .../migrations}/initial-settings.go | 0 {site => beszel/site}/.gitignore | 0 {site => beszel/site}/bun.lockb | Bin 146961 -> 146961 bytes {site => beszel/site}/components.json | 0 {site => beszel/site}/embed.go | 0 {site => beszel/site}/index.html | 0 {site => beszel/site}/package-lock.json | 0 {site => beszel/site}/package.json | 0 {site => beszel/site}/postcss.config.js | 0 {site => beszel/site}/public/static/apple.svg | 0 .../site}/public/static/bitbucket.svg | 0 .../site}/public/static/discord.svg | 0 .../site}/public/static/facebook.svg | 0 .../site}/public/static/favicon-green.svg | 0 .../site}/public/static/favicon-red.svg | 0 .../site}/public/static/favicon.svg | 0 {site => beszel/site}/public/static/gitea.svg | 0 {site => beszel/site}/public/static/gitee.svg | 0 .../site}/public/static/github.svg | 0 .../site}/public/static/gitlab.svg | 0 .../site}/public/static/google.svg | 0 .../site}/public/static/instagram.svg | 0 {site => beszel/site}/public/static/lock.svg | 0 {site => beszel/site}/public/static/oidc.svg | 0 .../site}/public/static/patreon.svg | 0 .../site}/public/static/spotify.svg | 0 .../site}/public/static/strava.svg | 0 .../site}/public/static/twitch.svg | 0 .../site}/public/static/twitter.svg | 0 .../site}/src/components/add-system.tsx | 0 .../src/components/charts/bandwidth-chart.tsx | 0 .../components/charts/chart-time-select.tsx | 0 .../components/charts/container-cpu-chart.tsx | 0 .../components/charts/container-mem-chart.tsx | 0 .../components/charts/container-net-chart.tsx | 0 .../site}/src/components/charts/cpu-chart.tsx | 0 .../src/components/charts/disk-chart.tsx | 0 .../src/components/charts/disk-io-chart.tsx | 0 .../site}/src/components/charts/mem-chart.tsx | 0 .../src/components/charts/swap-chart.tsx | 0 .../site}/src/components/command-palette.tsx | 0 .../site}/src/components/login/auth-form.tsx | 0 .../src/components/login/forgot-pass-form.tsx | 0 .../site}/src/components/login/login.tsx | 0 {site => beszel/site}/src/components/logo.tsx | 0 .../site}/src/components/mode-toggle.tsx | 0 .../site}/src/components/router.tsx | 0 .../site}/src/components/routes/home.tsx | 0 .../site}/src/components/routes/system.tsx | 0 .../site}/src/components/spinner.tsx | 0 .../src/components/systems-table/columns.tsx | 0 .../systems-table/systems-table.tsx | 0 .../site}/src/components/table-alerts.tsx | 0 .../site}/src/components/theme-provider.tsx | 0 .../site}/src/components/ui/alert-dialog.tsx | 0 .../site}/src/components/ui/button.tsx | 0 .../site}/src/components/ui/card.tsx | 0 .../site}/src/components/ui/chart.tsx | 0 .../site}/src/components/ui/command.tsx | 0 .../site}/src/components/ui/dialog.tsx | 0 .../site}/src/components/ui/dropdown-menu.tsx | 0 .../site}/src/components/ui/input.tsx | 0 .../site}/src/components/ui/label.tsx | 0 .../site}/src/components/ui/select.tsx | 0 .../site}/src/components/ui/separator.tsx | 0 .../site}/src/components/ui/slider.tsx | 0 .../site}/src/components/ui/switch.tsx | 0 .../site}/src/components/ui/table.tsx | 0 .../site}/src/components/ui/toast.tsx | 0 .../site}/src/components/ui/toaster.tsx | 0 .../site}/src/components/ui/tooltip.tsx | 0 .../site}/src/components/ui/use-toast.ts | 0 {site => beszel/site}/src/index.css | 0 {site => beszel/site}/src/lib/stores.ts | 0 {site => beszel/site}/src/lib/utils.ts | 0 {site => beszel/site}/src/main.tsx | 0 {site => beszel/site}/src/types.d.ts | 0 {site => beszel/site}/src/vite-env.d.ts | 0 {site => beszel/site}/tailwind.config.js | 0 {site => beszel/site}/tsconfig.app.json | 0 {site => beszel/site}/tsconfig.json | 0 {site => beszel/site}/tsconfig.node.json | 0 {site => beszel/site}/vite.config.ts | 0 version.go => beszel/version.go | 0 103 files changed, 84 insertions(+), 7 deletions(-) rename .goreleaser.yml => beszel/.goreleaser.yml (100%) rename {cmd => beszel/cmd}/agent/agent.go (100%) rename {cmd => beszel/cmd}/hub/hub.go (100%) rename dockerfile_Agent => beszel/dockerfile_Agent (100%) rename dockerfile_Hub => beszel/dockerfile_Hub (100%) rename go.mod => beszel/go.mod (94%) rename go.sum => beszel/go.sum (82%) rename {internal => beszel/internal}/agent/agent.go (100%) rename {internal => beszel/internal}/alerts/alerts.go (100%) rename {internal => beszel/internal}/entities/container/stats.go (100%) rename {internal => beszel/internal}/entities/email/email.go (100%) rename {internal => beszel/internal}/entities/server/server.go (100%) rename {internal => beszel/internal}/entities/system/stats.go (100%) rename {internal => beszel/internal}/entities/system/system.go (100%) rename {internal => beszel/internal}/hub/hub.go (100%) rename {internal => beszel/internal}/records/records.go (100%) rename {internal => beszel/internal}/update/update.go (100%) rename {migrations => beszel/migrations}/1722186612_collections_snapshot.go (100%) rename {migrations => beszel/migrations}/initial-settings.go (100%) rename {site => beszel/site}/.gitignore (100%) rename {site => beszel/site}/bun.lockb (99%) mode change 100644 => 100755 rename {site => beszel/site}/components.json (100%) rename {site => beszel/site}/embed.go (100%) rename {site => beszel/site}/index.html (100%) rename {site => beszel/site}/package-lock.json (100%) rename {site => beszel/site}/package.json (100%) rename {site => beszel/site}/postcss.config.js (100%) rename {site => beszel/site}/public/static/apple.svg (100%) rename {site => beszel/site}/public/static/bitbucket.svg (100%) rename {site => beszel/site}/public/static/discord.svg (100%) rename {site => beszel/site}/public/static/facebook.svg (100%) rename {site => beszel/site}/public/static/favicon-green.svg (100%) rename {site => beszel/site}/public/static/favicon-red.svg (100%) rename {site => beszel/site}/public/static/favicon.svg (100%) rename {site => beszel/site}/public/static/gitea.svg (100%) rename {site => beszel/site}/public/static/gitee.svg (100%) rename {site => beszel/site}/public/static/github.svg (100%) rename {site => beszel/site}/public/static/gitlab.svg (100%) rename {site => beszel/site}/public/static/google.svg (100%) rename {site => beszel/site}/public/static/instagram.svg (100%) rename {site => beszel/site}/public/static/lock.svg (100%) rename {site => beszel/site}/public/static/oidc.svg (100%) rename {site => beszel/site}/public/static/patreon.svg (100%) rename {site => beszel/site}/public/static/spotify.svg (100%) rename {site => beszel/site}/public/static/strava.svg (100%) rename {site => beszel/site}/public/static/twitch.svg (100%) rename {site => beszel/site}/public/static/twitter.svg (100%) rename {site => beszel/site}/src/components/add-system.tsx (100%) rename {site => beszel/site}/src/components/charts/bandwidth-chart.tsx (100%) rename {site => beszel/site}/src/components/charts/chart-time-select.tsx (100%) rename {site => beszel/site}/src/components/charts/container-cpu-chart.tsx (100%) rename {site => beszel/site}/src/components/charts/container-mem-chart.tsx (100%) rename {site => beszel/site}/src/components/charts/container-net-chart.tsx (100%) rename {site => beszel/site}/src/components/charts/cpu-chart.tsx (100%) rename {site => beszel/site}/src/components/charts/disk-chart.tsx (100%) rename {site => beszel/site}/src/components/charts/disk-io-chart.tsx (100%) rename {site => beszel/site}/src/components/charts/mem-chart.tsx (100%) rename {site => beszel/site}/src/components/charts/swap-chart.tsx (100%) rename {site => beszel/site}/src/components/command-palette.tsx (100%) rename {site => beszel/site}/src/components/login/auth-form.tsx (100%) rename {site => beszel/site}/src/components/login/forgot-pass-form.tsx (100%) rename {site => beszel/site}/src/components/login/login.tsx (100%) rename {site => beszel/site}/src/components/logo.tsx (100%) rename {site => beszel/site}/src/components/mode-toggle.tsx (100%) rename {site => beszel/site}/src/components/router.tsx (100%) rename {site => beszel/site}/src/components/routes/home.tsx (100%) rename {site => beszel/site}/src/components/routes/system.tsx (100%) rename {site => beszel/site}/src/components/spinner.tsx (100%) rename {site => beszel/site}/src/components/systems-table/columns.tsx (100%) rename {site => beszel/site}/src/components/systems-table/systems-table.tsx (100%) rename {site => beszel/site}/src/components/table-alerts.tsx (100%) rename {site => beszel/site}/src/components/theme-provider.tsx (100%) rename {site => beszel/site}/src/components/ui/alert-dialog.tsx (100%) rename {site => beszel/site}/src/components/ui/button.tsx (100%) rename {site => beszel/site}/src/components/ui/card.tsx (100%) rename {site => beszel/site}/src/components/ui/chart.tsx (100%) rename {site => beszel/site}/src/components/ui/command.tsx (100%) rename {site => beszel/site}/src/components/ui/dialog.tsx (100%) rename {site => beszel/site}/src/components/ui/dropdown-menu.tsx (100%) rename {site => beszel/site}/src/components/ui/input.tsx (100%) rename {site => beszel/site}/src/components/ui/label.tsx (100%) rename {site => beszel/site}/src/components/ui/select.tsx (100%) rename {site => beszel/site}/src/components/ui/separator.tsx (100%) rename {site => beszel/site}/src/components/ui/slider.tsx (100%) rename {site => beszel/site}/src/components/ui/switch.tsx (100%) rename {site => beszel/site}/src/components/ui/table.tsx (100%) rename {site => beszel/site}/src/components/ui/toast.tsx (100%) rename {site => beszel/site}/src/components/ui/toaster.tsx (100%) rename {site => beszel/site}/src/components/ui/tooltip.tsx (100%) rename {site => beszel/site}/src/components/ui/use-toast.ts (100%) rename {site => beszel/site}/src/index.css (100%) rename {site => beszel/site}/src/lib/stores.ts (100%) rename {site => beszel/site}/src/lib/utils.ts (100%) rename {site => beszel/site}/src/main.tsx (100%) rename {site => beszel/site}/src/types.d.ts (100%) rename {site => beszel/site}/src/vite-env.d.ts (100%) rename {site => beszel/site}/tailwind.config.js (100%) rename {site => beszel/site}/tsconfig.app.json (100%) rename {site => beszel/site}/tsconfig.json (100%) rename {site => beszel/site}/tsconfig.node.json (100%) rename {site => beszel/site}/vite.config.ts (100%) rename version.go => beszel/version.go (100%) diff --git a/.gitignore b/.gitignore index fcad27b..a123afb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ pb_data data temp .vscode -beszel beszel-agent beszel_data beszel_data* diff --git a/.goreleaser.yml b/beszel/.goreleaser.yml similarity index 100% rename from .goreleaser.yml rename to beszel/.goreleaser.yml diff --git a/cmd/agent/agent.go b/beszel/cmd/agent/agent.go similarity index 100% rename from cmd/agent/agent.go rename to beszel/cmd/agent/agent.go diff --git a/cmd/hub/hub.go b/beszel/cmd/hub/hub.go similarity index 100% rename from cmd/hub/hub.go rename to beszel/cmd/hub/hub.go diff --git a/dockerfile_Agent b/beszel/dockerfile_Agent similarity index 100% rename from dockerfile_Agent rename to beszel/dockerfile_Agent diff --git a/dockerfile_Hub b/beszel/dockerfile_Hub similarity index 100% rename from dockerfile_Hub rename to beszel/dockerfile_Hub diff --git a/go.mod b/beszel/go.mod similarity index 94% rename from go.mod rename to beszel/go.mod index 27fc7ca..5657ce3 100644 --- a/go.mod +++ b/beszel/go.mod @@ -5,8 +5,13 @@ go 1.22.4 require ( github.com/blang/semver v3.5.1+incompatible github.com/gliderlabs/ssh v0.3.7 + github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 + github.com/pocketbase/dbx v1.10.1 + github.com/pocketbase/pocketbase v0.22.18 github.com/rhysd/go-github-selfupdate v1.2.3 github.com/shirou/gopsutil/v4 v4.24.7 + github.com/spf13/cobra v1.8.1 + golang.org/x/crypto v0.26.0 ) require ( @@ -51,20 +56,16 @@ require ( github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 // indirect github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/pocketbase/dbx v1.10.1 // indirect - github.com/pocketbase/pocketbase v0.22.18 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tcnksm/go-gitconfig v0.1.2 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect @@ -75,7 +76,6 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opencensus.io v0.24.0 // indirect gocloud.dev v0.37.0 // indirect - golang.org/x/crypto v0.26.0 // indirect golang.org/x/image v0.18.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect diff --git a/go.sum b/beszel/go.sum similarity index 82% rename from go.sum rename to beszel/go.sum index 0d494cf..ed9ea2a 100644 --- a/go.sum +++ b/beszel/go.sum @@ -1,13 +1,31 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= +cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= +cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE= +cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs= +cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI= +cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= +cloud.google.com/go/compute v1.25.0 h1:H1/4SqSUhjPFE7L5ddzHOfY2bCAvjwNRZPNl6Ni5oYU= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY= +cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-sdk-go v1.51.11 h1:El5VypsMIz7sFwAAj/j06JX9UGs4KAbAIEaZ57bNY4s= +github.com/aws/aws-sdk-go v1.51.11/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= @@ -52,6 +70,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -68,6 +87,10 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= @@ -75,12 +98,18 @@ github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gc github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVHgnT4= +github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -100,6 +129,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -114,24 +145,39 @@ github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQF github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 h1:e+8XbKB6IMn8A4OAyZccO4pYfB3s7bt6azNIPE7AnPg= +github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 h1:FwuzbVh87iLiUQj1+uQUsuw9x5t9m5n5g7rG7o4svW4= github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61/go.mod h1:paQfF1YtHe+GrGg5fOgjsjoCX/UKDr9bc1DoWpZfns8= github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI= @@ -166,6 +212,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag= github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v4 v4.24.7 h1:V9UGTK4gQ8HvcnPKf6Zt3XHyQq/peaekfxpJ2HSocJk= github.com/shirou/gopsutil/v4 v4.24.7/go.mod h1:0uW/073rP7FYLOkvxolUQM5rMOLTNmRXnFKafpb71rw= @@ -207,6 +255,16 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= gocloud.dev v0.37.0/go.mod h1:7/O4kqdInCNsc6LqgmuFnS0GRew4XNNYWpA44yQnwco= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -223,6 +281,8 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -286,6 +346,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk= @@ -299,6 +361,10 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg= +google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= +google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY= +google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI= google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -323,14 +389,22 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= +modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= +modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= +modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e h1:WPC4v0rNIFb2PY+nBBEEKyugPPRHPzUgyN3xZPpGK58= modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= @@ -339,6 +413,10 @@ modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs= modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= diff --git a/internal/agent/agent.go b/beszel/internal/agent/agent.go similarity index 100% rename from internal/agent/agent.go rename to beszel/internal/agent/agent.go diff --git a/internal/alerts/alerts.go b/beszel/internal/alerts/alerts.go similarity index 100% rename from internal/alerts/alerts.go rename to beszel/internal/alerts/alerts.go diff --git a/internal/entities/container/stats.go b/beszel/internal/entities/container/stats.go similarity index 100% rename from internal/entities/container/stats.go rename to beszel/internal/entities/container/stats.go diff --git a/internal/entities/email/email.go b/beszel/internal/entities/email/email.go similarity index 100% rename from internal/entities/email/email.go rename to beszel/internal/entities/email/email.go diff --git a/internal/entities/server/server.go b/beszel/internal/entities/server/server.go similarity index 100% rename from internal/entities/server/server.go rename to beszel/internal/entities/server/server.go diff --git a/internal/entities/system/stats.go b/beszel/internal/entities/system/stats.go similarity index 100% rename from internal/entities/system/stats.go rename to beszel/internal/entities/system/stats.go diff --git a/internal/entities/system/system.go b/beszel/internal/entities/system/system.go similarity index 100% rename from internal/entities/system/system.go rename to beszel/internal/entities/system/system.go diff --git a/internal/hub/hub.go b/beszel/internal/hub/hub.go similarity index 100% rename from internal/hub/hub.go rename to beszel/internal/hub/hub.go diff --git a/internal/records/records.go b/beszel/internal/records/records.go similarity index 100% rename from internal/records/records.go rename to beszel/internal/records/records.go diff --git a/internal/update/update.go b/beszel/internal/update/update.go similarity index 100% rename from internal/update/update.go rename to beszel/internal/update/update.go diff --git a/migrations/1722186612_collections_snapshot.go b/beszel/migrations/1722186612_collections_snapshot.go similarity index 100% rename from migrations/1722186612_collections_snapshot.go rename to beszel/migrations/1722186612_collections_snapshot.go diff --git a/migrations/initial-settings.go b/beszel/migrations/initial-settings.go similarity index 100% rename from migrations/initial-settings.go rename to beszel/migrations/initial-settings.go diff --git a/site/.gitignore b/beszel/site/.gitignore similarity index 100% rename from site/.gitignore rename to beszel/site/.gitignore diff --git a/site/bun.lockb b/beszel/site/bun.lockb old mode 100644 new mode 100755 similarity index 99% rename from site/bun.lockb rename to beszel/site/bun.lockb index 6588bdaef066e29c88151b3db2791e9c63195ef8..92418a31ea75773c8d02c5d2ccb7167e7122fd00 GIT binary patch delta 25 hcmbREhhyR&j)pCaH%r+W;|%o-^eneOC}lJ}0RW5`3J?GQ delta 25 dcmbREhhyR&j)pCaH%r->7{FlrgHlGr699iF2)zIR diff --git a/site/components.json b/beszel/site/components.json similarity index 100% rename from site/components.json rename to beszel/site/components.json diff --git a/site/embed.go b/beszel/site/embed.go similarity index 100% rename from site/embed.go rename to beszel/site/embed.go diff --git a/site/index.html b/beszel/site/index.html similarity index 100% rename from site/index.html rename to beszel/site/index.html diff --git a/site/package-lock.json b/beszel/site/package-lock.json similarity index 100% rename from site/package-lock.json rename to beszel/site/package-lock.json diff --git a/site/package.json b/beszel/site/package.json similarity index 100% rename from site/package.json rename to beszel/site/package.json diff --git a/site/postcss.config.js b/beszel/site/postcss.config.js similarity index 100% rename from site/postcss.config.js rename to beszel/site/postcss.config.js diff --git a/site/public/static/apple.svg b/beszel/site/public/static/apple.svg similarity index 100% rename from site/public/static/apple.svg rename to beszel/site/public/static/apple.svg diff --git a/site/public/static/bitbucket.svg b/beszel/site/public/static/bitbucket.svg similarity index 100% rename from site/public/static/bitbucket.svg rename to beszel/site/public/static/bitbucket.svg diff --git a/site/public/static/discord.svg b/beszel/site/public/static/discord.svg similarity index 100% rename from site/public/static/discord.svg rename to beszel/site/public/static/discord.svg diff --git a/site/public/static/facebook.svg b/beszel/site/public/static/facebook.svg similarity index 100% rename from site/public/static/facebook.svg rename to beszel/site/public/static/facebook.svg diff --git a/site/public/static/favicon-green.svg b/beszel/site/public/static/favicon-green.svg similarity index 100% rename from site/public/static/favicon-green.svg rename to beszel/site/public/static/favicon-green.svg diff --git a/site/public/static/favicon-red.svg b/beszel/site/public/static/favicon-red.svg similarity index 100% rename from site/public/static/favicon-red.svg rename to beszel/site/public/static/favicon-red.svg diff --git a/site/public/static/favicon.svg b/beszel/site/public/static/favicon.svg similarity index 100% rename from site/public/static/favicon.svg rename to beszel/site/public/static/favicon.svg diff --git a/site/public/static/gitea.svg b/beszel/site/public/static/gitea.svg similarity index 100% rename from site/public/static/gitea.svg rename to beszel/site/public/static/gitea.svg diff --git a/site/public/static/gitee.svg b/beszel/site/public/static/gitee.svg similarity index 100% rename from site/public/static/gitee.svg rename to beszel/site/public/static/gitee.svg diff --git a/site/public/static/github.svg b/beszel/site/public/static/github.svg similarity index 100% rename from site/public/static/github.svg rename to beszel/site/public/static/github.svg diff --git a/site/public/static/gitlab.svg b/beszel/site/public/static/gitlab.svg similarity index 100% rename from site/public/static/gitlab.svg rename to beszel/site/public/static/gitlab.svg diff --git a/site/public/static/google.svg b/beszel/site/public/static/google.svg similarity index 100% rename from site/public/static/google.svg rename to beszel/site/public/static/google.svg diff --git a/site/public/static/instagram.svg b/beszel/site/public/static/instagram.svg similarity index 100% rename from site/public/static/instagram.svg rename to beszel/site/public/static/instagram.svg diff --git a/site/public/static/lock.svg b/beszel/site/public/static/lock.svg similarity index 100% rename from site/public/static/lock.svg rename to beszel/site/public/static/lock.svg diff --git a/site/public/static/oidc.svg b/beszel/site/public/static/oidc.svg similarity index 100% rename from site/public/static/oidc.svg rename to beszel/site/public/static/oidc.svg diff --git a/site/public/static/patreon.svg b/beszel/site/public/static/patreon.svg similarity index 100% rename from site/public/static/patreon.svg rename to beszel/site/public/static/patreon.svg diff --git a/site/public/static/spotify.svg b/beszel/site/public/static/spotify.svg similarity index 100% rename from site/public/static/spotify.svg rename to beszel/site/public/static/spotify.svg diff --git a/site/public/static/strava.svg b/beszel/site/public/static/strava.svg similarity index 100% rename from site/public/static/strava.svg rename to beszel/site/public/static/strava.svg diff --git a/site/public/static/twitch.svg b/beszel/site/public/static/twitch.svg similarity index 100% rename from site/public/static/twitch.svg rename to beszel/site/public/static/twitch.svg diff --git a/site/public/static/twitter.svg b/beszel/site/public/static/twitter.svg similarity index 100% rename from site/public/static/twitter.svg rename to beszel/site/public/static/twitter.svg diff --git a/site/src/components/add-system.tsx b/beszel/site/src/components/add-system.tsx similarity index 100% rename from site/src/components/add-system.tsx rename to beszel/site/src/components/add-system.tsx diff --git a/site/src/components/charts/bandwidth-chart.tsx b/beszel/site/src/components/charts/bandwidth-chart.tsx similarity index 100% rename from site/src/components/charts/bandwidth-chart.tsx rename to beszel/site/src/components/charts/bandwidth-chart.tsx diff --git a/site/src/components/charts/chart-time-select.tsx b/beszel/site/src/components/charts/chart-time-select.tsx similarity index 100% rename from site/src/components/charts/chart-time-select.tsx rename to beszel/site/src/components/charts/chart-time-select.tsx diff --git a/site/src/components/charts/container-cpu-chart.tsx b/beszel/site/src/components/charts/container-cpu-chart.tsx similarity index 100% rename from site/src/components/charts/container-cpu-chart.tsx rename to beszel/site/src/components/charts/container-cpu-chart.tsx diff --git a/site/src/components/charts/container-mem-chart.tsx b/beszel/site/src/components/charts/container-mem-chart.tsx similarity index 100% rename from site/src/components/charts/container-mem-chart.tsx rename to beszel/site/src/components/charts/container-mem-chart.tsx diff --git a/site/src/components/charts/container-net-chart.tsx b/beszel/site/src/components/charts/container-net-chart.tsx similarity index 100% rename from site/src/components/charts/container-net-chart.tsx rename to beszel/site/src/components/charts/container-net-chart.tsx diff --git a/site/src/components/charts/cpu-chart.tsx b/beszel/site/src/components/charts/cpu-chart.tsx similarity index 100% rename from site/src/components/charts/cpu-chart.tsx rename to beszel/site/src/components/charts/cpu-chart.tsx diff --git a/site/src/components/charts/disk-chart.tsx b/beszel/site/src/components/charts/disk-chart.tsx similarity index 100% rename from site/src/components/charts/disk-chart.tsx rename to beszel/site/src/components/charts/disk-chart.tsx diff --git a/site/src/components/charts/disk-io-chart.tsx b/beszel/site/src/components/charts/disk-io-chart.tsx similarity index 100% rename from site/src/components/charts/disk-io-chart.tsx rename to beszel/site/src/components/charts/disk-io-chart.tsx diff --git a/site/src/components/charts/mem-chart.tsx b/beszel/site/src/components/charts/mem-chart.tsx similarity index 100% rename from site/src/components/charts/mem-chart.tsx rename to beszel/site/src/components/charts/mem-chart.tsx diff --git a/site/src/components/charts/swap-chart.tsx b/beszel/site/src/components/charts/swap-chart.tsx similarity index 100% rename from site/src/components/charts/swap-chart.tsx rename to beszel/site/src/components/charts/swap-chart.tsx diff --git a/site/src/components/command-palette.tsx b/beszel/site/src/components/command-palette.tsx similarity index 100% rename from site/src/components/command-palette.tsx rename to beszel/site/src/components/command-palette.tsx diff --git a/site/src/components/login/auth-form.tsx b/beszel/site/src/components/login/auth-form.tsx similarity index 100% rename from site/src/components/login/auth-form.tsx rename to beszel/site/src/components/login/auth-form.tsx diff --git a/site/src/components/login/forgot-pass-form.tsx b/beszel/site/src/components/login/forgot-pass-form.tsx similarity index 100% rename from site/src/components/login/forgot-pass-form.tsx rename to beszel/site/src/components/login/forgot-pass-form.tsx diff --git a/site/src/components/login/login.tsx b/beszel/site/src/components/login/login.tsx similarity index 100% rename from site/src/components/login/login.tsx rename to beszel/site/src/components/login/login.tsx diff --git a/site/src/components/logo.tsx b/beszel/site/src/components/logo.tsx similarity index 100% rename from site/src/components/logo.tsx rename to beszel/site/src/components/logo.tsx diff --git a/site/src/components/mode-toggle.tsx b/beszel/site/src/components/mode-toggle.tsx similarity index 100% rename from site/src/components/mode-toggle.tsx rename to beszel/site/src/components/mode-toggle.tsx diff --git a/site/src/components/router.tsx b/beszel/site/src/components/router.tsx similarity index 100% rename from site/src/components/router.tsx rename to beszel/site/src/components/router.tsx diff --git a/site/src/components/routes/home.tsx b/beszel/site/src/components/routes/home.tsx similarity index 100% rename from site/src/components/routes/home.tsx rename to beszel/site/src/components/routes/home.tsx diff --git a/site/src/components/routes/system.tsx b/beszel/site/src/components/routes/system.tsx similarity index 100% rename from site/src/components/routes/system.tsx rename to beszel/site/src/components/routes/system.tsx diff --git a/site/src/components/spinner.tsx b/beszel/site/src/components/spinner.tsx similarity index 100% rename from site/src/components/spinner.tsx rename to beszel/site/src/components/spinner.tsx diff --git a/site/src/components/systems-table/columns.tsx b/beszel/site/src/components/systems-table/columns.tsx similarity index 100% rename from site/src/components/systems-table/columns.tsx rename to beszel/site/src/components/systems-table/columns.tsx diff --git a/site/src/components/systems-table/systems-table.tsx b/beszel/site/src/components/systems-table/systems-table.tsx similarity index 100% rename from site/src/components/systems-table/systems-table.tsx rename to beszel/site/src/components/systems-table/systems-table.tsx diff --git a/site/src/components/table-alerts.tsx b/beszel/site/src/components/table-alerts.tsx similarity index 100% rename from site/src/components/table-alerts.tsx rename to beszel/site/src/components/table-alerts.tsx diff --git a/site/src/components/theme-provider.tsx b/beszel/site/src/components/theme-provider.tsx similarity index 100% rename from site/src/components/theme-provider.tsx rename to beszel/site/src/components/theme-provider.tsx diff --git a/site/src/components/ui/alert-dialog.tsx b/beszel/site/src/components/ui/alert-dialog.tsx similarity index 100% rename from site/src/components/ui/alert-dialog.tsx rename to beszel/site/src/components/ui/alert-dialog.tsx diff --git a/site/src/components/ui/button.tsx b/beszel/site/src/components/ui/button.tsx similarity index 100% rename from site/src/components/ui/button.tsx rename to beszel/site/src/components/ui/button.tsx diff --git a/site/src/components/ui/card.tsx b/beszel/site/src/components/ui/card.tsx similarity index 100% rename from site/src/components/ui/card.tsx rename to beszel/site/src/components/ui/card.tsx diff --git a/site/src/components/ui/chart.tsx b/beszel/site/src/components/ui/chart.tsx similarity index 100% rename from site/src/components/ui/chart.tsx rename to beszel/site/src/components/ui/chart.tsx diff --git a/site/src/components/ui/command.tsx b/beszel/site/src/components/ui/command.tsx similarity index 100% rename from site/src/components/ui/command.tsx rename to beszel/site/src/components/ui/command.tsx diff --git a/site/src/components/ui/dialog.tsx b/beszel/site/src/components/ui/dialog.tsx similarity index 100% rename from site/src/components/ui/dialog.tsx rename to beszel/site/src/components/ui/dialog.tsx diff --git a/site/src/components/ui/dropdown-menu.tsx b/beszel/site/src/components/ui/dropdown-menu.tsx similarity index 100% rename from site/src/components/ui/dropdown-menu.tsx rename to beszel/site/src/components/ui/dropdown-menu.tsx diff --git a/site/src/components/ui/input.tsx b/beszel/site/src/components/ui/input.tsx similarity index 100% rename from site/src/components/ui/input.tsx rename to beszel/site/src/components/ui/input.tsx diff --git a/site/src/components/ui/label.tsx b/beszel/site/src/components/ui/label.tsx similarity index 100% rename from site/src/components/ui/label.tsx rename to beszel/site/src/components/ui/label.tsx diff --git a/site/src/components/ui/select.tsx b/beszel/site/src/components/ui/select.tsx similarity index 100% rename from site/src/components/ui/select.tsx rename to beszel/site/src/components/ui/select.tsx diff --git a/site/src/components/ui/separator.tsx b/beszel/site/src/components/ui/separator.tsx similarity index 100% rename from site/src/components/ui/separator.tsx rename to beszel/site/src/components/ui/separator.tsx diff --git a/site/src/components/ui/slider.tsx b/beszel/site/src/components/ui/slider.tsx similarity index 100% rename from site/src/components/ui/slider.tsx rename to beszel/site/src/components/ui/slider.tsx diff --git a/site/src/components/ui/switch.tsx b/beszel/site/src/components/ui/switch.tsx similarity index 100% rename from site/src/components/ui/switch.tsx rename to beszel/site/src/components/ui/switch.tsx diff --git a/site/src/components/ui/table.tsx b/beszel/site/src/components/ui/table.tsx similarity index 100% rename from site/src/components/ui/table.tsx rename to beszel/site/src/components/ui/table.tsx diff --git a/site/src/components/ui/toast.tsx b/beszel/site/src/components/ui/toast.tsx similarity index 100% rename from site/src/components/ui/toast.tsx rename to beszel/site/src/components/ui/toast.tsx diff --git a/site/src/components/ui/toaster.tsx b/beszel/site/src/components/ui/toaster.tsx similarity index 100% rename from site/src/components/ui/toaster.tsx rename to beszel/site/src/components/ui/toaster.tsx diff --git a/site/src/components/ui/tooltip.tsx b/beszel/site/src/components/ui/tooltip.tsx similarity index 100% rename from site/src/components/ui/tooltip.tsx rename to beszel/site/src/components/ui/tooltip.tsx diff --git a/site/src/components/ui/use-toast.ts b/beszel/site/src/components/ui/use-toast.ts similarity index 100% rename from site/src/components/ui/use-toast.ts rename to beszel/site/src/components/ui/use-toast.ts diff --git a/site/src/index.css b/beszel/site/src/index.css similarity index 100% rename from site/src/index.css rename to beszel/site/src/index.css diff --git a/site/src/lib/stores.ts b/beszel/site/src/lib/stores.ts similarity index 100% rename from site/src/lib/stores.ts rename to beszel/site/src/lib/stores.ts diff --git a/site/src/lib/utils.ts b/beszel/site/src/lib/utils.ts similarity index 100% rename from site/src/lib/utils.ts rename to beszel/site/src/lib/utils.ts diff --git a/site/src/main.tsx b/beszel/site/src/main.tsx similarity index 100% rename from site/src/main.tsx rename to beszel/site/src/main.tsx diff --git a/site/src/types.d.ts b/beszel/site/src/types.d.ts similarity index 100% rename from site/src/types.d.ts rename to beszel/site/src/types.d.ts diff --git a/site/src/vite-env.d.ts b/beszel/site/src/vite-env.d.ts similarity index 100% rename from site/src/vite-env.d.ts rename to beszel/site/src/vite-env.d.ts diff --git a/site/tailwind.config.js b/beszel/site/tailwind.config.js similarity index 100% rename from site/tailwind.config.js rename to beszel/site/tailwind.config.js diff --git a/site/tsconfig.app.json b/beszel/site/tsconfig.app.json similarity index 100% rename from site/tsconfig.app.json rename to beszel/site/tsconfig.app.json diff --git a/site/tsconfig.json b/beszel/site/tsconfig.json similarity index 100% rename from site/tsconfig.json rename to beszel/site/tsconfig.json diff --git a/site/tsconfig.node.json b/beszel/site/tsconfig.node.json similarity index 100% rename from site/tsconfig.node.json rename to beszel/site/tsconfig.node.json diff --git a/site/vite.config.ts b/beszel/site/vite.config.ts similarity index 100% rename from site/vite.config.ts rename to beszel/site/vite.config.ts diff --git a/version.go b/beszel/version.go similarity index 100% rename from version.go rename to beszel/version.go From dd55e74ec9c9f2641a96ba2dcdbf273a160fbf6a Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 11 Aug 2024 13:57:09 -0400 Subject: [PATCH 06/19] update goreleaser config --- .github/workflows/goreleaser-action.yml | 16 +++----------- beszel/.goreleaser.yml | 29 +++++++++++++++++++------ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/.github/workflows/goreleaser-action.yml b/.github/workflows/goreleaser-action.yml index 8b39306..fa11f6a 100644 --- a/.github/workflows/goreleaser-action.yml +++ b/.github/workflows/goreleaser-action.yml @@ -21,10 +21,10 @@ jobs: uses: oven-sh/setup-bun@v2 - name: Install dependencies - run: bun install --no-save --cwd ./hub/site + run: bun install --no-save --cwd ./beszel/site - name: Build site - run: bun run --cwd ./hub/site build + run: bun run --cwd ./beszel/site build - name: Set up Go uses: actions/setup-go@v5 @@ -34,17 +34,7 @@ jobs: - name: GoReleaser beszel uses: goreleaser/goreleaser-action@v6 with: - workdir: ./hub - distribution: goreleaser - version: latest - args: release --clean - env: - GITHUB_TOKEN: ${{ secrets.TOKEN }} - - - name: GoReleaser beszel-agent - uses: goreleaser/goreleaser-action@v6 - with: - workdir: ./agent + workdir: ./beszel distribution: goreleaser version: latest args: release --clean diff --git a/beszel/.goreleaser.yml b/beszel/.goreleaser.yml index bf0cb67..8b70be7 100644 --- a/beszel/.goreleaser.yml +++ b/beszel/.goreleaser.yml @@ -1,4 +1,4 @@ -# version: 1 +version: 2 project_name: beszel @@ -7,7 +7,10 @@ before: - go mod tidy builds: - - env: + - id: beszel + binary: beszel + main: cmd/hub/hub.go + env: - CGO_ENABLED=0 goos: - linux @@ -16,9 +19,11 @@ builds: - amd64 - arm64 - arm - main: cmd/hub/hub.go - - env: + - id: beszel-agent + binary: beszel-agent + main: cmd/agent/agent.go + env: - CGO_ENABLED=0 goos: - linux @@ -32,12 +37,22 @@ builds: ignore: - goos: freebsd goarch: arm - main: cmd/agent/agent.go archives: - - format: tar.gz + - id: beszel + format: tar.gz + builds: + - beszel-agent name_template: >- - {{ .ProjectName }}_ + {{ .Binary }}_ + {{- .Os }}_ + {{- .Arch }} + - id: beszel-agent + format: tar.gz + builds: + - beszel + name_template: >- + {{ .Binary }}_ {{- .Os }}_ {{- .Arch }} # use zip for windows archives From 9d2192f32302b4f638abb537718ada001317d52f Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 11 Aug 2024 15:14:58 -0400 Subject: [PATCH 07/19] update migrations / gitignore --- .gitignore | 4 +++- beszel/cmd/hub/hub.go | 1 + beszel/internal/hub/hub.go | 1 + beszel/migrations/1722186612_collections_snapshot.go | 2 +- beszel/migrations/initial-settings.go | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index a123afb..c0012b9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ beszel-agent beszel_data beszel_data* dist -*.exe \ No newline at end of file +*.exe +beszel/cmd/hub/hub +beszel/cmd/agent/agent diff --git a/beszel/cmd/hub/hub.go b/beszel/cmd/hub/hub.go index 428db4e..ffbe825 100644 --- a/beszel/cmd/hub/hub.go +++ b/beszel/cmd/hub/hub.go @@ -4,6 +4,7 @@ import ( "beszel" "beszel/internal/hub" "beszel/internal/update" + _ "beszel/migrations" "github.com/pocketbase/pocketbase" "github.com/spf13/cobra" diff --git a/beszel/internal/hub/hub.go b/beszel/internal/hub/hub.go index d78de0c..335fa6b 100644 --- a/beszel/internal/hub/hub.go +++ b/beszel/internal/hub/hub.go @@ -57,6 +57,7 @@ func (h *Hub) Run() { migratecmd.MustRegister(h.app, h.app.RootCmd, migratecmd.Config{ // (the isGoRun check is to enable it only during development) Automigrate: isGoRun, + Dir: "../../migrations", }) // set auth settings diff --git a/beszel/migrations/1722186612_collections_snapshot.go b/beszel/migrations/1722186612_collections_snapshot.go index e6fcadb..6cf10b5 100644 --- a/beszel/migrations/1722186612_collections_snapshot.go +++ b/beszel/migrations/1722186612_collections_snapshot.go @@ -1,4 +1,4 @@ -package main +package migrations import ( "encoding/json" diff --git a/beszel/migrations/initial-settings.go b/beszel/migrations/initial-settings.go index 22907f7..c528245 100644 --- a/beszel/migrations/initial-settings.go +++ b/beszel/migrations/initial-settings.go @@ -1,4 +1,4 @@ -package main +package migrations import ( "github.com/pocketbase/dbx" From c06eabefe0a797d95161cb26f194cc22dafa1ba5 Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 11 Aug 2024 15:22:30 -0400 Subject: [PATCH 08/19] add docker compose examples for hub / agent to supplemental --- supplemental/docker/agent/docker-compose.yml | 12 ++++++++++++ supplemental/docker/hub/docker-compose.yml | 9 +++++++++ 2 files changed, 21 insertions(+) create mode 100644 supplemental/docker/agent/docker-compose.yml create mode 100644 supplemental/docker/hub/docker-compose.yml diff --git a/supplemental/docker/agent/docker-compose.yml b/supplemental/docker/agent/docker-compose.yml new file mode 100644 index 0000000..687b8f9 --- /dev/null +++ b/supplemental/docker/agent/docker-compose.yml @@ -0,0 +1,12 @@ +services: + beszel-agent: + image: 'henrygd/beszel-agent' + container_name: 'beszel-agent' + restart: unless-stopped + network_mode: host + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + PORT: 45876 + KEY: 'ssh-ed25519 YOUR_PUBLIC_KEY' + # FILESYSTEM: /dev/sda1 # set to the correct filesystem for disk I/O stats diff --git a/supplemental/docker/hub/docker-compose.yml b/supplemental/docker/hub/docker-compose.yml new file mode 100644 index 0000000..a5bf3ec --- /dev/null +++ b/supplemental/docker/hub/docker-compose.yml @@ -0,0 +1,9 @@ +services: + beszel: + image: 'henrygd/beszel' + container_name: 'beszel' + restart: unless-stopped + ports: + - '8090:8090' + volumes: + - ./beszel_data:/beszel_data From 41055670514d544400d0db1aec58aef2b3e68141 Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 11 Aug 2024 15:54:27 -0400 Subject: [PATCH 09/19] remove cobra dependency for agent --- beszel/cmd/hub/hub.go | 2 +- beszel/internal/update/update.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/beszel/cmd/hub/hub.go b/beszel/cmd/hub/hub.go index ffbe825..dbe06fa 100644 --- a/beszel/cmd/hub/hub.go +++ b/beszel/cmd/hub/hub.go @@ -22,7 +22,7 @@ func main() { app.RootCmd.AddCommand(&cobra.Command{ Use: "update", Short: "Update " + beszel.AppName + " to the latest version", - Run: update.UpdateBeszel, + Run: func(_ *cobra.Command, _ []string) { update.UpdateBeszel() }, }) hubApp := hub.NewHub(app) diff --git a/beszel/internal/update/update.go b/beszel/internal/update/update.go index 9ad5c82..2320bf9 100644 --- a/beszel/internal/update/update.go +++ b/beszel/internal/update/update.go @@ -8,10 +8,9 @@ import ( "github.com/blang/semver" "github.com/rhysd/go-github-selfupdate/selfupdate" - "github.com/spf13/cobra" ) -func UpdateBeszel(cmd *cobra.Command, args []string) { +func UpdateBeszel() { var latest *selfupdate.Release var found bool var err error From 2ac5d797d2f83f4ab22d3eab4c2ae249c279defc Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 11 Aug 2024 16:20:29 -0400 Subject: [PATCH 10/19] update readme / .gitignore --- .gitignore | 1 + readme.md | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index c0012b9..613e06f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ dist *.exe beszel/cmd/hub/hub beszel/cmd/agent/agent +node_modules diff --git a/readme.md b/readme.md index f326c48..bf43d77 100644 --- a/readme.md +++ b/readme.md @@ -2,8 +2,8 @@ A lightweight server resource monitoring hub with historical data, docker stats, and alerts. -[![Docker Image Size (tag)](https://img.shields.io/docker/image-size/henrygd/beszel-agent/0.0.1-alpha.9?logo=docker&label=agent%20image%20size)](https://hub.docker.com/r/henrygd/beszel-agent) -[![Docker Image Size (tag)](https://img.shields.io/docker/image-size/henrygd/beszel/0.0.1-alpha.9?logo=docker&label=hub%20image%20size)](https://hub.docker.com/r/henrygd/beszel) +[![Docker Image Size (tag)](https://img.shields.io/docker/image-size/henrygd/beszel-agent/0.1.0?logo=docker&label=agent%20image%20size)](https://hub.docker.com/r/henrygd/beszel-agent) +[![Docker Image Size (tag)](https://img.shields.io/docker/image-size/henrygd/beszel/0.1.0?logo=docker&label=hub%20image%20size)](https://hub.docker.com/r/henrygd/beszel) ![Screenshot of the hub](https://henrygd-assets.b-cdn.net/beszel/screenshot.png) @@ -49,9 +49,9 @@ You may install the hub and agent as single binaries, or by using Docker. ### Docker -**Hub**: See the example [docker-compose.yml](/hub/docker-compose.yml) file. +**Hub**: See the example [docker-compose.yml](/supplemental/docker/hub/docker-compose.yml) file. -**Agent**: The hub provides compose content for the agent, but you can also reference the example [docker-compose.yml](/agent/docker-compose.yml) file. +**Agent**: The hub provides compose content for the agent, but you can also reference the example [docker-compose.yml](/supplemental/docker/agent/docker-compose.yml) file. The agent uses the host network mode so it can access network interface stats. This automatically exposes the port, so change the port using an environment variable if you need to. @@ -148,7 +148,7 @@ Visit the "Auth providers" page to enable your provider. The redirect / callback ## REST API -Because Beszel is built on PocketBase, you can use the PocketBase [Web APIs](https://pocketbase.io/docs/api-records/) and [Client-side SDKs](https://pocketbase.io/docs/client-side-sdks/) to read or update data from outside Beszel itself. +Because Beszel is built on PocketBase, you can use the PocketBase [web APIs](https://pocketbase.io/docs/api-records/) and [client-side SDKs](https://pocketbase.io/docs/client-side-sdks/) to read or update data from outside Beszel itself. ## Security @@ -219,13 +219,17 @@ If you pause / unpause the agent for longer than one minute, the data will be in Both the hub and agent are written in Go, so you can easily build them yourself, or cross-compile for different platforms. Please [install Go](https://go.dev/doc/install) first if you haven't already. -### Agent +### Prepare dependencies + +```bash +cd beszel && go mod tidy +``` + +### Agent + +Go to `beszel/cmd/agent` and run the following command to create a binary in the current directory: ```bash -cd agent -# prepare / install dependencies -go mod tidy -# create a binary in the current directory CGO_ENABLED=0 go build -ldflags "-w -s" . ``` @@ -234,15 +238,14 @@ CGO_ENABLED=0 go build -ldflags "-w -s" . The hub embeds the web UI in the binary, so you must build the website first. I use [Bun](https://bun.sh/), but you may use Node.js if you prefer: ```bash -cd hub/site +cd beszel/site bun install bun run build ``` -Then back in the hub directory: +Then in `beszel/cmd/hub`: ```bash -go mod tidy CGO_ENABLED=0 go build -ldflags "-w -s" . ``` @@ -250,10 +253,10 @@ CGO_ENABLED=0 go build -ldflags "-w -s" . You can cross-compile for different platforms using the `GOOS` and `GOARCH` environment variables. -For example, to build for Linux ARM64: +For example, to build for FreeBSD ARM64: ```bash -GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags "-w -s" . +GOOS=freebsd GOARCH=arm64 CGO_ENABLED=0 go build -ldflags "-w -s" . ``` You can see a list of valid options by running `go tool dist list`. From d0d4e546d990b6a976a4667cc5c90b25ab311d6b Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 11 Aug 2024 16:21:02 -0400 Subject: [PATCH 11/19] update dockerfiles and docker workflow --- .github/workflows/docker-images.yml | 16 ++++++++-------- beszel/dockerfile_Agent | 8 ++++---- beszel/dockerfile_Hub | 6 ++++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index 568e701..aabc263 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -12,12 +12,12 @@ jobs: fail-fast: false matrix: include: - - image: henrygd/beszel - context: ./hub - dockerfile: ./hub/Dockerfile - - image: henrygd/beszel-agent - context: ./agent - dockerfile: ./agent/Dockerfile + - image: henrygd/beszel-test + context: ./beszel + dockerfile: ./dockerfile_Hub + - image: henrygd/beszel-agent-test + context: ./beszel + dockerfile: ./dockerfile_Agent permissions: contents: read packages: write @@ -30,10 +30,10 @@ jobs: uses: oven-sh/setup-bun@v2 - name: Install dependencies - run: bun install --no-save --cwd ./hub/site + run: bun install --no-save --cwd ./beszel/site - name: Build site - run: bun run --cwd ./hub/site build + run: bun run --cwd ./beszel/site build - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/beszel/dockerfile_Agent b/beszel/dockerfile_Agent index 29873ca..21293f4 100644 --- a/beszel/dockerfile_Agent +++ b/beszel/dockerfile_Agent @@ -2,15 +2,15 @@ FROM --platform=$BUILDPLATFORM golang:alpine AS builder WORKDIR /app -# Download Go modules COPY go.mod go.sum ./ -RUN go mod download - +# RUN go mod download COPY *.go ./ +COPY cmd ./cmd +COPY internal ./internal # Build ARG TARGETOS TARGETARCH -RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent . +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./cmd/agent # ? ------------------------- FROM scratch diff --git a/beszel/dockerfile_Hub b/beszel/dockerfile_Hub index 1f4251d..2e8ff7a 100644 --- a/beszel/dockerfile_Hub +++ b/beszel/dockerfile_Hub @@ -4,10 +4,12 @@ WORKDIR /app # Download Go modules COPY go.mod go.sum ./ -RUN go mod download +# RUN go mod download # Copy source files COPY *.go ./ +COPY cmd ./cmd +COPY internal ./internal COPY migrations ./migrations COPY site/dist ./site/dist COPY site/*.go ./site @@ -20,7 +22,7 @@ RUN update-ca-certificates # Build ARG TARGETOS TARGETARCH -RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /beszel . +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /beszel ./cmd/hub # ? ------------------------- FROM scratch From f8d216148906ceba729c1f2a1c46e6c20de82a63 Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Mon, 12 Aug 2024 19:13:42 -0400 Subject: [PATCH 12/19] refactor: alerts / emails --- beszel/cmd/hub/hub.go | 5 +-- beszel/internal/alerts/alerts.go | 41 ++++++++----------- beszel/internal/entities/container/stats.go | 3 ++ beszel/internal/entities/email/email.go | 27 ------------ beszel/internal/hub/hub.go | 12 ++++-- .../site/src/components/charts/mem-chart.tsx | 1 + 6 files changed, 32 insertions(+), 57 deletions(-) delete mode 100644 beszel/internal/entities/email/email.go diff --git a/beszel/cmd/hub/hub.go b/beszel/cmd/hub/hub.go index dbe06fa..379470a 100644 --- a/beszel/cmd/hub/hub.go +++ b/beszel/cmd/hub/hub.go @@ -25,8 +25,5 @@ func main() { Run: func(_ *cobra.Command, _ []string) { update.UpdateBeszel() }, }) - hubApp := hub.NewHub(app) - - hubApp.Run() - + hub.NewHub(app).Run() } diff --git a/beszel/internal/alerts/alerts.go b/beszel/internal/alerts/alerts.go index 6ffbbd5..4e68bb1 100644 --- a/beszel/internal/alerts/alerts.go +++ b/beszel/internal/alerts/alerts.go @@ -1,7 +1,6 @@ package alerts import ( - "beszel/internal/entities/email" "beszel/internal/entities/system" "fmt" "net/mail" @@ -72,12 +71,12 @@ func (am *AlertManager) handleSlidingValueAlert(newRecord *models.Record, alertR if !triggered && curValue > threshold { alertRecord.Set("triggered", true) systemName := newRecord.GetString("name") - subject = fmt.Sprintf("%s usage threshold exceeded on %s", name, systemName) + subject = fmt.Sprintf("%s usage above threshold on %s", name, systemName) body = fmt.Sprintf("%s usage on %s is %.1f%%.\n\n%s\n\n- Beszel", name, systemName, curValue, am.app.Settings().Meta.AppUrl+"/system/"+systemName) } else if triggered && curValue <= threshold { alertRecord.Set("triggered", false) systemName := newRecord.GetString("name") - subject = fmt.Sprintf("%s usage returned below threshold on %s", name, systemName) + subject = fmt.Sprintf("%s usage below threshold on %s", name, systemName) body = fmt.Sprintf("%s usage on %s is below threshold at %.1f%%.\n\n%s\n\n- Beszel", name, systemName, curValue, am.app.Settings().Meta.AppUrl+"/system/"+systemName) } else { // fmt.Println(name, "not triggered") @@ -93,11 +92,11 @@ func (am *AlertManager) handleSlidingValueAlert(newRecord *models.Record, alertR return } if user := alertRecord.ExpandedOne("user"); user != nil { - am.sendAlert(email.NewEmailData( - user.GetString("email"), - subject, - body, - )) + am.sendAlert(&mailer.Message{ + To: []mail.Address{{Address: user.GetString("email")}}, + Subject: subject, + Text: body, + }) } } @@ -130,24 +129,20 @@ func (am *AlertManager) handleStatusAlerts(newStatus string, oldRecord *models.R } // send alert systemName := oldRecord.GetString("name") - am.sendAlert(email.NewEmailData( - user.GetString("email"), - fmt.Sprintf("Connection to %s is %s %v", systemName, alertStatus, emoji), - fmt.Sprintf("Connection to %s is %s\n\n- Beszel", systemName, alertStatus), - )) + am.sendAlert(&mailer.Message{ + To: []mail.Address{{Address: user.GetString("email")}}, + Subject: fmt.Sprintf("Connection to %s is %s %v", systemName, alertStatus, emoji), + Text: fmt.Sprintf("Connection to %s is %s\n\n- Beszel", systemName, alertStatus), + }) + return nil } -func (am *AlertManager) sendAlert(data *email.EmailData) { - // fmt.Println("sending alert", "to", data.to, "subj", data.subj, "body", data.body) - message := &mailer.Message{ - From: mail.Address{ - Address: am.app.Settings().Meta.SenderAddress, - Name: am.app.Settings().Meta.SenderName, - }, - To: []mail.Address{{Address: data.To()}}, - Subject: data.Subject(), - Text: data.Body(), +func (am *AlertManager) sendAlert(message *mailer.Message) { + // fmt.Println("sending alert", "to", message.To, "subj", message.Subject, "body", message.Text) + message.From = mail.Address{ + Address: am.app.Settings().Meta.SenderAddress, + Name: am.app.Settings().Meta.SenderName, } if err := am.mailClient.Send(message); err != nil { am.app.Logger().Error("Failed to send alert: ", "err", err.Error()) diff --git a/beszel/internal/entities/container/stats.go b/beszel/internal/entities/container/stats.go index 80aab5e..bec7a5d 100644 --- a/beszel/internal/entities/container/stats.go +++ b/beszel/internal/entities/container/stats.go @@ -2,6 +2,7 @@ package container import "time" +// Docker container resources info from /containers/id/stats type Container struct { Id string IdShort string @@ -24,6 +25,7 @@ type Container struct { // Mounts []MountPoint } +// Stats to return to the hub type ContainerStats struct { Name string `json:"n"` Cpu float64 `json:"c"` @@ -32,6 +34,7 @@ type ContainerStats struct { NetworkRecv float64 `json:"nr"` } +// Keeps track of container stats from previous run type PrevContainerStats struct { Cpu [2]uint64 Net struct { diff --git a/beszel/internal/entities/email/email.go b/beszel/internal/entities/email/email.go deleted file mode 100644 index a1d3321..0000000 --- a/beszel/internal/entities/email/email.go +++ /dev/null @@ -1,27 +0,0 @@ -package email - -type EmailData struct { - to string - subj string - body string -} - -func NewEmailData(to, subj, body string) *EmailData { - return &EmailData{ - to: to, - subj: subj, - body: body, - } -} - -func (e *EmailData) To() string { - return e.to -} - -func (e *EmailData) Subject() string { - return e.subj -} - -func (e *EmailData) Body() string { - return e.body -} diff --git a/beszel/internal/hub/hub.go b/beszel/internal/hub/hub.go index 335fa6b..d47e51c 100644 --- a/beszel/internal/hub/hub.go +++ b/beszel/internal/hub/hub.go @@ -46,9 +46,8 @@ func NewHub(app *pocketbase.PocketBase) *Hub { } func (h *Hub) Run() { - - rm := records.NewRecordManager(h.app) - am := alerts.NewAlertManager(h.app) + var rm *records.RecordManager + var am *alerts.AlertManager // loosely check if it was executed using "go run" isGoRun := strings.HasPrefix(os.Args[0], os.TempDir()) @@ -60,6 +59,13 @@ func (h *Hub) Run() { Dir: "../../migrations", }) + // set up record manager and alert manager + h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + rm = records.NewRecordManager(h.app) + am = alerts.NewAlertManager(h.app) + return nil + }) + // set auth settings h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { usersCollection, err := h.app.Dao().FindCollectionByNameOrId("users") diff --git a/beszel/site/src/components/charts/mem-chart.tsx b/beszel/site/src/components/charts/mem-chart.tsx index a4eeadb..9458f4f 100644 --- a/beszel/site/src/components/charts/mem-chart.tsx +++ b/beszel/site/src/components/charts/mem-chart.tsx @@ -46,6 +46,7 @@ export default function MemChart({ Date: Wed, 14 Aug 2024 11:28:43 -0400 Subject: [PATCH 13/19] refactor: hub --- beszel/internal/entities/server/server.go | 17 --- beszel/internal/hub/hub.go | 166 ++++++++++------------ 2 files changed, 78 insertions(+), 105 deletions(-) delete mode 100644 beszel/internal/entities/server/server.go diff --git a/beszel/internal/entities/server/server.go b/beszel/internal/entities/server/server.go deleted file mode 100644 index 282ce21..0000000 --- a/beszel/internal/entities/server/server.go +++ /dev/null @@ -1,17 +0,0 @@ -package server - -import "golang.org/x/crypto/ssh" - -type Server struct { - Host string - Port string - Status string - Client *ssh.Client -} - -func NewServer(host, port string) *Server { - return &Server{ - Host: host, - Port: port, - } -} diff --git a/beszel/internal/hub/hub.go b/beszel/internal/hub/hub.go index d47e51c..2a53c7e 100644 --- a/beszel/internal/hub/hub.go +++ b/beszel/internal/hub/hub.go @@ -2,13 +2,11 @@ package hub import ( "beszel/internal/alerts" - "beszel/internal/entities/server" "beszel/internal/entities/system" "beszel/internal/records" "beszel/site" "bytes" "crypto/ed25519" - "encoding/json" "encoding/pem" "errors" "fmt" @@ -21,6 +19,8 @@ import ( "sync" "time" + "github.com/goccy/go-json" + "github.com/labstack/echo/v5" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/apis" @@ -32,16 +32,17 @@ import ( ) type Hub struct { - app *pocketbase.PocketBase - serverConnectionsLock *sync.Mutex - serverConnections map[string]*server.Server + app *pocketbase.PocketBase + connectionLock *sync.Mutex + systemConnections map[string]*ssh.Client + sshClientConfig *ssh.ClientConfig } func NewHub(app *pocketbase.PocketBase) *Hub { return &Hub{ - app: app, - serverConnectionsLock: &sync.Mutex{}, - serverConnections: make(map[string]*server.Server), + app: app, + connectionLock: &sync.Mutex{}, + systemConnections: make(map[string]*ssh.Client), } } @@ -59,15 +60,17 @@ func (h *Hub) Run() { Dir: "../../migrations", }) - // set up record manager and alert manager + // initial setup h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + // set up record manager and alert manager rm = records.NewRecordManager(h.app) am = alerts.NewAlertManager(h.app) - return nil - }) - - // set auth settings - h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + // create ssh client config + err := h.createSSHClientConfig() + if err != nil { + log.Fatal(err) + } + // set auth settings usersCollection, err := h.app.Dao().FindCollectionByNameOrId("users") if err != nil { return err @@ -122,11 +125,9 @@ func (h *Hub) Run() { return nil }) - // ssh key setup + // custom api routes h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { - // create ssh key if it doesn't exist - h.getSSHKey() - // api route to return public key + // returns public key e.Router.GET("/api/beszel/getkey", func(c echo.Context) error { requestData := apis.RequestInfo(c) if requestData.AuthRecord == nil { @@ -138,11 +139,6 @@ func (h *Hub) Run() { } return c.JSON(http.StatusOK, map[string]string{"key": strings.TrimSuffix(string(key), "\n")}) }) - return nil - }) - - // other api routes - h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { // check if first time setup on login page e.Router.GET("/api/beszel/first-run", func(c echo.Context) error { adminNum, err := h.app.Dao().TotalAdmins() @@ -171,7 +167,7 @@ func (h *Hub) Run() { return nil }) - // immediately create connection for new servers + // immediately create connection for new systems h.app.OnModelAfterCreate("systems").Add(func(e *core.ModelEvent) error { go h.updateSystem(e.Model.(*models.Record)) return nil @@ -183,12 +179,12 @@ func (h *Hub) Run() { oldRecord := newRecord.OriginalCopy() newStatus := newRecord.GetString("status") - // if server is disconnected and connection exists, remove it + // if system is disconnected and connection exists, remove it if newStatus == "down" || newStatus == "paused" { - h.deleteServerConnection(newRecord) + h.deleteSystemConnection(newRecord) } - // if server is set to pending (unpause), try to connect immediately + // if system is set to pending (unpause), try to connect immediately if newStatus == "pending" { go h.updateSystem(newRecord) } @@ -200,8 +196,8 @@ func (h *Hub) Run() { // do things after a systems record is deleted h.app.OnModelAfterDelete("systems").Add(func(e *core.ModelEvent) error { - // if server connection exists, close it - h.deleteServerConnection(e.Model.(*models.Record)) + // if system connection exists, close it + h.deleteSystemConnection(e.Model.(*models.Record)) return nil }) @@ -258,38 +254,36 @@ func (h *Hub) updateSystems() { } func (h *Hub) updateSystem(record *models.Record) { - var s *server.Server - // check if server connection data exists - if _, ok := h.serverConnections[record.Id]; ok { - s = h.serverConnections[record.Id] + var client *ssh.Client + var err error + + // check if system connection data exists + if _, ok := h.systemConnections[record.Id]; ok { + client = h.systemConnections[record.Id] } else { - // create server connection struct - s = server.NewServer( - record.GetString("host"), - record.GetString("port")) - client, err := h.getServerConnection(s) + // create system connection + client, err = h.createSystemConnection(record) if err != nil { - h.app.Logger().Error("Failed to connect:", "err", err.Error(), "server", s.Host, "port", s.Port) - h.updateServerStatus(record, "down") + h.app.Logger().Error("Failed to connect:", "err", err.Error(), "system", record.GetString("host"), "port", record.GetString("port")) + h.updateSystemStatus(record, "down") return } - s.Client = client - h.serverConnectionsLock.Lock() - h.serverConnections[record.Id] = s - h.serverConnectionsLock.Unlock() + h.connectionLock.Lock() + h.systemConnections[record.Id] = client + h.connectionLock.Unlock() } - // get server stats from agent - systemData, err := requestJson(s) + // get system stats from agent + systemData, err := requestJson(client) if err != nil { if err.Error() == "retry" { // if previous connection was closed, try again - h.app.Logger().Error("Existing SSH connection closed. Retrying...", "host", s.Host, "port", s.Port) - h.deleteServerConnection(record) + h.app.Logger().Error("Existing SSH connection closed. Retrying...", "host", record.GetString("host"), "port", record.GetString("port")) + h.deleteSystemConnection(record) h.updateSystem(record) return } - h.app.Logger().Error("Failed to get server stats: ", "err", err.Error()) - h.updateServerStatus(record, "down") + h.app.Logger().Error("Failed to get system stats: ", "err", err.Error()) + h.updateSystemStatus(record, "down") return } // update system record @@ -300,33 +294,28 @@ func (h *Hub) updateSystem(record *models.Record) { } // add new system_stats record system_stats, _ := h.app.Dao().FindCollectionByNameOrId("system_stats") - system_stats_record := models.NewRecord(system_stats) - system_stats_record.Set("system", record.Id) - system_stats_record.Set("stats", systemData.Stats) - system_stats_record.Set("type", "1m") - if err := h.app.Dao().SaveRecord(system_stats_record); err != nil { + systemStatsRecord := models.NewRecord(system_stats) + systemStatsRecord.Set("system", record.Id) + systemStatsRecord.Set("stats", systemData.Stats) + systemStatsRecord.Set("type", "1m") + if err := h.app.Dao().SaveRecord(systemStatsRecord); err != nil { h.app.Logger().Error("Failed to save record: ", "err", err.Error()) } // add new container_stats record if len(systemData.Containers) > 0 { container_stats, _ := h.app.Dao().FindCollectionByNameOrId("container_stats") - container_stats_record := models.NewRecord(container_stats) - container_stats_record.Set("system", record.Id) - container_stats_record.Set("stats", systemData.Containers) - container_stats_record.Set("type", "1m") - if err := h.app.Dao().SaveRecord(container_stats_record); err != nil { + containerStatsRecord := models.NewRecord(container_stats) + containerStatsRecord.Set("system", record.Id) + containerStatsRecord.Set("stats", systemData.Containers) + containerStatsRecord.Set("type", "1m") + if err := h.app.Dao().SaveRecord(containerStatsRecord); err != nil { h.app.Logger().Error("Failed to save record: ", "err", err.Error()) } } } -// set server to status down and close connection -func (h *Hub) updateServerStatus(record *models.Record, status string) { - // if in map, close connection and remove from map - // this is now down automatically in an after update hook - // if status == "down" || status == "paused" { - // deleteServerConnection(record) - // } +// set system to status down and close connection +func (h *Hub) updateSystemStatus(record *models.Record, status string) { if record.GetString("status") != status { record.Set("status", status) if err := h.app.Dao().SaveRecord(record); err != nil { @@ -335,32 +324,39 @@ func (h *Hub) updateServerStatus(record *models.Record, status string) { } } -func (h *Hub) deleteServerConnection(record *models.Record) { - if _, ok := h.serverConnections[record.Id]; ok { - if h.serverConnections[record.Id].Client != nil { - h.serverConnections[record.Id].Client.Close() +func (h *Hub) deleteSystemConnection(record *models.Record) { + if _, ok := h.systemConnections[record.Id]; ok { + if h.systemConnections[record.Id] != nil { + h.systemConnections[record.Id].Close() } - h.serverConnectionsLock.Lock() - defer h.serverConnectionsLock.Unlock() - delete(h.serverConnections, record.Id) + h.connectionLock.Lock() + defer h.connectionLock.Unlock() + delete(h.systemConnections, record.Id) } } -func (h *Hub) getServerConnection(server *server.Server) (*ssh.Client, error) { - // h.app.Logger().Debug("new ssh connection", "server", server.Host) +func (h *Hub) createSystemConnection(record *models.Record) (*ssh.Client, error) { + client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", record.GetString("host"), record.GetString("port")), h.sshClientConfig) + if err != nil { + return nil, err + } + return client, nil +} + +func (h *Hub) createSSHClientConfig() error { key, err := h.getSSHKey() if err != nil { h.app.Logger().Error("Failed to get SSH key: ", "err", err.Error()) - return nil, err + return err } // Create the Signer for this private key. signer, err := ssh.ParsePrivateKey(key) if err != nil { - return nil, err + return err } - config := &ssh.ClientConfig{ + h.sshClientConfig = &ssh.ClientConfig{ User: "u", Auth: []ssh.AuthMethod{ ssh.PublicKeys(signer), @@ -368,17 +364,11 @@ func (h *Hub) getServerConnection(server *server.Server) (*ssh.Client, error) { HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: 5 * time.Second, } - - client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", server.Host, server.Port), config) - if err != nil { - return nil, err - } - - return client, nil + return nil } -func requestJson(server *server.Server) (system.SystemData, error) { - session, err := server.Client.NewSession() +func requestJson(client *ssh.Client) (system.SystemData, error) { + session, err := client.NewSession() if err != nil { return system.SystemData{}, errors.New("retry") } From c7e67a9b63ea08aa6e14cb930c501b4d0e942b2c Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Wed, 14 Aug 2024 14:14:41 -0400 Subject: [PATCH 14/19] refactor: agent and entities --- beszel/cmd/agent/agent.go | 14 +-- beszel/internal/agent/agent.go | 81 +++++++------ beszel/internal/alerts/alerts.go | 7 +- .../stats.go => container/container.go} | 108 ++++++++++-------- beszel/internal/entities/container/stats.go | 45 -------- beszel/internal/entities/system/system.go | 47 +++++++- beszel/internal/hub/hub.go | 16 +-- beszel/internal/records/records.go | 21 ++-- 8 files changed, 168 insertions(+), 171 deletions(-) rename beszel/internal/entities/{system/stats.go => container/container.go} (73%) delete mode 100644 beszel/internal/entities/container/stats.go diff --git a/beszel/cmd/agent/agent.go b/beszel/cmd/agent/agent.go index 2918644..a8e081d 100644 --- a/beszel/cmd/agent/agent.go +++ b/beszel/cmd/agent/agent.go @@ -29,20 +29,14 @@ func main() { log.Fatal("KEY environment variable is not set") } - var port string - + port := ":45876" if p, exists := os.LookupEnv("PORT"); exists { // allow passing an address in the form of "127.0.0.1:45876" - if !strings.Contains(port, ":") { - port = ":" + port + if !strings.Contains(p, ":") { + p = ":" + p } port = p - } else { - port = ":45876" } - a := agent.NewAgent(pubKey, port) - - a.Run() - + agent.NewAgent(pubKey, port).Run() } diff --git a/beszel/internal/agent/agent.go b/beszel/internal/agent/agent.go index 0392280..7a09989 100644 --- a/beszel/internal/agent/agent.go +++ b/beszel/internal/agent/agent.go @@ -35,6 +35,7 @@ type Agent struct { containerStatsMutex *sync.Mutex diskIoStats system.DiskIoStats netIoStats system.NetIoStats + dockerClient *http.Client } func NewAgent(pubKey []byte, port string) *Agent { @@ -45,6 +46,7 @@ func NewAgent(pubKey []byte, port string) *Agent { containerStatsMutex: &sync.Mutex{}, diskIoStats: system.DiskIoStats{}, netIoStats: system.NetIoStats{}, + dockerClient: newDockerClient(), } } @@ -56,11 +58,8 @@ func (a *Agent) releaseSemaphore() { <-a.sem } -// client for docker engine api -var dockerClient = newDockerClient() - -func (a *Agent) getSystemStats() (*system.SystemInfo, *system.SystemStats) { - systemStats := &system.SystemStats{} +func (a *Agent) getSystemStats() (*system.Info, *system.Stats) { + systemStats := &system.Stats{} // cpu percent cpuPct, err := cpu.Percent(0, false) @@ -127,7 +126,7 @@ func (a *Agent) getSystemStats() (*system.SystemInfo, *system.SystemStats) { a.netIoStats.Time = time.Now() } - systemInfo := &system.SystemInfo{ + systemInfo := &system.Info{ Cpu: systemStats.Cpu, MemPct: systemStats.MemPct, DiskPct: systemStats.DiskPct, @@ -153,21 +152,21 @@ func (a *Agent) getSystemStats() (*system.SystemInfo, *system.SystemStats) { } -func (a *Agent) getDockerStats() ([]*container.ContainerStats, error) { - resp, err := dockerClient.Get("http://localhost/containers/json") +func (a *Agent) getDockerStats() ([]*container.Stats, error) { + resp, err := a.dockerClient.Get("http://localhost/containers/json") if err != nil { - closeIdleConnections(err) - return []*container.ContainerStats{}, err + a.closeIdleConnections(err) + return []*container.Stats{}, err } defer resp.Body.Close() - var containers []*container.Container + var containers []*container.ApiInfo if err := json.NewDecoder(resp.Body).Decode(&containers); err != nil { log.Printf("Error decoding containers: %+v\n", err) - return []*container.ContainerStats{}, err + return []*container.Stats{}, err } - containerStats := make([]*container.ContainerStats, 0, len(containers)) + containerStats := make([]*container.Stats, 0, len(containers)) // store valid ids to clean up old container ids from map validIds := make(map[string]struct{}, len(containers)) @@ -188,12 +187,10 @@ func (a *Agent) getDockerStats() ([]*container.ContainerStats, error) { defer wg.Done() cstats, err := a.getContainerStats(ctr) if err != nil { - // Check if the error is a network timeout - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - // Close idle connections to prevent reuse of stale connections - closeIdleConnections(err) - } else { - // otherwise delete container from map + // close idle connections if error is a network timeout + isTimeout := a.closeIdleConnections(err) + // delete container from map if not a timeout + if !isTimeout { a.deleteContainerStatsSync(ctr.IdShort) } // retry once @@ -219,19 +216,19 @@ func (a *Agent) getDockerStats() ([]*container.ContainerStats, error) { return containerStats, nil } -func (a *Agent) getContainerStats(ctr *container.Container) (*container.ContainerStats, error) { +func (a *Agent) getContainerStats(ctr *container.ApiInfo) (*container.Stats, error) { // use semaphore to limit concurrency a.acquireSemaphore() defer a.releaseSemaphore() - resp, err := dockerClient.Get("http://localhost/containers/" + ctr.IdShort + "/stats?stream=0&one-shot=1") + resp, err := a.dockerClient.Get("http://localhost/containers/" + ctr.IdShort + "/stats?stream=0&one-shot=1") if err != nil { - return &container.ContainerStats{}, err + return &container.Stats{}, err } defer resp.Body.Close() - var statsJson system.CStats + var statsJson container.ApiStats if err := json.NewDecoder(resp.Body).Decode(&statsJson); err != nil { - panic(err) + log.Fatal(err) } name := ctr.Names[0][1:] @@ -258,7 +255,7 @@ func (a *Agent) getContainerStats(ctr *container.Container) (*container.Containe systemDelta := statsJson.CPUStats.SystemUsage - stats.Cpu[1] cpuPct := float64(cpuDelta) / float64(systemDelta) * 100 if cpuPct > 100 { - return &container.ContainerStats{}, fmt.Errorf("%s cpu pct greater than 100: %+v", name, cpuPct) + return &container.Stats{}, fmt.Errorf("%s cpu pct greater than 100: %+v", name, cpuPct) } stats.Cpu = [2]uint64{statsJson.CPUStats.CPUUsage.TotalUsage, statsJson.CPUStats.SystemUsage} @@ -280,7 +277,7 @@ func (a *Agent) getContainerStats(ctr *container.Container) (*container.Containe stats.Net.Recv = total_recv stats.Net.Time = time.Now() - cStats := &container.ContainerStats{ + cStats := &container.Stats{ Name: name, Cpu: twoDecimals(cpuPct), Mem: bytesToMegabytes(float64(usedMemory)), @@ -297,19 +294,18 @@ func (a *Agent) deleteContainerStatsSync(id string) { delete(containerStatsMap, id) } -func (a *Agent) gatherStats() *system.SystemData { +func (a *Agent) gatherStats() *system.CombinedData { systemInfo, systemStats := a.getSystemStats() - stats := &system.SystemData{ - Stats: systemStats, - Info: systemInfo, - Containers: []*container.ContainerStats{}, + systemData := &system.CombinedData{ + Stats: systemStats, + Info: systemInfo, + // Containers: []*container.Stats{}, } - containerStats, err := a.getDockerStats() - if err == nil { - stats.Containers = containerStats + if containerStats, err := a.getDockerStats(); err == nil { + systemData.Containers = containerStats } // fmt.Printf("%+v\n", stats) - return stats + return systemData } func (a *Agent) startServer(addr string, pubKey []byte) { @@ -324,8 +320,7 @@ func (a *Agent) startServer(addr string, pubKey []byte) { log.Printf("Starting SSH server on %s", addr) if err := sshServer.ListenAndServe(addr, nil, sshServer.NoPty(), sshServer.PublicKeyAuth(func(ctx sshServer.Context, key sshServer.PublicKey) bool { - data := []byte(pubKey) - allowed, _, _, _, _ := sshServer.ParseAuthorizedKey(data) + allowed, _, _, _, _ := sshServer.ParseAuthorizedKey(pubKey) return sshServer.KeysEqual(key, allowed) }), ); err != nil { @@ -334,7 +329,6 @@ func (a *Agent) startServer(addr string, pubKey []byte) { } func (a *Agent) Run() { - if filesystem, exists := os.LookupEnv("FILESYSTEM"); exists { a.diskIoStats.Filesystem = filesystem } else { @@ -452,7 +446,12 @@ func newDockerClient() *http.Client { } } -func closeIdleConnections(err error) { - log.Printf("Closing idle connections. Error: %+v\n", err) - dockerClient.Transport.(*http.Transport).CloseIdleConnections() +// closes idle connections on timeouts to prevent reuse of stale connections +func (a *Agent) closeIdleConnections(err error) (isTimeout bool) { + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + log.Printf("Closing idle connections. Error: %+v\n", err) + a.dockerClient.Transport.(*http.Transport).CloseIdleConnections() + return true + } + return false } diff --git a/beszel/internal/alerts/alerts.go b/beszel/internal/alerts/alerts.go index 4e68bb1..1f4f03e 100644 --- a/beszel/internal/alerts/alerts.go +++ b/beszel/internal/alerts/alerts.go @@ -1,3 +1,4 @@ +// Package alerts handles alert management and delivery. package alerts import ( @@ -32,7 +33,7 @@ func (am *AlertManager) HandleSystemAlerts(newStatus string, newRecord *models.R return } // log.Println("found alerts", len(alertRecords)) - var systemInfo *system.SystemInfo + var systemInfo *system.Info for _, alertRecord := range alertRecords { name := alertRecord.GetString("name") switch name { @@ -56,8 +57,8 @@ func (am *AlertManager) HandleSystemAlerts(newStatus string, newRecord *models.R } } -func getSystemInfo(record *models.Record) *system.SystemInfo { - var SystemInfo system.SystemInfo +func getSystemInfo(record *models.Record) *system.Info { + var SystemInfo system.Info record.UnmarshalJSONField("info", &SystemInfo) return &SystemInfo } diff --git a/beszel/internal/entities/system/stats.go b/beszel/internal/entities/container/container.go similarity index 73% rename from beszel/internal/entities/system/stats.go rename to beszel/internal/entities/container/container.go index caafcc8..92eedc1 100644 --- a/beszel/internal/entities/system/stats.go +++ b/beszel/internal/entities/container/container.go @@ -1,36 +1,50 @@ -package system +package container import "time" -type SystemStats struct { - Cpu float64 `json:"cpu"` - Mem float64 `json:"m"` - MemUsed float64 `json:"mu"` - MemPct float64 `json:"mp"` - MemBuffCache float64 `json:"mb"` - Swap float64 `json:"s"` - SwapUsed float64 `json:"su"` - Disk float64 `json:"d"` - DiskUsed float64 `json:"du"` - DiskPct float64 `json:"dp"` - DiskRead float64 `json:"dr"` - DiskWrite float64 `json:"dw"` - NetworkSent float64 `json:"ns"` - NetworkRecv float64 `json:"nr"` +// Docker container info from /containers/json +type ApiInfo struct { + Id string + IdShort string + Names []string + Status string + // Image string + // ImageID string + // Command string + // Created int64 + // Ports []Port + // SizeRw int64 `json:",omitempty"` + // SizeRootFs int64 `json:",omitempty"` + // Labels map[string]string + // State string + // HostConfig struct { + // NetworkMode string `json:",omitempty"` + // Annotations map[string]string `json:",omitempty"` + // } + // NetworkSettings *SummaryNetworkSettings + // Mounts []MountPoint } -type DiskIoStats struct { - Read uint64 - Write uint64 - Time time.Time - Filesystem string -} +// Docker container resources from /containers/{id}/stats +type ApiStats struct { + // Common stats + // Read time.Time `json:"read"` + // PreRead time.Time `json:"preread"` -type NetIoStats struct { - BytesRecv uint64 - BytesSent uint64 - Time time.Time - Name string + // Linux specific stats, not populated on Windows. + // PidsStats PidsStats `json:"pids_stats,omitempty"` + // BlkioStats BlkioStats `json:"blkio_stats,omitempty"` + + // Windows specific stats, not populated on Linux. + // NumProcs uint32 `json:"num_procs"` + // StorageStats StorageStats `json:"storage_stats,omitempty"` + // Networks request version >=1.21 + Networks map[string]NetworkStats + + // Shared stats + CPUStats CPUStats `json:"cpu_stats,omitempty"` + // PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" + MemoryStats MemoryStats `json:"memory_stats,omitempty"` } type CPUStats struct { @@ -70,27 +84,6 @@ type CPUUsage struct { // UsageInUsermode uint64 `json:"usage_in_usermode"` } -type CStats struct { - // Common stats - // Read time.Time `json:"read"` - // PreRead time.Time `json:"preread"` - - // Linux specific stats, not populated on Windows. - // PidsStats PidsStats `json:"pids_stats,omitempty"` - // BlkioStats BlkioStats `json:"blkio_stats,omitempty"` - - // Windows specific stats, not populated on Linux. - // NumProcs uint32 `json:"num_procs"` - // StorageStats StorageStats `json:"storage_stats,omitempty"` - // Networks request version >=1.21 - Networks map[string]NetworkStats - - // Shared stats - CPUStats CPUStats `json:"cpu_stats,omitempty"` - // PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" - MemoryStats MemoryStats `json:"memory_stats,omitempty"` -} - type MemoryStats struct { // current res_counter usage for memory @@ -119,3 +112,22 @@ type NetworkStats struct { // Bytes sent. Windows and Linux. TxBytes uint64 `json:"tx_bytes"` } + +// Container stats to return to the hub +type Stats struct { + Name string `json:"n"` + Cpu float64 `json:"c"` + Mem float64 `json:"m"` + NetworkSent float64 `json:"ns"` + NetworkRecv float64 `json:"nr"` +} + +// Keeps track of container stats from previous run +type PrevContainerStats struct { + Cpu [2]uint64 + Net struct { + Sent uint64 + Recv uint64 + Time time.Time + } +} diff --git a/beszel/internal/entities/container/stats.go b/beszel/internal/entities/container/stats.go deleted file mode 100644 index bec7a5d..0000000 --- a/beszel/internal/entities/container/stats.go +++ /dev/null @@ -1,45 +0,0 @@ -package container - -import "time" - -// Docker container resources info from /containers/id/stats -type Container struct { - Id string - IdShort string - Names []string - Status string - // Image string - // ImageID string - // Command string - // Created int64 - // Ports []Port - // SizeRw int64 `json:",omitempty"` - // SizeRootFs int64 `json:",omitempty"` - // Labels map[string]string - // State string - // HostConfig struct { - // NetworkMode string `json:",omitempty"` - // Annotations map[string]string `json:",omitempty"` - // } - // NetworkSettings *SummaryNetworkSettings - // Mounts []MountPoint -} - -// Stats to return to the hub -type ContainerStats struct { - Name string `json:"n"` - Cpu float64 `json:"c"` - Mem float64 `json:"m"` - NetworkSent float64 `json:"ns"` - NetworkRecv float64 `json:"nr"` -} - -// Keeps track of container stats from previous run -type PrevContainerStats struct { - Cpu [2]uint64 - Net struct { - Sent uint64 - Recv uint64 - Time time.Time - } -} diff --git a/beszel/internal/entities/system/system.go b/beszel/internal/entities/system/system.go index 941ce7f..6c9550c 100644 --- a/beszel/internal/entities/system/system.go +++ b/beszel/internal/entities/system/system.go @@ -1,8 +1,42 @@ package system -import "beszel/internal/entities/container" +import ( + "beszel/internal/entities/container" + "time" +) -type SystemInfo struct { +type Stats struct { + Cpu float64 `json:"cpu"` + Mem float64 `json:"m"` + MemUsed float64 `json:"mu"` + MemPct float64 `json:"mp"` + MemBuffCache float64 `json:"mb"` + Swap float64 `json:"s"` + SwapUsed float64 `json:"su"` + Disk float64 `json:"d"` + DiskUsed float64 `json:"du"` + DiskPct float64 `json:"dp"` + DiskRead float64 `json:"dr"` + DiskWrite float64 `json:"dw"` + NetworkSent float64 `json:"ns"` + NetworkRecv float64 `json:"nr"` +} + +type DiskIoStats struct { + Read uint64 + Write uint64 + Time time.Time + Filesystem string +} + +type NetIoStats struct { + BytesRecv uint64 + BytesSent uint64 + Time time.Time + Name string +} + +type Info struct { Cores int `json:"c"` Threads int `json:"t"` CpuModel string `json:"m"` @@ -13,8 +47,9 @@ type SystemInfo struct { DiskPct float64 `json:"dp"` } -type SystemData struct { - Stats *SystemStats `json:"stats"` - Info *SystemInfo `json:"info"` - Containers []*container.ContainerStats `json:"container"` +// Final data structure to return to the hub +type CombinedData struct { + Stats *Stats `json:"stats"` + Info *Info `json:"info"` + Containers []*container.Stats `json:"container"` } diff --git a/beszel/internal/hub/hub.go b/beszel/internal/hub/hub.go index 2a53c7e..8a4a4af 100644 --- a/beszel/internal/hub/hub.go +++ b/beszel/internal/hub/hub.go @@ -97,7 +97,7 @@ func (h *Hub) Run() { Scheme: "http", Host: "localhost:5173", }) - e.Router.GET("/static/*", apis.StaticDirectoryHandler(os.DirFS("./site/public/static"), false)) + e.Router.GET("/static/*", apis.StaticDirectoryHandler(os.DirFS("../../site/public/static"), false)) e.Router.Any("/*", echo.WrapHandler(proxy)) // e.Router.Any("/", echo.WrapHandler(proxy)) default: @@ -162,7 +162,7 @@ func (h *Hub) Run() { // system creation defaults h.app.OnModelBeforeCreate("systems").Add(func(e *core.ModelEvent) error { record := e.Model.(*models.Record) - record.Set("info", system.SystemInfo{}) + record.Set("info", system.Info{}) record.Set("status", "pending") return nil }) @@ -367,10 +367,10 @@ func (h *Hub) createSSHClientConfig() error { return nil } -func requestJson(client *ssh.Client) (system.SystemData, error) { +func requestJson(client *ssh.Client) (system.CombinedData, error) { session, err := client.NewSession() if err != nil { - return system.SystemData{}, errors.New("retry") + return system.CombinedData{}, errors.New("retry") } defer session.Close() @@ -379,19 +379,19 @@ func requestJson(client *ssh.Client) (system.SystemData, error) { session.Stdout = &outputBuffer if err := session.Shell(); err != nil { - return system.SystemData{}, err + return system.CombinedData{}, err } err = session.Wait() if err != nil { - return system.SystemData{}, err + return system.CombinedData{}, err } // Unmarshal the output into our struct - var systemData system.SystemData + var systemData system.CombinedData err = json.Unmarshal(outputBuffer.Bytes(), &systemData) if err != nil { - return system.SystemData{}, err + return system.CombinedData{}, err } return systemData, nil diff --git a/beszel/internal/records/records.go b/beszel/internal/records/records.go index be8d028..58c595d 100644 --- a/beszel/internal/records/records.go +++ b/beszel/internal/records/records.go @@ -1,3 +1,4 @@ +// Package records handles creating longer records and deleting old records. package records import ( @@ -95,12 +96,12 @@ func (rm *RecordManager) CreateLongerRecords(collectionName string, shorterRecor } // calculate the average stats of a list of system_stats records -func (rm *RecordManager) AverageSystemStats(records []*models.Record) system.SystemStats { +func (rm *RecordManager) AverageSystemStats(records []*models.Record) system.Stats { count := float64(len(records)) - sum := reflect.New(reflect.TypeOf(system.SystemStats{})).Elem() + sum := reflect.New(reflect.TypeOf(system.Stats{})).Elem() for _, record := range records { - var stats system.SystemStats + var stats system.Stats record.UnmarshalJSONField("stats", &stats) statValue := reflect.ValueOf(stats) for i := 0; i < statValue.NumField(); i++ { @@ -109,24 +110,24 @@ func (rm *RecordManager) AverageSystemStats(records []*models.Record) system.Sys } } - average := reflect.New(reflect.TypeOf(system.SystemStats{})).Elem() + average := reflect.New(reflect.TypeOf(system.Stats{})).Elem() for i := 0; i < sum.NumField(); i++ { average.Field(i).SetFloat(twoDecimals(sum.Field(i).Float() / count)) } - return average.Interface().(system.SystemStats) + return average.Interface().(system.Stats) } // calculate the average stats of a list of container_stats records -func (rm *RecordManager) AverageContainerStats(records []*models.Record) (stats []container.ContainerStats) { - sums := make(map[string]*container.ContainerStats) +func (rm *RecordManager) AverageContainerStats(records []*models.Record) (stats []container.Stats) { + sums := make(map[string]*container.Stats) count := float64(len(records)) for _, record := range records { - var stats []container.ContainerStats + var stats []container.Stats record.UnmarshalJSONField("stats", &stats) for _, stat := range stats { if _, ok := sums[stat.Name]; !ok { - sums[stat.Name] = &container.ContainerStats{Name: stat.Name, Cpu: 0, Mem: 0} + sums[stat.Name] = &container.Stats{Name: stat.Name, Cpu: 0, Mem: 0} } sums[stat.Name].Cpu += stat.Cpu sums[stat.Name].Mem += stat.Mem @@ -135,7 +136,7 @@ func (rm *RecordManager) AverageContainerStats(records []*models.Record) (stats } } for _, value := range sums { - stats = append(stats, container.ContainerStats{ + stats = append(stats, container.Stats{ Name: value.Name, Cpu: twoDecimals(value.Cpu / count), Mem: twoDecimals(value.Mem / count), From 683dc74cbfd608e4e05241b85dad6ffd81713f1c Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Wed, 14 Aug 2024 14:56:01 -0400 Subject: [PATCH 15/19] update workflows --- .github/workflows/docker-images.yml | 9 +++++---- .github/workflows/{goreleaser-action.yml => release.yml} | 0 2 files changed, 5 insertions(+), 4 deletions(-) rename .github/workflows/{goreleaser-action.yml => release.yml} (100%) diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index aabc263..ded197b 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -12,12 +12,12 @@ jobs: fail-fast: false matrix: include: - - image: henrygd/beszel-test + - image: henrygd/beszel context: ./beszel - dockerfile: ./dockerfile_Hub - - image: henrygd/beszel-agent-test + dockerfile: ./beszel/dockerfile_Hub + - image: henrygd/beszel-agent context: ./beszel - dockerfile: ./dockerfile_Agent + dockerfile: ./beszel/dockerfile_Agent permissions: contents: read packages: write @@ -49,6 +49,7 @@ jobs: tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }} # https://github.com/docker/login-action diff --git a/.github/workflows/goreleaser-action.yml b/.github/workflows/release.yml similarity index 100% rename from .github/workflows/goreleaser-action.yml rename to .github/workflows/release.yml From b5607025f78dd2ebfa8110c50377df1b5b9d7bb0 Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 18 Aug 2024 17:45:39 -0400 Subject: [PATCH 16/19] slight improvements to agent memory usage --- beszel/cmd/agent/agent.go | 12 +-- beszel/internal/agent/agent.go | 176 ++++++++++++++++++++------------- 2 files changed, 113 insertions(+), 75 deletions(-) diff --git a/beszel/cmd/agent/agent.go b/beszel/cmd/agent/agent.go index a8e081d..0ea0097 100644 --- a/beszel/cmd/agent/agent.go +++ b/beszel/cmd/agent/agent.go @@ -29,14 +29,14 @@ func main() { log.Fatal("KEY environment variable is not set") } - port := ":45876" - if p, exists := os.LookupEnv("PORT"); exists { + addr := ":45876" + if portEnvVar, exists := os.LookupEnv("PORT"); exists { // allow passing an address in the form of "127.0.0.1:45876" - if !strings.Contains(p, ":") { - p = ":" + p + if !strings.Contains(portEnvVar, ":") { + portEnvVar = ":" + portEnvVar } - port = p + addr = portEnvVar } - agent.NewAgent(pubKey, port).Run() + agent.NewAgent(pubKey, addr).Run() } diff --git a/beszel/internal/agent/agent.go b/beszel/internal/agent/agent.go index 7a09989..b6e656a 100644 --- a/beszel/internal/agent/agent.go +++ b/beszel/internal/agent/agent.go @@ -3,6 +3,7 @@ package agent import ( "beszel/internal/entities/container" "beszel/internal/entities/system" + "bytes" "context" "encoding/json" "fmt" @@ -26,27 +27,39 @@ import ( psutilNet "github.com/shirou/gopsutil/v4/net" ) -var containerStatsMap = make(map[string]*container.PrevContainerStats) - type Agent struct { - port string + addr string pubKey []byte sem chan struct{} + containerStatsMap map[string]*container.PrevContainerStats containerStatsMutex *sync.Mutex - diskIoStats system.DiskIoStats - netIoStats system.NetIoStats + diskIoStats *system.DiskIoStats + netIoStats *system.NetIoStats dockerClient *http.Client + containerStatsPool *sync.Pool + bufferPool *sync.Pool } -func NewAgent(pubKey []byte, port string) *Agent { +func NewAgent(pubKey []byte, addr string) *Agent { return &Agent{ + addr: addr, pubKey: pubKey, sem: make(chan struct{}, 15), - port: port, + containerStatsMap: make(map[string]*container.PrevContainerStats), containerStatsMutex: &sync.Mutex{}, - diskIoStats: system.DiskIoStats{}, - netIoStats: system.NetIoStats{}, + diskIoStats: &system.DiskIoStats{}, + netIoStats: &system.NetIoStats{}, dockerClient: newDockerClient(), + containerStatsPool: &sync.Pool{ + New: func() interface{} { + return new(container.Stats) + }, + }, + bufferPool: &sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, + }, } } @@ -156,14 +169,14 @@ func (a *Agent) getDockerStats() ([]*container.Stats, error) { resp, err := a.dockerClient.Get("http://localhost/containers/json") if err != nil { a.closeIdleConnections(err) - return []*container.Stats{}, err + return nil, err } defer resp.Body.Close() var containers []*container.ApiInfo if err := json.NewDecoder(resp.Body).Decode(&containers); err != nil { log.Printf("Error decoding containers: %+v\n", err) - return []*container.Stats{}, err + return nil, err } containerStats := make([]*container.Stats, 0, len(containers)) @@ -206,10 +219,10 @@ func (a *Agent) getDockerStats() ([]*container.Stats, error) { wg.Wait() - for id := range containerStatsMap { + for id := range a.containerStatsMap { if _, exists := validIds[id]; !exists { // log.Printf("Removing container cpu map entry: %+v\n", id) - delete(containerStatsMap, id) + delete(a.containerStatsMap, id) } } @@ -220,15 +233,27 @@ func (a *Agent) getContainerStats(ctr *container.ApiInfo) (*container.Stats, err // use semaphore to limit concurrency a.acquireSemaphore() defer a.releaseSemaphore() + resp, err := a.dockerClient.Get("http://localhost/containers/" + ctr.IdShort + "/stats?stream=0&one-shot=1") if err != nil { - return &container.Stats{}, err + return nil, err } defer resp.Body.Close() + // get a buffer from the pool + buf := a.bufferPool.Get().(*bytes.Buffer) + defer a.bufferPool.Put(buf) + buf.Reset() + // read the response body into the buffer + _, err = io.Copy(buf, resp.Body) + if err != nil { + return nil, err + } + + // unmarshal the json data from the buffer var statsJson container.ApiStats - if err := json.NewDecoder(resp.Body).Decode(&statsJson); err != nil { - log.Fatal(err) + if err := json.Unmarshal(buf.Bytes(), &statsJson); err != nil { + return nil, err } name := ctr.Names[0][1:] @@ -244,10 +269,10 @@ func (a *Agent) getContainerStats(ctr *container.ApiInfo) (*container.Stats, err defer a.containerStatsMutex.Unlock() // add empty values if they doesn't exist in map - stats, initialized := containerStatsMap[ctr.IdShort] + stats, initialized := a.containerStatsMap[ctr.IdShort] if !initialized { stats = &container.PrevContainerStats{} - containerStatsMap[ctr.IdShort] = stats + a.containerStatsMap[ctr.IdShort] = stats } // cpu @@ -255,7 +280,7 @@ func (a *Agent) getContainerStats(ctr *container.ApiInfo) (*container.Stats, err systemDelta := statsJson.CPUStats.SystemUsage - stats.Cpu[1] cpuPct := float64(cpuDelta) / float64(systemDelta) * 100 if cpuPct > 100 { - return &container.Stats{}, fmt.Errorf("%s cpu pct greater than 100: %+v", name, cpuPct) + return nil, fmt.Errorf("%s cpu pct greater than 100: %+v", name, cpuPct) } stats.Cpu = [2]uint64{statsJson.CPUStats.CPUUsage.TotalUsage, statsJson.CPUStats.SystemUsage} @@ -277,13 +302,13 @@ func (a *Agent) getContainerStats(ctr *container.ApiInfo) (*container.Stats, err stats.Net.Recv = total_recv stats.Net.Time = time.Now() - cStats := &container.Stats{ - Name: name, - Cpu: twoDecimals(cpuPct), - Mem: bytesToMegabytes(float64(usedMemory)), - NetworkSent: bytesToMegabytes(sent_delta), - NetworkRecv: bytesToMegabytes(recv_delta), - } + cStats := a.containerStatsPool.Get().(*container.Stats) + cStats.Name = name + cStats.Cpu = twoDecimals(cpuPct) + cStats.Mem = bytesToMegabytes(float64(usedMemory)) + cStats.NetworkSent = bytesToMegabytes(sent_delta) + cStats.NetworkRecv = bytesToMegabytes(recv_delta) + return cStats, nil } @@ -291,7 +316,7 @@ func (a *Agent) getContainerStats(ctr *container.ApiInfo) (*container.Stats, err func (a *Agent) deleteContainerStatsSync(id string) { a.containerStatsMutex.Lock() defer a.containerStatsMutex.Unlock() - delete(containerStatsMap, id) + delete(a.containerStatsMap, id) } func (a *Agent) gatherStats() *system.CombinedData { @@ -299,28 +324,28 @@ func (a *Agent) gatherStats() *system.CombinedData { systemData := &system.CombinedData{ Stats: systemStats, Info: systemInfo, - // Containers: []*container.Stats{}, } if containerStats, err := a.getDockerStats(); err == nil { systemData.Containers = containerStats } - // fmt.Printf("%+v\n", stats) + // fmt.Printf("%+v\n", systemData) return systemData } -func (a *Agent) startServer(addr string, pubKey []byte) { - sshServer.Handle(func(s sshServer.Session) { - stats := a.gatherStats() - var jsonStats []byte - jsonStats, _ = json.Marshal(stats) - io.WriteString(s, string(jsonStats)) - s.Exit(0) - }) +// return container stats to pool +func (a *Agent) returnStatsToPool(containerStats []*container.Stats) { + for _, stats := range containerStats { + a.containerStatsPool.Put(stats) + } +} - log.Printf("Starting SSH server on %s", addr) - if err := sshServer.ListenAndServe(addr, nil, sshServer.NoPty(), +func (a *Agent) startServer() { + sshServer.Handle(a.handleSession) + + log.Printf("Starting SSH server on %s", a.addr) + if err := sshServer.ListenAndServe(a.addr, nil, sshServer.NoPty(), sshServer.PublicKeyAuth(func(ctx sshServer.Context, key sshServer.PublicKey) bool { - allowed, _, _, _, _ := sshServer.ParseAuthorizedKey(pubKey) + allowed, _, _, _, _ := sshServer.ParseAuthorizedKey(a.pubKey) return sshServer.KeysEqual(key, allowed) }), ); err != nil { @@ -328,6 +353,18 @@ func (a *Agent) startServer(addr string, pubKey []byte) { } } +func (a *Agent) handleSession(s sshServer.Session) { + stats := a.gatherStats() + defer a.returnStatsToPool(stats.Containers) + encoder := json.NewEncoder(s) + if err := encoder.Encode(stats); err != nil { + log.Println("Error encoding stats:", err.Error()) + s.Exit(1) + return + } + s.Exit(0) +} + func (a *Agent) Run() { if filesystem, exists := os.LookupEnv("FILESYSTEM"); exists { a.diskIoStats.Filesystem = filesystem @@ -338,7 +375,35 @@ func (a *Agent) Run() { a.initializeDiskIoStats() a.initializeNetIoStats() - a.startServer(a.port, a.pubKey) + a.startServer() +} + +func (a *Agent) initializeDiskIoStats() { + if io, err := disk.IOCounters(a.diskIoStats.Filesystem); err == nil { + for _, d := range io { + a.diskIoStats.Time = time.Now() + a.diskIoStats.Read = d.ReadBytes + a.diskIoStats.Write = d.WriteBytes + } + } +} + +func (a *Agent) initializeNetIoStats() { + if netIO, err := psutilNet.IOCounters(true); err == nil { + bytesSent := uint64(0) + bytesRecv := uint64(0) + for _, v := range netIO { + if skipNetworkInterface(&v) { + continue + } + log.Printf("Found network interface: %+v (%+v recv, %+v sent)\n", v.Name, v.BytesRecv, v.BytesSent) + bytesSent += v.BytesSent + bytesRecv += v.BytesRecv + } + a.netIoStats.BytesSent = bytesSent + a.netIoStats.BytesRecv = bytesRecv + a.netIoStats.Time = time.Now() + } } func bytesToMegabytes(b float64) float64 { @@ -379,34 +444,6 @@ func skipNetworkInterface(v *psutilNet.IOCountersStat) bool { } } -func (a *Agent) initializeDiskIoStats() { - if io, err := disk.IOCounters(a.diskIoStats.Filesystem); err == nil { - for _, d := range io { - a.diskIoStats.Time = time.Now() - a.diskIoStats.Read = d.ReadBytes - a.diskIoStats.Write = d.WriteBytes - } - } -} - -func (a *Agent) initializeNetIoStats() { - if netIO, err := psutilNet.IOCounters(true); err == nil { - bytesSent := uint64(0) - bytesRecv := uint64(0) - for _, v := range netIO { - if skipNetworkInterface(&v) { - continue - } - log.Printf("Found network interface: %+v (%+v recv, %+v sent)\n", v.Name, v.BytesRecv, v.BytesSent) - bytesSent += v.BytesSent - bytesRecv += v.BytesRecv - } - a.netIoStats.BytesSent = bytesSent - a.netIoStats.BytesRecv = bytesRecv - a.netIoStats.Time = time.Now() - } -} - func newDockerClient() *http.Client { dockerHost := "unix:///var/run/docker.sock" if dockerHostEnv, exists := os.LookupEnv("DOCKER_HOST"); exists { @@ -422,6 +459,7 @@ func newDockerClient() *http.Client { ForceAttemptHTTP2: false, IdleConnTimeout: 90 * time.Second, DisableCompression: true, + MaxConnsPerHost: 20, MaxIdleConnsPerHost: 20, DisableKeepAlives: false, } From 0566433aa1ec6f6041a541ba45a28fed6bd296ac Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 18 Aug 2024 18:23:17 -0400 Subject: [PATCH 17/19] move longer records creation to a scheduled job --- beszel/internal/hub/hub.go | 26 +-- beszel/internal/records/records.go | 351 +++++++++++++++++++---------- 2 files changed, 238 insertions(+), 139 deletions(-) diff --git a/beszel/internal/hub/hub.go b/beszel/internal/hub/hub.go index 8a4a4af..70d5298 100644 --- a/beszel/internal/hub/hub.go +++ b/beszel/internal/hub/hub.go @@ -107,20 +107,16 @@ func (h *Hub) Run() { return nil }) - // set up cron jobs / ticker for system updates + // set up scheduled jobs / ticker for system updates h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { // 15 second ticker for system updates go h.startSystemUpdateTicker() - // cron job to delete old records + // set up cron jobs scheduler := cron.New() - scheduler.MustAdd("delete old records", "8 * * * *", func() { - collections := []string{"system_stats", "container_stats"} - rm.DeleteOldRecords(collections, "1m", time.Hour) - rm.DeleteOldRecords(collections, "10m", 12*time.Hour) - rm.DeleteOldRecords(collections, "20m", 24*time.Hour) - rm.DeleteOldRecords(collections, "120m", 7*24*time.Hour) - rm.DeleteOldRecords(collections, "480m", 30*24*time.Hour) - }) + // delete old records once every hour + scheduler.MustAdd("delete old records", "8 * * * *", rm.DeleteOldRecords) + // create longer records every 10 minutes + scheduler.MustAdd("create longer records", "*/10 * * * *", rm.CreateLongerRecords) scheduler.Start() return nil }) @@ -201,16 +197,6 @@ func (h *Hub) Run() { return nil }) - h.app.OnModelAfterCreate("system_stats").Add(func(e *core.ModelEvent) error { - rm.CreateLongerRecords("system_stats", e.Model.(*models.Record)) - return nil - }) - - h.app.OnModelAfterCreate("container_stats").Add(func(e *core.ModelEvent) error { - rm.CreateLongerRecords("container_stats", e.Model.(*models.Record)) - return nil - }) - if err := h.app.Start(); err != nil { log.Fatal(err) } diff --git a/beszel/internal/records/records.go b/beszel/internal/records/records.go index 58c595d..673c820 100644 --- a/beszel/internal/records/records.go +++ b/beszel/internal/records/records.go @@ -4,9 +4,8 @@ package records import ( "beszel/internal/entities/container" "beszel/internal/entities/system" - "fmt" + "log" "math" - "reflect" "time" "github.com/pocketbase/dbx" @@ -19,113 +18,202 @@ type RecordManager struct { app *pocketbase.PocketBase } +type LongerRecordData struct { + shorterType string + longerType string + longerTimeDuration time.Duration + expectedShorterRecords int +} + +type RecordDeletionData struct { + recordType string + retention time.Duration +} + func NewRecordManager(app *pocketbase.PocketBase) *RecordManager { - return &RecordManager{app: app} + return &RecordManager{app} } -func (rm *RecordManager) CreateLongerRecords(collectionName string, shorterRecord *models.Record) { - shorterRecordType := shorterRecord.GetString("type") - systemId := shorterRecord.GetString("system") - // fmt.Println("create longer records", "recordType", shorterRecordType, "systemId", systemId) - var longerRecordType string - var timeAgo time.Duration - var expectedShorterRecords int - switch shorterRecordType { - case "1m": - longerRecordType = "10m" - timeAgo = -10 * time.Minute - expectedShorterRecords = 10 - case "10m": - longerRecordType = "20m" - timeAgo = -20 * time.Minute - expectedShorterRecords = 2 - case "20m": - longerRecordType = "120m" - timeAgo = -120 * time.Minute - expectedShorterRecords = 6 - default: - longerRecordType = "480m" - timeAgo = -480 * time.Minute - expectedShorterRecords = 4 +// Create longer records by averaging shorter records +func (rm *RecordManager) CreateLongerRecords() { + // start := time.Now() + recordData := []LongerRecordData{ + { + shorterType: "1m", + expectedShorterRecords: 10, + longerType: "10m", + longerTimeDuration: -10 * time.Minute, + }, + { + shorterType: "10m", + expectedShorterRecords: 2, + longerType: "20m", + longerTimeDuration: -20 * time.Minute, + }, + { + shorterType: "20m", + expectedShorterRecords: 6, + longerType: "120m", + longerTimeDuration: -120 * time.Minute, + }, + { + shorterType: "120m", + expectedShorterRecords: 4, + longerType: "480m", + longerTimeDuration: -480 * time.Minute, + }, } - - longerRecordPeriod := time.Now().UTC().Add(timeAgo + 10*time.Second).Format("2006-01-02 15:04:05") - // check creation time of last 10m record - lastLongerRecord, err := rm.app.Dao().FindFirstRecordByFilter( - collectionName, - "type = {:type} && system = {:system} && created > {:created}", - dbx.Params{"type": longerRecordType, "system": systemId, "created": longerRecordPeriod}, - ) - // return if longer record exists - if err == nil || lastLongerRecord != nil { - // log.Println("longer record found. returning") - return - } - // get shorter records from the past x minutes - // shorterRecordPeriod := time.Now().UTC().Add(timeAgo + time.Second).Format("2006-01-02 15:04:05") - allShorterRecords, err := rm.app.Dao().FindRecordsByFilter( - collectionName, - "type = {:type} && system = {:system} && created > {:created}", - "-created", - -1, - 0, - dbx.Params{"type": shorterRecordType, "system": systemId, "created": longerRecordPeriod}, - ) - // return if not enough shorter records - if err != nil || len(allShorterRecords) < expectedShorterRecords { - // log.Println("not enough shorter records. returning") - return - } - // average the shorter records and create longer record - var stats interface{} - switch collectionName { - case "system_stats": - stats = rm.AverageSystemStats(allShorterRecords) - case "container_stats": - stats = rm.AverageContainerStats(allShorterRecords) - } - collection, _ := rm.app.Dao().FindCollectionByNameOrId(collectionName) - longerRecord := models.NewRecord(collection) - longerRecord.Set("system", systemId) - longerRecord.Set("stats", stats) - longerRecord.Set("type", longerRecordType) - if err := rm.app.Dao().SaveRecord(longerRecord); err != nil { - fmt.Println("failed to save longer record", "err", err.Error()) - } - -} - -// calculate the average stats of a list of system_stats records -func (rm *RecordManager) AverageSystemStats(records []*models.Record) system.Stats { - count := float64(len(records)) - sum := reflect.New(reflect.TypeOf(system.Stats{})).Elem() - - for _, record := range records { - var stats system.Stats - record.UnmarshalJSONField("stats", &stats) - statValue := reflect.ValueOf(stats) - for i := 0; i < statValue.NumField(); i++ { - field := sum.Field(i) - field.SetFloat(field.Float() + statValue.Field(i).Float()) + // wrap the operations in a transaction + rm.app.Dao().RunInTransaction(func(txDao *daos.Dao) error { + activeSystems, err := txDao.FindRecordsByExpr("systems", dbx.NewExp("status = 'up'")) + if err != nil { + log.Println("failed to get active systems", "err", err.Error()) + return err } - } - average := reflect.New(reflect.TypeOf(system.Stats{})).Elem() - for i := 0; i < sum.NumField(); i++ { - average.Field(i).SetFloat(twoDecimals(sum.Field(i).Float() / count)) - } + collections := map[string]*models.Collection{} + for _, collectionName := range []string{"system_stats", "container_stats"} { + collection, _ := txDao.FindCollectionByNameOrId(collectionName) + collections[collectionName] = collection + } - return average.Interface().(system.Stats) + // loop through all active systems, time periods, and collections + for _, system := range activeSystems { + // log.Println("processing system", system.GetString("name")) + for _, recordData := range recordData { + // log.Println("processing longer record type", recordData.longerType) + // add one minute padding for longer records because they are created slightly later than the job start time + longerRecordPeriod := time.Now().UTC().Add(recordData.longerTimeDuration + time.Minute) + // shorter records are created independently of longer records, so we shouldn't need to add padding + shorterRecordPeriod := time.Now().UTC().Add(recordData.longerTimeDuration) + // loop through both collections + for _, collection := range collections { + // check creation time of last longer record if not 10m, since 10m is created every run + if recordData.longerType != "10m" { + lastLongerRecord, err := txDao.FindFirstRecordByFilter( + collection.Id, + "type = {:type} && system = {:system} && created > {:created}", + dbx.Params{"type": recordData.longerType, "system": system.Id, "created": longerRecordPeriod}, + ) + // continue if longer record exists + if err == nil || lastLongerRecord != nil { + // log.Println("longer record found. continuing") + continue + } + } + // get shorter records from the past x minutes + allShorterRecords, err := txDao.FindRecordsByExpr( + collection.Id, + dbx.NewExp( + "type = {:type} AND system = {:system} AND created > {:created}", + dbx.Params{"type": recordData.shorterType, "system": system.Id, "created": shorterRecordPeriod}, + ), + ) + + // continue if not enough shorter records + if err != nil || len(allShorterRecords) < recordData.expectedShorterRecords { + // log.Println("not enough shorter records. continue.", len(allShorterRecords), recordData.expectedShorterRecords) + continue + } + // average the shorter records and create longer record + var stats interface{} + switch collection.Name { + case "system_stats": + stats = rm.AverageSystemStats(allShorterRecords) + case "container_stats": + stats = rm.AverageContainerStats(allShorterRecords) + } + longerRecord := models.NewRecord(collection) + longerRecord.Set("system", system.Id) + longerRecord.Set("stats", stats) + longerRecord.Set("type", recordData.longerType) + if err := txDao.SaveRecord(longerRecord); err != nil { + log.Println("failed to save longer record", "err", err.Error()) + } + } + } + } + + return nil + }) + + // log.Println("finished creating longer records", "time (ms)", time.Since(start).Milliseconds()) } -// calculate the average stats of a list of container_stats records +// Calculate the average stats of a list of system_stats records with reflect +// func (rm *RecordManager) AverageSystemStats(records []*models.Record) system.Stats { +// count := float64(len(records)) +// sum := reflect.New(reflect.TypeOf(system.Stats{})).Elem() + +// var stats system.Stats +// for _, record := range records { +// record.UnmarshalJSONField("stats", &stats) +// statValue := reflect.ValueOf(stats) +// for i := 0; i < statValue.NumField(); i++ { +// field := sum.Field(i) +// field.SetFloat(field.Float() + statValue.Field(i).Float()) +// } +// } + +// average := reflect.New(reflect.TypeOf(system.Stats{})).Elem() +// for i := 0; i < sum.NumField(); i++ { +// average.Field(i).SetFloat(twoDecimals(sum.Field(i).Float() / count)) +// } + +// return average.Interface().(system.Stats) +// } + +// Calculate the average stats of a list of system_stats records without reflect +func (rm *RecordManager) AverageSystemStats(records []*models.Record) system.Stats { + var sum system.Stats + count := float64(len(records)) + + var stats system.Stats + for _, record := range records { + record.UnmarshalJSONField("stats", &stats) + sum.Cpu += stats.Cpu + sum.Mem += stats.Mem + sum.MemUsed += stats.MemUsed + sum.MemPct += stats.MemPct + sum.MemBuffCache += stats.MemBuffCache + sum.Swap += stats.Swap + sum.SwapUsed += stats.SwapUsed + sum.Disk += stats.Disk + sum.DiskUsed += stats.DiskUsed + sum.DiskPct += stats.DiskPct + sum.DiskRead += stats.DiskRead + sum.DiskWrite += stats.DiskWrite + sum.NetworkSent += stats.NetworkSent + sum.NetworkRecv += stats.NetworkRecv + } + + return system.Stats{ + Cpu: twoDecimals(sum.Cpu / count), + Mem: twoDecimals(sum.Mem / count), + MemUsed: twoDecimals(sum.MemUsed / count), + MemPct: twoDecimals(sum.MemPct / count), + MemBuffCache: twoDecimals(sum.MemBuffCache / count), + Swap: twoDecimals(sum.Swap / count), + SwapUsed: twoDecimals(sum.SwapUsed / count), + Disk: twoDecimals(sum.Disk / count), + DiskUsed: twoDecimals(sum.DiskUsed / count), + DiskPct: twoDecimals(sum.DiskPct / count), + DiskRead: twoDecimals(sum.DiskRead / count), + DiskWrite: twoDecimals(sum.DiskWrite / count), + NetworkSent: twoDecimals(sum.NetworkSent / count), + NetworkRecv: twoDecimals(sum.NetworkRecv / count), + } +} + +// Calculate the average stats of a list of container_stats records func (rm *RecordManager) AverageContainerStats(records []*models.Record) (stats []container.Stats) { sums := make(map[string]*container.Stats) count := float64(len(records)) + + var containerStats []container.Stats for _, record := range records { - var stats []container.Stats - record.UnmarshalJSONField("stats", &stats) - for _, stat := range stats { + record.UnmarshalJSONField("stats", &containerStats) + for _, stat := range containerStats { if _, ok := sums[stat.Name]; !ok { sums[stat.Name] = &container.Stats{Name: stat.Name, Cpu: 0, Mem: 0} } @@ -135,6 +223,7 @@ func (rm *RecordManager) AverageContainerStats(records []*models.Record) (stats sums[stat.Name].NetworkRecv += stat.NetworkRecv } } + for _, value := range sums { stats = append(stats, container.Stats{ Name: value.Name, @@ -147,33 +236,57 @@ func (rm *RecordManager) AverageContainerStats(records []*models.Record) (stats return stats } -/* Round float to two decimals */ -func twoDecimals(value float64) float64 { - return math.Round(value*100) / 100 -} - -/* Delete records of specified collections and type that are older than timeLimit */ -func (rm *RecordManager) DeleteOldRecords(collections []string, recordType string, timeLimit time.Duration) { - timeLimitStamp := time.Now().UTC().Add(-timeLimit).Format("2006-01-02 15:04:05") - - // db query - expType := dbx.NewExp("type = {:type}", dbx.Params{"type": recordType}) - expCreated := dbx.NewExp("created < {:created}", dbx.Params{"created": timeLimitStamp}) - - var records []*models.Record - for _, collection := range collections { - if collectionRecords, err := rm.app.Dao().FindRecordsByExpr(collection, expType, expCreated); err == nil { - records = append(records, collectionRecords...) - } +func (rm *RecordManager) DeleteOldRecords() { + // start := time.Now() + collections := []string{"system_stats", "container_stats"} + recordData := []RecordDeletionData{ + { + recordType: "1m", + retention: time.Hour, + }, + { + recordType: "10m", + retention: 12 * time.Hour, + }, + { + recordType: "20m", + retention: 24 * time.Hour, + }, + { + recordType: "120m", + retention: 7 * 24 * time.Hour, + }, + { + recordType: "480m", + retention: 30 * 24 * time.Hour, + }, } - rm.app.Dao().RunInTransaction(func(txDao *daos.Dao) error { - for _, record := range records { - err := txDao.DeleteRecord(record) - if err != nil { - return err + for _, recordData := range recordData { + exp := dbx.NewExp( + "type = {:type} AND created < {:created}", + dbx.Params{"type": recordData.recordType, "created": time.Now().UTC().Add(-recordData.retention)}, + ) + for _, collectionSlug := range collections { + collectionRecords, err := txDao.FindRecordsByExpr(collectionSlug, exp) + if err != nil { + return err + } + for _, record := range collectionRecords { + err := txDao.DeleteRecord(record) + if err != nil { + rm.app.Logger().Error("Failed to delete records", "err", err.Error()) + return err + } + } } } return nil }) + // log.Println("finished deleting old records", "time (ms)", time.Since(start).Milliseconds()) +} + +/* Round float to two decimals */ +func twoDecimals(value float64) float64 { + return math.Round(value*100) / 100 } From b7934931cf0116affefabd6f218634831c717961 Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 18 Aug 2024 18:30:44 -0400 Subject: [PATCH 18/19] refactor hub requestJsonFromAgent --- beszel/internal/hub/hub.go | 40 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/beszel/internal/hub/hub.go b/beszel/internal/hub/hub.go index 70d5298..99b5acd 100644 --- a/beszel/internal/hub/hub.go +++ b/beszel/internal/hub/hub.go @@ -5,10 +5,8 @@ import ( "beszel/internal/entities/system" "beszel/internal/records" "beszel/site" - "bytes" "crypto/ed25519" "encoding/pem" - "errors" "fmt" "log" "net/http" @@ -211,7 +209,7 @@ func (h *Hub) startSystemUpdateTicker() { func (h *Hub) updateSystems() { records, err := h.app.Dao().FindRecordsByFilter( - "2hz5ncl8tizk5nx", // collection + "2hz5ncl8tizk5nx", // systems collection "status != 'paused'", // filter "updated", // sort -1, // limit @@ -259,9 +257,9 @@ func (h *Hub) updateSystem(record *models.Record) { h.connectionLock.Unlock() } // get system stats from agent - systemData, err := requestJson(client) - if err != nil { - if err.Error() == "retry" { + var systemData system.CombinedData + if err := requestJsonFromAgent(client, &systemData); err != nil { + if err.Error() == "bad client" { // if previous connection was closed, try again h.app.Logger().Error("Existing SSH connection closed. Retrying...", "host", record.GetString("host"), "port", record.GetString("port")) h.deleteSystemConnection(record) @@ -300,7 +298,7 @@ func (h *Hub) updateSystem(record *models.Record) { } } -// set system to status down and close connection +// set system to specified status and save record func (h *Hub) updateSystemStatus(record *models.Record, status string) { if record.GetString("status") != status { record.Set("status", status) @@ -353,34 +351,32 @@ func (h *Hub) createSSHClientConfig() error { return nil } -func requestJson(client *ssh.Client) (system.CombinedData, error) { +func requestJsonFromAgent(client *ssh.Client, systemData *system.CombinedData) error { session, err := client.NewSession() if err != nil { - return system.CombinedData{}, errors.New("retry") + return fmt.Errorf("bad client") } defer session.Close() - // Create a buffer to capture the output - var outputBuffer bytes.Buffer - session.Stdout = &outputBuffer + stdout, err := session.StdoutPipe() + if err != nil { + return err + } if err := session.Shell(); err != nil { - return system.CombinedData{}, err + return err } - err = session.Wait() - if err != nil { - return system.CombinedData{}, err + if err := json.NewDecoder(stdout).Decode(systemData); err != nil { + return err } - // Unmarshal the output into our struct - var systemData system.CombinedData - err = json.Unmarshal(outputBuffer.Bytes(), &systemData) - if err != nil { - return system.CombinedData{}, err + // wait for the session to complete + if err := session.Wait(); err != nil { + return err } - return systemData, nil + return nil } func (h *Hub) getSSHKey() ([]byte, error) { From 61723a24e05a93b29e30f1591051b46d0b9d1d31 Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Sun, 18 Aug 2024 18:32:15 -0400 Subject: [PATCH 19/19] tweak opacity of non-stacked area charts --- beszel/site/src/components/charts/bandwidth-chart.tsx | 4 ++-- beszel/site/src/components/charts/disk-io-chart.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/beszel/site/src/components/charts/bandwidth-chart.tsx b/beszel/site/src/components/charts/bandwidth-chart.tsx index 2eca2f2..51c0754 100644 --- a/beszel/site/src/components/charts/bandwidth-chart.tsx +++ b/beszel/site/src/components/charts/bandwidth-chart.tsx @@ -83,7 +83,7 @@ export default function BandwidthChart({ name="Sent" type="monotoneX" fill="hsl(var(--chart-5))" - fillOpacity={0.4} + fillOpacity={0.2} stroke="hsl(var(--chart-5))" // animationDuration={1200} isAnimationActive={false} @@ -93,7 +93,7 @@ export default function BandwidthChart({ name="Received" type="monotoneX" fill="hsl(var(--chart-2))" - fillOpacity={0.4} + fillOpacity={0.2} stroke="hsl(var(--chart-2))" // animationDuration={1200} isAnimationActive={false} diff --git a/beszel/site/src/components/charts/disk-io-chart.tsx b/beszel/site/src/components/charts/disk-io-chart.tsx index fba4bfc..a270247 100644 --- a/beszel/site/src/components/charts/disk-io-chart.tsx +++ b/beszel/site/src/components/charts/disk-io-chart.tsx @@ -87,7 +87,7 @@ export default function DiskIoChart({ name="Write" type="monotoneX" fill="hsl(var(--chart-3))" - fillOpacity={0.4} + fillOpacity={0.3} stroke="hsl(var(--chart-3))" // animationDuration={1200} isAnimationActive={false} @@ -97,7 +97,7 @@ export default function DiskIoChart({ name="Read" type="monotoneX" fill="hsl(var(--chart-1))" - fillOpacity={0.4} + fillOpacity={0.3} stroke="hsl(var(--chart-1))" // animationDuration={1200} isAnimationActive={false}