├── internal ├── util │ └── util.go ├── model │ └── model.go ├── service │ └── service.go ├── middleware │ └── middleware.go └── handler │ └── handler.go ├── bun.lockb ├── pb_data ├── data.db └── logs.db ├── static ├── css │ ├── input.css │ └── styles.css └── js │ ├── pocketbase.min.js │ └── alpine.min.js ├── tailwind.config.js ├── package.json ├── views ├── components │ ├── Icons.templ │ ├── Navbar.templ │ ├── Icons_templ.go │ └── Navbar_templ.go ├── layouts │ ├── BaseLayout.templ │ └── BaseLayout_templ.go └── pages │ ├── Login.templ │ ├── Login_templ.go │ ├── Signup.templ │ ├── Signup_templ.go │ ├── HomePage.templ │ ├── HomePage_templ.go │ ├── Dashboard.templ │ └── Dashboard_templ.go ├── .gitignore ├── LICENSE ├── cmd └── GoCards │ └── main.go ├── go.mod ├── README.md ├── Makefile └── go.sum /internal/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | -------------------------------------------------------------------------------- /internal/model/model.go: -------------------------------------------------------------------------------- 1 | package model 2 | -------------------------------------------------------------------------------- /internal/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | -------------------------------------------------------------------------------- /internal/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morethancoder/gocards/main/bun.lockb -------------------------------------------------------------------------------- /pb_data/data.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morethancoder/gocards/main/pb_data/data.db -------------------------------------------------------------------------------- /pb_data/logs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morethancoder/gocards/main/pb_data/logs.db -------------------------------------------------------------------------------- /static/css/input.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ["./views/**/*.templ"], 3 | theme: { 4 | extend: {} 5 | }, 6 | plugins: [] 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { "tailwindcss": "latest" }, 3 | "devDependencies": { 4 | "@tailwindcss/forms": "^0.5.9" 5 | } 6 | } -------------------------------------------------------------------------------- /views/components/Icons.templ: -------------------------------------------------------------------------------- 1 | package components 2 | 3 | templ IconHeart(attrs templ.Attributes) { 4 | 6 | 7 | 8 | } 9 | -------------------------------------------------------------------------------- /internal/handler/handler.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "GoCards/views/layouts" 5 | 6 | "github.com/a-h/templ" 7 | "github.com/labstack/echo/v5" 8 | ) 9 | 10 | func Render(c echo.Context, status int, t templ.Component) error { 11 | //response header 12 | c.Response().Writer.WriteHeader(status) 13 | //response header content type 14 | c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTML) 15 | 16 | isAlpine := c.Request().Header.Get("X-Requested-With") == "AlpineJS" 17 | route := c.Path() 18 | 19 | if !isAlpine { 20 | return layouts.BaseLayout(route). 21 | Render(c.Request().Context(), c.Response().Writer) 22 | } 23 | 24 | //render our templ component 25 | return t.Render(c.Request().Context(), c.Response().Writer) 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | go.work.sum 23 | 24 | # env file 25 | .env 26 | 27 | 28 | # Dependencies 29 | node_modules/ 30 | npm-debug.log 31 | yarn-debug.log* 32 | yarn-error.log* 33 | .pnpm-debug.log* 34 | 35 | # Environment 36 | .env 37 | .env.local 38 | .env.development.local 39 | .env.test.local 40 | .env.production.local 41 | 42 | # Bun 43 | bun.lockb 44 | 45 | # Package managers 46 | package-lock.json 47 | yarn.lock 48 | 49 | # Build outputs 50 | dist/ 51 | build/ 52 | 53 | # IDE 54 | .vscode/ 55 | .idea/ 56 | *.swp 57 | *.swo 58 | 59 | # OS 60 | .DS_Store 61 | Thumbs.db 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ali T. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /views/components/Navbar.templ: -------------------------------------------------------------------------------- 1 | package components 2 | 3 | templ Navbar() { 4 | 5 |
6 | 32 |
33 | 34 | } 35 | -------------------------------------------------------------------------------- /cmd/GoCards/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "GoCards/internal/handler" 5 | "GoCards/views/pages" 6 | "log" 7 | "net/http" 8 | "os" 9 | 10 | "github.com/labstack/echo/v5" 11 | "github.com/pocketbase/pocketbase" 12 | "github.com/pocketbase/pocketbase/apis" 13 | "github.com/pocketbase/pocketbase/core" 14 | ) 15 | 16 | func main() { 17 | app := pocketbase.New() 18 | 19 | app.OnBeforeServe().Add(func(e *core.ServeEvent) error { 20 | 21 | e.Router.GET("/static/*", 22 | apis.StaticDirectoryHandler(os.DirFS("./static"), false)) 23 | 24 | e.Router.GET("/", func(c echo.Context) error { 25 | return handler.Render(c, http.StatusOK, pages.HomePage()) 26 | }) 27 | 28 | e.Router.GET("/dashboard", func(c echo.Context) error { 29 | return handler.Render(c, http.StatusOK, pages.DashboardPage()) 30 | }) 31 | 32 | e.Router.GET("/login", func(c echo.Context) error { 33 | return handler.Render(c, http.StatusOK, pages.LoginPage()) 34 | }) 35 | 36 | e.Router.GET("/signup", func(c echo.Context) error { 37 | return handler.Render(c, http.StatusOK, pages.SignupPage()) 38 | }) 39 | 40 | return nil 41 | }) 42 | 43 | err := app.Start() 44 | if err != nil { 45 | log.Fatal(err) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /views/layouts/BaseLayout.templ: -------------------------------------------------------------------------------- 1 | package layouts 2 | 3 | import "fmt" 4 | import "GoCards/views/components" 5 | import "os" 6 | 7 | templ BaseLayout(route string) { 8 | 9 | 10 | 11 | 12 | 13 | GoCards 14 | 15 | 16 | 17 | 18 | 19 | 20 | 50 | @components.Navbar() 51 |
52 |
53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /views/components/Icons_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package components 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | func IconHeart(attrs templ.Attributes) templ.Component { 12 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 13 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 14 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 15 | return templ_7745c5c3_CtxErr 16 | } 17 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 18 | if !templ_7745c5c3_IsBuffer { 19 | defer func() { 20 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 21 | if templ_7745c5c3_Err == nil { 22 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 23 | } 24 | }() 25 | } 26 | ctx = templ.InitializeContext(ctx) 27 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 28 | if templ_7745c5c3_Var1 == nil { 29 | templ_7745c5c3_Var1 = templ.NopComponent 30 | } 31 | ctx = templ.ClearChildren(ctx) 32 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 41 | if templ_7745c5c3_Err != nil { 42 | return templ_7745c5c3_Err 43 | } 44 | return templ_7745c5c3_Err 45 | }) 46 | } 47 | 48 | var _ = templruntime.GeneratedTemplate 49 | -------------------------------------------------------------------------------- /views/components/Navbar_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package components 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | func Navbar() templ.Component { 12 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 13 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 14 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 15 | return templ_7745c5c3_CtxErr 16 | } 17 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 18 | if !templ_7745c5c3_IsBuffer { 19 | defer func() { 20 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 21 | if templ_7745c5c3_Err == nil { 22 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 23 | } 24 | }() 25 | } 26 | ctx = templ.InitializeContext(ctx) 27 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 28 | if templ_7745c5c3_Var1 == nil { 29 | templ_7745c5c3_Var1 = templ.NopComponent 30 | } 31 | ctx = templ.ClearChildren(ctx) 32 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 33 | if templ_7745c5c3_Err != nil { 34 | return templ_7745c5c3_Err 35 | } 36 | return templ_7745c5c3_Err 37 | }) 38 | } 39 | 40 | var _ = templruntime.GeneratedTemplate 41 | -------------------------------------------------------------------------------- /views/layouts/BaseLayout_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package layouts 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "fmt" 12 | import "GoCards/views/components" 13 | import "os" 14 | 15 | func BaseLayout(route string) templ.Component { 16 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 17 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 18 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 19 | return templ_7745c5c3_CtxErr 20 | } 21 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 22 | if !templ_7745c5c3_IsBuffer { 23 | defer func() { 24 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 25 | if templ_7745c5c3_Err == nil { 26 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 27 | } 28 | }() 29 | } 30 | ctx = templ.InitializeContext(ctx) 31 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 32 | if templ_7745c5c3_Var1 == nil { 33 | templ_7745c5c3_Var1 = templ.NopComponent 34 | } 35 | ctx = templ.ClearChildren(ctx) 36 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("GoCards") 77 | if templ_7745c5c3_Err != nil { 78 | return templ_7745c5c3_Err 79 | } 80 | templ_7745c5c3_Err = components.Navbar().Render(ctx, templ_7745c5c3_Buffer) 81 | if templ_7745c5c3_Err != nil { 82 | return templ_7745c5c3_Err 83 | } 84 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 85 | if templ_7745c5c3_Err != nil { 86 | return templ_7745c5c3_Err 87 | } 88 | return templ_7745c5c3_Err 89 | }) 90 | } 91 | 92 | var _ = templruntime.GeneratedTemplate 93 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module GoCards 2 | 3 | go 1.22.0 4 | 5 | require github.com/pocketbase/pocketbase v0.22.23 6 | 7 | require ( 8 | github.com/AlecAivazis/survey/v2 v2.3.7 // indirect 9 | github.com/a-h/templ v0.2.793 // indirect 10 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect 11 | github.com/aws/aws-sdk-go-v2 v1.32.2 // indirect 12 | github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 // indirect 13 | github.com/aws/aws-sdk-go-v2/config v1.27.31 // indirect 14 | github.com/aws/aws-sdk-go-v2/credentials v1.17.30 // indirect 15 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect 16 | github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.15 // indirect 17 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect 18 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect 19 | github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect 20 | github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 // indirect 21 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect 22 | github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.18 // indirect 23 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect 24 | github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 // indirect 25 | github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1 // indirect 26 | github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect 27 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect 28 | github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect 29 | github.com/aws/smithy-go v1.22.0 // indirect 30 | github.com/disintegration/imaging v1.6.2 // indirect 31 | github.com/domodwyer/mailyak/v3 v3.6.2 // indirect 32 | github.com/dustin/go-humanize v1.0.1 // indirect 33 | github.com/fatih/color v1.17.0 // indirect 34 | github.com/gabriel-vasile/mimetype v1.4.5 // indirect 35 | github.com/ganigeorgiev/fexpr v0.4.1 // indirect 36 | github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect 37 | github.com/goccy/go-json v0.10.3 // indirect 38 | github.com/golang-jwt/jwt/v4 v4.5.0 // indirect 39 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 40 | github.com/google/uuid v1.6.0 // indirect 41 | github.com/googleapis/gax-go/v2 v2.13.0 // indirect 42 | github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect 43 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 44 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect 45 | github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 // indirect 46 | github.com/mattn/go-colorable v0.1.13 // indirect 47 | github.com/mattn/go-isatty v0.0.20 // indirect 48 | github.com/mattn/go-sqlite3 v1.14.22 // indirect 49 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect 50 | github.com/ncruces/go-strftime v0.1.9 // indirect 51 | github.com/pocketbase/dbx v1.10.1 // indirect 52 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect 53 | github.com/spf13/cast v1.7.0 // indirect 54 | github.com/spf13/cobra v1.8.1 // indirect 55 | github.com/spf13/pflag v1.0.5 // indirect 56 | github.com/valyala/bytebufferpool v1.0.0 // indirect 57 | github.com/valyala/fasttemplate v1.2.2 // indirect 58 | go.opencensus.io v0.24.0 // indirect 59 | gocloud.dev v0.39.0 // indirect 60 | golang.org/x/crypto v0.28.0 // indirect 61 | golang.org/x/image v0.19.0 // indirect 62 | golang.org/x/net v0.30.0 // indirect 63 | golang.org/x/oauth2 v0.22.0 // indirect 64 | golang.org/x/sync v0.8.0 // indirect 65 | golang.org/x/sys v0.26.0 // indirect 66 | golang.org/x/term v0.25.0 // indirect 67 | golang.org/x/text v0.19.0 // indirect 68 | golang.org/x/time v0.6.0 // indirect 69 | golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect 70 | google.golang.org/api v0.194.0 // indirect 71 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect 72 | google.golang.org/grpc v1.65.0 // indirect 73 | google.golang.org/protobuf v1.34.2 // indirect 74 | modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a // indirect 75 | modernc.org/libc v1.55.3 // indirect 76 | modernc.org/mathutil v1.6.0 // indirect 77 | modernc.org/memory v1.8.0 // indirect 78 | modernc.org/sqlite v1.32.0 // indirect 79 | modernc.org/strutil v1.2.0 // indirect 80 | modernc.org/token v1.1.0 // indirect 81 | ) 82 | -------------------------------------------------------------------------------- /views/pages/Login.templ: -------------------------------------------------------------------------------- 1 | package pages 2 | 3 | templ LoginPage() { 4 |
24 |
25 |
26 |

Sign in

27 |

28 | Don't have an account yet? 29 | 32 | Sign up here 33 | 34 |

35 |
36 | 37 |
38 | 39 |
40 | 41 |
42 | 43 |
44 | 45 | 50 |
51 | 52 |
53 | 54 | 55 | 56 |
57 |
58 | 59 | Forgot password? 60 |
61 |
62 | 63 | 68 |
69 | 70 |
71 | 72 | 73 | 74 | 81 |
82 | 83 |
84 |
85 |
86 | } 87 | -------------------------------------------------------------------------------- /views/pages/Login_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package pages 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | func LoginPage() templ.Component { 12 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 13 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 14 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 15 | return templ_7745c5c3_CtxErr 16 | } 17 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 18 | if !templ_7745c5c3_IsBuffer { 19 | defer func() { 20 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 21 | if templ_7745c5c3_Err == nil { 22 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 23 | } 24 | }() 25 | } 26 | ctx = templ.InitializeContext(ctx) 27 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 28 | if templ_7745c5c3_Var1 == nil { 29 | templ_7745c5c3_Var1 = templ.NopComponent 30 | } 31 | ctx = templ.ClearChildren(ctx) 32 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Sign in

Don't have an account yet? Sign up here

Please include a valid email address so we can get back to you

8+ characters required

") 33 | if templ_7745c5c3_Err != nil { 34 | return templ_7745c5c3_Err 35 | } 36 | return templ_7745c5c3_Err 37 | }) 38 | } 39 | 40 | var _ = templruntime.GeneratedTemplate 41 | -------------------------------------------------------------------------------- /views/pages/Signup.templ: -------------------------------------------------------------------------------- 1 | package pages 2 | 3 | templ SignupPage() { 4 |
39 |
40 |
41 |

Sign up

42 |

43 | Already have an account? 44 | 47 | Sign in here 48 | 49 |

50 |
51 | 52 |
53 |
54 | 55 |
56 | 57 |
58 | 59 | 64 |
65 | 66 |
67 | 68 | 69 | 70 |
71 | 72 |
73 | 74 | 79 |
80 | 81 |
82 | 83 | 84 | 85 |
86 | 87 |
88 | 89 | 94 |
95 | 96 |
97 | 98 | 99 | 100 | 103 |
104 | 105 |
106 |
107 |
108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Build a Simple Full-stack App with Golang in 2 Hours! 2 | 3 | This repository contains the code for the ["Build a Simple Full-stack App with Golang in 2 Hours!"](https://youtu.be/bem0bdDBs8A) tutorial, showcasing how to build a social interaction app called **GoCards** using the **GOAT Stack** (Go, a-h/templ, Alpine.js, Tailwind CSS) and **PocketBase** as a Backend-as-a-Service (BaaS). Users can sign up, create cards, like cards, and view/read cards created by others. This project is designed for learning and rapid prototyping, *not* for production-ready applications. 4 | 5 | **Project Overview:** 6 | 7 | GoCards leverages the speed and efficiency of Go for server-side rendering with `a-h/templ`, the dynamic capabilities of Alpine.js for user interactions, the styling power of Tailwind CSS, and the simplicity of PocketBase for user authentication, data storage, and real-time capabilities. 8 | 9 | * **Backend:** Go (with server-side rendering using `a-h/templ`), PocketBase v0.22.23 (BaaS) 10 | * **Frontend:** Alpine.js (for dynamic interactions) 11 | * **Styling:** Tailwind CSS 12 | * **Database:** PocketBase (handles user accounts, card data, and likes) 13 | * **Editor:** Neovim (for development) 14 | 15 | **Important Version Note:** 16 | This project uses PocketBase v0.22.23. As PocketBase is still pre-1.0 and undergoes frequent breaking changes, newer versions may cause compatibility issues. Please stick to version 0.22.23 when following this tutorial: 17 | 18 | ```go 19 | require github.com/pocketbase/pocketbase v0.22.23 20 | ``` 21 | 22 | **Important Disclaimer:** 23 | 24 | This project uses a simplified architecture for educational purposes and rapid prototyping. It is *not* suitable for large, complex, or production-ready applications. For those, you'll need a more robust architecture, potentially involving custom backend logic, more sophisticated data modeling, and considerations for scaling and security that go beyond the scope of this tutorial. 25 | 26 | ## Getting Started 27 | 28 | ### Prerequisites 29 | 30 | * [Go](https://go.dev/dl/) (version 1.20 or later recommended) 31 | * [Bun](https://bun.sh/) (for managing JavaScript dependencies) 32 | * [Neovim](https://neovim.io/) (our chosen editor) 33 | * [Git](https://git-scm.com/downloads) 34 | * [fswatch](https://github.com/emcrisostomo/fswatch) 35 | * [templ](https://github.com/a-h/templ) 36 | 37 | ### Usage 38 | 39 | 1. First, create a new directory and clone the Makefile: 40 | 41 | ```bash 42 | mkdir my-gocards 43 | cd my-gocards 44 | curl -O https://raw.githubusercontent.com/morethancoder/gocards/main/Makefile 45 | ``` 46 | 47 | 2. View available commands: 48 | 49 | ```bash 50 | make help 51 | ``` 52 | 53 | This will show all available make commands: 54 | * `make init` → Initialize project 55 | * `make build` → Build project 56 | * `make css` → Generate CSS 57 | * `make serve` → Start server 58 | * `make watch` → Watch for changes 59 | * `make clean` → Clean build files 60 | * `make source` → Load environment variables 61 | * `make sync` → Run browser-sync 62 | * `make test` → Run tests 63 | 64 | 3. Initialize the project: 65 | 66 | ```bash 67 | make init 68 | ``` 69 | 70 | The `make init` command will: 71 | * Check all required dependencies 72 | * Create the project directory structure 73 | * Initialize the Go module 74 | * Set up Tailwind CSS configuration 75 | * Download Alpine.js 76 | 77 | ### Project Structure 78 | 79 | ``` 80 | . 81 | ├── LICENSE 82 | ├── Makefile 83 | ├── build/ # Build outputs 84 | ├── cmd/ 85 | │ └── GoCards/ 86 | │ └── main.go # Main application entry 87 | ├── internal/ # Internal packages 88 | │ ├── handler/ 89 | │ ├── middleware/ 90 | │ ├── model/ 91 | │ ├── service/ 92 | │ └── util/ 93 | ├── static/ # Static assets 94 | │ ├── css/ 95 | │ │ ├── input.css 96 | │ │ └── styles.css 97 | │ └── js/ 98 | │ ├── alpine.min.js 99 | │ └── pocketbase.min.js 100 | ├── views/ # templ templates 101 | │ ├── components/ 102 | │ │ ├── Icons.templ 103 | │ │ └── Navbar.templ 104 | │ ├── layouts/ 105 | │ │ └── BaseLayout.templ 106 | │ └── pages/ 107 | │ ├── Dashboard.templ 108 | │ ├── HomePage.templ 109 | │ ├── Login.templ 110 | │ └── Signup.templ 111 | └── pb_data/ # PocketBase data directory 112 | ├── data.db 113 | ├── logs.db 114 | └── storage/ 115 | ``` 116 | 117 | ### Running the Application 118 | 119 | 1. Start all services: 120 | 121 | ```bash 122 | make serve 123 | ``` 124 | 125 | This command: 126 | * Generates templ files 127 | * Compiles CSS with Tailwind 128 | * Runs the Go server 129 | 130 | 2. Watch for changes during development: 131 | 132 | ```bash 133 | make watch 134 | ``` 135 | 136 | 3. Access the applications: 137 | * Main app: http://localhost:8090 138 | * PocketBase admin: http://localhost:8090/_/ 139 | 140 | ### Development Workflow 141 | 142 | 1. Start the development server with file watching: 143 | ```bash 144 | make watch 145 | ``` 146 | 147 | 2. Make changes in Neovim 148 | 3. The server will automatically rebuild when: 149 | * `.templ` files are modified 150 | * Go files are changed 151 | * CSS is updated 152 | 153 | 4. Run browser-sync for live reload (optional): 154 | ```bash 155 | make sync 156 | ``` 157 | 158 | ### Additional Commands 159 | 160 | * `make css` - Regenerate Tailwind CSS 161 | * `make clean` - Remove built artifacts and generated files 162 | * `make test` - Run the test suite 163 | * `make source` - Load environment variables from .env 164 | * `make build` - Create a production build 165 | 166 | ## Related Resources 167 | 168 | * [Tutorial Video Part 1](https://youtu.be/bem0bdDBs8A) 169 | * More videos coming soon! 170 | 171 | ## Connect With Me 172 | 173 | * Telegram Channel: [AliTahseenDev](https://t.me/+-aFYIKA-ZGU4M2Uy) 174 | * Website: [MoreThanCoder](https://morethancoder.com) 175 | 176 | ## License 177 | 178 | [MIT License](LICENSE) 179 | -------------------------------------------------------------------------------- /views/pages/Signup_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package pages 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | func SignupPage() templ.Component { 12 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 13 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 14 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 15 | return templ_7745c5c3_CtxErr 16 | } 17 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 18 | if !templ_7745c5c3_IsBuffer { 19 | defer func() { 20 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 21 | if templ_7745c5c3_Err == nil { 22 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 23 | } 24 | }() 25 | } 26 | ctx = templ.InitializeContext(ctx) 27 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 28 | if templ_7745c5c3_Var1 == nil { 29 | templ_7745c5c3_Var1 = templ.NopComponent 30 | } 31 | ctx = templ.ClearChildren(ctx) 32 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Sign up

Already have an account? Sign in here

Please include a valid email address so we can get back to you

8+ characters required

Password does not match the password

") 33 | if templ_7745c5c3_Err != nil { 34 | return templ_7745c5c3_Err 35 | } 36 | return templ_7745c5c3_Err 37 | }) 38 | } 39 | 40 | var _ = templruntime.GeneratedTemplate 41 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Tools 2 | GO_BIN := $(shell which go) 3 | BUN_BIN := $(shell which bun) 4 | FSWATCH_BIN := $(shell which fswatch) 5 | TEMPL_BIN := $(shell which templ) 6 | 7 | # Project info 8 | PROJECT_NAME := $(shell basename $(CURDIR)) 9 | STATIC_DIR := static 10 | 11 | # Build configuration 12 | BUILD_DIR := build 13 | MAIN_GO := cmd/$(PROJECT_NAME)/main.go 14 | TEMPL_FILES := $(shell find . -type f -name "*.templ") 15 | TEMPL_GO_FILES := $(TEMPL_FILES:.templ=_templ.go) 16 | 17 | # Simple color scheme 18 | CYAN := \033[36m 19 | DIM := \033[2m 20 | RESET := \033[0m 21 | 22 | # Basic symbols 23 | CHECK := ✓ 24 | ARROW := → 25 | 26 | # URLs and resources 27 | ALPINE_URL := https://cdn.jsdelivr.net/npm/alpinejs@latest/dist/cdn.min.js 28 | 29 | # Simplified Tailwind config focused on templ files 30 | TAILWIND_CONFIG := 'module.exports = {\n\ 31 | content: ["./views/**/*.templ"],\n\ 32 | theme: {\n\ 33 | extend: {}\n\ 34 | },\n\ 35 | plugins: []\n\ 36 | }' 37 | 38 | .PHONY: check-deps init create-dirs setup-go setup-tailwind download-alpine build serve watch clean help templ 39 | 40 | check-deps: 41 | @printf "\n$(CYAN)Checking dependencies$(RESET)\n" 42 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 43 | @test -n "$(GO_BIN)" || (printf "✗ Go not installed\n" && exit 1) 44 | @test -n "$(BUN_BIN)" || (printf "✗ Bun not installed\n" && exit 1) 45 | @test -n "$(FSWATCH_BIN)" || (printf "✗ fswatch not installed\n" && exit 1) 46 | @test -n "$(TEMPL_BIN)" || (printf "✗ templ not installed\n" && exit 1) 47 | @printf "$(CHECK) All dependencies ready\n" 48 | 49 | create-dirs: 50 | @printf "\n$(CYAN)Creating project structure$(RESET)\n" 51 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 52 | @mkdir -p $(STATIC_DIR)/js 53 | @mkdir -p $(STATIC_DIR)/css 54 | @mkdir -p views/{components,layouts,pages} 55 | @mkdir -p internal/{handler,middleware,model,service,util} 56 | @mkdir -p cmd/$(PROJECT_NAME) 57 | @mkdir -p $(BUILD_DIR) 58 | @echo "package main\n\nfunc main() {\n\t// TODO: Initialize your server here\n}" > cmd/$(PROJECT_NAME)/main.go 59 | @echo "package handler" > internal/handler/handler.go 60 | @echo "package middleware" > internal/middleware/middleware.go 61 | @echo "package model" > internal/model/model.go 62 | @echo "package service" > internal/service/service.go 63 | @echo "package util" > internal/util/util.go 64 | @echo "// Base layout component" > views/layouts/BaseLayout.templ 65 | @echo "// Navigation component" > views/components/Navbar.templ 66 | @echo "// Home page component" > views/pages/HomePage.templ 67 | @printf "$(CHECK) Project structure created\n" 68 | 69 | setup-go: 70 | @printf "\n$(CYAN)Initializing Go module$(RESET)\n" 71 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 72 | @$(GO_BIN) mod init $(PROJECT_NAME) 2>/dev/null || true 73 | @$(GO_BIN) mod tidy >/dev/null 2>&1 74 | @printf "$(CHECK) Go modules ready\n" 75 | 76 | setup-tailwind: 77 | @printf "\n$(CYAN)Setting up Tailwind CSS$(RESET)\n" 78 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 79 | @$(BUN_BIN) install tailwindcss@latest >/dev/null 2>&1 80 | @echo $(TAILWIND_CONFIG) > tailwind.config.js 81 | @echo '@tailwind base;\n@tailwind components;\n@tailwind utilities;' > $(STATIC_DIR)/css/input.css 82 | @printf "$(CHECK) Tailwind CSS ready\n" 83 | 84 | download-alpine: 85 | @printf "\n$(CYAN)Downloading Alpine.js$(RESET)\n" 86 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 87 | @mkdir -p $(STATIC_DIR)/js 88 | @curl -s $(ALPINE_URL) -o $(STATIC_DIR)/js/alpine.min.js 89 | @printf "$(CHECK) Alpine.js ready\n" 90 | 91 | build: check-deps 92 | @printf "\n$(CYAN)Building project$(RESET)\n" 93 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 94 | @$(GO_BIN) build -o $(BUILD_DIR)/$(PROJECT_NAME) $(MAIN_GO) 95 | @printf "$(CHECK) Build complete\n" 96 | 97 | templ: 98 | @printf "\n$(CYAN)Generating templ files$(RESET)\n" 99 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 100 | @$(TEMPL_BIN) generate 101 | @printf "$(CHECK) Templ files generated\n" 102 | 103 | css: 104 | @printf "\n$(CYAN)Generating CSS$(RESET)\n" 105 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 106 | @$(BUN_BIN) tailwindcss -i $(STATIC_DIR)/css/input.css -o $(STATIC_DIR)/css/styles.css --minify 107 | @printf "$(CHECK) CSS generated\n" 108 | 109 | serve: templ css 110 | @printf "\n$(CYAN)Starting server$(RESET)\n" 111 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 112 | @$(GO_BIN) run $(MAIN_GO) serve 113 | 114 | watch: 115 | @printf "\n$(CYAN)Watching for changes$(RESET)\n" 116 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 117 | @printf "\n$(CYAN)Rebuilding...$(RESET)\n" 118 | @find views -type f -name "*.templ" | entr -r make serve 119 | 120 | clean: 121 | @printf "\n$(CYAN)Cleaning build files$(RESET)\n" 122 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 123 | @rm -rf $(BUILD_DIR) 124 | @find . -type f -name "*_templ.go" -delete 125 | @printf "$(CHECK) Clean complete\n" 126 | 127 | init: check-deps create-dirs setup-go setup-tailwind download-alpine 128 | @printf "\n$(CHECK) Project setup complete!\n" 129 | 130 | test: 131 | @printf "\n$(CYAN)Running tests$(RESET)\n" 132 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 133 | @$(GO_BIN) test -v -count=1 -cover ./... 134 | 135 | source: 136 | @printf "\n$(CYAN)Loading environment variables (dotenv)$(RESET)\n" 137 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 138 | @export $(cat .env | xargs) 139 | @printf "\n$(CHECK) Environment variables loaded\n" 140 | 141 | sync: 142 | @printf "\n$(CYAN)Running browser-sync$(RESET)\n" 143 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 144 | @browser-sync start --proxy "localhost:8090" --files "views/**/*.templ" 145 | 146 | help: 147 | @printf "\n$(CYAN)Available commands$(RESET)\n" 148 | @printf "$(DIM)────────────────────────────────────$(RESET)\n" 149 | @printf " make init$(RESET) $(ARROW) Initialize project\n" 150 | @printf " make build$(RESET) $(ARROW) Build project\n" 151 | @printf " make css$(RESET) $(ARROW) Generate CSS\n" 152 | @printf " make serve$(RESET) $(ARROW) Start server\n" 153 | @printf " make watch$(RESET) $(ARROW) Watch for changes\n" 154 | @printf " make clean$(RESET) $(ARROW) Clean build files\n" 155 | @printf " make source$(RESET) $(ARROW) Load environment variables\n" 156 | @printf " make sync$(RESET) $(ARROW) run browser-sync\n" 157 | @printf " make test$(RESET) $(ARROW) Run tests\n\n" 158 | 159 | -------------------------------------------------------------------------------- /views/pages/HomePage.templ: -------------------------------------------------------------------------------- 1 | package pages 2 | 3 | import "GoCards/views/components" 4 | 5 | templ HomePage() { 6 | 7 |
12 |
13 | 14 |
15 |

16 | Where Cards Go Places 17 |

18 |
19 | 20 | 21 |
22 |

23 | Get inspired or inpire others :) 24 |

25 |
26 | 27 | 28 | 39 | 40 |
41 |
42 | 43 | 44 | 45 |
46 | 47 |
48 |

The Cards

49 |

Latest

50 |
51 | 52 | 53 | 54 |
80 |
81 | 84 | 87 |
88 | 89 | 90 | 91 |
92 | 101 |
102 |
103 | 104 |
105 | 106 | } 107 | 108 | 109 | 110 | templ Card() { 111 |
168 |
170 |
171 |

174 | Title 175 |

176 |

179 | Content 180 |

181 |
182 |
183 | @components.IconHeart(templ.Attributes{ 184 | "class" : "size-6", 185 | ":class" : "like ? 'fill-red-200' :'' ", 186 | "@click" : "toggleLike()", 187 | "x-show": "verbose || like", 188 | }) 189 | 190 |
191 |
192 |
193 | 194 | } 195 | -------------------------------------------------------------------------------- /views/pages/HomePage_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package pages 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "GoCards/views/components" 12 | 13 | func HomePage() templ.Component { 14 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 15 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 16 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 17 | return templ_7745c5c3_CtxErr 18 | } 19 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 20 | if !templ_7745c5c3_IsBuffer { 21 | defer func() { 22 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 23 | if templ_7745c5c3_Err == nil { 24 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 25 | } 26 | }() 27 | } 28 | ctx = templ.InitializeContext(ctx) 29 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 30 | if templ_7745c5c3_Var1 == nil { 31 | templ_7745c5c3_Var1 = templ.NopComponent 32 | } 33 | ctx = templ.ClearChildren(ctx) 34 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Where Cards Go Places

Get inspired or inpire others :)

The Cards

Latest

") 43 | if templ_7745c5c3_Err != nil { 44 | return templ_7745c5c3_Err 45 | } 46 | return templ_7745c5c3_Err 47 | }) 48 | } 49 | 50 | func Card() templ.Component { 51 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 52 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 53 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 54 | return templ_7745c5c3_CtxErr 55 | } 56 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 57 | if !templ_7745c5c3_IsBuffer { 58 | defer func() { 59 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 60 | if templ_7745c5c3_Err == nil { 61 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 62 | } 63 | }() 64 | } 65 | ctx = templ.InitializeContext(ctx) 66 | templ_7745c5c3_Var2 := templ.GetChildren(ctx) 67 | if templ_7745c5c3_Var2 == nil { 68 | templ_7745c5c3_Var2 = templ.NopComponent 69 | } 70 | ctx = templ.ClearChildren(ctx) 71 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Title

Content

") 72 | if templ_7745c5c3_Err != nil { 73 | return templ_7745c5c3_Err 74 | } 75 | templ_7745c5c3_Err = components.IconHeart(templ.Attributes{ 76 | "class": "size-6", 77 | ":class": "like ? 'fill-red-200' :'' ", 78 | "@click": "toggleLike()", 79 | "x-show": "verbose || like", 80 | }).Render(ctx, templ_7745c5c3_Buffer) 81 | if templ_7745c5c3_Err != nil { 82 | return templ_7745c5c3_Err 83 | } 84 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 85 | if templ_7745c5c3_Err != nil { 86 | return templ_7745c5c3_Err 87 | } 88 | return templ_7745c5c3_Err 89 | }) 90 | } 91 | 92 | var _ = templruntime.GeneratedTemplate 93 | -------------------------------------------------------------------------------- /views/pages/Dashboard.templ: -------------------------------------------------------------------------------- 1 | package pages 2 | 3 | templ DashboardPage() { 4 |
20 | 25 |
26 | } 27 | 28 | templ DashboardContent() { 29 | 30 |
31 |
32 | 33 |
34 |

35 | Welcome to the Dashboard 36 |

37 |
38 | 39 | 40 |
41 |

43 |

44 |
45 | 46 | 47 |
48 | 53 |
54 | 55 |
56 |
57 | 58 | 59 | 60 |
61 | 62 |
63 |

My Cards

64 |

Latest

65 |
66 | 67 | 68 | 69 |
100 |
101 | @CreateCard() 102 | 105 | 108 |
109 | 110 | 111 |
112 | 121 |
122 | 123 | 124 |
125 | 126 |
127 | 128 | } 129 | 130 | templ DashboardCard() { 131 |
179 |
181 | 182 |
183 | 184 | 185 |
186 |
187 |

190 | Title 191 |

192 |

195 | Content 196 |

197 |
198 | 199 |
200 | 203 | 204 | 206 |
207 |
208 |
209 | 210 | } 211 | 212 | 213 | templ CreateCard() { 214 | 215 |
245 | 246 | 250 | 251 |
252 | 253 |
254 |
255 | 256 | 259 |
260 |
261 | 262 | 265 |
266 |
267 | 268 |
269 | 272 | 273 | 275 |
276 |
277 |
278 | 279 | } 280 | 281 | -------------------------------------------------------------------------------- /views/pages/Dashboard_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package pages 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | func DashboardPage() templ.Component { 12 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 13 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 14 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 15 | return templ_7745c5c3_CtxErr 16 | } 17 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 18 | if !templ_7745c5c3_IsBuffer { 19 | defer func() { 20 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 21 | if templ_7745c5c3_Err == nil { 22 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 23 | } 24 | }() 25 | } 26 | ctx = templ.InitializeContext(ctx) 27 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 28 | if templ_7745c5c3_Var1 == nil { 29 | templ_7745c5c3_Var1 = templ.NopComponent 30 | } 31 | ctx = templ.ClearChildren(ctx) 32 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 41 | if templ_7745c5c3_Err != nil { 42 | return templ_7745c5c3_Err 43 | } 44 | return templ_7745c5c3_Err 45 | }) 46 | } 47 | 48 | func DashboardContent() templ.Component { 49 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 50 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 51 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 52 | return templ_7745c5c3_CtxErr 53 | } 54 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 55 | if !templ_7745c5c3_IsBuffer { 56 | defer func() { 57 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 58 | if templ_7745c5c3_Err == nil { 59 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 60 | } 61 | }() 62 | } 63 | ctx = templ.InitializeContext(ctx) 64 | templ_7745c5c3_Var2 := templ.GetChildren(ctx) 65 | if templ_7745c5c3_Var2 == nil { 66 | templ_7745c5c3_Var2 = templ.NopComponent 67 | } 68 | ctx = templ.ClearChildren(ctx) 69 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Welcome to the Dashboard

My Cards

Latest

") 70 | if templ_7745c5c3_Err != nil { 71 | return templ_7745c5c3_Err 72 | } 73 | templ_7745c5c3_Err = CreateCard().Render(ctx, templ_7745c5c3_Buffer) 74 | if templ_7745c5c3_Err != nil { 75 | return templ_7745c5c3_Err 76 | } 77 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 86 | if templ_7745c5c3_Err != nil { 87 | return templ_7745c5c3_Err 88 | } 89 | return templ_7745c5c3_Err 90 | }) 91 | } 92 | 93 | func DashboardCard() templ.Component { 94 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 95 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 96 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 97 | return templ_7745c5c3_CtxErr 98 | } 99 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 100 | if !templ_7745c5c3_IsBuffer { 101 | defer func() { 102 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 103 | if templ_7745c5c3_Err == nil { 104 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 105 | } 106 | }() 107 | } 108 | ctx = templ.InitializeContext(ctx) 109 | templ_7745c5c3_Var3 := templ.GetChildren(ctx) 110 | if templ_7745c5c3_Var3 == nil { 111 | templ_7745c5c3_Var3 = templ.NopComponent 112 | } 113 | ctx = templ.ClearChildren(ctx) 114 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Title

Content

") 115 | if templ_7745c5c3_Err != nil { 116 | return templ_7745c5c3_Err 117 | } 118 | return templ_7745c5c3_Err 119 | }) 120 | } 121 | 122 | func CreateCard() templ.Component { 123 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 124 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 125 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 126 | return templ_7745c5c3_CtxErr 127 | } 128 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 129 | if !templ_7745c5c3_IsBuffer { 130 | defer func() { 131 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 132 | if templ_7745c5c3_Err == nil { 133 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 134 | } 135 | }() 136 | } 137 | ctx = templ.InitializeContext(ctx) 138 | templ_7745c5c3_Var4 := templ.GetChildren(ctx) 139 | if templ_7745c5c3_Var4 == nil { 140 | templ_7745c5c3_Var4 = templ.NopComponent 141 | } 142 | ctx = templ.ClearChildren(ctx) 143 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") 144 | if templ_7745c5c3_Err != nil { 145 | return templ_7745c5c3_Err 146 | } 147 | return templ_7745c5c3_Err 148 | }) 149 | } 150 | 151 | var _ = templruntime.GeneratedTemplate 152 | -------------------------------------------------------------------------------- /static/css/styles.css: -------------------------------------------------------------------------------- 1 | *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.14 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.pointer-events-none{pointer-events:none}.\!visible{visibility:visible!important}.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.end-0{inset-inline-end:0}.end-2{inset-inline-end:.5rem}.top-0{top:0}.top-2{top:.5rem}.z-50{z-index:50}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-10{margin-bottom:2.5rem}.mb-2{margin-bottom:.5rem}.mt-1{margin-top:.25rem}.mt-12{margin-top:3rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-7{margin-top:1.75rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[3\/4\]{aspect-ratio:3/4}.size-5{width:1.25rem;height:1.25rem}.size-6{width:1.5rem;height:1.5rem}.h-full{height:100%}.min-h-12{min-height:3rem}.min-h-36{min-height:9rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-\[85rem\]{max-width:85rem}.max-w-screen-lg{max-width:1024px}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.flex-none{flex:none}.resize-none{resize:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-3{gap:.75rem}.gap-6{gap:1.5rem}.gap-x-1{-moz-column-gap:.25rem;column-gap:.25rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-4{row-gap:1rem}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-\[2rem\]{border-radius:2rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-800{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity))}.border-transparent{border-color:transparent}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-gradient-to-tl{background-image:linear-gradient(to top left,var(--tw-gradient-stops))}.from-blue-600{--tw-gradient-from:#2563eb var(--tw-gradient-from-position);--tw-gradient-to:rgba(37,99,235,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-blue-600{--tw-gradient-to:#2563eb var(--tw-gradient-to-position)}.fill-red-200{fill:#fecaca}.p-1\.5{padding:.375rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-10{padding-bottom:2.5rem}.pe-3{padding-inline-end:.75rem}.pt-24{padding-top:6rem}.pt-5{padding-top:1.25rem}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.decoration-2{text-decoration-thickness:2px}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:start-1\/2:before{content:var(--tw-content);inset-inline-start:50%}.before\:top-0:before{content:var(--tw-content);top:0}.before\:-z-\[1\]:before{content:var(--tw-content);z-index:-1}.before\:size-full:before{content:var(--tw-content);width:100%;height:100%}.before\:-translate-x-1\/2:before{--tw-translate-x:-50%}.before\:-translate-x-1\/2:before,.before\:transform:before{content:var(--tw-content);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.before\:bg-\[url\(\'https\:\/\/preline\.co\/assets\/svg\/examples\/squared-bg-element\.svg\'\)\]:before{content:var(--tw-content);background-image:url(https://preline.co/assets/svg/examples/squared-bg-element.svg)}.before\:bg-top:before{content:var(--tw-content);background-position:top}.before\:bg-no-repeat:before{content:var(--tw-content);background-repeat:no-repeat}.hover\:border-transparent:hover{border-color:transparent}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.hover\:from-blue-600:hover{--tw-gradient-from:#2563eb var(--tw-gradient-from-position);--tw-gradient-to:rgba(37,99,235,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.hover\:to-blue-600:hover{--tw-gradient-to:#2563eb var(--tw-gradient-to-position)}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:border-blue-500:focus{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity))}.focus\:border-transparent:focus{border-color:transparent}.focus\:bg-blue-700:focus{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity))}.focus\:bg-gray-50:focus{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.focus\:from-blue-600:focus{--tw-gradient-from:#2563eb var(--tw-gradient-from-position);--tw-gradient-to:rgba(37,99,235,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.focus\:to-blue-600:focus{--tw-gradient-to:#2563eb var(--tw-gradient-to-position)}.focus\:underline:focus{text-decoration-line:underline}.focus\:opacity-80:focus{opacity:.8}.focus\:shadow-lg:focus{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:p-7{padding:1.75rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media (min-width:768px){.md\:mx-auto{margin-left:auto;margin-right:auto}.md\:flex{display:flex}.md\:flex-nowrap{flex-wrap:nowrap}.md\:items-center{align-items:center}.md\:justify-start{justify-content:flex-start}.md\:justify-between{justify-content:space-between}.md\:px-0{padding-left:0;padding-right:0}.md\:px-1{padding-left:.25rem;padding-right:.25rem}.md\:px-4{padding-left:1rem;padding-right:1rem}.md\:py-0{padding-top:0;padding-bottom:0}.md\:py-3{padding-top:.75rem;padding-bottom:.75rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:leading-tight{line-height:1.25}}@media (min-width:1024px){.lg\:mb-14{margin-bottom:3.5rem}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-14{padding-top:3.5rem;padding-bottom:3.5rem}.lg\:text-6xl{font-size:3.75rem;line-height:1}} -------------------------------------------------------------------------------- /static/js/pocketbase.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).PocketBase=t()}(this,(function(){"use strict";class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieSerialize(t,s,i){const n=Object.assign({},i||{}),o=n.encode||defaultEncode;if(!e.test(t))throw new TypeError("argument name is invalid");const r=o(s);if(r&&!e.test(r))throw new TypeError("argument val is invalid");let a=t+"="+r;if(null!=n.maxAge){const e=n.maxAge-0;if(isNaN(e)||!isFinite(e))throw new TypeError("option maxAge is invalid");a+="; Max-Age="+Math.floor(e)}if(n.domain){if(!e.test(n.domain))throw new TypeError("option domain is invalid");a+="; Domain="+n.domain}if(n.path){if(!e.test(n.path))throw new TypeError("option path is invalid");a+="; Path="+n.path}if(n.expires){if(!function isDate(e){return"[object Date]"===Object.prototype.toString.call(e)||e instanceof Date}(n.expires)||isNaN(n.expires.valueOf()))throw new TypeError("option expires is invalid");a+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(a+="; HttpOnly"),n.secure&&(a+="; Secure"),n.priority){switch("string"==typeof n.priority?n.priority.toLowerCase():n.priority){case"low":a+="; Priority=Low";break;case"medium":a+="; Priority=Medium";break;case"high":a+="; Priority=High";break;default:throw new TypeError("option priority is invalid")}}if(n.sameSite){switch("string"==typeof n.sameSite?n.sameSite.toLowerCase():n.sameSite){case!0:a+="; SameSite=Strict";break;case"lax":a+="; SameSite=Lax";break;case"strict":a+="; SameSite=Strict";break;case"none":a+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}}return a}function defaultDecode(e){return-1!==e.indexOf("%")?decodeURIComponent(e):e}function defaultEncode(e){return encodeURIComponent(e)}const t="undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal;let s;function getTokenPayload(e){if(e)try{const t=decodeURIComponent(s(e.split(".")[1]).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));return JSON.parse(t)||{}}catch(e){}return{}}function isTokenExpired(e,t=0){let s=getTokenPayload(e);return!(Object.keys(s).length>0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,o=0,r="";i=t.charAt(o++);~i&&(s=n%4?64*s+i:i,n++%4)?r+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return r}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isAdmin(){return"admin"===getTokenPayload(this.token).type}get isAuthRecord(){return"authRecord"===getTokenPayload(this.token).type}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},t||{}).decode||defaultDecode;let n=0;for(;n4096){o.model={id:o?.model?.id,email:o?.model?.email};const s=["collectionId","username","verified"];for(const e in this.model)s.includes(e)&&(o.model[e]=this.model[e]);r=cookieSerialize(t,JSON.stringify(o),e)}return r}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.model),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.model)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get model(){return(this._storageGet(this.storageKey)||{}).model||null}save(e,t){this._storageSet(this.storageKey,{token:e,model:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s){return s=Object.assign({method:"POST",body:{email:e,template:t}},s),this.client.send("/api/settings/test/email",s).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,o){return o=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},o),this.client.send("/api/settings/apple/generate-client-secret",o)}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildUrl(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class AdminService extends CrudService{get baseCrudPath(){return"/api/admins"}async update(e,t,s){return super.update(e,t,s).then((e=>(this.client.authStore.model?.id===e.id&&void 0===this.client.authStore.model?.collectionId&&this.client.authStore.save(this.client.authStore.token,e),e)))}async delete(e,t){return super.delete(e,t).then((t=>(t&&this.client.authStore.model?.id===e&&void 0===this.client.authStore.model?.collectionId&&this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.admin||{});return e?.token&&e?.admin&&this.client.authStore.save(e.token,t),Object.assign({},e,{token:e?.token||"",admin:t})}async authWithPassword(e,t,s,i){let n={method:"POST",body:{identity:e,password:t}};n=normalizeLegacyOptionsArgs("This form of authWithPassword(email, pass, body?, query?) is deprecated. Consider replacing it with authWithPassword(email, pass, options?).",n,s,i);const o=n.autoRefreshThreshold;delete n.autoRefreshThreshold,n.autoRefresh||resetAutoRefresh(this.client);let r=await this.client.send(this.baseCrudPath+"/auth-with-password",n);return r=this.authResponse(r),o&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,o=e.authStore.model,r=e.authStore.onChange(((t,s)=>{(!t||s?.id!=o?.id||(s?.collectionId||o?.collectionId)&&s?.collectionId!=o?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){r(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(o,r)=>{const a=e.authStore.token;if(r.query?.autoRefresh)return n?n(o,r):{url:o,sendOptions:r};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=r.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return r.headers=l,n?n(o,r):{url:o,sendOptions:r}}}(this.client,o,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},n)))),r}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCrudPath+"/auth-refresh",s).then(this.authResponse.bind(this))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCrudPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let o={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return o=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(resetToken, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(resetToken, password, passwordConfirm, options?).",o,i,n),this.client.send(this.baseCrudPath+"/confirm-password-reset",o).then((()=>!0))}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildUrl("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>(this.client.authStore.model?.id!==e?.id||this.client.authStore.model?.collectionId!==this.collectionIdOrName&&this.client.authStore.model?.collectionName!==this.collectionIdOrName||this.client.authStore.save(this.client.authStore.token,e),e)))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.model?.id!==e||this.client.authStore.model?.collectionId!==this.collectionIdOrName&&this.client.authStore.model?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e).then((e=>Object.assign({},e,{usernamePassword:!!e?.usernamePassword,emailPassword:!!e?.emailPassword,authProviders:Array.isArray(e?.authProviders)?e?.authProviders:[]})))}async authWithPassword(e,t,s,i){let n={method:"POST",body:{identity:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of authWithPassword(usernameOrEmail, pass, body?, query?) is deprecated. Consider replacing it with authWithPassword(usernameOrEmail, pass, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/auth-with-password",n).then((e=>this.authResponse(e)))}async authWithOAuth2Code(e,t,s,i,n,o,r){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectUrl:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectUrl, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectUrl, createData?, options?).",a,o,r),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},o=t.requestKey;return o&&(n.requestKey=o),this.listAuthMethods(n).then((e=>{const n=e.authProviders.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const r=this.client.buildUrl("/api/oauth2-redirect"),a=o?this.client.cancelControllers?.[o]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,o)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const o=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,r,t.createData,i);e(o)}catch(e){o(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authUrl+r,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),o(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let o={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return o=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",o,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",o).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.model;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.model;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/external-auths",t)}async unlinkExternalAuth(e,t,s){return s=Object.assign({method:"DELETE"},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/external-auths/"+encodeURIComponent(t),s).then((()=>!0))}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},o=i.split("&");for(const e of o){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let o=i/2-t/2,r=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+r+",left="+o+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildUrl("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildUrl(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return this.client.buildUrl(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}return class Client{constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseUrl=e,this.lang=s,this.authStore=t||new LocalAuthStore,this.admins=new AdminService(this),this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return this.files.getUrl(e,t,s)}buildUrl(e){let t=this.baseUrl;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseUrl.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseUrl),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildUrl(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=this.serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let t={};try{t=await e.json()}catch(e){}if(this.afterSend&&(t=await this.afterSend(e,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:t});return t})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=this.convertToFormDataIfNeeded(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||this.isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||this.isFormData(e)||!this.hasBlobField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||this.hasBlobField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}hasBlobField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if("undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File)return!0}return!1}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}}})); 2 | //# sourceMappingURL=pocketbase.umd.js.map 3 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= 3 | cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= 4 | cloud.google.com/go/auth v0.9.1 h1:+pMtLEV2k0AXKvs/tGZojuj6QaioxfUjOpMsG5Gtx+w= 5 | cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk= 6 | cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= 7 | cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= 8 | cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= 9 | cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= 10 | cloud.google.com/go/iam v1.1.13 h1:7zWBXG9ERbMLrzQBRhFliAV+kjcRToDTgQT3CTwYyv4= 11 | cloud.google.com/go/iam v1.1.13/go.mod h1:K8mY0uSXwEXS30KrnVb+j54LB/ntfZu1dr+4zFMNbus= 12 | cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= 13 | cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= 14 | filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= 15 | filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 16 | github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= 17 | github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= 18 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 19 | github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= 20 | github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= 21 | github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= 22 | github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= 23 | github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= 24 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= 25 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= 26 | github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= 27 | github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= 28 | github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= 29 | github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= 30 | github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU= 31 | github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw= 32 | github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI= 33 | github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM= 34 | github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= 35 | github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= 36 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= 37 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= 38 | github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.15 h1:ijB7hr56MngOiELJe0C5aQRaBQ11LveNgWFyG02AUto= 39 | github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.15/go.mod h1:0QEmQSSWMVfiAk93l1/ayR9DQ9+jwni7gHS2NARZXB0= 40 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= 41 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= 42 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= 43 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= 44 | github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= 45 | github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= 46 | github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 h1:mimdLQkIX1zr8GIPY1ZtALdBQGxcASiBd2MOp8m/dMc= 47 | github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16/go.mod h1:YHk6owoSwrIsok+cAH9PENCOGoH5PU2EllX4vLtSrsY= 48 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= 49 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= 50 | github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.18 h1:GckUnpm4EJOAio1c8o25a+b3lVfwVzC9gnSBqiiNmZM= 51 | github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.18/go.mod h1:Br6+bxfG33Dk3ynmkhsW2Z/t9D4+lRqdLDNCKi85w0U= 52 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ= 53 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= 54 | github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 h1:jg16PhLPUiHIj8zYIW6bqzeQSuHVEiWnGA0Brz5Xv2I= 55 | github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16/go.mod h1:Uyk1zE1VVdsHSU7096h/rwnXDzOzYQVl+FNPhPw7ShY= 56 | github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1 h1:mx2ucgtv+MWzJesJY9Ig/8AFHgoE5FwLXwUVgW/FGdI= 57 | github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= 58 | github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= 59 | github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= 60 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= 61 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= 62 | github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= 63 | github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= 64 | github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= 65 | github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= 66 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 67 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 68 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 69 | github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 70 | github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= 71 | github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 72 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 73 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 74 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 75 | github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= 76 | github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= 77 | github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8= 78 | github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c= 79 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 80 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 81 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 82 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 83 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 84 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 85 | github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= 86 | github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= 87 | github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 88 | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 89 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 90 | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 91 | github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= 92 | github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= 93 | github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k= 94 | github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE= 95 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 96 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 97 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 98 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 99 | github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= 100 | github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= 101 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 102 | github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= 103 | github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= 104 | github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= 105 | github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= 106 | github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= 107 | github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= 108 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 109 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 110 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 111 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 112 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 113 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 114 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 115 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 116 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 117 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 118 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 119 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 120 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 121 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 122 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 123 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 124 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 125 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 126 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 127 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 128 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 129 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 130 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 131 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 132 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 133 | github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= 134 | github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= 135 | github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= 136 | github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= 137 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 138 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 139 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 140 | github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= 141 | github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= 142 | github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= 143 | github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= 144 | github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= 145 | github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= 146 | github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= 147 | github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 148 | github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= 149 | github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= 150 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 151 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 152 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 153 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 154 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= 155 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 156 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 157 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 158 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 159 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 160 | github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 h1:FwuzbVh87iLiUQj1+uQUsuw9x5t9m5n5g7rG7o4svW4= 161 | github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61/go.mod h1:paQfF1YtHe+GrGg5fOgjsjoCX/UKDr9bc1DoWpZfns8= 162 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 163 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 164 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 165 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 166 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 167 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 168 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 169 | github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= 170 | github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 171 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 172 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= 173 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 174 | github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= 175 | github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= 176 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 177 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 178 | github.com/pocketbase/dbx v1.10.1 h1:cw+vsyfCJD8YObOVeqb93YErnlxwYMkNZ4rwN0G0AaA= 179 | github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs= 180 | github.com/pocketbase/pocketbase v0.22.23 h1:cnjSiBcMf7VIhXmoBmZCAV8qKYkOubHCOQQPZMKFBAk= 181 | github.com/pocketbase/pocketbase v0.22.23/go.mod h1:h2ojT2pqBWH9LLl1aiawkwXiICKtzZA/kjM/8VhydR4= 182 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 183 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 184 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 185 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 186 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 187 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 188 | github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= 189 | github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 190 | github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= 191 | github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 192 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 193 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 194 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 195 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 196 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 197 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 198 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 199 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 200 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 201 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 202 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 203 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 204 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 205 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 206 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= 207 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 208 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 209 | go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= 210 | go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 211 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= 212 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= 213 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= 214 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= 215 | go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= 216 | go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= 217 | go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= 218 | go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= 219 | go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= 220 | go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= 221 | gocloud.dev v0.39.0 h1:EYABYGhAalPUaMrbSKOr5lejxoxvXj99nE8XFtsDgds= 222 | gocloud.dev v0.39.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ= 223 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 224 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 225 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 226 | golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= 227 | golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= 228 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 229 | golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 230 | golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ= 231 | golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys= 232 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 233 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 234 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 235 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 236 | golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= 237 | golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 238 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 239 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 240 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 241 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 242 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 243 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 244 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 245 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 246 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 247 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 248 | golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= 249 | golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= 250 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 251 | golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= 252 | golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 253 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 254 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 255 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 256 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 257 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 258 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 259 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 260 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 261 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 262 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 263 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 264 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 265 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 266 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 267 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 268 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 269 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 270 | golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= 271 | golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 272 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 273 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 274 | golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= 275 | golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= 276 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 277 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 278 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 279 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 280 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 281 | golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= 282 | golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 283 | golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= 284 | golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 285 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 286 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 287 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 288 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 289 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 290 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 291 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 292 | golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= 293 | golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= 294 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 295 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 296 | golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk= 297 | golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 298 | google.golang.org/api v0.194.0 h1:dztZKG9HgtIpbI35FhfuSNR/zmaMVdxNlntHj1sIS4s= 299 | google.golang.org/api v0.194.0/go.mod h1:AgvUFdojGANh3vI+P7EVnxj3AISHllxGCJSFmggmnd0= 300 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 301 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 302 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 303 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 304 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 305 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 306 | google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142 h1:oLiyxGgE+rt22duwci1+TG7bg2/L1LQsXwfjPlmuJA0= 307 | google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142/go.mod h1:G11eXq53iI5Q+kyNOmCvnzBaxEA2Q/Ik5Tj7nqBE8j4= 308 | google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk= 309 | google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM= 310 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg= 311 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= 312 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 313 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 314 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 315 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 316 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 317 | google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= 318 | google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= 319 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 320 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 321 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 322 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 323 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 324 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 325 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 326 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 327 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 328 | google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= 329 | google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 330 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 331 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 332 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 333 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 334 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 335 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 336 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 337 | modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= 338 | modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= 339 | modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= 340 | modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= 341 | modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= 342 | modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= 343 | modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= 344 | modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= 345 | modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a h1:CfbpOLEo2IwNzJdMvE8aiRbPMxoTpgAJeyePh0SmO8M= 346 | modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= 347 | modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= 348 | modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= 349 | modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= 350 | modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= 351 | modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= 352 | modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= 353 | modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= 354 | modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= 355 | modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= 356 | modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= 357 | modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= 358 | modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= 359 | modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= 360 | modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= 361 | modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= 362 | modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= 363 | -------------------------------------------------------------------------------- /static/js/alpine.min.js: -------------------------------------------------------------------------------- 1 | (()=>{var nt=!1,it=!1,W=[],ot=-1;function Ut(e){Rn(e)}function Rn(e){W.includes(e)||W.push(e),Mn()}function Wt(e){let t=W.indexOf(e);t!==-1&&t>ot&&W.splice(t,1)}function Mn(){!it&&!nt&&(nt=!0,queueMicrotask(Nn))}function Nn(){nt=!1,it=!0;for(let e=0;ee.effect(t,{scheduler:r=>{st?Ut(r):r()}}),at=e.raw}function ct(e){N=e}function Yt(e){let t=()=>{};return[n=>{let i=N(n);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),$(i))},i},()=>{t()}]}function Se(e,t){let r=!0,n,i=N(()=>{let o=e();JSON.stringify(o),r?n=o:queueMicrotask(()=>{t(o,n),n=o}),r=!1});return()=>$(i)}var Xt=[],Zt=[],Qt=[];function er(e){Qt.push(e)}function te(e,t){typeof t=="function"?(e._x_cleanups||(e._x_cleanups=[]),e._x_cleanups.push(t)):(t=e,Zt.push(t))}function Ae(e){Xt.push(e)}function Oe(e,t,r){e._x_attributeCleanups||(e._x_attributeCleanups={}),e._x_attributeCleanups[t]||(e._x_attributeCleanups[t]=[]),e._x_attributeCleanups[t].push(r)}function lt(e,t){e._x_attributeCleanups&&Object.entries(e._x_attributeCleanups).forEach(([r,n])=>{(t===void 0||t.includes(r))&&(n.forEach(i=>i()),delete e._x_attributeCleanups[r])})}function tr(e){for(e._x_effects?.forEach(Wt);e._x_cleanups?.length;)e._x_cleanups.pop()()}var ut=new MutationObserver(mt),ft=!1;function ue(){ut.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),ft=!0}function dt(){Dn(),ut.disconnect(),ft=!1}var le=[];function Dn(){let e=ut.takeRecords();le.push(()=>e.length>0&&mt(e));let t=le.length;queueMicrotask(()=>{if(le.length===t)for(;le.length>0;)le.shift()()})}function m(e){if(!ft)return e();dt();let t=e();return ue(),t}var pt=!1,ve=[];function rr(){pt=!0}function nr(){pt=!1,mt(ve),ve=[]}function mt(e){if(pt){ve=ve.concat(e);return}let t=new Set,r=new Set,n=new Map,i=new Map;for(let o=0;os.nodeType===1&&t.add(s)),e[o].removedNodes.forEach(s=>s.nodeType===1&&r.add(s))),e[o].type==="attributes")){let s=e[o].target,a=e[o].attributeName,c=e[o].oldValue,l=()=>{n.has(s)||n.set(s,[]),n.get(s).push({name:a,value:s.getAttribute(a)})},u=()=>{i.has(s)||i.set(s,[]),i.get(s).push(a)};s.hasAttribute(a)&&c===null?l():s.hasAttribute(a)?(u(),l()):u()}i.forEach((o,s)=>{lt(s,o)}),n.forEach((o,s)=>{Xt.forEach(a=>a(s,o))});for(let o of r)t.has(o)||Zt.forEach(s=>s(o));t.forEach(o=>{o._x_ignoreSelf=!0,o._x_ignore=!0});for(let o of t)r.has(o)||o.isConnected&&(delete o._x_ignoreSelf,delete o._x_ignore,Qt.forEach(s=>s(o)),o._x_ignore=!0,o._x_ignoreSelf=!0);t.forEach(o=>{delete o._x_ignoreSelf,delete o._x_ignore}),t=null,r=null,n=null,i=null}function Ce(e){return B(F(e))}function D(e,t,r){return e._x_dataStack=[t,...F(r||e)],()=>{e._x_dataStack=e._x_dataStack.filter(n=>n!==t)}}function F(e){return e._x_dataStack?e._x_dataStack:typeof ShadowRoot=="function"&&e instanceof ShadowRoot?F(e.host):e.parentNode?F(e.parentNode):[]}function B(e){return new Proxy({objects:e},Pn)}var Pn={ownKeys({objects:e}){return Array.from(new Set(e.flatMap(t=>Object.keys(t))))},has({objects:e},t){return t==Symbol.unscopables?!1:e.some(r=>Object.prototype.hasOwnProperty.call(r,t)||Reflect.has(r,t))},get({objects:e},t,r){return t=="toJSON"?In:Reflect.get(e.find(n=>Reflect.has(n,t))||{},t,r)},set({objects:e},t,r,n){let i=e.find(s=>Object.prototype.hasOwnProperty.call(s,t))||e[e.length-1],o=Object.getOwnPropertyDescriptor(i,t);return o?.set&&o?.get?o.set.call(n,r)||!0:Reflect.set(i,t,r)}};function In(){return Reflect.ownKeys(this).reduce((t,r)=>(t[r]=Reflect.get(this,r),t),{})}function Te(e){let t=n=>typeof n=="object"&&!Array.isArray(n)&&n!==null,r=(n,i="")=>{Object.entries(Object.getOwnPropertyDescriptors(n)).forEach(([o,{value:s,enumerable:a}])=>{if(a===!1||s===void 0||typeof s=="object"&&s!==null&&s.__v_skip)return;let c=i===""?o:`${i}.${o}`;typeof s=="object"&&s!==null&&s._x_interceptor?n[o]=s.initialize(e,c,o):t(s)&&s!==n&&!(s instanceof Element)&&r(s,c)})};return r(e)}function Re(e,t=()=>{}){let r={initialValue:void 0,_x_interceptor:!0,initialize(n,i,o){return e(this.initialValue,()=>kn(n,i),s=>ht(n,i,s),i,o)}};return t(r),n=>{if(typeof n=="object"&&n!==null&&n._x_interceptor){let i=r.initialize.bind(r);r.initialize=(o,s,a)=>{let c=n.initialize(o,s,a);return r.initialValue=c,i(o,s,a)}}else r.initialValue=n;return r}}function kn(e,t){return t.split(".").reduce((r,n)=>r[n],e)}function ht(e,t,r){if(typeof t=="string"&&(t=t.split(".")),t.length===1)e[t[0]]=r;else{if(t.length===0)throw error;return e[t[0]]||(e[t[0]]={}),ht(e[t[0]],t.slice(1),r)}}var ir={};function y(e,t){ir[e]=t}function fe(e,t){let r=Ln(t);return Object.entries(ir).forEach(([n,i])=>{Object.defineProperty(e,`$${n}`,{get(){return i(t,r)},enumerable:!1})}),e}function Ln(e){let[t,r]=_t(e),n={interceptor:Re,...t};return te(e,r),n}function or(e,t,r,...n){try{return r(...n)}catch(i){re(i,e,t)}}function re(e,t,r=void 0){e=Object.assign(e??{message:"No error message given."},{el:t,expression:r}),console.warn(`Alpine Expression Error: ${e.message} 2 | 3 | ${r?'Expression: "'+r+`" 4 | 5 | `:""}`,t),setTimeout(()=>{throw e},0)}var Me=!0;function De(e){let t=Me;Me=!1;let r=e();return Me=t,r}function R(e,t,r={}){let n;return x(e,t)(i=>n=i,r),n}function x(...e){return sr(...e)}var sr=xt;function ar(e){sr=e}function xt(e,t){let r={};fe(r,e);let n=[r,...F(e)],i=typeof t=="function"?$n(n,t):Fn(n,t,e);return or.bind(null,e,t,i)}function $n(e,t){return(r=()=>{},{scope:n={},params:i=[]}={})=>{let o=t.apply(B([n,...e]),i);Ne(r,o)}}var gt={};function jn(e,t){if(gt[e])return gt[e];let r=Object.getPrototypeOf(async function(){}).constructor,n=/^[\n\s]*if.*\(.*\)/.test(e.trim())||/^(let|const)\s/.test(e.trim())?`(async()=>{ ${e} })()`:e,o=(()=>{try{let s=new r(["__self","scope"],`with (scope) { __self.result = ${n} }; __self.finished = true; return __self.result;`);return Object.defineProperty(s,"name",{value:`[Alpine] ${e}`}),s}catch(s){return re(s,t,e),Promise.resolve()}})();return gt[e]=o,o}function Fn(e,t,r){let n=jn(t,r);return(i=()=>{},{scope:o={},params:s=[]}={})=>{n.result=void 0,n.finished=!1;let a=B([o,...e]);if(typeof n=="function"){let c=n(n,a).catch(l=>re(l,r,t));n.finished?(Ne(i,n.result,a,s,r),n.result=void 0):c.then(l=>{Ne(i,l,a,s,r)}).catch(l=>re(l,r,t)).finally(()=>n.result=void 0)}}}function Ne(e,t,r,n,i){if(Me&&typeof t=="function"){let o=t.apply(r,n);o instanceof Promise?o.then(s=>Ne(e,s,r,n)).catch(s=>re(s,i,t)):e(o)}else typeof t=="object"&&t instanceof Promise?t.then(o=>e(o)):e(t)}var wt="x-";function C(e=""){return wt+e}function cr(e){wt=e}var Pe={};function d(e,t){return Pe[e]=t,{before(r){if(!Pe[r]){console.warn(String.raw`Cannot find directive \`${r}\`. \`${e}\` will use the default order of execution`);return}let n=G.indexOf(r);G.splice(n>=0?n:G.indexOf("DEFAULT"),0,e)}}}function lr(e){return Object.keys(Pe).includes(e)}function pe(e,t,r){if(t=Array.from(t),e._x_virtualDirectives){let o=Object.entries(e._x_virtualDirectives).map(([a,c])=>({name:a,value:c})),s=Et(o);o=o.map(a=>s.find(c=>c.name===a.name)?{name:`x-bind:${a.name}`,value:`"${a.value}"`}:a),t=t.concat(o)}let n={};return t.map(dr((o,s)=>n[o]=s)).filter(mr).map(zn(n,r)).sort(Kn).map(o=>Bn(e,o))}function Et(e){return Array.from(e).map(dr()).filter(t=>!mr(t))}var yt=!1,de=new Map,ur=Symbol();function fr(e){yt=!0;let t=Symbol();ur=t,de.set(t,[]);let r=()=>{for(;de.get(t).length;)de.get(t).shift()();de.delete(t)},n=()=>{yt=!1,r()};e(r),n()}function _t(e){let t=[],r=a=>t.push(a),[n,i]=Yt(e);return t.push(i),[{Alpine:z,effect:n,cleanup:r,evaluateLater:x.bind(x,e),evaluate:R.bind(R,e)},()=>t.forEach(a=>a())]}function Bn(e,t){let r=()=>{},n=Pe[t.type]||r,[i,o]=_t(e);Oe(e,t.original,o);let s=()=>{e._x_ignore||e._x_ignoreSelf||(n.inline&&n.inline(e,t,i),n=n.bind(n,e,t,i),yt?de.get(ur).push(n):n())};return s.runCleanups=o,s}var Ie=(e,t)=>({name:r,value:n})=>(r.startsWith(e)&&(r=r.replace(e,t)),{name:r,value:n}),ke=e=>e;function dr(e=()=>{}){return({name:t,value:r})=>{let{name:n,value:i}=pr.reduce((o,s)=>s(o),{name:t,value:r});return n!==t&&e(n,t),{name:n,value:i}}}var pr=[];function ne(e){pr.push(e)}function mr({name:e}){return hr().test(e)}var hr=()=>new RegExp(`^${wt}([^:^.]+)\\b`);function zn(e,t){return({name:r,value:n})=>{let i=r.match(hr()),o=r.match(/:([a-zA-Z0-9\-_:]+)/),s=r.match(/\.[^.\]]+(?=[^\]]*$)/g)||[],a=t||e[r]||r;return{type:i?i[1]:null,value:o?o[1]:null,modifiers:s.map(c=>c.replace(".","")),expression:n,original:a}}}var bt="DEFAULT",G=["ignore","ref","data","id","anchor","bind","init","for","model","modelable","transition","show","if",bt,"teleport"];function Kn(e,t){let r=G.indexOf(e.type)===-1?bt:e.type,n=G.indexOf(t.type)===-1?bt:t.type;return G.indexOf(r)-G.indexOf(n)}function J(e,t,r={}){e.dispatchEvent(new CustomEvent(t,{detail:r,bubbles:!0,composed:!0,cancelable:!0}))}function P(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>P(i,t));return}let r=!1;if(t(e,()=>r=!0),r)return;let n=e.firstElementChild;for(;n;)P(n,t,!1),n=n.nextElementSibling}function E(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var _r=!1;function gr(){_r&&E("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),_r=!0,document.body||E("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's `