From 21a5524fedf3ed08d0ffdc707a028ee5dbd5e25b Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Fri, 1 May 2026 17:42:55 +0300 Subject: [PATCH] added superuser ips whitelist --- apis/backup.go | 9 +- apis/backup_test.go | 52 +++++ apis/base.go | 1 + apis/batch_test.go | 66 +++++- apis/file.go | 10 + apis/file_test.go | 44 ++++ apis/middlewares.go | 25 +++ apis/middlewares_rate_limit.go | 36 +++ apis/middlewares_test.go | 93 ++++++++ apis/record_helpers.go | 7 + apis/record_helpers_test.go | 36 +++ cmd/superuser.go | 36 +++ cmd/superuser_test.go | 61 +++++ core/base.go | 4 +- core/notify_watcher.go | 210 ++++++++++++++++++ core/notify_watcher_test.go | 185 +++++++++++++++ core/settings_model.go | 17 ++ core/settings_model_test.go | 6 +- core/validators/file.go | 4 +- core/validators/string.go | 28 +++ core/validators/string_test.go | 29 +++ core/validators/validators.go | 7 + ui/.env | 27 +-- .../{index-CsbGEmKA.js => index-B5eik2f8.js} | 13 +- ...{index-e0-DEGQo.css => index-ZC1aK-6Z.css} | 2 +- ui/dist/index.html | 4 +- ui/src/collections/collectionUpsertModal.js | 2 +- ui/src/css/base.css | 4 +- ui/src/pb.js | 8 - ui/src/settings/application/batchAccordion.js | 2 +- .../application/pageApplicationSettings.js | 69 +++++- .../application/rateLimitAccordion.js | 1 - .../application/superuserAccordion.js | 158 +++++++++++++ ui/src/store.js | 15 +- 34 files changed, 1224 insertions(+), 47 deletions(-) create mode 100644 core/notify_watcher.go create mode 100644 core/notify_watcher_test.go rename ui/dist/assets/{index-CsbGEmKA.js => index-B5eik2f8.js} (85%) rename ui/dist/assets/{index-e0-DEGQo.css => index-ZC1aK-6Z.css} (52%) create mode 100644 ui/src/settings/application/superuserAccordion.js diff --git a/apis/backup.go b/apis/backup.go index f1f2eb6e..289a37fc 100644 --- a/apis/backup.go +++ b/apis/backup.go @@ -70,8 +70,10 @@ func backupDownload(e *core.RequestEvent) error { return e.ForbiddenError("Insufficient permissions to access the resource.", err) } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) - defer cancel() + allowedIPs := e.App.Settings().SuperuserIPs + if len(allowedIPs) > 0 && !isIPInList(allowedIPs, e.RealIP()) { + return e.ForbiddenError("Insufficient permissions to access the resource.", nil) + } fsys, err := e.App.NewBackupsFilesystem() if err != nil { @@ -79,6 +81,9 @@ func backupDownload(e *core.RequestEvent) error { } defer fsys.Close() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + defer cancel() + fsys.SetContext(ctx) key := e.Request.PathValue("key") diff --git a/apis/backup_test.go b/apis/backup_test.go index 0bc70985..637ef2df 100644 --- a/apis/backup_test.go +++ b/apis/backup_test.go @@ -528,6 +528,58 @@ func TestBackupsDownload(t *testing.T) { }, ExpectedEvents: map[string]int{"*": 0}, }, + { + Name: "with valid superuser file token AND whitelisted IP", + Method: http.MethodGet, + URL: "/api/backups/test1.zip?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc", + Headers: map[string]string{"x-test-ip": "127.0.0.1"}, + BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) { + if err := createTestBackups(app); err != nil { + t.Fatal(err) + } + + app.Settings().TrustedProxy = core.TrustedProxyConfig{ + Headers: []string{"x-test-ip"}, + } + + app.Settings().SuperuserIPs = []string{"127.0.0.1"} + + if err := app.Save(app.Settings()); err != nil { + t.Fatal(err) + } + }, + ExpectedStatus: 200, + ExpectedContent: []string{ + "storage/", + "data.db", + "auxiliary.db", + }, + ExpectedEvents: map[string]int{"*": 0}, + }, + { + Name: "with valid superuser file token BUT non-whitelisted IP", + Method: http.MethodGet, + URL: "/api/backups/test1.zip?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc", + Headers: map[string]string{"x-test-ip": "127.0.0.1"}, + BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) { + if err := createTestBackups(app); err != nil { + t.Fatal(err) + } + + app.Settings().TrustedProxy = core.TrustedProxyConfig{ + Headers: []string{"x-test-ip"}, + } + + app.Settings().SuperuserIPs = []string{"0.0.0.0"} + + if err := app.Save(app.Settings()); err != nil { + t.Fatal(err) + } + }, + ExpectedStatus: 403, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{"*": 0}, + }, } for _, scenario := range scenarios { diff --git a/apis/base.go b/apis/base.go index c57075d4..b1febc8a 100644 --- a/apis/base.go +++ b/apis/base.go @@ -31,6 +31,7 @@ func NewRouter(app core.App) (*router.Router[*core.RequestEvent], error) { pbRouter.Bind(panicRecover()) pbRouter.Bind(rateLimit()) pbRouter.Bind(loadAuthToken()) + pbRouter.Bind(superuserIPsWhitelist()) pbRouter.Bind(securityHeaders()) pbRouter.Bind(BodyLimit(DefaultMaxBodySize)) diff --git a/apis/batch_test.go b/apis/batch_test.go index 5ec6d44a..566e7886 100644 --- a/apis/batch_test.go +++ b/apis/batch_test.go @@ -224,7 +224,7 @@ func TestBatchRequest(t *testing.T) { }, }, { - Name: "mixed create/update/delete (rules failure)", + Name: "mixed create/update/delete (non-superuser rule failure)", Method: http.MethodPost, URL: "/api/batch", Body: strings.NewReader(`{ @@ -284,6 +284,70 @@ func TestBatchRequest(t *testing.T) { } }, }, + { + Name: "mixed create/update/delete (superuser rule failure)", + Method: http.MethodPost, + URL: "/api/batch", + Headers: map[string]string{ + // test@example.com, clients + "Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImdrMzkwcWVnczR5NDd3biIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoidjg1MXE0cjc5MHJoa25sIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.0ONnm_BsvPRZyDNT31GN1CKUB6uQRxvVvQ-Wc9AZfG0", + }, + Body: strings.NewReader(`{ + "requests": [ + {"method":"DELETE", "url":"/api/collections/demo2/records/achvryl401bhse3", "headers": {"Authorization": "ignored"}}, + {"method":"PATCH", "url":"/api/collections/demo3/records/1tmknxy2868d869", "body": {"title": "batch_update"}, "headers": {"Authorization": "ignored"}}, + {"method":"POST", "url":"/api/collections/_superusers/records", "body": {"email":"test_batch@example.com","password":"1234567890"}} + ] + }`), + ExpectedStatus: 400, + ExpectedContent: []string{ + `"data":{`, + `"requests":{`, + `"2":{"code":"batch_request_failed"`, + `403`, + }, + NotExpectedContent: []string{ + `"0":`, + `"1":`, + }, + ExpectedEvents: map[string]int{ + "*": 0, + "OnBatchRequest": 1, + "OnModelUpdate": 1, + "OnModelUpdateExecute": 1, + "OnModelAfterUpdateError": 1, + "OnModelDelete": 1, + "OnModelDeleteExecute": 1, + "OnModelAfterDeleteError": 1, + "OnModelValidate": 1, + "OnRecordUpdateRequest": 1, + "OnRecordUpdate": 1, + "OnRecordUpdateExecute": 1, + "OnRecordAfterUpdateError": 1, + "OnRecordDeleteRequest": 1, + "OnRecordDelete": 1, + "OnRecordDeleteExecute": 1, + "OnRecordAfterDeleteError": 1, + "OnRecordEnrich": 1, + "OnRecordValidate": 1, + }, + AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) { + _, err = app.FindRecordById("demo2", "achvryl401bhse3") + if err != nil { + t.Fatal("Expected record to not be deleted") + } + + _, err = app.FindFirstRecordByFilter("demo3", `title="batch_update"`) + if err == nil { + t.Fatal("Expected record to not be updated") + } + + _, err = app.FindAuthRecordByEmail(core.CollectionNameSuperusers, "test_batch@example.com") + if err == nil { + t.Fatal("Expected superuser to not be created") + } + }, + }, { Name: "mixed create/update/delete (rules success)", Method: http.MethodPost, diff --git a/apis/file.go b/apis/file.go index f0d2390b..bc340b2c 100644 --- a/apis/file.go +++ b/apis/file.go @@ -60,6 +60,7 @@ type fileApi struct { } func (api *fileApi) fileToken(e *core.RequestEvent) error { + // extra check for just in case the handler is called in a different context if e.Auth == nil { return e.UnauthorizedError("Missing auth context.", nil) } @@ -114,6 +115,15 @@ func (api *fileApi) download(e *core.RequestEvent) error { token := e.Request.URL.Query().Get("token") authRecord, _ := e.App.FindAuthRecordByToken(token, core.TokenTypeFile) + // reset the auth state if it is superuser and it is not whitelisted + // (not critical because file tokens are short-lived but checked nonetheless as an extra precaution) + if authRecord != nil && authRecord.IsSuperuser() { + allowedIPs := e.App.Settings().SuperuserIPs + if len(allowedIPs) > 0 && !isIPInList(allowedIPs, e.RealIP()) { + authRecord = nil + } + } + // create a shallow copy of the cached request data and adjust it to the current auth record (if any) requestInfo := *originalRequestInfo requestInfo.Context = core.RequestInfoContextProtectedFile diff --git a/apis/file_test.go b/apis/file_test.go index daee78f1..59a4c957 100644 --- a/apis/file_test.go +++ b/apis/file_test.go @@ -353,6 +353,50 @@ func TestFileDownload(t *testing.T) { "OnFileDownloadRequest": 1, }, }, + { + Name: "protected file - superuser with non-whitelisted IP", + Method: http.MethodGet, + URL: "/api/files/demo1/al1h9ijdeojtsjy/300_Jsjq7RdBgA.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc", + Headers: map[string]string{"x-test-ip": "127.0.0.1"}, + BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) { + app.Settings().TrustedProxy = core.TrustedProxyConfig{ + Headers: []string{"x-test-ip"}, + } + + app.Settings().SuperuserIPs = []string{"0.0.0.0"} + + err := app.Save(app.Settings()) + if err != nil { + t.Fatal(err) + } + }, + ExpectedStatus: 404, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{"*": 0}, + }, + { + Name: "protected file - superuser with whitelisted IP", + Method: http.MethodGet, + URL: "/api/files/demo1/al1h9ijdeojtsjy/300_Jsjq7RdBgA.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc", + Headers: map[string]string{"x-test-ip": "127.0.0.1"}, + BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) { + app.Settings().TrustedProxy = core.TrustedProxyConfig{ + Headers: []string{"x-test-ip"}, + } + + app.Settings().SuperuserIPs = []string{"127.0.0.1"} + + if err := app.Save(app.Settings()); err != nil { + t.Fatal(err) + } + }, + ExpectedStatus: 200, + ExpectedContent: []string{"PNG"}, + ExpectedEvents: map[string]int{ + "*": 0, + "OnFileDownloadRequest": 1, + }, + }, { Name: "protected file - guest without view access", Method: http.MethodGet, diff --git a/apis/middlewares.go b/apis/middlewares.go index dc1d44c3..c4df9aef 100644 --- a/apis/middlewares.go +++ b/apis/middlewares.go @@ -42,6 +42,9 @@ const ( DefaultLoadAuthTokenMiddlewarePriority = DefaultRateLimitMiddlewarePriority - 20 DefaultLoadAuthTokenMiddlewareId = "pbLoadAuthToken" + DefaultSuperuserIPsWhitelistMiddlewarePriority = DefaultLoadAuthTokenMiddlewarePriority + 5 + DefaultSuperuserIPsWhitelistMiddlewareId = "pbSuperuserIPsWhitelist" + DefaultSecurityHeadersMiddlewarePriority = DefaultRateLimitMiddlewarePriority - 10 DefaultSecurityHeadersMiddlewareId = "pbSecurityHeaders" @@ -299,6 +302,28 @@ func securityHeaders() *hook.Handler[*core.RequestEvent] { } } +// superuserIPsWhitelist middleware checks the current authenticated superuser IP +// against the configured SuperuserIPs whitelist setting. +// +// This middleware is registered by default for all routes. +func superuserIPsWhitelist() *hook.Handler[*core.RequestEvent] { + return &hook.Handler[*core.RequestEvent]{ + Id: DefaultSuperuserIPsWhitelistMiddlewareId, + Priority: DefaultSuperuserIPsWhitelistMiddlewarePriority, + Func: func(e *core.RequestEvent) error { + if e.HasSuperuserAuth() { + ips := e.App.Settings().SuperuserIPs + + if len(ips) > 0 && !isIPInList(ips, e.RealIP()) { + return e.ForbiddenError("", errors.New("superuser IP is not whitelisted")) + } + } + + return e.Next() + }, + } +} + // SkipSuccessActivityLog is a helper middleware that instructs the global // activity logger to log only requests that have failed/returned an error. func SkipSuccessActivityLog() *hook.Handler[*core.RequestEvent] { diff --git a/apis/middlewares_rate_limit.go b/apis/middlewares_rate_limit.go index 809423eb..9cf90782 100644 --- a/apis/middlewares_rate_limit.go +++ b/apis/middlewares_rate_limit.go @@ -2,6 +2,7 @@ package apis import ( "errors" + "net/netip" "sync" "time" @@ -106,6 +107,41 @@ func checkCollectionRateLimit(e *core.RequestEvent, collection *core.Collection, return nil } +// isIPInList checks if the specified IP is in a list of other individual IPs or subnets. +func isIPInList(ipsOrSubnets []string, ip string) bool { + if ip == "" || len(ipsOrSubnets) == 0 { + return false + } + + // normalize + searchAddr, err := netip.ParseAddr(ip) + if err != nil { + return false + } + + for _, item := range ipsOrSubnets { + // subnet? + prefix, err := netip.ParsePrefix(item) + if err == nil { + if prefix.Contains(searchAddr) { + return true + } + continue + } + + // individual ip? + addr, err := netip.ParseAddr(item) + if err == nil { + if addr == searchAddr { + return true + } + continue + } + } + + return false +} + // ------------------------------------------------------------------- // @todo consider exporting as helper? diff --git a/apis/middlewares_test.go b/apis/middlewares_test.go index 2a54afe8..19302f32 100644 --- a/apis/middlewares_test.go +++ b/apis/middlewares_test.go @@ -553,3 +553,96 @@ func TestRequireSameCollectionContextAuth(t *testing.T) { scenario.Test(t) } } + +func TestSuperuserIPsWhitelist(t *testing.T) { + t.Parallel() + + setupWhitelist := func(superuserIPs ...string) func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) { + return func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) { + // allow loading a mock IP from the test scenario + app.Settings().TrustedProxy = core.TrustedProxyConfig{ + Headers: []string{"x-test-ip"}, + } + + app.Settings().SuperuserIPs = superuserIPs + + err := app.Save(app.Settings()) + if err != nil { + t.Fatal(err) + } + + e.Router.GET("/my/test", func(e *core.RequestEvent) error { + return e.String(200, "test123") + }) + } + } + + scenarios := []tests.ApiScenario{ + { + Name: "guest with non-matching IP", + Method: http.MethodGet, + URL: "/my/test", + Headers: map[string]string{"x-test-ip": "127.0.0.1"}, + BeforeTestFunc: setupWhitelist("0.0.0.0"), + ExpectedStatus: 200, + ExpectedContent: []string{"test123"}, + ExpectedEvents: map[string]int{"*": 0}, + }, + { + Name: "regular user with non-matching IP", + Method: http.MethodGet, + URL: "/my/test", + Headers: map[string]string{ + "x-test-ip": "127.0.0.1", + "Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.ZT3F0Z3iM-xbGgSG3LEKiEzHrPHr8t8IuHLZGGNuxLo", + }, + BeforeTestFunc: setupWhitelist("0.0.0.0"), + ExpectedStatus: 200, + ExpectedContent: []string{"test123"}, + ExpectedEvents: map[string]int{"*": 0}, + }, + { + Name: "superuser with non-matching IP", + Method: http.MethodGet, + URL: "/my/test", + Headers: map[string]string{ + "x-test-ip": "127.0.0.1", + "Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY", + }, + BeforeTestFunc: setupWhitelist("0.0.0.0"), + ExpectedStatus: 403, + ExpectedContent: []string{`"data":{}`}, + ExpectedEvents: map[string]int{"*": 0}, + }, + { + Name: "superuser with matching IP", + Method: http.MethodGet, + URL: "/my/test", + Headers: map[string]string{ + "x-test-ip": "127.0.0.1", + "Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY", + }, + BeforeTestFunc: setupWhitelist("0.0.0.0", "127.0.0.1"), + ExpectedStatus: 200, + ExpectedContent: []string{"test123"}, + ExpectedEvents: map[string]int{"*": 0}, + }, + { + Name: "superuser with no whitelisted IPs", + Method: http.MethodGet, + URL: "/my/test", + Headers: map[string]string{ + "x-test-ip": "127.0.0.1", + "Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY", + }, + BeforeTestFunc: setupWhitelist(), + ExpectedStatus: 200, + ExpectedContent: []string{"test123"}, + ExpectedEvents: map[string]int{"*": 0}, + }, + } + + for _, scenario := range scenarios { + scenario.Test(t) + } +} diff --git a/apis/record_helpers.go b/apis/record_helpers.go index 71095f97..27992d8d 100644 --- a/apis/record_helpers.go +++ b/apis/record_helpers.go @@ -43,6 +43,13 @@ func RecordAuthResponse(e *core.RequestEvent, authRecord *core.Record, authMetho } func recordAuthResponse(e *core.RequestEvent, authRecord *core.Record, token string, authMethod string, meta any) error { + if authRecord.IsSuperuser() { + allowedIPs := e.App.Settings().SuperuserIPs + if len(allowedIPs) > 0 && !isIPInList(allowedIPs, e.RealIP()) { + return e.ForbiddenError("", errors.New("superuser IP is not whitelisted")) + } + } + originalRequestInfo, err := e.RequestInfo() if err != nil { return err diff --git a/apis/record_helpers_test.go b/apis/record_helpers_test.go index d0458d3f..d479ef62 100644 --- a/apis/record_helpers_test.go +++ b/apis/record_helpers_test.go @@ -759,3 +759,39 @@ func TestRecordAuthResponseMFACheck(t *testing.T) { } }) } + +func TestRecordAuthResponseSuperuserIPsWhitelistCheck(t *testing.T) { + app, _ := tests.NewTestApp() + defer app.Cleanup() + + superuser, err := app.FindAuthRecordByEmail(core.CollectionNameSuperusers, "test@example.com") + if err != nil { + t.Fatal(err) + } + + app.Settings().TrustedProxy.Headers = []string{"x-test-ip"} + + event := new(core.RequestEvent) + event.App = app + event.Request = httptest.NewRequest(http.MethodGet, "/", nil) + event.Request.Header.Set("x-test-ip", "127.0.0.1") + event.Response = httptest.NewRecorder() + + t.Run("non-whitelisted", func(t *testing.T) { + app.Settings().SuperuserIPs = []string{"0.0.0.0"} + + err = apis.RecordAuthResponse(event, superuser, "example", nil) + if err == nil { + t.Fatal("Expected response error, got nil") + } + }) + + t.Run("whitelisted", func(t *testing.T) { + app.Settings().SuperuserIPs = []string{"0.0.0.0", "127.0.0.1"} + + err = apis.RecordAuthResponse(event, superuser, "example", nil) + if err != nil { + t.Fatal(err) + } + }) +} diff --git a/cmd/superuser.go b/cmd/superuser.go index 523fa532..54bc5476 100644 --- a/cmd/superuser.go +++ b/cmd/superuser.go @@ -24,6 +24,7 @@ func NewSuperuserCommand(app core.App) *cobra.Command { command.AddCommand(superuserUpdateCommand(app)) command.AddCommand(superuserDeleteCommand(app)) command.AddCommand(superuserOTPCommand(app)) + command.AddCommand(superuserIPsCommand(app)) return command } @@ -209,3 +210,38 @@ func superuserOTPCommand(app core.App) *cobra.Command { return command } + +func superuserIPsCommand(app core.App) *cobra.Command { + command := &cobra.Command{ + Use: "ips", + Example: "superuser ips 127.0.0.1 10.0.0.0/24", + Short: "Updates the superuser IPs whitelist setting (the IPs/subnets arguments must be space separated; leave empty to clear the whitelist restriction)", + SilenceUsage: true, + RunE: func(command *cobra.Command, args []string) error { + settings := app.Settings() + settings.SuperuserIPs = args + + if err := app.Save(settings); err != nil { + return err + } + + if len(args) == 0 { + color.Green("Successfully cleared SuperuserIPs setting!") + } else { + color.New(color.BgGreen, color.FgBlack).Println("Successfully updated SuperuserIPs setting:") + superuserIPs := app.Settings().SuperuserIPs + for i, ip := range superuserIPs { + if i == len(superuserIPs)-1 { + color.Green("└─ %s", ip) + } else { + color.Green("├─ %s", ip) + } + } + } + + return nil + }, + } + + return command +} diff --git a/cmd/superuser_test.go b/cmd/superuser_test.go index dd3681d7..215b53c5 100644 --- a/cmd/superuser_test.go +++ b/cmd/superuser_test.go @@ -1,6 +1,7 @@ package cmd_test import ( + "slices" "testing" "github.com/pocketbase/pocketbase/cmd" @@ -401,3 +402,63 @@ func TestSuperuserOTPCommand(t *testing.T) { }) } } + +func TestSuperuserIPsCommand(t *testing.T) { + app, _ := tests.NewTestApp() + defer app.Cleanup() + + scenarios := []struct { + name string + ips []string + expectError bool + }{ + { + "no ips", + nil, + false, + }, + { + "invalid ips", + []string{"127.0.0.1", "invalid"}, + true, + }, + { + "valid ips", + []string{"127.0.0.1", "::1", "127.0.0.1/24"}, + false, + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + args := []string{"ips"} + args = append(args, s.ips...) + + command := cmd.NewSuperuserCommand(app) + command.SetArgs(args) + + err := command.Execute() + + hasErr := err != nil + if s.expectError != hasErr { + t.Fatalf("Expected hasErr %v, got %v (%v)", s.expectError, hasErr, err) + } + + if hasErr { + return + } + + settingIPs := app.Settings().SuperuserIPs + + if len(settingIPs) != len(s.ips) { + t.Fatalf("Expected %d ips, got %d (%v)", len(s.ips), len(settingIPs), settingIPs) + } + + for _, ip := range settingIPs { + if !slices.Contains(s.ips, ip) { + t.Fatalf("Missing expected ip %q (%v)", ip, settingIPs) + } + } + }) + } +} diff --git a/core/base.go b/core/base.go index e932eb1b..4551e3f4 100644 --- a/core/base.go +++ b/core/base.go @@ -38,8 +38,9 @@ const ( LocalStorageDirName string = "storage" LocalBackupsDirName string = "backups" - LocalTempDirName string = ".pb_temp_to_delete" // temp pb_data sub directory that will be deleted on each app.Bootstrap() LocalAutocertCacheDirName string = ".autocert_cache" + LocalNotifyDirName string = ".notify" // optional watched directory that is used as a cross-platform workaround for synchronizing various runtime states between multiple PocketBase instances pointing to the same pb_data + LocalTempDirName string = ".pb_temp_to_delete" // temp pb_data sub directory that will be deleted on each app.Bootstrap() // @todo consider removing after backups refactoring lostFoundDirName string = "lost+found" @@ -1382,6 +1383,7 @@ func (app *BaseApp) registerBaseHooks() { app.registerMFAHooks() app.registerOTPHooks() app.registerAuthOriginHooks() + app.registerNotifyWatcherHooks() } // getLoggerMinLevel returns the logger min level based on the diff --git a/core/notify_watcher.go b/core/notify_watcher.go new file mode 100644 index 00000000..1f548cda --- /dev/null +++ b/core/notify_watcher.go @@ -0,0 +1,210 @@ +package core + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "github.com/fatih/color" + "github.com/fsnotify/fsnotify" + "github.com/pocketbase/pocketbase/tools/hook" + "github.com/pocketbase/pocketbase/tools/security" +) + +const systemHookIdNotifyWatcher = "__pbNotifyWatcherSystemHook__" + +func (app *BaseApp) registerNotifyWatcherHooks() { + var notifyWatcher *fsnotify.Watcher + + instanceId := "@" + security.PseudorandomString(10) + + localNotifyDirPath := filepath.Join(app.DataDir(), LocalNotifyDirName) + settingsFile := filepath.Join(localNotifyDirPath, "settings"+instanceId) + collectionsFile := filepath.Join(localNotifyDirPath, "collections"+instanceId) + + // init + app.OnBootstrap().Bind(&hook.Handler[*BootstrapEvent]{ + Id: systemHookIdNotifyWatcher, + Func: func(e *BootstrapEvent) error { + err := e.Next() + if err != nil { + return err + } + + if notifyWatcher != nil { + _ = notifyWatcher.Close() + } + + notifyWatcher, err = createNotifyDirWatcher(e.App, instanceId, localNotifyDirPath) + if err != nil { + e.App.Logger().Warn("Notify dir watcher failure.", "error", err) + } + + return nil + }, + Priority: -998, + }) + + // cleanup + app.OnTerminate().Bind(&hook.Handler[*TerminateEvent]{ + Id: systemHookIdNotifyWatcher, + Func: func(e *TerminateEvent) error { + if notifyWatcher != nil { + _ = notifyWatcher.Close() + } + + _ = os.Remove(settingsFile) + _ = os.Remove(collectionsFile) + + return e.Next() + }, + Priority: -998, + }) + + // --------------------------------------------------------------- + + settingsNotify := func(e *ModelEvent) error { + err := e.Next() + if err != nil || e.Model.PK() != paramsKeySettings { + return err + } + + if notifyWatcher != nil { + if err := os.WriteFile(settingsFile, nil, 0644); err != nil { + e.App.Logger().Warn("Failed to write watcher file", "error", err, "file", settingsFile) + } + _ = os.Remove(settingsFile) + } + + return nil + } + app.OnModelAfterCreateSuccess(paramsTable).Bind(&hook.Handler[*ModelEvent]{ + Id: systemHookIdNotifyWatcher, + Func: settingsNotify, + Priority: 999, + }) + app.OnModelAfterUpdateSuccess(paramsTable).Bind(&hook.Handler[*ModelEvent]{ + Id: systemHookIdNotifyWatcher, + Func: settingsNotify, + Priority: 999, + }) + + // --------------------------------------------------------------- + + collectionsNotify := func(e *CollectionEvent) error { + if err := e.Next(); err != nil { + return err + } + + if notifyWatcher != nil { + if err := os.WriteFile(collectionsFile, nil, 0644); err != nil { + e.App.Logger().Warn("Failed to write watcher file", "error", err, "file", collectionsFile) + } + _ = os.Remove(collectionsFile) + } + + return nil + } + app.OnCollectionAfterCreateSuccess().Bind(&hook.Handler[*CollectionEvent]{ + Id: systemHookIdNotifyWatcher, + Func: collectionsNotify, + Priority: 999, + }) + app.OnCollectionAfterUpdateSuccess().Bind(&hook.Handler[*CollectionEvent]{ + Id: systemHookIdNotifyWatcher, + Func: collectionsNotify, + Priority: 999, + }) + app.OnCollectionAfterDeleteSuccess().Bind(&hook.Handler[*CollectionEvent]{ + Id: systemHookIdNotifyWatcher, + Func: collectionsNotify, + Priority: 999, + }) +} + +func createNotifyDirWatcher(app App, instanceId string, localNotifyDirPath string) (*fsnotify.Watcher, error) { + // create the notify dir (if not already) + err := os.MkdirAll(localNotifyDirPath, os.ModePerm) + if err != nil { + return nil, fmt.Errorf("failed to create a notify dir: %w", err) + } + + watcher, err := fsnotify.NewWatcher() + if err != nil { + return nil, fmt.Errorf("failed to init notify dir watcher: %w", err) + } + + err = watcher.Add(localNotifyDirPath) + if err != nil { + _ = watcher.Close() + return nil, fmt.Errorf("unable to watch notify dir: %w", err) + } + + var debounceTimer *time.Timer + + stopDebounceTimer := func() { + if debounceTimer != nil { + debounceTimer.Stop() + debounceTimer = nil + } + } + + // watch + go func() { + defer stopDebounceTimer() + + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + + // modified from within the current app instance or cleanup event + if strings.HasSuffix(event.Name, instanceId) || event.Has(fsnotify.Remove) || !app.IsBootstrapped() { + continue + } + + stopDebounceTimer() + + debounceTimer = time.AfterFunc(50*time.Millisecond, func() { + filename := filepath.Base(event.Name) + + // settings changed + if strings.HasPrefix(filename, "settings@") { + app.Logger().Debug("Reloading settings after notify event") + + err := app.ReloadSettings() + if err != nil { + app.Logger().Warn("Failed to reload app settings after notify", "error", err) + } + return + } + + // collections changed + if strings.HasPrefix(filename, "collections@") { + app.Logger().Debug("Reloading cached collections after notify event") + + err := app.ReloadCachedCollections() + if err != nil { + app.Logger().Warn("Failed to reload cached collections after notify", "error", err) + } + return + } + }) + case err, ok := <-watcher.Errors: + if app.IsDev() && err != nil { + color.Red("Notify dir watch error:", err) + } + + if !ok { + return + } + } + } + }() + + return watcher, err +} diff --git a/core/notify_watcher_test.go b/core/notify_watcher_test.go new file mode 100644 index 00000000..8c30663e --- /dev/null +++ b/core/notify_watcher_test.go @@ -0,0 +1,185 @@ +package core_test + +import ( + "context" + "database/sql" + "os" + "testing" + "time" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/tools/store" + "golang.org/x/sync/semaphore" +) + +func TestNotifyWatcher_SettingsUpdate(t *testing.T) { + t.Parallel() + + testEvents := store.New[core.App, int](nil) + + tmpDir, err := os.MkdirTemp("", "pb_notify_test*") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + app1 := core.NewBaseApp(core.BaseAppConfig{ + DataDir: tmpDir, + }) + if err := app1.Bootstrap(); err != nil { + t.Fatal(err) + } + + app2 := core.NewBaseApp(core.BaseAppConfig{ + DataDir: tmpDir, + }) + if err := app2.Bootstrap(); err != nil { + t.Fatal(err) + } + + ctx, cancelCtx := context.WithTimeout(context.Background(), 1*time.Second) + defer cancelCtx() + + sem := semaphore.NewWeighted(1) + sem.Acquire(ctx, 1) + + app1.OnSettingsReload().BindFunc(func(e *core.SettingsReloadEvent) error { + testEvents.SetFunc(app1, func(old int) int { + return old + 1 + }) + return e.Next() + }) + + app2.OnSettingsReload().BindFunc(func(e *core.SettingsReloadEvent) error { + testEvents.SetFunc(app2, func(old int) int { + sem.Release(1) + + return old + 1 + }) + return e.Next() + }) + + // updating app1 settings should trigger a reload in app2 + app1.Settings().SuperuserIPs = []string{"127.0.0.1"} + if err := app1.Save(app1.Settings()); err != nil { + t.Fatal(err) + } + + // block until released or timeouted + sem.Acquire(ctx, 1) + + if app1Total := testEvents.Get(app1); app1Total != 1 { + t.Fatalf("Expected 1 app1 event, got %d", app1Total) + } + + if app2Total := testEvents.Get(app2); app2Total != 1 { + t.Fatalf("Expected 1 app2 event, got %d", app2Total) + } + + app2SuperuserIPs := app2.Settings().SuperuserIPs + if len(app2SuperuserIPs) != 1 || app2SuperuserIPs[0] != "127.0.0.1" { + t.Fatalf("Expected exactly 127.0.0.1 superuser IP in app2 settings event, got %v", app2SuperuserIPs) + } +} + +func TestNotifyWatcher_CollectionsUpdate(t *testing.T) { + t.Parallel() + + tmpDir, err := os.MkdirTemp("", "pb_notify_test*") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + app1 := core.NewBaseApp(core.BaseAppConfig{ + DataDir: tmpDir, + }) + if err := app1.Bootstrap(); err != nil { + t.Fatal(err) + } + + app2 := core.NewBaseApp(core.BaseAppConfig{ + DataDir: tmpDir, + }) + if err := app2.Bootstrap(); err != nil { + t.Fatal(err) + } + + testQueries := store.New[string, []string](nil) + app2.ConcurrentDB().(*dbx.DB).QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) { + testQueries.SetFunc("concurrent", func(old []string) []string { + return append(old, sql) + }) + } + app2.ConcurrentDB().(*dbx.DB).ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) { + testQueries.SetFunc("concurrent", func(old []string) []string { + return append(old, sql) + }) + } + app2.NonconcurrentDB().(*dbx.DB).QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) { + testQueries.SetFunc("nonconcurrent", func(old []string) []string { + return append(old, sql) + }) + } + app2.NonconcurrentDB().(*dbx.DB).ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) { + testQueries.SetFunc("nonconcurrent", func(old []string) []string { + return append(old, sql) + }) + } + + ctx, cancelCtx := context.WithTimeout(context.Background(), 1*time.Second) + defer cancelCtx() + + sem := semaphore.NewWeighted(1) + sem.Acquire(ctx, 1) + + // currently there is no hook for the collections cache reload so we pool instead + done := make(chan bool, 1) + ticker := time.NewTicker(100 * time.Millisecond) + go func() { + for { + select { + case <-ticker.C: + if len(testQueries.Get("concurrent")) == 1 { + sem.Release(1) + return + } + case <-done: + return + } + } + }() + + // create/update/delete app1 collections should trigger a reload in app2 + dummyCollection := core.NewBaseCollection("test") + if err := app1.Save(dummyCollection); err != nil { + t.Fatal(err) + } + dummyCollection.Fields.Add(&core.TextField{Name: "test"}) + if err := app1.Save(dummyCollection); err != nil { + t.Fatal(err) + } + if err := app1.Delete(dummyCollection); err != nil { + } + + // block until released or timeouted + sem.Acquire(ctx, 1) + ticker.Stop() + done <- true + + nonconcurrentQueries := testQueries.Get("nonconcurrent") + concurrentQueries := testQueries.Get("concurrent") + + if len(nonconcurrentQueries) != 0 { + t.Fatalf("Expected 0 concurrent queries, got %d (%v)", len(nonconcurrentQueries), nonconcurrentQueries) + } + if len(concurrentQueries) != 1 { + t.Fatalf("Expected 1 concurrent query, got %d (%v)", len(concurrentQueries), concurrentQueries) + } + + expectedQuery := "SELECT {{_collections}}.* FROM `_collections` ORDER BY `rowid` ASC" + if concurrentQueries[0] != expectedQuery { + t.Fatalf("Expected query\n%s\ngot\n%s", expectedQuery, concurrentQueries[0]) + } +} diff --git a/core/settings_model.go b/core/settings_model.go index 1adead7b..0b915384 100644 --- a/core/settings_model.go +++ b/core/settings_model.go @@ -120,6 +120,10 @@ var ( ) type settings struct { + // SuperuserIPs defines an optional list of the superuser allowed + // individual IPs and subnets (in CIDR notation). + SuperuserIPs []string `form:"superuserIPs" json:"superuserIPs"` + SMTP SMTPConfig `form:"smtp" json:"smtp"` Backups BackupsConfig `form:"backups" json:"backups"` S3 S3Config `form:"s3" json:"s3"` @@ -253,6 +257,12 @@ func (s *Settings) DBExport(app App) (map[string]any, error) { } result["updated"] = now + // @todo remove with encoding/json/2 + // serialize as empty array + if s.settings.SuperuserIPs == nil { + s.settings.SuperuserIPs = []string{} + } + encoded, err := json.Marshal(s.settings) if err != nil { return nil, err @@ -280,6 +290,7 @@ func (s *Settings) PostValidate(ctx context.Context, app App) error { defer s.mu.RUnlock() return validation.ValidateStructWithContext(ctx, s, + validation.Field(&s.SuperuserIPs, validation.Each(validation.By(validators.IPOrSubnet))), validation.Field(&s.Meta), validation.Field(&s.Logs), validation.Field(&s.SMTP), @@ -343,6 +354,12 @@ func (s *Settings) MarshalJSON() ([]byte, error) { } } + // @todo remove with encoding/json/2 + // serialize as empty array + if copy.SuperuserIPs == nil { + copy.SuperuserIPs = []string{} + } + return json.Marshal(copy) } diff --git a/core/settings_model_test.go b/core/settings_model_test.go index 5f577f8d..9631a3bf 100644 --- a/core/settings_model_test.go +++ b/core/settings_model_test.go @@ -84,7 +84,7 @@ func TestSettings_DBExport(t *testing.T) { valueStr = string(export["value"].([]byte)) } - expected := `{"smtp":{"enabled":false,"port":0,"host":"smtp_host","username":"smtp_username","password":"","authMethod":"","tls":false,"localName":""},"backups":{"cron":"* * * * *","cronMaxKeep":0,"s3":{"enabled":true,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false}},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"s3_endpoint","accessKey":"","secret":"s3_secret","forcePathStyle":false},"meta":{"accentColor":"","appName":"test_app_name","appURL":"","senderName":"","senderAddress":"","hideControls":false},"rateLimits":{"rules":[],"enabled":true},"trustedProxy":{"headers":[],"useLeftmostIP":true},"batch":{"enabled":false,"maxRequests":0,"timeout":15,"maxBodySize":0},"logs":{"maxDays":123,"minLevel":0,"logIP":false,"logAuthId":false}}` + expected := `{"superuserIPs":[],"smtp":{"enabled":false,"port":0,"host":"smtp_host","username":"smtp_username","password":"","authMethod":"","tls":false,"localName":""},"backups":{"cron":"* * * * *","cronMaxKeep":0,"s3":{"enabled":true,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false}},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"s3_endpoint","accessKey":"","secret":"s3_secret","forcePathStyle":false},"meta":{"accentColor":"","appName":"test_app_name","appURL":"","senderName":"","senderAddress":"","hideControls":false},"rateLimits":{"rules":[],"enabled":true},"trustedProxy":{"headers":[],"useLeftmostIP":true},"batch":{"enabled":false,"maxRequests":0,"timeout":15,"maxBodySize":0},"logs":{"maxDays":123,"minLevel":0,"logIP":false,"logAuthId":false}}` if valueStr != expected { t.Fatalf("Expected exported settings\n%s\ngot\n%s", expected, valueStr) } @@ -180,7 +180,7 @@ func TestSettingsMarshalJSON(t *testing.T) { } rawStr := string(raw) - expected := `{"smtp":{"enabled":false,"port":0,"host":"","username":"abc","authMethod":"","tls":false,"localName":""},"backups":{"cron":"","cronMaxKeep":0,"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false}},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false},"meta":{"accentColor":"","appName":"test123","appURL":"","senderName":"","senderAddress":"","hideControls":false},"rateLimits":{"rules":[],"enabled":false},"trustedProxy":{"headers":[],"useLeftmostIP":false},"batch":{"enabled":false,"maxRequests":0,"timeout":0,"maxBodySize":0},"logs":{"maxDays":0,"minLevel":0,"logIP":false,"logAuthId":false}}` + expected := `{"superuserIPs":[],"smtp":{"enabled":false,"port":0,"host":"","username":"abc","authMethod":"","tls":false,"localName":""},"backups":{"cron":"","cronMaxKeep":0,"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false}},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false},"meta":{"accentColor":"","appName":"test123","appURL":"","senderName":"","senderAddress":"","hideControls":false},"rateLimits":{"rules":[],"enabled":false},"trustedProxy":{"headers":[],"useLeftmostIP":false},"batch":{"enabled":false,"maxRequests":0,"timeout":0,"maxBodySize":0},"logs":{"maxDays":0,"minLevel":0,"logIP":false,"logAuthId":false}}` if rawStr != expected { t.Fatalf("Expected\n%v\ngot\n%v", expected, rawStr) @@ -196,6 +196,7 @@ func TestSettingsValidate(t *testing.T) { s := app.Settings() // set invalid settings data + s.SuperuserIPs = []string{"127.0.0.1", "invalid"} s.Meta.AppName = "" s.Logs.MaxDays = -10 s.SMTP.Enabled = true @@ -217,6 +218,7 @@ func TestSettingsValidate(t *testing.T) { } expectations := []string{ + `"superuserIPs":{`, `"meta":{`, `"logs":{`, `"smtp":{`, diff --git a/core/validators/file.go b/core/validators/file.go index e3e556e9..f7a959ce 100644 --- a/core/validators/file.go +++ b/core/validators/file.go @@ -31,7 +31,7 @@ func UploadedFileSize(maxBytes int64) validation.RuleFunc { "validation_file_size_limit", "Failed to upload {{.file}} - the maximum allowed file size is {{.maxSize}} bytes.", ).SetParams(map[string]any{ - "file": v.OriginalName, + "file": cutStr(v.OriginalName, 300), "maxSize": maxBytes, }) } @@ -60,7 +60,7 @@ func UploadedFileMimeType(validTypes []string) validation.RuleFunc { baseErr := validation.NewError( "validation_invalid_mime_type", - fmt.Sprintf("Failed to upload %q due to unsupported file type.", v.OriginalName), + fmt.Sprintf("Failed to upload %q due to unsupported file type.", cutStr(v.OriginalName, 300)), ) if len(validTypes) == 0 { diff --git a/core/validators/string.go b/core/validators/string.go index c0d885b5..7f7a12a7 100644 --- a/core/validators/string.go +++ b/core/validators/string.go @@ -1,6 +1,7 @@ package validators import ( + "net/netip" "regexp" validation "github.com/go-ozzo/ozzo-validation/v4" @@ -27,3 +28,30 @@ func IsRegex(value any) error { return nil } + +// IPOrSubnet checks whether the validated value is an individual +// IPv4/IPv6 or CIDR subnet. +func IPOrSubnet(value any) error { + v, ok := value.(string) + if !ok { + return ErrUnsupportedValueType + } + + if v == "" { + return nil // nothing to check + } + + // subnet + _, err := netip.ParsePrefix(v) + if err == nil { + return nil + } + + // individual IP + _, err = netip.ParseAddr(v) + if err == nil { + return nil + } + + return validation.NewError("validation_invlaid_ip_or_subnet", "invalid IP or CIDR subnet") +} diff --git a/core/validators/string_test.go b/core/validators/string_test.go index dead6df7..da876e94 100644 --- a/core/validators/string_test.go +++ b/core/validators/string_test.go @@ -31,3 +31,32 @@ func TestIsRegex(t *testing.T) { }) } } + +func TestIPOrSubnet(t *testing.T) { + t.Parallel() + + scenarios := []struct { + val string + expectError bool + }{ + {"", false}, + {`invalid`, true}, + {`127.0`, true}, // incomplete + {`127.0.0.1`, false}, + {`::1`, false}, + {`0000:0000:0000:0000:0000:0000:0000:0001`, false}, + {`127.0.0.1/24`, false}, + {`::/128`, false}, + } + + for i, s := range scenarios { + t.Run(fmt.Sprintf("%d_%#v", i, s.val), func(t *testing.T) { + err := validators.IPOrSubnet(s.val) + + hasErr := err != nil + if hasErr != s.expectError { + t.Fatalf("Expected hasErr to be %v, got %v (%v)", s.expectError, hasErr, err) + } + }) + } +} diff --git a/core/validators/validators.go b/core/validators/validators.go index a4ce3a6f..9e12488a 100644 --- a/core/validators/validators.go +++ b/core/validators/validators.go @@ -38,3 +38,10 @@ func JoinValidationErrors(errA, errB error) error { return errors.Join(errA, errB) } + +func cutStr(str string, max int) string { + if len(str) > max { + return str[:max] + "..." + } + return str +} diff --git a/ui/.env b/ui/.env index 4e2822ed..b07d3652 100644 --- a/ui/.env +++ b/ui/.env @@ -1,14 +1,15 @@ # all environments should start with 'PB_' prefix -PB_BACKEND_URL = "../" -PB_MFA_DOCS = "https://pocketbase.io/docs/authentication#multi-factor-authentication" -PB_OAUTH2_DOCS = "https://pocketbase.io/docs/authentication#authenticate-with-oauth2" -PB_RULES_SYNTAX_DOCS = "https://pocketbase.io/docs/api-rules-and-filters" -PB_FILE_UPLOAD_DOCS = "https://pocketbase.io/docs/files-handling" -PB_PROTECTED_FILE_DOCS = "https://pocketbase.io/docs/files-handling#protected-files" -PB_REALTIME_DOCS = "https://pocketbase.io/docs/api-realtime/" -PB_FIELDS_DOCS = "https://pocketbase.io/docs/collections/#fields" -PB_DOCS_URL = "https://pocketbase.io/docs" -PB_JS_SDK_URL = "https://github.com/pocketbase/js-sdk" -PB_DART_SDK_URL = "https://github.com/pocketbase/dart-sdk" -PB_RELEASES = "https://github.com/pocketbase/pocketbase/releases" -PB_VERSION = "v0.37.6-dev" +PB_BACKEND_URL = "../" +PB_MFA_DOCS = "https://pocketbase.io/docs/authentication#multi-factor-authentication" +PB_OAUTH2_DOCS = "https://pocketbase.io/docs/authentication#authenticate-with-oauth2" +PB_RULES_SYNTAX_DOCS = "https://pocketbase.io/docs/api-rules-and-filters" +PB_FILE_UPLOAD_DOCS = "https://pocketbase.io/docs/files-handling" +PB_PROTECTED_FILE_DOCS = "https://pocketbase.io/docs/files-handling#protected-files" +PB_REALTIME_DOCS = "https://pocketbase.io/docs/api-realtime/" +PB_FIELDS_DOCS = "https://pocketbase.io/docs/collections/#fields" +PB_SUPERUSER_IPS_RESET_DOCS = "https://pocketbase.io/docs/going-to-production/#limit-superusers-to-specific-ipssubnets" +PB_DOCS_URL = "https://pocketbase.io/docs" +PB_JS_SDK_URL = "https://github.com/pocketbase/js-sdk" +PB_DART_SDK_URL = "https://github.com/pocketbase/dart-sdk" +PB_RELEASES = "https://github.com/pocketbase/pocketbase/releases" +PB_VERSION = "v0.37.6-dev" diff --git a/ui/dist/assets/index-CsbGEmKA.js b/ui/dist/assets/index-B5eik2f8.js similarity index 85% rename from ui/dist/assets/index-CsbGEmKA.js rename to ui/dist/assets/index-B5eik2f8.js index 519ac5e6..671f6c8e 100644 --- a/ui/dist/assets/index-CsbGEmKA.js +++ b/ui/dist/assets/index-B5eik2f8.js @@ -2,7 +2,8 @@ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./docsList-BAfVNUIM.js import{a as e,n,r,t as i}from"./pocketbase.es-B_4DUNUU.js";var a=Object.create,o=Object.defineProperty,s=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,l=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty,d=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports),f=(e,n,r,i)=>{if(n&&typeof n==`object`||typeof n==`function`)for(var a=c(n),l=0,d=a.length,f;ln[e]).bind(null,f),enumerable:!(i=s(n,f))||i.enumerable});return e},p=(e,n,r)=>(r=e==null?{}:a(l(e)),f(n||!e||!e.__esModule?o(r,`default`,{value:e,enumerable:!0}):r,e));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))r(e);new MutationObserver(e=>{for(let n of e)if(n.type===`childList`)for(let e of n.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&r(e)}).observe(document,{childList:!0,subtree:!0});function n(e){let n={};return e.integrity&&(n.integrity=e.integrity),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?n.credentials=`include`:e.crossOrigin===`anonymous`?n.credentials=`omit`:n.credentials=`same-origin`,n}function r(e){if(e.ep)return;e.ep=!0;let r=n(e);fetch(e.href,r)}})();var m=`abcdefghijklmnopqrstuvwxyz0123456789`,h=`pb_redirect`,g=store({hash:window.location.hash});window.addEventListener(`hashchange`,()=>{g.hash=window.location.hash}),Prism.languages.pbrule={string:Prism.languages.js.string,number:Prism.languages.js.number,function:Prism.languages.js.function,boolean:/\b(?:true|false)\b/i,constant:/\b(?:null)\b/i,comment:{pattern:/\/\/.*/,greedy:!0},italic:/_via_|\:\w+/,keyword:/&&|\|\||\??(?:!~|!=|>=|<=|=|~|>|>|<)(?=[@\w\s]|$)/};var _={isObject(e){return typeof e==`object`&&!!e&&e.constructor===Object},isEmpty(e){return e==null||e===``||Array.isArray(e)&&e.length===0||typeof e==`object`&&app.utils.isEmptyObject(e)},isEmptyObject(e){for(let n in e)return!1;return!0},toArray(e,n=!1){return Array.isArray(e)?e.slice():(n||!_.isEmpty(e))&&e!==void 0?[e]:[]},removeByValue(e,n){if(!Array.isArray(e)){console.warn(`[removeByValue] not an array:`,e);return}for(let r=e.length-1;r>=0;r--)if(e[r]==n){e.splice(r,1);break}},removeByKey(e,n,r){if(!Array.isArray(e)){console.warn(`[removeByKey] not an array:`,e);return}for(let i in e)if(e[i][n]==r){e.splice(i,1);break}},pushUnique(e,n){if(!Array.isArray(e)){console.warn(`[pushUnique] not an array:`,e);return}e.includes(n)||e.push(n)},mergeUnique(e,n){for(let r of n)app.utils.pushUnique(e,r);return e},pushOrReplaceObject(e,n,r=`id`){for(let i=e.length-1;i>=0;i--)if(e[i][r]==n[r]){e[i]=n;return}e.push(n)},filterDuplicatesByKey(e,n=`id`){e=Array.isArray(e)?e:[];let r={};for(let i of e)r[i[n]]=i;return Object.values(r)},filterRedactedProps(e,n=`******`){let r=JSON.parse(JSON.stringify(e||{}));for(let e in r)typeof r[e]==`object`&&r[e]!==null?r[e]=_.filterRedactedProps(r[e],n):r[e]===n&&delete r[e];return r},getByPath(e,n,r=null,i=`.`){let a=e||{},o=(n||``).split(i);for(let e of o){if(!_.isObject(a)&&!Array.isArray(a)||a[e]===void 0)return r;a=a[e]}return a},setByPath(e,n,r,i=`.`){if(typeof e!=`object`||!e){console.warn(`setByPath: data not an object or array.`);return}let a=e,o=n.split(i),s=o.pop();for(let e of o)(!_.isObject(a)&&!Array.isArray(a)||!_.isObject(a[e])&&!Array.isArray(a[e]))&&(a[e]={}),a=a[e];a[s]=r},deleteByPath(e,n,r=`.`){let i=e||{},a=(n||``).split(r),o=a.pop();for(let e of a)(!_.isObject(i)&&!Array.isArray(i)||!_.isObject(i[e])&&!Array.isArray(i[e]))&&(i[e]={}),i=i[e];Array.isArray(i)?i.splice(o,1):_.isObject(i)&&delete i[o],a.length>0&&(Array.isArray(i)&&!i.length||_.isObject(i)&&!Object.keys(i).length)&&(Array.isArray(e)&&e.length>0||_.isObject(e)&&Object.keys(e).length>0)&&_.deleteByPath(e,a.join(r),r)},emptyClone(e,n=[]){let r=JSON.parse(JSON.stringify(e));for(let e in r)n.includes(e)||(typeof r[e]==`string`?r[e]=``:typeof r[e]==`number`?r[e]=0:typeof r[e]==`boolean`?r[e]=!1:Array.isArray(r[e])?r[e]=[]:app.utils.isObject(r[e])&&(r[e]={}));return r},randomString(e=8,n=m){let r=``;for(let i=0;i`u`)return app.utils.randomString(e);let n=new Uint8Array(e);crypto.getRandomValues(n);let r=``;for(let i=0;i`,`>`).replaceAll(`"`,`"`).replaceAll(`'`,`'`):``},plainText(e){return e?(new DOMParser().parseFromString(e,`text/html`).body.textContent||``).trim():``},truncate(e,n=150,r=!0){if(e=``+e,e.length<=n)return e;if(e=e.slice(0,n),r){for(;e.endsWith(`.`);)e=e.slice(0,-1);e+=`...`}return e},truncateObject(e,n=150,r=!0){let i=Array.isArray(e)?[]:{};for(let a in e){let o=e[a];typeof o==`string`?o=app.utils.truncate(o,n,r):(Array.isArray(o)||app.utils.isObject(o))&&(o=app.utils.truncateObject(o,n,r)),i[a]=o}return i},displayValue(e,n=150,r=`N/A`){if(_.isEmpty(e))return r;if(typeof e!=`string`)if(typeof e==`boolean`)e=e?`True`:`False`;else if(Array.isArray(e)&&typeof e[0]!=`object`)e=e.map(e=>_.displayValue(e,n,r)).join(`, `);else try{e=JSON.stringify(e)||``}catch{e=``+e}return e?_.truncate(e,n):r},splitNonEmpty(e,n=`,`){let r=(e||``).split(n),i=[];for(let e of r)e=e.trim(),_.isEmpty(e)||i.push(e);return i},joinNonEmpty(e,n=`, `){e||=[];let r=[];for(let n of e)n=typeof n==`string`?n.trim():n,_.isEmpty(n)||r.push(``+n);return r.join(n)},formattedFileSize(e){let n=e?Math.floor(Math.log(e)/Math.log(1024)):0;return(e/1024**n).toFixed(2)*1+` `+[`B`,`KB`,`MB`,`GB`,`TB`][n]},toRFC3339Datetime(e){if(!e)return``;let n;return n=e instanceof Date?e:typeof e==`string`?new Date(e.replace(` `,`T`)):new Date(e),n.toISOString().replace(`T`,` `)},toLocalDatetime(e){if(!e)return``;let n;n=e instanceof Date?e:typeof e==`string`?new Date(e.replace(` `,`T`)):new Date(e);let r=n.getFullYear();return isNaN(r)?``:`${r}-${(n.getMonth()+1).toString().padStart(2,`0`)}-${n.getDate().toString().padStart(2,`0`)} ${n.getHours().toString().padStart(2,`0`)}:${n.getMinutes().toString().padStart(2,`0`)}:${n.getSeconds().toString().padStart(2,`0`)}.${n.getMilliseconds().toString().padStart(3,`0`)}`},toDatetimeLocalInputValue(e){if(!e)return``;let n;n=e instanceof Date?e:typeof e==`string`?new Date(e.replaceAll(` `,`T`)):new Date(e);let r=n.getFullYear();return isNaN(r)?``:`${r}-${(n.getMonth()+1).toString().padStart(2,`0`)}-${n.getDate().toString().padStart(2,`0`)}T${n.getHours().toString().padStart(2,`0`)}:${n.getMinutes().toString().padStart(2,`0`)}:${n.getSeconds().toString().padStart(2,`0`)}`},async copyToClipboard(e){if(e=e==null?``:e instanceof Date?e.toISOString():typeof e==`object`?JSON.stringify(e):``+e,!(!e.length||!window.navigator?.clipboard))return window.navigator.clipboard.writeText(e).catch(e=>{console.warn(`Failed to copy.`,e)})},download(e,n){let r=document.createElement(`a`);r.setAttribute(`href`,e),r.setAttribute(`download`,n),r.setAttribute(`target`,`_blank`),r.setAttribute(`rel`,`noopener noreferrer`),r.click(),r=null},downloadJSON(e,n){n=n.endsWith(`.json`)?n:n+`.json`;let r=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),i=window.URL.createObjectURL(r);_.download(i,n)},getApiExampleURL(){let e;if(app.pb.baseURL.startsWith(`http://`)||app.pb.baseURL.startsWith(`https://`))e=app.pb.baseURL;else{e=window.location.href;let n=e.indexOf(`/_/`);e=n>=0?e.substring(0,n):window.location.origin}return e.replace(`//localhost`,`//127.0.0.1`)},isActivePath(e,n=!0,r=``){r||=g.hash;let i;return i=RegExp(n?`^`+RegExp.escape(e)+`\\/?.*$`:`^`+RegExp.escape(e)+`\\/?(?:\\?.+)?$`),i.test(r)},getHashQueryParams(e=``){e||=g.hash;let n=``,r=e.indexOf(`?`);return r>-1&&(n=window.location.hash.substring(r+1)),Object.fromEntries(new URLSearchParams(n))},replaceHashQueryParams(e,n=null){e||={};let r=``,i=window.location.hash,a=i.indexOf(`?`);a>-1&&(r=i.substring(a+1),i=i.substring(0,a));let o=new URLSearchParams(r);for(let n in e){let r=e[n];_.isEmpty(r)?o.delete(n):o.set(n,r)}r=o.toString(),r!=``&&(i+=`?`+r);let s=window.location.href,c=s.indexOf(`#`);c>-1&&(s=s.substring(0,c));let l=s+i;return n===!1||(n===!0?window.history.pushState(null,``,l):window.history.replaceState(null,``,l)),l},rememberPath(){window.localStorage.setItem(h,window.location.hash)},toRememberedPath(e=`#/collections`){let n=window.localStorage.getItem(h);n&&window.localStorage.removeItem(h),window.location.hash=n||e},getLocalHistory(e,n=null){try{let r=window.localStorage.getItem(e);if(r)return JSON.parse(r)||n}catch(n){console.log(`failed to load local history:`,e,n)}return n},saveLocalHistory(e,n){try{app.utils.isEmpty(n)?window.localStorage.removeItem(e):typeof n==`string`?window.localStorage.setItem(e,n):window.localStorage.setItem(e,JSON.stringify(n))}catch(n){console.log(`failed to save local history:`,e,n)}},generateThumb(e,n=100,r=100){return new Promise(i=>{let a=new FileReader;a.onload=function(a){let o=new Image;o.onload=function(){let a=document.createElement(`canvas`),s=a.getContext(`2d`),c=o.width,l=o.height;return a.width=n,a.height=r,s.drawImage(o,c>l?(c-l)/2:0,0,c>l?l:c,c>l?l:c,0,0,n,r),i(a.toDataURL(e.type))},o.src=a.target.result},a.readAsDataURL(e)})},normalizeSearchFilter(e,n=[]){if(e=(e||``).trim(),!e||!n.length)return e;for(let n of[`=`,`!=`,`~`,`!~`,`>`,`>=`,`<`,`<=`])if(e.includes(n))return e;return e=isNaN(e)&&e!=`true`&&e!=`false`?`"${e.replace(/^[\"\'\`]|[\"\'\`]$/gm,``)}"`:e,n.map(n=>`${n}~${e}`).join(`||`)},logLevels:{[-4]:{label:`DEBUG`,class:``},0:{label:`INFO`,class:`success`},4:{label:`WARN`,class:`warning`},8:{label:`ERROR`,class:`danger`}},logDataFormatters:{execTime:function(e){return e?.data?.execTime===void 0?`N/A`:e.data.execTime+`ms`}},extendStore(e,n={},...r){let i=[];for(let a in n){let o=n[a];typeof e.__raw?.[a]==`function`||typeof o!=`function`||a.length>2&&a.startsWith(`on`)||r.includes(a)?e[a]=o:i.push(watch(o,n=>{e[a]=n}))}return i},cssTimeToMs(e){return e?(e=e.toLowerCase(),e.endsWith(`ms`)?Number(e.substring(0,e.length-2)):e.endsWith(`s`)?Number(e.substring(0,e.length-1)):Number(e)||0):0},isDarkEnoughForWhiteText(e){if(e=e?.startsWith(`#`)?e.substring(1):e,e?.length!=6)return!1;let n=parseInt(e.substring(0,2),16),r=parseInt(e.substring(2,4),16),i=parseInt(e.substring(4,6),16);return(n*299+r*587+i*114)/1e3<128},imageExtensions:[`.jpg`,`.jpeg`,`.png`,`.svg`,`.gif`,`.jfif`,`.webp`,`.avif`],videoExtensions:[`.mp4`,`.avi`,`.mov`,`.3gp`,`.wmv`],audioExtensions:[`.aa`,`.aac`,`.m4v`,`.mp3`,`.ogg`,`.oga`,`.mogg`,`.amr`],documentExtensions:[`.pdf`,`.doc`,`.docx`,`.xls`,`.xlsx`,`.ppt`,`.pptx`,`.odp`,`.odt`,`.ods`,`.txt`],hasImageExtension(e){return e=(e||``).toLowerCase(),!!app.utils.imageExtensions.find(n=>e.endsWith(n))},hasVideoExtension(e){return e=(e||``).toLowerCase(),!!app.utils.videoExtensions.find(n=>e.endsWith(n))},hasAudioExtension(e){return e=(e||``).toLowerCase(),!!app.utils.audioExtensions.find(n=>e.endsWith(n))},hasDocumentExtension(e){return e=(e||``).toLowerCase(),!!app.utils.documentExtensions.find(n=>e.endsWith(n))},getFileType(e){return app.utils.hasImageExtension(e)?`image`:app.utils.hasVideoExtension(e)?`video`:app.utils.hasAudioExtension(e)?`audio`:app.utils.hasDocumentExtension(e)?`document`:`file`},fileTypeIcons:{image:`ri-image-line`,video:`ri-movie-line`,audio:`ri-music-2-line`,document:`ri-file-line`,file:`ri-file-line`},fallbackFieldIcon:`ri-puzzle-line`,fallbackCollectionIcon:`ri-puzzle-line`,fallbackProviderIcon:`ri-puzzle-line`,fallbackPresentableProps:[`title`,`name`,`slug`,`email`,`username`,`nickname`,`displayName`,`label`,`subject`,`topic`,`message`,`heading`,`headline`,`header`,`caption`,`key`,`identifier`,`id`],sortedCollections(e=[]){let n,r;function i(e,i){return n=e.name.startsWith(`_`),r=i.name.startsWith(`_`),n&&!r?1:!n&&r?-1:e.name>i.name?1:e.namee?.id&&!a.find(n=>n.id==e.id)),s=a.filter(e=>e?.id&&!i.find(n=>n.id==e.id)),c=a.filter(e=>{let n=app.utils.isObject(e)&&i.find(n=>n.id==e.id);if(!n)return!1;for(let r in n)if(JSON.stringify(e[r])!=JSON.stringify(n[r]))return!0;return!1});return!!(s.length||c.length||r&&o.length)},extractColumnsFromQuery(e){let n=`__PBGROUP__`;e=(e||``).replace(/\([\s\S]+?\)/gm,n).replace(/[\t\r\n]|(?:\s\s)+/g,` `);let r=e.match(/select\s+([\s\S]+)\s+from/)?.[1]?.split(`,`)||[],i=[];for(let e of r){let r=e.trim().split(` `).pop();r!=``&&r!=n&&i.push(r.replace(/[\'\"\`\[\]\s]/g,``))}return i},getAllCollectionIdentifiers(e,n=``){if(!e)return[];let r=[n+`id`],i=e.type==`auth`;if(e.type===`view`)for(let i of app.utils.extractColumnsFromQuery(e.viewQuery))app.utils.pushUnique(r,n+i);let a=e.fields||[];for(let e of a)if(!(e.type==`password`||i&&e.name==`tokenKey`))if(app.fieldTypes[e.type]?.identifierExtractor){let i=app.utils.toArray(app.fieldTypes[e.type]?.identifierExtractor(e,n));for(let e of i)app.utils.pushUnique(r,e)}else app.utils.pushUnique(r,n+e.name);return r},getDummyFieldsData(e,n=!1){let r=e?.fields||[],i={};for(let e of r)if(!e.hidden)if(app.fieldTypes[e.type]?.dummyData){let r=app.fieldTypes[e.type].dummyData(e,n);r!==void 0&&(i[e.name]=r)}else i[e.name]=`[[DATA]]`;return i},parseIndex(e){let n={unique:!1,optional:!1,schemaName:``,indexName:``,tableName:``,columns:[],where:``},r=/create\s+(unique\s+)?\s*index\s*(if\s+not\s+exists\s+)?(\S*)\s+on\s+(\S*)\s*\(([\s\S]*)\)(?:\s*where\s+([\s\S]*))?/gim.exec((e||``).trim());if(r?.length!=7)return n;let i=/^[\"\'\`\[\{}]|[\"\'\`\]\}]$/gm;n.unique=r[1]?.trim().toLowerCase()===`unique`,n.optional=!app.utils.isEmpty(r[2]?.trim());let a=(r[3]||``).split(`.`);a.length==2?(n.schemaName=a[0].replace(i,``),n.indexName=a[1].replace(i,``)):(n.schemaName=``,n.indexName=a[0].replace(i,``)),n.tableName=(r[4]||``).replace(i,``);let o=(r[5]||``).replace(/,(?=[^\(]*\))/gim,`{PB_TEMP}`).split(`,`);for(let e of o){e=e.trim().replaceAll(`{PB_TEMP}`,`,`);let r=/^([\s\S]+?)(?:\s+collate\s+([\w]+))?(?:\s+(asc|desc))?$/gim.exec(e);if(r?.length!=4)continue;let a=r[1]?.trim()?.replace(i,``);a&&n.columns.push({name:a,collate:r[2]||``,sort:r[3]?.toUpperCase()||``})}return n.where=r[6]||``,n},buildIndex(e){let n=`CREATE `;e.unique&&(n+=`UNIQUE `),n+=`INDEX `,e.optional&&(n+=`IF NOT EXISTS `),e.schemaName&&(n+=`\`${e.schemaName}\`.`),n+=`\`${e.indexName||`idx_`+app.utils.randomString(10)}\` `,n+=`ON \`${e.tableName}\` (`;let r=e.columns.filter(e=>!!e?.name);return r.length>1&&(n+=` `),n+=r.map(e=>{let n=``;return e.name.includes(`(`)||e.name.includes(` `)?n+=e.name:n+="`"+e.name+"`",e.collate&&(n+=` COLLATE `+e.collate),e.sort&&(n+=` `+e.sort.toUpperCase()),n}).join(`, `),r.length>1&&(n+=` -`),n+=`)`,e.where&&(n+=` WHERE ${e.where}`),n},replaceIndexFields(e,n){let r=app.utils.parseIndex(e);return typeof n==`function`?Object.assign(r,n(r)||{}):Object.assign(r,n||{}),app.utils.buildIndex(r)},replaceIndexColumn(e,n,r){if(n===r)return e;let i=app.utils.parseIndex(e),a=!1;for(let e of i.columns)e.name===n&&(e.name=r,a=!0);return a?app.utils.buildIndex(i):e}};window.app=window.app||{},window.app.utils=_,window.app=window.app||{},window.app.utils=window.app.utils||{},window.app.utils.mimeTypes=[{ext:``,mimeType:`application/octet-stream`},{ext:`.xpm`,mimeType:`image/x-xpixmap`},{ext:`.7z`,mimeType:`application/x-7z-compressed`},{ext:`.zip`,mimeType:`application/zip`},{ext:`.xlsx`,mimeType:`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`},{ext:`.docx`,mimeType:`application/vnd.openxmlformats-officedocument.wordprocessingml.document`},{ext:`.pptx`,mimeType:`application/vnd.openxmlformats-officedocument.presentationml.presentation`},{ext:`.epub`,mimeType:`application/epub+zip`},{ext:`.apk`,mimeType:`application/vnd.android.package-archive`},{ext:`.jar`,mimeType:`application/jar`},{ext:`.odt`,mimeType:`application/vnd.oasis.opendocument.text`},{ext:`.ott`,mimeType:`application/vnd.oasis.opendocument.text-template`},{ext:`.ods`,mimeType:`application/vnd.oasis.opendocument.spreadsheet`},{ext:`.ots`,mimeType:`application/vnd.oasis.opendocument.spreadsheet-template`},{ext:`.odp`,mimeType:`application/vnd.oasis.opendocument.presentation`},{ext:`.otp`,mimeType:`application/vnd.oasis.opendocument.presentation-template`},{ext:`.odg`,mimeType:`application/vnd.oasis.opendocument.graphics`},{ext:`.otg`,mimeType:`application/vnd.oasis.opendocument.graphics-template`},{ext:`.odf`,mimeType:`application/vnd.oasis.opendocument.formula`},{ext:`.odc`,mimeType:`application/vnd.oasis.opendocument.chart`},{ext:`.sxc`,mimeType:`application/vnd.sun.xml.calc`},{ext:`.pdf`,mimeType:`application/pdf`},{ext:`.fdf`,mimeType:`application/vnd.fdf`},{ext:``,mimeType:`application/x-ole-storage`},{ext:`.msi`,mimeType:`application/x-ms-installer`},{ext:`.aaf`,mimeType:`application/octet-stream`},{ext:`.msg`,mimeType:`application/vnd.ms-outlook`},{ext:`.xls`,mimeType:`application/vnd.ms-excel`},{ext:`.pub`,mimeType:`application/vnd.ms-publisher`},{ext:`.ppt`,mimeType:`application/vnd.ms-powerpoint`},{ext:`.doc`,mimeType:`application/msword`},{ext:`.ps`,mimeType:`application/postscript`},{ext:`.psd`,mimeType:`image/vnd.adobe.photoshop`},{ext:`.p7s`,mimeType:`application/pkcs7-signature`},{ext:`.ogg`,mimeType:`application/ogg`},{ext:`.oga`,mimeType:`audio/ogg`},{ext:`.ogv`,mimeType:`video/ogg`},{ext:`.png`,mimeType:`image/png`},{ext:`.png`,mimeType:`image/vnd.mozilla.apng`},{ext:`.jpg`,mimeType:`image/jpeg`},{ext:`.jxl`,mimeType:`image/jxl`},{ext:`.jp2`,mimeType:`image/jp2`},{ext:`.jpf`,mimeType:`image/jpx`},{ext:`.jpm`,mimeType:`image/jpm`},{ext:`.jxs`,mimeType:`image/jxs`},{ext:`.gif`,mimeType:`image/gif`},{ext:`.webp`,mimeType:`image/webp`},{ext:`.exe`,mimeType:`application/vnd.microsoft.portable-executable`},{ext:``,mimeType:`application/x-elf`},{ext:``,mimeType:`application/x-object`},{ext:``,mimeType:`application/x-executable`},{ext:`.so`,mimeType:`application/x-sharedlib`},{ext:``,mimeType:`application/x-coredump`},{ext:`.a`,mimeType:`application/x-archive`},{ext:`.deb`,mimeType:`application/vnd.debian.binary-package`},{ext:`.tar`,mimeType:`application/x-tar`},{ext:`.xar`,mimeType:`application/x-xar`},{ext:`.bz2`,mimeType:`application/x-bzip2`},{ext:`.fits`,mimeType:`application/fits`},{ext:`.tiff`,mimeType:`image/tiff`},{ext:`.bmp`,mimeType:`image/bmp`},{ext:`.ico`,mimeType:`image/x-icon`},{ext:`.mp3`,mimeType:`audio/mpeg`},{ext:`.flac`,mimeType:`audio/flac`},{ext:`.midi`,mimeType:`audio/midi`},{ext:`.ape`,mimeType:`audio/ape`},{ext:`.mpc`,mimeType:`audio/musepack`},{ext:`.amr`,mimeType:`audio/amr`},{ext:`.wav`,mimeType:`audio/wav`},{ext:`.aiff`,mimeType:`audio/aiff`},{ext:`.au`,mimeType:`audio/basic`},{ext:`.mpeg`,mimeType:`video/mpeg`},{ext:`.mov`,mimeType:`video/quicktime`},{ext:`.mp4`,mimeType:`video/mp4`},{ext:`.avif`,mimeType:`image/avif`},{ext:`.3gp`,mimeType:`video/3gpp`},{ext:`.3g2`,mimeType:`video/3gpp2`},{ext:`.mp4`,mimeType:`audio/mp4`},{ext:`.mqv`,mimeType:`video/quicktime`},{ext:`.m4a`,mimeType:`audio/x-m4a`},{ext:`.m4v`,mimeType:`video/x-m4v`},{ext:`.heic`,mimeType:`image/heic`},{ext:`.heic`,mimeType:`image/heic-sequence`},{ext:`.heif`,mimeType:`image/heif`},{ext:`.heif`,mimeType:`image/heif-sequence`},{ext:`.mj2`,mimeType:`video/mj2`},{ext:`.dvb`,mimeType:`video/vnd.dvb.file`},{ext:`.webm`,mimeType:`video/webm`},{ext:`.avi`,mimeType:`video/x-msvideo`},{ext:`.flv`,mimeType:`video/x-flv`},{ext:`.mkv`,mimeType:`video/x-matroska`},{ext:`.asf`,mimeType:`video/x-ms-asf`},{ext:`.asf`,mimeType:`video/x-ms-wmv`},{ext:`.asf`,mimeType:`video/asf`},{ext:`.aac`,mimeType:`audio/aac`},{ext:`.voc`,mimeType:`audio/x-unknown`},{ext:`.m3u`,mimeType:`application/vnd.apple.mpegurl`},{ext:`.rmvb`,mimeType:`application/vnd.rn-realmedia-vbr`},{ext:`.gz`,mimeType:`application/gzip`},{ext:`.class`,mimeType:`application/x-java-applet`},{ext:`.swf`,mimeType:`application/x-shockwave-flash`},{ext:`.crx`,mimeType:`application/x-chrome-extension`},{ext:`.ttf`,mimeType:`font/ttf`},{ext:`.woff`,mimeType:`font/woff`},{ext:`.woff2`,mimeType:`font/woff2`},{ext:`.otf`,mimeType:`font/otf`},{ext:`.ttc`,mimeType:`font/collection`},{ext:`.eot`,mimeType:`application/vnd.ms-fontobject`},{ext:`.wasm`,mimeType:`application/wasm`},{ext:`.shx`,mimeType:`application/vnd.shx`},{ext:`.shp`,mimeType:`application/vnd.shp`},{ext:`.dbf`,mimeType:`application/x-dbf`},{ext:`.dcm`,mimeType:`application/dicom`},{ext:`.rar`,mimeType:`application/x-rar-compressed`},{ext:`.djvu`,mimeType:`image/vnd.djvu`},{ext:`.mobi`,mimeType:`application/x-mobipocket-ebook`},{ext:`.lit`,mimeType:`application/x-ms-reader`},{ext:`.bpg`,mimeType:`image/bpg`},{ext:`.cbor`,mimeType:`application/cbor`},{ext:`.sqlite`,mimeType:`application/vnd.sqlite3`},{ext:`.dwg`,mimeType:`image/vnd.dwg`},{ext:`.nes`,mimeType:`application/vnd.nintendo.snes.rom`},{ext:`.lnk`,mimeType:`application/x-ms-shortcut`},{ext:`.macho`,mimeType:`application/x-mach-binary`},{ext:`.qcp`,mimeType:`audio/qcelp`},{ext:`.icns`,mimeType:`image/x-icns`},{ext:`.hdr`,mimeType:`image/vnd.radiance`},{ext:`.mrc`,mimeType:`application/marc`},{ext:`.mdb`,mimeType:`application/x-msaccess`},{ext:`.accdb`,mimeType:`application/x-msaccess`},{ext:`.zst`,mimeType:`application/zstd`},{ext:`.cab`,mimeType:`application/vnd.ms-cab-compressed`},{ext:`.rpm`,mimeType:`application/x-rpm`},{ext:`.xz`,mimeType:`application/x-xz`},{ext:`.lz`,mimeType:`application/lzip`},{ext:`.torrent`,mimeType:`application/x-bittorrent`},{ext:`.cpio`,mimeType:`application/x-cpio`},{ext:``,mimeType:`application/tzif`},{ext:`.xcf`,mimeType:`image/x-xcf`},{ext:`.pat`,mimeType:`image/x-gimp-pat`},{ext:`.gbr`,mimeType:`image/x-gimp-gbr`},{ext:`.glb`,mimeType:`model/gltf-binary`},{ext:`.cab`,mimeType:`application/x-installshield`},{ext:`.jxr`,mimeType:`image/jxr`},{ext:`.parquet`,mimeType:`application/vnd.apache.parquet`},{ext:`.txt`,mimeType:`text/plain`},{ext:`.html`,mimeType:`text/html`},{ext:`.svg`,mimeType:`image/svg+xml`},{ext:`.xml`,mimeType:`text/xml`},{ext:`.rss`,mimeType:`application/rss+xml`},{ext:`.atom`,mimeType:`application/atom+xml`},{ext:`.x3d`,mimeType:`model/x3d+xml`},{ext:`.kml`,mimeType:`application/vnd.google-earth.kml+xml`},{ext:`.xlf`,mimeType:`application/x-xliff+xml`},{ext:`.dae`,mimeType:`model/vnd.collada+xml`},{ext:`.gml`,mimeType:`application/gml+xml`},{ext:`.gpx`,mimeType:`application/gpx+xml`},{ext:`.tcx`,mimeType:`application/vnd.garmin.tcx+xml`},{ext:`.amf`,mimeType:`application/x-amf`},{ext:`.3mf`,mimeType:`application/vnd.ms-package.3dmanufacturing-3dmodel+xml`},{ext:`.xfdf`,mimeType:`application/vnd.adobe.xfdf`},{ext:`.owl`,mimeType:`application/owl+xml`},{ext:`.php`,mimeType:`text/x-php`},{ext:`.js`,mimeType:`text/javascript`},{ext:`.lua`,mimeType:`text/x-lua`},{ext:`.pl`,mimeType:`text/x-perl`},{ext:`.py`,mimeType:`text/x-python`},{ext:`.json`,mimeType:`application/json`},{ext:`.geojson`,mimeType:`application/geo+json`},{ext:`.har`,mimeType:`application/json`},{ext:`.ndjson`,mimeType:`application/x-ndjson`},{ext:`.rtf`,mimeType:`text/rtf`},{ext:`.srt`,mimeType:`application/x-subrip`},{ext:`.tcl`,mimeType:`text/x-tcl`},{ext:`.csv`,mimeType:`text/csv`},{ext:`.tsv`,mimeType:`text/tab-separated-values`},{ext:`.vcf`,mimeType:`text/vcard`},{ext:`.ics`,mimeType:`text/calendar`},{ext:`.warc`,mimeType:`application/warc`},{ext:`.vtt`,mimeType:`text/vtt`},{ext:`.pbm`,mimeType:`image/x-portable-bitmap`},{ext:`.pgm`,mimeType:`image/x-portable-graymap`},{ext:`.ppm`,mimeType:`image/x-portable-pixmap`},{ext:`.eml`,mimeType:`message/rfc822`}];var v=new BroadcastChannel(`tabsSync`),ee=`pbSettings`,te=`pbColorScheme`;window.app=window.app||{},window.app.store=store({_ready:!1,superuser:null,showHeader:!0,page:t.div({className:`page`},()=>{if(!app.store._ready)return t.span({className:`loader lg m-auto`,title:`Loading plugins...`})}),mainLogo:`./images/logo.svg`,headerLogo:`./images/logo_white.svg`,favicon:``,title:``,_mediaColorScheme:``,userColorScheme:window.localStorage.getItem(te)||``,get activeColorScheme(){return app.store.userColorScheme?app.store.userColorScheme:app.store._mediaColorScheme||`light`},errors:null,creditLinks:[{href:`https://pocketbase.io/docs`,icon:`ri-book-open-line`,label:`Docs`},{href:`https://github.com/pocketbase/pocketbase/releases`,icon:`ri-github-line`,label:`PocketBase v0.37.6-dev`}],headerLinks:[{href:`#/collections`,icon:`ri-database-2-line`,label:`Collections`},{href:`#/logs`,icon:`ri-bar-chart-box-line`,label:`Logs`},{href:`#/settings`,icon:`ri-settings-3-line`,label:`Settings`}],settingsNavGroups:{System:[{href:`#/settings`,icon:`ri-home-gear-line`,label:`Application`},{href:`#/settings/mail`,icon:`ri-send-plane-2-line`,label:`Mail settings`},{href:`#/settings/storage`,icon:`ri-archive-drawer-line`,label:`Files storage`},{href:`#/settings/backups`,icon:`ri-archive-line`,label:`Backups`},{href:`#/settings/crons`,icon:`ri-time-line`,label:`Crons`}],Sync:[{href:`#/settings/export-collections`,icon:`ri-uninstall-line`,label:`Export collections`},{href:`#/settings/import-collections`,icon:`ri-install-line`,label:`Import collections`}]},predefinedAccentColors:[`#1055c9`,`#a3142a`,`#096d5c`,`#e6620a`,`#007d9c`,`#3f3da9`],settings:app.utils.getLocalHistory(ee,{}),isLoadingSettings:!1,async loadSettings(){app.store.isLoadingSettings=!0;try{let e=await app.pb.settings.getAll({requestKey:`appStore.loadSettings`});app.store.settings=e,app.store.isLoadingSettings=!1}catch(e){e.isAbort||(app.store.isLoadingSettings=!1,app.checkApiError(e))}},collections:[],collectionScaffolds:{},isLoadingCollections:!1,_activeCollectionIdOrName:``,get activeCollection(){let e=app.store._activeCollectionIdOrName;return app.store.collections.find(n=>n.id==e||n.name==e)||app.store.collections[0]},set activeCollection(e){typeof e==`string`?app.store._activeCollectionIdOrName=e:app.store._activeCollectionIdOrName=e?.id},async silentlyReloadCollections(){try{let e=await app.pb.collections.getFullList({requestKey:`appStore.silentlyReloadCollections`});e=app.utils.sortedCollectionsByType(e),JSON.stringify(e)!=JSON.stringify(app.store.collections)&&(app.store.collections=e)}catch(e){e.isAbort||console.warn(`failed to reload app store collections:`,e)}},async loadCollections(e=null){app.store.isLoadingCollections=!0;try{let[n,r]=await Promise.all([app.pb.collections.getScaffolds({requestKey:`appStore.loadCollections.getScaffolds`}),app.pb.collections.getFullList({requestKey:`appStore.loadCollections.getFullList`})]);r=app.utils.sortedCollectionsByType(r),JSON.stringify(app.store.collections)!=JSON.stringify(r)&&(app.store.collections=r),app.store.collectionScaffolds=n,app.store._activeCollectionIdOrName=e||app.store._activeCollectionIdOrName||app.store.collections[0]?.id||``,app.store.isLoadingCollections=!1}catch(e){e.isAbort||(app.store.isLoadingCollections=!1,app.checkApiError(e))}},addOrUpdateCollection(e){let n=app.store.collections.findIndex(n=>n.id==e.id);n>=0?(app.store.activeCollection.id==e.id&&(app.store._activeCollectionIdOrName=e.id),app.store.collections[n]=e):app.store.collections.push(e),app.store.collections=app.utils.sortedCollectionsByType(app.store.collections)},oauth2Providers:[],isLoadingOAuth2Providers:!1,async loadOAuth2Providers(){app.store.isLoadingOAuth2Providers=!0;try{app.store.oauth2Providers=await app.pb.send(`/api/collections/meta/oauth2-providers`),app.store.isLoadingOAuth2Providers=!1}catch(e){e.isAbort||(app.checkApiError(e),app.store.isLoadingOAuth2Providers=!1)}}}),window.addEventListener(`hashchange`,()=>{app.store.title=``,app.store.errors=null}),watch(()=>{let e=app.utils.toArray(app.store.title),n=app.store.settings?.meta?.appName||``;n&&e.push(n),document.title=e.join(` - `)});var y;watch(()=>app.store.settings?.meta?.accentColor,e=>{y||(y=t.meta({name:`theme-color`}),document.head.appendChild(y)),e?(y?.setAttribute(`content`,e),document.documentElement.style.setProperty(`--accentColor`,e)):(y?.removeAttribute(`content`),document.documentElement.style.removeProperty(`--accentColor`))});var ne;watch(()=>app.store.favicon,e=>{ne||(ne=t.link({rel:`icon`}),document.head.appendChild(ne)),e?ne.href=e:ne.href=window.location.href.startsWith(`https://`)?`./images/favicon_prod.png`:`./images/favicon.png`});var re=window.matchMedia(`(prefers-color-scheme: dark)`);app.store._mediaColorScheme=re.matches?`dark`:`light`,re.addEventListener(`change`,({matches:e})=>{app.store._mediaColorScheme=e?`dark`:`light`}),watch(()=>app.store.userColorScheme,e=>{e?window.localStorage.setItem(te,e):window.localStorage.removeItem(te),v?.postMessage({colorScheme:e})});var ie;watch(()=>app.store.activeColorScheme,e=>{clearTimeout(ie),document.documentElement.style.setProperty(`--animationSpeed`,`0`),document.documentElement.setAttribute(`data-color-scheme`,e),ie=setTimeout(()=>{document.documentElement.style.removeProperty(`--animationSpeed`)},100)});function ae(e,n){e.__errListener&&=(e.removeEventListener(`input`,e.__errListener),e.removeEventListener(`change`,e.__errListener),null),e.setCustomValidity&&(e.setCustomValidity(``),e._oldTitle?e.setAttribute(`title`,e._oldTitle):e.removeAttribute(`title`)),e.removeAttribute(`data-error`);let r=n.nextSibling;r&&r.classList?.contains(`generated-error`)&&r.getAttribute(`data-input-name`)==e.getAttribute(`name`)&&r.remove(),n.querySelector(`[data-error]`)||n.classList.remove(`error`)}watch(()=>JSON.stringify(app.store.errors)&&app.store.errors,e=>{let n=document.querySelectorAll(`[name]`);for(let r of n){if(r.classList.contains(`no-error`))continue;let n=r.closest(`.field-list`)||r.closest(`.fields`)||r.closest(`.field`);if(!n)continue;let i=r.getAttribute(`name`);ae(r,n);let a=app.utils.getByPath(e,i)?.message;a&&(n.classList.add(`error`),r.__errListener=function(){ae(r,n),app.utils.deleteByPath(app.store.errors,i)},r.addEventListener(`input`,r.__errListener),r.addEventListener(`change`,r.__errListener),r.setAttribute(`data-error`,!0),r.setCustomValidity&&r.reportValidity&&r.classList.contains(`inline-error`)?(r.setCustomValidity(a),r.reportValidity(),r._oldTitle=r.title,r.title=a):n.after(t.div({"html-data-input-name":i,className:`field-help error generated-error`,textContent:a})))}}),v.onmessage=e=>{e.data?.collections&&JSON.stringify(app.store.collections)!=JSON.stringify(e.data.collections)&&(app.store.collections=e.data.collections),e.data?.settings&&JSON.stringify(app.store.settings)!=JSON.stringify(e.data.settings)&&(app.store.settings=e.data.settings),e.data?.colorScheme&&(app.store.userColorScheme=e.data.colorScheme)},watch(()=>JSON.stringify(app.store.collections),(e,n)=>{e&&e!=`[]`&&n&&n!=`[]`&&e!=n&&v?.postMessage({collections:JSON.parse(e)})}),watch(()=>JSON.stringify(app.store.settings),(e,n)=>{e&&e!=`{}`&&n&&n!=`{}`&&e!=n&&v?.postMessage({settings:JSON.parse(e)}),window.localStorage.setItem(ee,e)});var b=`#/login`,x=window.location.pathname.endsWith(`/`)?window.location.pathname.substring(0,window.location.pathname.length-1):window.location.pathname;window.app=window.app||{},window.app.pb=new i(`../`,new r(`__pb_superusers__`+x)),app.pb.beforeSend=function(e,n){return n.headers[`x-request-source`]=`pbui`,{url:e,options:n}},app.store.superuser=app.pb.authStore.record,app.pb.authStore.onChange((e,n)=>{!n&&window.location.hash!=b&&(app.modals.close(),window.location.hash=b),app.store.superuser=n}),app.pb.authStore.isValid&&app.pb.collection(app.pb.authStore.record?.collectionName||`_superusers`).authRefresh().catch(e=>{console.warn(`Failed to refresh the existing auth token:`,e);let n=e?.status<<0;(n==401||n==403)&&(app.utils.rememberPath(),app.pb.cancelAllRequests(),app.pb.authStore.clear())}),app.pb.authStore.onChange((e,n)=>{n?.id&&(app.store.loadCollections(),app.store.loadSettings(),app.store.loadOAuth2Providers())});var oe=app.pb.collection;app.pb.collection=function(e){let n=oe.call(this,e);return se(n),n};function se(e){if(e.__customUIEvents)return;e.__customUIEvents=!0;let n=e.create;e.create=function(){return n.apply(e,arguments).then(e=>(setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:create`,{detail:e})),document.dispatchEvent(new CustomEvent(`record:save`,{detail:e}))},0),e))};let r=e.update;e.update=function(){return r.apply(e,arguments).then(e=>(setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:update`,{detail:e})),document.dispatchEvent(new CustomEvent(`record:save`,{detail:e}))},0),e))};let i=e.delete;e.delete=function(){return i.apply(e,arguments).then(n=>{let r={id:arguments[0],collectionId:e.collectionIdOrName,collectionName:e.collectionIdOrName};return setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:delete`,{detail:r}))},0),n})}}var ce=`pbLastFileToken`,S=!1,le=[];app.pb.authStore.onChange((e,n)=>{n?.id||window.localStorage.removeItem(ce)}),window.app.getFileToken=async function(n=``){let r=n&&app.store.collections?.find(e=>e.id==n||e.name==n);if(r&&!r.fields?.find(e=>e.type==`file`&&e.protected))return;let i=window.localStorage.getItem(ce);return(!i||e(i,60))&&(i=await C()),i};async function C(){return new Promise(async(e,n)=>{if(le.push({resolve:e,reject:n}),!S){S=!0;try{let e=await app.pb.files.getToken();window.localStorage.setItem(ce,e),le.forEach(n=>n.resolve(e))}catch(e){le.forEach(n=>n.reject(e))}S=!1,le=[]}})}window.app.checkApiError=function(e,n=!0){if(!e||!(e instanceof Error)||e.isAbort){console.warn(`checkApiError - unexpected error type:`,e);return}let r=e?.status<<0,i=e?.response||{},a=n&&(i.message||e.message||`Something went wrong!`);if(a&&app.toasts.error(a),r==0&&console.log(e),app.utils.isEmpty(i.data)||(app.store.errors=i.data),r===401&&window.location.hash!=b)return app.utils.rememberPath(),app.pb.cancelAllRequests(),app.pb.authStore.clear();r===403&&(app.pb.cancelAllRequests(),window.location.hash!=b&&(window.location.hash=b))};function ue(){return()=>{if(!(!app.store._ready||!app.store.showHeader||!app.store.superuser?.id))return t.header({pbEvent:`appHeader`,rid:`appHeader`,className:`app-header accent-surface`,onmount:async e=>{await new Promise(e=>setTimeout(e,0)),e._scrollToActiveMenuItem=function(){e?.querySelector(`.app-main-nav .header-link.active`)?.scrollIntoView()},e._scrollToActiveMenuItem(),window.addEventListener(`hashchange`,e._scrollToActiveMenuItem)},onunmount:e=>{window.removeEventListener(`hashchange`,e?._scrollToActiveMenuItem)}},t.a({href:`#/`,className:`logo`},t.img({src:()=>app.store.headerLogo,alt:`App logo`})),t.nav({pbEvent:`mainNav`,className:`app-main-nav`},()=>app.store.headerLinks.map(e=>{let n=e.href.startsWith(`#/`);return t.a({href:()=>e.href,target:()=>n?void 0:`_blank`,rel:()=>n?void 0:`noopener noreferrer`,className:n=>`header-link ${e.isActive?.(n)||app.utils.isActivePath(e.href)?`active`:``}`},()=>{if(e.icon)return t.i({className:e.icon,ariaHidden:!0})},t.span({className:`txt`},()=>e.label))})),t.div({className:`flex-fill app-header-separator`}),w(),t.button({type:`button`,className:`header-link logged-user txt-normal`,"html-popovertarget":`logged-user-dropdown`},t.span({className:`superuser-name txt-ellipsis`},()=>app.store.superuser?.email),t.i({className:`ri-arrow-drop-down-line`,ariaHidden:!0})),t.div({pbEvent:`loggedUserDropdown`,id:`logged-user-dropdown`,className:`dropdown sm nowrap logged-user-dropdown`,popover:`auto`},t.a({className:`dropdown-item dropdown-item-manage`,href:`#/collections?collection=_superusers`,onclick:e=>{e.target.closest(`.dropdown`).hidePopover()}},t.i({className:`ri-group-line`,ariaHidden:!0}),t.span({className:`txt`},`Manage superusers`)),t.hr(),t.button({type:`button`,className:`dropdown-item txt-danger dropdown-item-logout`,onclick:()=>app.pb.authStore.clear()},t.i({className:`ri-logout-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Logout`))))}}function w(){let e=[{value:`light`,icon:`ri-sun-line`,label:`Light`},{value:`dark`,icon:`ri-moon-line`,label:`Dark`},{value:``,icon:`ri-subtract-line`,label:`Auto`}];return[t.button({type:`button`,className:`header-link color-scheme-picker`,"html-popovertarget":`color-scheme-dropdown`,title:`Color scheme`},t.i({className:()=>app.store.activeColorScheme==`dark`?`ri-moon-line`:`ri-sun-line`,ariaHidden:!0})),t.div({pbEvent:`colorSchemeDropdown`,id:`color-scheme-dropdown`,className:`dropdown sm nowrap color-scheme-dropdown`,popover:`auto`},()=>e.map(e=>t.button({type:`button`,className:()=>`dropdown-item dropdown-item-light ${app.store.userColorScheme==e.value?`active`:``}`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),app.store.userColorScheme=e.value}},t.i({className:e.icon,ariaHidden:!0}),t.span({className:`txt`},e.label))))]}document.addEventListener(`invalid`,e=>{let n=e.target.closest(`details`);n&&!n.open&&!e.target.closest(`summary`)&&(n.open=!0,e.target.reportValidity&&e.target.reportValidity())},!0);var T=`dropdown-item`;document.addEventListener(`toggle`,e=>{if(e.newState!=`open`||!e.target||e.target.__keyboardNavRegistered||!e.target.matches(`.dropdown`))return;e.target.__keyboardNavRegistered=!0;let n=e.target;function r(e){if(!n.isConnected){document.removeEventListener(`keydown`,r);return}let i;if(i=document.activeElement&&document.activeElement.classList.contains(T)?document.activeElement:n.querySelector(`.`+T+`:not([hidden]):not(.disabled)`),i){if(e.key==`ArrowUp`){e.preventDefault();let n=D(i,-1);i==document.activeElement&&n?.classList?.contains(T)?n?.focus():i.focus()}else if(e.key==`ArrowDown`){e.preventDefault();let n=D(i,1);i==document.activeElement&&n?.classList?.contains(T)?n?.focus():i.focus()}else if(e.keyCode>=65&&e.keyCode<=90||e.keyCode>=48&&e.keyCode<=57){let e=n.querySelectorAll(`input,textare,select`);e.length==1&&e[0].focus()}}}n.addEventListener(`toggle`,e=>{e.newState==`open`?(E(e.target.id,!0),document.addEventListener(`keydown`,r)):(E(e.target.id,!1),document.removeEventListener(`keydown`,r))})},!0);function E(e,n=!1){e&&document.querySelectorAll(`[popovertarget='`+e+`']`)?.forEach(e=>e.setAttribute(`data-popover-state`,n))}function D(e,n=-1){let r=n<0?e.previousElementSibling:e.nextElementSibling;return r&&(r.hidden||r.classList.contains(`disabled`)||!r.classList.contains(T))?D(r,n):r}var O=5,k=t.div({ariaHidden:!0,popover:`manual`,className:`pb-tooltip`});document.body.appendChild(k);function A(e,n){let r=e.getBoundingClientRect();k.setAttribute(`data-position`,n),k.style.top=`0px`,k.style.left=`0px`;let i=k.offsetHeight,a=k.offsetWidth,o=0,s=0;n==`left`?(o=r.top+r.height/2-i/2,s=r.left-a-O):n==`right`?(o=r.top+r.height/2-i/2,s=r.right+O):n==`top`?(o=r.top-i-O,s=r.left+r.width/2-a/2):n==`top-left`?(o=r.top-i-O,s=r.left):n==`top-right`?(o=r.top-i-O,s=r.right-a):n==`bottom-left`?(o=r.top+r.height+O,s=r.left):n==`bottom-right`?(o=r.top+r.height+O,s=r.right-a):(o=r.top+r.height+O,s=r.left+r.width/2-a/2),s+a>document.documentElement.clientWidth&&(s=document.documentElement.clientWidth-a),s=s>=0?s:0,o+i>document.documentElement.clientHeight&&(o=document.documentElement.clientHeight-i),o=o>=0?o:0,k.style.top=o+`px`,k.style.left=s+`px`}function j(){k.hidePopover()}function de(e,n,r){if(!e||!n){j();return}k.showPopover(),k.textContent=n,A(e,r)}document.body.addEventListener(`mouseleave`,()=>{j()});function fe(e,n=`top`){return r=>{if(!r._tooltipText){r._tooltipText=store({value:``});let e;function i(){e?.unwatch(),e=watch(()=>r._tooltipText.value,async e=>{de(r,e,n)})}async function a(){e?.unwatch(),e=null,j()}r.addEventListener(`mouseenter`,i),r.addEventListener(`focusin`,i),r.addEventListener(`mouseleave`,a),r.addEventListener(`focusout`,a),r.addEventListener(`blur`,a);let o=r.onunmount;r.onunmount=n=>{e?.unwatch(),n._tooltipText=null,n?.removeEventListener(`mouseenter`,i),n?.removeEventListener(`focusin`,i),n?.removeEventListener(`mouseleave`,a),n?.removeEventListener(`focusout`,a),n?.removeEventListener(`blur`,a),o(n)}}return typeof e==`function`?r._tooltipText.value=e():r._tooltipText.value=e,r._tooltipText.value}}window.app=window.app||{},window.app.attrs=window.app.attrs||{},window.app.attrs.tooltip=fe,window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.confirm=function(e,n,r,i={className:void 0,yesButton:``,noButton:``}){M.textOrElem=e,M.yesCallback=n,M.yesCallbackWaiting=!1,M.noCallback=r,M.noCallbackWaiting=!1,M.className=typeof i.className==`string`?i.className:`sm`,M.yesButton=i.yesButton||`Yes`,M.noButton=i.noButton||`No`,pe.isConnected||document.body.appendChild(pe),window.app.modals.open(pe)};var M=store({className:``,textOrElem:null,yesButton:``,yesCallback:null,yesCallbackWaiting:!1,noButton:``,noCallback:null,noCallbackWaiting:!1,get isBusy(){return M.yesCallbackWaiting||M.noCallbackWaiting}}),pe=t.div({className:()=>`modal popup manual ${M.className||``}`},t.div({className:`modal-content`},e=>typeof M.textOrElem==`string`?t.h6({className:`block txt-center`},M.textOrElem):typeof M.textOrElem==`function`?M.textOrElem(e):M.textOrElem),t.footer({className:`modal-footer p-sm`},t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.button({type:`button`,className:()=>`btn lg block secondary ${M.noCallbackWaiting?`loading`:``}`,disabled:()=>M.isBusy,onclick:async()=>{if(M.noCallback){M.noCallbackWaiting=!0;try{if(await M.noCallback()===!1)return}catch(e){console.log(`confirm noCallback error:`,e)}finally{M.noCallbackWaiting=!1}}window.app.modals.close(pe)}},()=>typeof M.noButton==`string`?t.span({className:`txt`},M.noButton):typeof M.noButton==`function`?M.noButton(el):M.noButton)),t.div({className:`col-sm-6`},t.button({type:`button`,className:()=>`btn lg block warning ${M.yesCallbackWaiting?`loading`:``}`,disabled:()=>M.isBusy,onclick:async()=>{if(M.yesCallback){M.yesCallbackWaiting=!0;try{if(await M.yesCallback()===!1)return}catch(e){console.log(`confirm yesCallback error:`,e)}finally{M.yesCallbackWaiting=!1}}window.app.modals.close(pe)}},()=>typeof M.yesButton==`string`?t.span({className:`txt`},M.yesButton):typeof M.yesButton==`function`?M.yesButton(el):M.yesButton)))));window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.dragline=function(e={}){let n,r=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,tolerance:0,ondragstart:function(e){},ondragstop:function(e){},ondragging:function(e,n,r){}}),i=app.utils.extendStore(r,e),a=store({dragStarted:!1}),o,s,c,l;function u(){document.addEventListener(`touchmove`,m),document.addEventListener(`mousemove`,m),document.addEventListener(`touchend`,p),document.addEventListener(`mouseup`,p)}function d(){document.removeEventListener(`touchmove`,m),document.removeEventListener(`mousemove`,m),document.removeEventListener(`touchend`,p),document.removeEventListener(`mouseup`,p)}function f(e){e.stopPropagation(),o=e.clientX,s=e.clientY,c=e.clientX-n.offsetLeft,l=e.clientY-n.offsetTop,u()}function p(e){a.dragStarted&&(e.preventDefault(),a.dragStarted=!1,r.ondragstop?.(e)),d()}function m(e){let i=e.clientX-o,u=e.clientY-s,d=e.clientX-c,f=e.clientY-l;!a.dragStarted&&Math.abs(d-n.offsetLeft)r.id,hidden:()=>r.hidden,inert:()=>r.inert,className:()=>`dragline ${a.dragStarted?`dragging`:``} ${r.className}`,onmousedown:e=>{e.button==0&&f(e)},ontouchstart:f,onunmount:()=>{d(),i.forEach(e=>e?.unwatch())}}),n},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.slide=function(e,...n){let r;return t.div({className:n=>`block slide-block ${e?.(n)?``:`hidden`}`,onmount:e=>{r=setTimeout(()=>{e?.setAttribute(`data-slide`,`1`)},200)},onunmount:()=>{clearTimeout(r)}},...n)},window.app=window.app||{},window.app.modals=window.app.modals||{};var N=`data-modal-state`,me=`manual`,he;window.app.modals.open=async function(e){if(!e?.isConnected){console.error(`modals.open requies an active DOM element`,e);return}let n;if(e.onbeforeopen&&(n=await e.onbeforeopen(e)),n===!1)return;if(e.onafteropen){let n=new ResizeObserver(r=>{for(let i of r)i.contentRect.height>0&&e?.onafteropen&&(e.onafteropen(e),n.disconnect(),n=null)});n.observe(e)}he=document.activeElement,ge(e),e._forceClose=()=>app.modals.close(e,!0),window.addEventListener(`popstate`,e._forceClose);let r=Math.max(_e(e)?.style.zIndex<<0,1e3);e.style.zIndex=r+1,e.setAttribute(N,`open`)},window.app.modals.close=async function(e=null,n=!1){if(e||=_e(),e){if(window.removeEventListener(`popstate`,e._forceClose),n)e.onbeforeclose?.(e,!0),e.setAttribute(N,`close`),e.onafterclose?.(e,!0);else{if(e.onbeforeclose&&await e.onbeforeclose(e,!1)===!1)return;if(e.onafterclose){let n=new ResizeObserver(r=>{for(let i of r)i.contentRect.height<=0&&e?.onafterclose&&(e.onafterclose(e,!1),n.disconnect(),n=null)});n.observe(e)}e.setAttribute(N,`close`)}he&&(he.focus?.(),setTimeout(()=>{he?.blur?.(),he=null},0))}};function ge(e){if(e.getAttribute(`tabindex`)||e.setAttribute(`tabindex`,`-1`),setTimeout(()=>{let n=e?.querySelector(`[autofocus]`);n?n.focus():e?.focus()},0),e.getAttribute(N))return;e.setAttribute(N,``),e.addEventListener(`keydown`,n=>{n.key!=`Escape`||e.classList.contains(me)||n.target!==e&&e.contains(n.target)||window.app.modals.close(e)});let n=!1,r=r=>{n=r.target!==e&&e.contains(r.target)};e.addEventListener(`mousedown`,r),e.addEventListener(`touchstart`,r);let i=!1,a=n=>{i=n.target!==e&&e.contains(n.target)};e.addEventListener(`mouseup`,a),e.addEventListener(`touchend`,a),e.addEventListener(`click`,r=>{n||i||e.classList.contains(me)||r.target!==e&&e.contains(r.target)||window.app.modals.close(e)})}function _e(e){let n=document.querySelectorAll(`[${N}="open"]`),r=0,i=0,a;for(let o of n)e&&o==e||(r=o.style.zIndex<<0,r>i&&(i=r,a=o));return a}var ve=new Map,ye=t.div({className:`toasts-container`});function be(e,n=!0){let r=ve.get(e);!r||!r.isConnected||(ve.delete(e),clearTimeout(r._removeTimeout),n?(r.classList.add(`removing`),setTimeout(()=>{r.remove()},300)):r.remove())}function xe(e=!0){ve.forEach((n,r)=>{window.app.toasts.remove(r,e)})}function Se(e,n={}){n.type=`info`,n.duration=n.duration||3e3,Te(e,n)}function Ce(e,n={}){n.type=`success`,n.duration=n.duration||3e3,Te(e,n)}function we(e,n={}){n.type=`error`,n.duration=n.duration||3500,Te(e,n)}function Te(e,n={}){n=Object.assign({duration:3e3,key:void 0,type:`info`},n),ye.isConnected||document.body.appendChild(ye);let r=n.key||e;ve.has(r)&&be(r,!1);function i(e){e?._removeTimeout&&clearTimeout(e?._removeTimeout),e._removeTimeout=setTimeout(()=>{be(r)},n.duration)}let a=t.div({className:`toast ${n.type||``}`,onmount:e=>{i(e)},onunmount:e=>{e?._removeTimeout&&(clearTimeout(e?._removeTimeout),a=null)},onmouseover:()=>{clearTimeout(a?._removeTimeout)},onmouseout:()=>{i(a)}},t.div({className:`toast-container`},t.div({className:`toast-icon`}),t.div({className:`toast-content`},e,t.button({type:`button`,className:`m-l-auto btn circle sm transparent secondary toast-remove`,title:`Clear`,onclick:()=>be(r)},t.i({className:`ri-close-line`,ariaHidden:!0})))));ve.set(r,a),ye.prepend(a)}window.app=window.app||{},window.app.toasts=window.app.toasts||{},window.app.toasts.info=Se,window.app.toasts.error=we,window.app.toasts.success=Ce,window.app.toasts.remove=be,window.app.toasts.removeAll=xe,window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.sortable=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,data:[],dataItem:function(e,n,r){return t.span(null,`Item `+n)},onchange:function(e,n,r){},handle:``,before:void 0,after:void 0}),r=app.utils.extendStore(n,e);function i(e){function r(){e.querySelectorAll(`:scope > [data-dragstart="true"]`)?.forEach(e=>{e.dataset.dragstart=!1}),e.querySelectorAll(`:scope > [data-dragover="true"]`)?.forEach(e=>{e.dataset.dragover=!1})}e.addEventListener(`dragstart`,r=>{if(n.handle&&!r.target.closest(n.handle)){r.preventDefault();return}let i=o(e,r.target);i&&(i.dataset.dragstart=!0)}),e.addEventListener(`dragenter`,n=>{for(let n of e.children)n.dataset.dragover&&(n.dataset.dragover=!1);let r=o(e,n.target);r&&(r.dataset.dragover=!0)}),e.addEventListener(`dragend`,e=>{r()}),e.addEventListener(`dragover`,e=>{e.preventDefault()}),e.addEventListener(`drop`,i=>{if(!n.onchange){r();return}let s=e.querySelector(`:scope > [data-dragstart="true"]`),c=o(e,i.target);if(r(),!s||!c||c==s)return;let l=a(s),u=a(c),d=n.data.slice(),f=d.splice(l,1);d.splice(u,0,f[0]),n.onchange(d,l,u)})}function a(e){if(!e?.parentNode)return-1;for(let n=0;nn.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>n.className,onmount:e=>{i(e)},onunmount:e=>{r.forEach(e=>e?.unwatch())}},e=>typeof n.before==`function`?n.before(e):n.before,e=>{let r=[];for(let i=0;itypeof n.after==`function`?n.after(e):n.after)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.copyButton=function(e,...n){let r=store({active:!1}),i;function a(){let n=e;typeof n==`function`&&(n=e()),app.utils.copyToClipboard(n),r.active=!0,clearTimeout(i),i=setTimeout(()=>{r.active=!1},500)}return t.button({tabIndex:-1,type:`button`,className:()=>`copy-to-clipboard ${r.active?`active`:``}`,title:`Copy`,ariaDescription:app.attrs.tooltip(()=>r.active?`Copied`:null),onclick:e=>{e.preventDefault(),e.stopPropagation(),a()}},t.i({hidden:n?.length,ariaHidden:!0,className:()=>`copy-icon ${r.active?`ri-check-double-line`:`ri-file-copy-line`}`}),...n)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeBlock=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,language:`js`,value:void 0,footnote:void 0}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`code-wrapper ${n.className}`,tabIndex:-1,onmount:e=>{e.addEventListener(`keydown`,n=>{(n.ctrlKey||n.metaKey)&&(n.key==`a`||n.key==`A`)&&(n.preventDefault(),window.getSelection().selectAllChildren(e))})},onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.code({className:`block`,innerHTML:()=>Ee(n.value,n.language)}),t.div({className:`footnote`},e=>typeof n.footnote==`function`?n.footnote(e):n.footnote))};function Ee(e,n){return e=typeof e==`string`?e:``,e=Prism.plugins.NormalizeWhitespace.normalize(e,{"remove-trailing":!0,"remove-indent":!0,"left-trim":!0,"right-trim":!0}),Prism.highlight(e,Prism.languages[n]||Prism.languages.js,n)}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeEditor=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,name:void 0,className:``,value:``,language:`js`,placeholder:``,disabled:!1,required:!1,singleLine:!1,autocomplete:void 0,oninput:function(e){},onfocus:function(e){},onblur:function(e){}}),r=app.utils.extendStore(n,e,`autocomplete`),i,a,o=!0;function s(e){c(),i=t.div({className:`dropdown autocomplete code-editor-dropdown`,onmount:e=>{e._updatePosition=()=>{o?Pe(i):c()},e._closeOnEsc=e=>{e.key==`Escape`&&(e.preventDefault(),c())},window.addEventListener(`scroll`,e._updatePosition,!0),window.addEventListener(`resize`,e._updatePosition),window.addEventListener(`keydown`,e._closeOnEsc),e._updatePosition()},onunmount:e=>{e&&(window.removeEventListener(`scroll`,e._updatePosition,!0),window.removeEventListener(`resize`,e._updatePosition),window.removeEventListener(`keydown`,e._closeOnEsc))}},e),document.body.appendChild(i),f&&(a?.disconnect(),a=new IntersectionObserver(([e])=>{o=e.isIntersecting},{root:null,threshold:.1}),a.observe(f))}function c(){i&&=(i.remove(),null),a&&=(a.disconnect(),null),o=!0}function l(e){n.value=e,n.oninput?.(e),f.dispatchEvent(new CustomEvent(`change`,{detail:e}))}let u=!1,d,f=t.div({contentEditable:()=>n.disabled?!1:`plaintext-only`,tabIndex:0,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,role:`textbox`,className:`editor-content`,"html-data-placeholder":()=>n.placeholder,onmount:e=>{d?.unwatch(),d=watch(()=>n.value,e=>{e!=f.textContent&&(f.textContent=e,c())})},onunmount:e=>{d?.unwatch(),c()},onfocus:()=>{n.onfocus?.(n.value)},onblur:e=>{i&&!i.contains(e.relatedTarget)&&c(),n.onblur?.(n.value)},oninput:e=>{if(c(),l(f.textContent),!n.value?.length){f.textContent=``;return}if(!f?.isConnected)return;let r=Ne(f),i=Ae(n.value,r);if(!i.word.length||r==i.start)return;let a=[];if(typeof n.autocomplete==`function`)a=n.autocomplete(i.word)||[];else if(!app.utils.isEmpty(n.autocomplete)){let e=i.word.toLowerCase();a=n.autocomplete.filter(n=>(typeof n==`object`&&(n=n?.value),n=n?.toLowerCase(),n&&n!=e&&n.includes(e)))}a?.length&&s(()=>a.map((e,n)=>t.button({type:`button`,className:`dropdown-item ${n==0?`active`:``}`,textContent:e.label||e.value||e,onclick:n=>{n.preventDefault(),f.focus();let r=e.value||e;f.textContent=f.textContent.substring(0,i.start)+r+f.textContent.substring(i.end+1),l(f.textContent);try{window.getSelection().setPosition(f.childNodes[0],i.start+r.length)}catch(e){console.warn(`failed to set caret position`,e)}c()}})))},onkeydown:e=>{if(u=e.ctrlKey||e.metaKey,(e.key==`Enter`||e.key==`Tab`)&&i?.isConnected){e.preventDefault(),i.querySelector(`.dropdown-item.active`)?.click();return}if(e.key==`ArrowUp`&&i?.isConnected){e.preventDefault();let n=i.querySelector(`.dropdown-item.active`);n?.previousElementSibling&&(n.classList.remove(`active`),n.previousElementSibling.classList.add(`active`),n.previousElementSibling.scrollIntoView(!1));return}if(e.key==`ArrowDown`&&i?.isConnected){e.preventDefault();let n=i.querySelector(`.dropdown-item.active`);n?.nextElementSibling&&(n.classList.remove(`active`),n.nextElementSibling.classList.add(`active`),n.nextElementSibling.scrollIntoView(!1));return}if(u&&e.key.toLowerCase()==`l`){e.preventDefault(),je(f);return}if(u&&e.key.toLowerCase()==`d`){e.preventDefault(),Me(f);return}if(!n.singleLine&&e.key==`Tab`){e.preventDefault();let n=window.getSelection();if(!n)return;if(e.shiftKey){n.modify(`extend`,`backward`,`character`),n.toString()[0]==` `?(n.deleteFromDocument(),l(f.textContent)):(n.modify(`extend`,`forward`,`character`),n.toString()[0]==` `&&(n.deleteFromDocument(),l(f.textContent)));return}let r=n.getRangeAt(0);r&&(r.deleteContents(),r.insertNode(document.createTextNode(` `)),r.collapse(),l(f.textContent));return}if(n.singleLine&&e.key==`Enter`){e.preventDefault(),m.click();return}},onscroll:()=>{c(),p&&(p.scrollLeft=f.scrollLeft,p.scrollTop=f.scrollTop)}}),p=t.div({className:`highlight-overlay`,innerHTML:()=>Oe(n.value,n.language),onscroll:()=>{f&&(f.scrollLeft=p.scrollLeft,f.scrollTop=p.scrollTop)}}),m=t.button({type:`submit`,className:`hidden`});return t.div({rid:n.rid,id:()=>n.id,inert:()=>n.inert,hidden:()=>n.hidden,"html-name":()=>n.name,"html-required":()=>n.required||void 0,className:()=>`input code-editor ${n.className} ${n.disabled?`disabled`:``} ${n.singleLine?`single-line`:``}`,onclick:()=>{f?.focus()},onunmount:()=>{r?.forEach(e=>e?.unwatch())}},t.div({className:`code-editor-container`},f,p,m))};var De=500;function Oe(e,n){return e=typeof e==`string`?e:``,e?((!Prism.languages[n]||e.length>De)&&(n=`plain`),Prism.highlight(e,Prism.languages[n],n)):``}var ke=new RegExp(/[\p{Alphabetic}\p{Number}_@:\."'{}]/,`u`);function Ae(e,n){let r=n;for(let i=n-1;i>=0&&ke.test(e[i]);i--)r=i;let i=r;for(let r=n-1;rdocument.documentElement.clientHeight&&(o=Math.max(n.top-r,0)),a+i>document.documentElement.clientWidth&&(a=Math.max(document.documentElement.clientWidth-i,0)),e.style.left=a+`px`,e.style.top=o+`px`}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeBlockTabs=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,activeTabIndex:0,historyKey:``,tabs:[],get activeTab(){return n.tabs[n.activeTabIndex]||n.tabs[0]}}),r=app.utils.extendStore(n,e);return r.push(watch(()=>n.activeTabIndex,(e,r)=>{r!=null&&n.historyKey&&localStorage.setItem(n.historyKey,e)})),t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden||!n.tabs.length,inert:()=>n.inert,className:()=>`code-block-tabs ${n.className}`,onmount:()=>{n.historyKey&&(n.activeTabIndex=localStorage.getItem(n.historyKey)<<0)},onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.header({className:`tabs-header`},()=>n.tabs.map((e,r)=>t.button({type:`button`,className:()=>`tab-item ${n.activeTabIndex==r?`active`:``}`,onclick:()=>n.activeTabIndex=r},n=>typeof e.title==`function`?e.title(n):e.title))),t.div({className:`code-block-tabs-content`},()=>{if(n.activeTab)return app.components.codeBlock(n.activeTab)}))},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.select=function(e={}){let n=store({rid:void 0,id:void 0,name:void 0,hidden:void 0,inert:void 0,className:``,value:void 0,options:[],before:null,after:null,max:1,searchThreshold:6,required:!1,disabled:!1,placeholder:`- Select -`,noItemsFoundText:`No items found`,onchange:function(e){},ondropdowntoggle:function(e){}}),r=app.utils.extendStore(n,e);n.max<=0&&(n.max=1);let i=store({selected:[],search:``,get hasSearch(){return i.search?.length>0},get allowRemove(){return!n.disabled&&(!n.required||n.max>1)}});function a(){if(n.value===void 0)return;let e=app.utils.toArray(n.value,!0),r=e.slice(0,n.max||1);e.length!=r.length&&(console.warn(`[select] the provided select values (${e.length}) are more than the allowed max selected options (${r.length}):`,e),n.value=n.max>1?r:r[0]),i.selected=e.map(e=>n.options.find(n=>n.value===e)).filter(Boolean)}r.push(watch(()=>n.value,()=>a()));async function o(e){let r=i.selected.findIndex(n=>n.value===e.value);if(r>=0){if(!i.allowRemove){f?.hidePopover();return}i.selected.splice(r,1)}else{let r=i.selected.length-n.max;for(;r>=0;)i.selected.pop(),r--;i.selected.push(e)}n.max<=1&&f?.hidePopover(),n.onchange&&(await n.onchange(i.selected),a()),p?.isConnected&&p.dispatchEvent(new CustomEvent(`change`,{detail:i.selected,bubbles:!0}))}function s(e){return i.selected.findIndex(n=>n.value===e.value)>=0}let c=t.input({type:`text`,placeholder:`Search...`,value:()=>i.search,oninput:e=>i.search=e.target.value});function l(e=!1){i.search=``,e&&c?.focus()}let u=t.div({className:`txt-hint txt-center m-0 p-5`,hidden:!0},n.noItemsFoundText);async function d(){f&&(await new Promise(e=>setTimeout(e,0)),f.querySelector(`.select-option:not([hidden])`)?u.hidden=!0:u.hidden=!1)}let f=t.div({tabIndex:-1,popover:`auto`,className:`dropdown`,onbeforetoggle:e=>(e.newState==`closed`&&l(),n.ondropdowntoggle?.(e))},t.div({className:`fields dropdown-search`,hidden:()=>n.options.length!i.hasSearch},t.button({type:`button`,title:`Clear`,className:`btn sm secondary transparent circle`,onclick:()=>l(!0)},t.i({className:`ri-close-line`,ariaHidden:!0})))),()=>n.before?.__raw||n.before,()=>n.options.map(e=>t.button({type:`button`,className:()=>`dropdown-item select-option ${s(e)?`active`:``}`,onclick:()=>(o(e),!1)},e.label||e.value)),u,()=>n.after?.__raw||n.after),p=t.button({type:`button`,id:()=>n.id,name:()=>n.name,disabled:()=>n.disabled,className:()=>`selected-container ${n.className}`,popoverTargetElement:f,onclick:e=>{e.stopPropagation()}},()=>i.selected.length?i.selected.map(e=>t.div({className:`selected-item`},e.selected||e.label||e.value,()=>{if(i.allowRemove)return t.i({tabIndex:-1,role:`button`,className:`ri-close-line link-hint btn-option-unset`,ariaLabel:app.attrs.tooltip(`Unset`),onclick:()=>(o(e),!1)})})):t.span({rid:`selected-placeholder`,className:`placeholder`},()=>n.placeholder));r.push(watch(()=>n.options,()=>{d()}));let m;return r.push(watch(()=>i.search,()=>{let e=i.search.toLowerCase().replaceAll(` `,``);clearTimeout(m),m=setTimeout(()=>{let n=f.querySelectorAll(`.select-option`);e.length?n.forEach(n=>{n.textContent.toLowerCase().replaceAll(` `,``).includes(e)?n.hidden=!1:n.hidden=!0}):n.forEach(e=>e.hidden=!1),d()},100)})),t.div({rid:n.rid,hidden:()=>n.hidden,inert:()=>n.inert,onmount:e=>{e.addEventListener(`focusout`,function(n){(!n.relatedTarget||!e.contains(n.relatedTarget))&&f?.hidePopover()})},onunmount:()=>{clearTimeout(m),r.forEach(e=>e.unwatch())},className:()=>[`input`,`select`,n.max>1?`multiple`:`single`,n.disabled?`disabled`:``,n.required?`required`:``].join(` `)},p,f)},window.app=window.app||{},window.app.components=window.app.components||{};var Fe=Intl.DateTimeFormat().resolvedOptions().timeZone;window.app.components.formattedDate=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,value:``,short:!1}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,ariaDescription:app.attrs.tooltip(()=>n.short&&n.value?app.utils.toLocalDatetime(n.value)+` +`),n+=`)`,e.where&&(n+=` WHERE ${e.where}`),n},replaceIndexFields(e,n){let r=app.utils.parseIndex(e);return typeof n==`function`?Object.assign(r,n(r)||{}):Object.assign(r,n||{}),app.utils.buildIndex(r)},replaceIndexColumn(e,n,r){if(n===r)return e;let i=app.utils.parseIndex(e),a=!1;for(let e of i.columns)e.name===n&&(e.name=r,a=!0);return a?app.utils.buildIndex(i):e}};window.app=window.app||{},window.app.utils=_,window.app=window.app||{},window.app.utils=window.app.utils||{},window.app.utils.mimeTypes=[{ext:``,mimeType:`application/octet-stream`},{ext:`.xpm`,mimeType:`image/x-xpixmap`},{ext:`.7z`,mimeType:`application/x-7z-compressed`},{ext:`.zip`,mimeType:`application/zip`},{ext:`.xlsx`,mimeType:`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`},{ext:`.docx`,mimeType:`application/vnd.openxmlformats-officedocument.wordprocessingml.document`},{ext:`.pptx`,mimeType:`application/vnd.openxmlformats-officedocument.presentationml.presentation`},{ext:`.epub`,mimeType:`application/epub+zip`},{ext:`.apk`,mimeType:`application/vnd.android.package-archive`},{ext:`.jar`,mimeType:`application/jar`},{ext:`.odt`,mimeType:`application/vnd.oasis.opendocument.text`},{ext:`.ott`,mimeType:`application/vnd.oasis.opendocument.text-template`},{ext:`.ods`,mimeType:`application/vnd.oasis.opendocument.spreadsheet`},{ext:`.ots`,mimeType:`application/vnd.oasis.opendocument.spreadsheet-template`},{ext:`.odp`,mimeType:`application/vnd.oasis.opendocument.presentation`},{ext:`.otp`,mimeType:`application/vnd.oasis.opendocument.presentation-template`},{ext:`.odg`,mimeType:`application/vnd.oasis.opendocument.graphics`},{ext:`.otg`,mimeType:`application/vnd.oasis.opendocument.graphics-template`},{ext:`.odf`,mimeType:`application/vnd.oasis.opendocument.formula`},{ext:`.odc`,mimeType:`application/vnd.oasis.opendocument.chart`},{ext:`.sxc`,mimeType:`application/vnd.sun.xml.calc`},{ext:`.pdf`,mimeType:`application/pdf`},{ext:`.fdf`,mimeType:`application/vnd.fdf`},{ext:``,mimeType:`application/x-ole-storage`},{ext:`.msi`,mimeType:`application/x-ms-installer`},{ext:`.aaf`,mimeType:`application/octet-stream`},{ext:`.msg`,mimeType:`application/vnd.ms-outlook`},{ext:`.xls`,mimeType:`application/vnd.ms-excel`},{ext:`.pub`,mimeType:`application/vnd.ms-publisher`},{ext:`.ppt`,mimeType:`application/vnd.ms-powerpoint`},{ext:`.doc`,mimeType:`application/msword`},{ext:`.ps`,mimeType:`application/postscript`},{ext:`.psd`,mimeType:`image/vnd.adobe.photoshop`},{ext:`.p7s`,mimeType:`application/pkcs7-signature`},{ext:`.ogg`,mimeType:`application/ogg`},{ext:`.oga`,mimeType:`audio/ogg`},{ext:`.ogv`,mimeType:`video/ogg`},{ext:`.png`,mimeType:`image/png`},{ext:`.png`,mimeType:`image/vnd.mozilla.apng`},{ext:`.jpg`,mimeType:`image/jpeg`},{ext:`.jxl`,mimeType:`image/jxl`},{ext:`.jp2`,mimeType:`image/jp2`},{ext:`.jpf`,mimeType:`image/jpx`},{ext:`.jpm`,mimeType:`image/jpm`},{ext:`.jxs`,mimeType:`image/jxs`},{ext:`.gif`,mimeType:`image/gif`},{ext:`.webp`,mimeType:`image/webp`},{ext:`.exe`,mimeType:`application/vnd.microsoft.portable-executable`},{ext:``,mimeType:`application/x-elf`},{ext:``,mimeType:`application/x-object`},{ext:``,mimeType:`application/x-executable`},{ext:`.so`,mimeType:`application/x-sharedlib`},{ext:``,mimeType:`application/x-coredump`},{ext:`.a`,mimeType:`application/x-archive`},{ext:`.deb`,mimeType:`application/vnd.debian.binary-package`},{ext:`.tar`,mimeType:`application/x-tar`},{ext:`.xar`,mimeType:`application/x-xar`},{ext:`.bz2`,mimeType:`application/x-bzip2`},{ext:`.fits`,mimeType:`application/fits`},{ext:`.tiff`,mimeType:`image/tiff`},{ext:`.bmp`,mimeType:`image/bmp`},{ext:`.ico`,mimeType:`image/x-icon`},{ext:`.mp3`,mimeType:`audio/mpeg`},{ext:`.flac`,mimeType:`audio/flac`},{ext:`.midi`,mimeType:`audio/midi`},{ext:`.ape`,mimeType:`audio/ape`},{ext:`.mpc`,mimeType:`audio/musepack`},{ext:`.amr`,mimeType:`audio/amr`},{ext:`.wav`,mimeType:`audio/wav`},{ext:`.aiff`,mimeType:`audio/aiff`},{ext:`.au`,mimeType:`audio/basic`},{ext:`.mpeg`,mimeType:`video/mpeg`},{ext:`.mov`,mimeType:`video/quicktime`},{ext:`.mp4`,mimeType:`video/mp4`},{ext:`.avif`,mimeType:`image/avif`},{ext:`.3gp`,mimeType:`video/3gpp`},{ext:`.3g2`,mimeType:`video/3gpp2`},{ext:`.mp4`,mimeType:`audio/mp4`},{ext:`.mqv`,mimeType:`video/quicktime`},{ext:`.m4a`,mimeType:`audio/x-m4a`},{ext:`.m4v`,mimeType:`video/x-m4v`},{ext:`.heic`,mimeType:`image/heic`},{ext:`.heic`,mimeType:`image/heic-sequence`},{ext:`.heif`,mimeType:`image/heif`},{ext:`.heif`,mimeType:`image/heif-sequence`},{ext:`.mj2`,mimeType:`video/mj2`},{ext:`.dvb`,mimeType:`video/vnd.dvb.file`},{ext:`.webm`,mimeType:`video/webm`},{ext:`.avi`,mimeType:`video/x-msvideo`},{ext:`.flv`,mimeType:`video/x-flv`},{ext:`.mkv`,mimeType:`video/x-matroska`},{ext:`.asf`,mimeType:`video/x-ms-asf`},{ext:`.asf`,mimeType:`video/x-ms-wmv`},{ext:`.asf`,mimeType:`video/asf`},{ext:`.aac`,mimeType:`audio/aac`},{ext:`.voc`,mimeType:`audio/x-unknown`},{ext:`.m3u`,mimeType:`application/vnd.apple.mpegurl`},{ext:`.rmvb`,mimeType:`application/vnd.rn-realmedia-vbr`},{ext:`.gz`,mimeType:`application/gzip`},{ext:`.class`,mimeType:`application/x-java-applet`},{ext:`.swf`,mimeType:`application/x-shockwave-flash`},{ext:`.crx`,mimeType:`application/x-chrome-extension`},{ext:`.ttf`,mimeType:`font/ttf`},{ext:`.woff`,mimeType:`font/woff`},{ext:`.woff2`,mimeType:`font/woff2`},{ext:`.otf`,mimeType:`font/otf`},{ext:`.ttc`,mimeType:`font/collection`},{ext:`.eot`,mimeType:`application/vnd.ms-fontobject`},{ext:`.wasm`,mimeType:`application/wasm`},{ext:`.shx`,mimeType:`application/vnd.shx`},{ext:`.shp`,mimeType:`application/vnd.shp`},{ext:`.dbf`,mimeType:`application/x-dbf`},{ext:`.dcm`,mimeType:`application/dicom`},{ext:`.rar`,mimeType:`application/x-rar-compressed`},{ext:`.djvu`,mimeType:`image/vnd.djvu`},{ext:`.mobi`,mimeType:`application/x-mobipocket-ebook`},{ext:`.lit`,mimeType:`application/x-ms-reader`},{ext:`.bpg`,mimeType:`image/bpg`},{ext:`.cbor`,mimeType:`application/cbor`},{ext:`.sqlite`,mimeType:`application/vnd.sqlite3`},{ext:`.dwg`,mimeType:`image/vnd.dwg`},{ext:`.nes`,mimeType:`application/vnd.nintendo.snes.rom`},{ext:`.lnk`,mimeType:`application/x-ms-shortcut`},{ext:`.macho`,mimeType:`application/x-mach-binary`},{ext:`.qcp`,mimeType:`audio/qcelp`},{ext:`.icns`,mimeType:`image/x-icns`},{ext:`.hdr`,mimeType:`image/vnd.radiance`},{ext:`.mrc`,mimeType:`application/marc`},{ext:`.mdb`,mimeType:`application/x-msaccess`},{ext:`.accdb`,mimeType:`application/x-msaccess`},{ext:`.zst`,mimeType:`application/zstd`},{ext:`.cab`,mimeType:`application/vnd.ms-cab-compressed`},{ext:`.rpm`,mimeType:`application/x-rpm`},{ext:`.xz`,mimeType:`application/x-xz`},{ext:`.lz`,mimeType:`application/lzip`},{ext:`.torrent`,mimeType:`application/x-bittorrent`},{ext:`.cpio`,mimeType:`application/x-cpio`},{ext:``,mimeType:`application/tzif`},{ext:`.xcf`,mimeType:`image/x-xcf`},{ext:`.pat`,mimeType:`image/x-gimp-pat`},{ext:`.gbr`,mimeType:`image/x-gimp-gbr`},{ext:`.glb`,mimeType:`model/gltf-binary`},{ext:`.cab`,mimeType:`application/x-installshield`},{ext:`.jxr`,mimeType:`image/jxr`},{ext:`.parquet`,mimeType:`application/vnd.apache.parquet`},{ext:`.txt`,mimeType:`text/plain`},{ext:`.html`,mimeType:`text/html`},{ext:`.svg`,mimeType:`image/svg+xml`},{ext:`.xml`,mimeType:`text/xml`},{ext:`.rss`,mimeType:`application/rss+xml`},{ext:`.atom`,mimeType:`application/atom+xml`},{ext:`.x3d`,mimeType:`model/x3d+xml`},{ext:`.kml`,mimeType:`application/vnd.google-earth.kml+xml`},{ext:`.xlf`,mimeType:`application/x-xliff+xml`},{ext:`.dae`,mimeType:`model/vnd.collada+xml`},{ext:`.gml`,mimeType:`application/gml+xml`},{ext:`.gpx`,mimeType:`application/gpx+xml`},{ext:`.tcx`,mimeType:`application/vnd.garmin.tcx+xml`},{ext:`.amf`,mimeType:`application/x-amf`},{ext:`.3mf`,mimeType:`application/vnd.ms-package.3dmanufacturing-3dmodel+xml`},{ext:`.xfdf`,mimeType:`application/vnd.adobe.xfdf`},{ext:`.owl`,mimeType:`application/owl+xml`},{ext:`.php`,mimeType:`text/x-php`},{ext:`.js`,mimeType:`text/javascript`},{ext:`.lua`,mimeType:`text/x-lua`},{ext:`.pl`,mimeType:`text/x-perl`},{ext:`.py`,mimeType:`text/x-python`},{ext:`.json`,mimeType:`application/json`},{ext:`.geojson`,mimeType:`application/geo+json`},{ext:`.har`,mimeType:`application/json`},{ext:`.ndjson`,mimeType:`application/x-ndjson`},{ext:`.rtf`,mimeType:`text/rtf`},{ext:`.srt`,mimeType:`application/x-subrip`},{ext:`.tcl`,mimeType:`text/x-tcl`},{ext:`.csv`,mimeType:`text/csv`},{ext:`.tsv`,mimeType:`text/tab-separated-values`},{ext:`.vcf`,mimeType:`text/vcard`},{ext:`.ics`,mimeType:`text/calendar`},{ext:`.warc`,mimeType:`application/warc`},{ext:`.vtt`,mimeType:`text/vtt`},{ext:`.pbm`,mimeType:`image/x-portable-bitmap`},{ext:`.pgm`,mimeType:`image/x-portable-graymap`},{ext:`.ppm`,mimeType:`image/x-portable-pixmap`},{ext:`.eml`,mimeType:`message/rfc822`}];var v=new BroadcastChannel(`tabsSync`),ee=`pbSettings`,te=`pbColorScheme`;window.app=window.app||{},window.app.store=store({_ready:!1,superuser:null,showHeader:!0,page:t.div({className:`page`},()=>{if(!app.store._ready)return t.span({className:`loader lg m-auto`,title:`Loading plugins...`})}),mainLogo:`./images/logo.svg`,headerLogo:`./images/logo_white.svg`,favicon:``,title:``,_mediaColorScheme:``,userColorScheme:window.localStorage.getItem(te)||``,get activeColorScheme(){return app.store.userColorScheme?app.store.userColorScheme:app.store._mediaColorScheme||`light`},errors:null,creditLinks:[{href:`https://pocketbase.io/docs`,icon:`ri-book-open-line`,label:`Docs`},{href:`https://github.com/pocketbase/pocketbase/releases`,icon:`ri-github-line`,label:`PocketBase v0.37.6-dev`}],headerLinks:[{href:`#/collections`,icon:`ri-database-2-line`,label:`Collections`},{href:`#/logs`,icon:`ri-bar-chart-box-line`,label:`Logs`},{href:`#/settings`,icon:`ri-settings-3-line`,label:`Settings`}],settingsNavGroups:{System:[{href:`#/settings`,icon:`ri-home-gear-line`,label:`Application`},{href:`#/settings/mail`,icon:`ri-send-plane-2-line`,label:`Mail settings`},{href:`#/settings/storage`,icon:`ri-archive-drawer-line`,label:`Files storage`},{href:`#/settings/backups`,icon:`ri-archive-line`,label:`Backups`},{href:`#/settings/crons`,icon:`ri-time-line`,label:`Crons`}],Sync:[{href:`#/settings/export-collections`,icon:`ri-uninstall-line`,label:`Export collections`},{href:`#/settings/import-collections`,icon:`ri-install-line`,label:`Import collections`}]},predefinedAccentColors:[`#1055c9`,`#a3142a`,`#096d5c`,`#e6620a`,`#007d9c`,`#3f3da9`],settings:app.utils.getLocalHistory(ee,{}),isLoadingSettings:!1,async loadSettings(){app.store.isLoadingSettings=!0;try{let e=await app.pb.settings.getAll({requestKey:`appStore.loadSettings`});app.store.settings=e,app.store.isLoadingSettings=!1}catch(e){e.isAbort||(app.store.isLoadingSettings=!1,app.checkApiError(e))}},collections:[],collectionScaffolds:{},isLoadingCollections:!1,_activeCollectionIdOrName:``,get activeCollection(){let e=app.store._activeCollectionIdOrName;return app.store.collections.find(n=>n.id==e||n.name==e)||app.store.collections[0]},set activeCollection(e){typeof e==`string`?app.store._activeCollectionIdOrName=e:app.store._activeCollectionIdOrName=e?.id},async silentlyReloadCollections(){try{let e=await app.pb.collections.getFullList({requestKey:`appStore.silentlyReloadCollections`});e=app.utils.sortedCollectionsByType(e),JSON.stringify(e)!=JSON.stringify(app.store.collections)&&(app.store.collections=e)}catch(e){e.isAbort||console.warn(`failed to reload app store collections:`,e)}},async loadCollections(e=null){app.store.isLoadingCollections=!0;try{let[n,r]=await Promise.all([app.pb.collections.getScaffolds({requestKey:`appStore.loadCollections.getScaffolds`}),app.pb.collections.getFullList({requestKey:`appStore.loadCollections.getFullList`})]);r=app.utils.sortedCollectionsByType(r),JSON.stringify(app.store.collections)!=JSON.stringify(r)&&(app.store.collections=r),app.store.collectionScaffolds=n,app.store._activeCollectionIdOrName=e||app.store._activeCollectionIdOrName||app.store.collections[0]?.id||``,app.store.isLoadingCollections=!1}catch(e){e.isAbort||(app.store.isLoadingCollections=!1,app.checkApiError(e))}},addOrUpdateCollection(e){let n=app.store.collections.findIndex(n=>n.id==e.id);n>=0?(app.store.activeCollection.id==e.id&&(app.store._activeCollectionIdOrName=e.id),app.store.collections[n]=e):app.store.collections.push(e),app.store.collections=app.utils.sortedCollectionsByType(app.store.collections)},oauth2Providers:[],isLoadingOAuth2Providers:!1,async loadOAuth2Providers(){app.store.isLoadingOAuth2Providers=!0;try{app.store.oauth2Providers=await app.pb.send(`/api/collections/meta/oauth2-providers`),app.store.isLoadingOAuth2Providers=!1}catch(e){e.isAbort||(app.checkApiError(e),app.store.isLoadingOAuth2Providers=!1)}}}),window.addEventListener(`hashchange`,()=>{app.store.title=``,app.store.errors=null}),watch(()=>{let e=app.utils.toArray(app.store.title),n=app.store.settings?.meta?.appName||``;n&&e.push(n),document.title=e.join(` - `)});var y;watch(()=>app.store.settings?.meta?.accentColor,e=>{y||(y=t.meta({name:`theme-color`}),document.head.appendChild(y)),e?(y?.setAttribute(`content`,e),document.documentElement.style.setProperty(`--accentColor`,e)):(y?.removeAttribute(`content`),document.documentElement.style.removeProperty(`--accentColor`))});var ne;watch(()=>app.store.favicon,e=>{ne||(ne=t.link({rel:`icon`}),document.head.appendChild(ne)),e?ne.href=e:ne.href=window.location.href.startsWith(`https://`)?`./images/favicon_prod.png`:`./images/favicon.png`});var re=window.matchMedia(`(prefers-color-scheme: dark)`);app.store._mediaColorScheme=re.matches?`dark`:`light`,re.addEventListener(`change`,({matches:e})=>{app.store._mediaColorScheme=e?`dark`:`light`}),watch(()=>app.store.userColorScheme,e=>{e?window.localStorage.setItem(te,e):window.localStorage.removeItem(te),v?.postMessage({colorScheme:e})});var ie;watch(()=>app.store.activeColorScheme,e=>{clearTimeout(ie),document.documentElement.style.setProperty(`--animationSpeed`,`0`),document.documentElement.setAttribute(`data-color-scheme`,e),ie=setTimeout(()=>{document.documentElement.style.removeProperty(`--animationSpeed`)},100)});function ae(e,n){e.__errListener&&=(e.removeEventListener(`input`,e.__errListener),e.removeEventListener(`change`,e.__errListener),null),e.setCustomValidity&&(e.setCustomValidity(``),e._oldTitle?e.setAttribute(`title`,e._oldTitle):e.removeAttribute(`title`)),e.removeAttribute(`data-error`);let r=n.nextSibling;r&&r.classList?.contains(`generated-error`)&&r.getAttribute(`data-input-name`)==e.getAttribute(`name`)&&r.remove(),n.querySelector(`[data-error]`)||n.classList.remove(`error`)}watch(()=>JSON.stringify(app.store.errors)&&app.store.errors,e=>{let n=document.querySelectorAll(`[name]`);for(let r of n){if(r.classList.contains(`no-error`))continue;let n=r.closest(`.field-list`)||r.closest(`.fields`)||r.closest(`.field`);if(!n)continue;let i=r.getAttribute(`name`);ae(r,n);let a=app.utils.getByPath(e,i),o=a?.message||``;if(!o&&!app.utils.isEmpty(a)){let e=[];for(let n in a)a[n]?.message&&e.push(`${n}: ${a[n]?.message}`);o=e.join(` +`)}o&&(n.classList.add(`error`),r.__errListener=function(){ae(r,n),app.utils.deleteByPath(app.store.errors,i)},r.addEventListener(`input`,r.__errListener),r.addEventListener(`change`,r.__errListener),r.setAttribute(`data-error`,!0),r.setCustomValidity&&r.reportValidity&&r.classList.contains(`inline-error`)?(r.setCustomValidity(o),r.reportValidity(),r._oldTitle=r.title,r.title=o):n.after(t.div({"html-data-input-name":i,className:`field-help error generated-error`,textContent:o})))}}),v.onmessage=e=>{e.data?.collections&&JSON.stringify(app.store.collections)!=JSON.stringify(e.data.collections)&&(app.store.collections=e.data.collections),e.data?.settings&&JSON.stringify(app.store.settings)!=JSON.stringify(e.data.settings)&&(app.store.settings=e.data.settings),e.data?.colorScheme&&(app.store.userColorScheme=e.data.colorScheme)},watch(()=>JSON.stringify(app.store.collections),(e,n)=>{e&&e!=`[]`&&n&&n!=`[]`&&e!=n&&v?.postMessage({collections:JSON.parse(e)})}),watch(()=>JSON.stringify(app.store.settings),(e,n)=>{e&&e!=`{}`&&n&&n!=`{}`&&e!=n&&v?.postMessage({settings:JSON.parse(e)}),window.localStorage.setItem(ee,e)});var b=`#/login`,x=window.location.pathname.endsWith(`/`)?window.location.pathname.substring(0,window.location.pathname.length-1):window.location.pathname;window.app=window.app||{},window.app.pb=new i(`../`,new r(`__pb_superusers__`+x)),app.pb.beforeSend=function(e,n){return n.headers[`x-request-source`]=`pbui`,{url:e,options:n}},app.store.superuser=app.pb.authStore.record,app.pb.authStore.onChange((e,n)=>{!n&&window.location.hash!=b&&(app.modals.close(),window.location.hash=b),app.store.superuser=n}),app.pb.authStore.isValid&&app.pb.collection(app.pb.authStore.record?.collectionName||`_superusers`).authRefresh().catch(e=>{console.warn(`Failed to refresh the existing auth token:`,e);let n=e?.status<<0;(n==401||n==403)&&(app.utils.rememberPath(),app.pb.cancelAllRequests(),app.pb.authStore.clear())}),app.pb.authStore.onChange((e,n)=>{n?.id&&(app.store.loadCollections(),app.store.loadSettings(),app.store.loadOAuth2Providers())});var oe=app.pb.collection;app.pb.collection=function(e){let n=oe.call(this,e);return se(n),n};function se(e){if(e.__customUIEvents)return;e.__customUIEvents=!0;let n=e.create;e.create=function(){return n.apply(e,arguments).then(e=>(setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:create`,{detail:e})),document.dispatchEvent(new CustomEvent(`record:save`,{detail:e}))},0),e))};let r=e.update;e.update=function(){return r.apply(e,arguments).then(e=>(setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:update`,{detail:e})),document.dispatchEvent(new CustomEvent(`record:save`,{detail:e}))},0),e))};let i=e.delete;e.delete=function(){return i.apply(e,arguments).then(n=>{let r={id:arguments[0],collectionId:e.collectionIdOrName,collectionName:e.collectionIdOrName};return setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:delete`,{detail:r}))},0),n})}}var ce=`pbLastFileToken`,S=!1,le=[];app.pb.authStore.onChange((e,n)=>{n?.id||window.localStorage.removeItem(ce)}),window.app.getFileToken=async function(n=``){let r=n&&app.store.collections?.find(e=>e.id==n||e.name==n);if(r&&!r.fields?.find(e=>e.type==`file`&&e.protected))return;let i=window.localStorage.getItem(ce);return(!i||e(i,60))&&(i=await C()),i};async function C(){return new Promise(async(e,n)=>{if(le.push({resolve:e,reject:n}),!S){S=!0;try{let e=await app.pb.files.getToken();window.localStorage.setItem(ce,e),le.forEach(n=>n.resolve(e))}catch(e){le.forEach(n=>n.reject(e))}S=!1,le=[]}})}window.app.checkApiError=function(e,n=!0){if(!e||!(e instanceof Error)||e.isAbort){console.warn(`checkApiError - unexpected error type:`,e);return}let r=e?.status<<0,i=e?.response||{},a=n&&(i.message||e.message||`Something went wrong!`);if(a&&app.toasts.error(a),r==0&&console.log(e),app.utils.isEmpty(i.data)||(app.store.errors=i.data),r===401&&window.location.hash!=b)return app.utils.rememberPath(),app.pb.cancelAllRequests(),app.pb.authStore.clear()};function ue(){return()=>{if(!(!app.store._ready||!app.store.showHeader||!app.store.superuser?.id))return t.header({pbEvent:`appHeader`,rid:`appHeader`,className:`app-header accent-surface`,onmount:async e=>{await new Promise(e=>setTimeout(e,0)),e._scrollToActiveMenuItem=function(){e?.querySelector(`.app-main-nav .header-link.active`)?.scrollIntoView()},e._scrollToActiveMenuItem(),window.addEventListener(`hashchange`,e._scrollToActiveMenuItem)},onunmount:e=>{window.removeEventListener(`hashchange`,e?._scrollToActiveMenuItem)}},t.a({href:`#/`,className:`logo`},t.img({src:()=>app.store.headerLogo,alt:`App logo`})),t.nav({pbEvent:`mainNav`,className:`app-main-nav`},()=>app.store.headerLinks.map(e=>{let n=e.href.startsWith(`#/`);return t.a({href:()=>e.href,target:()=>n?void 0:`_blank`,rel:()=>n?void 0:`noopener noreferrer`,className:n=>`header-link ${e.isActive?.(n)||app.utils.isActivePath(e.href)?`active`:``}`},()=>{if(e.icon)return t.i({className:e.icon,ariaHidden:!0})},t.span({className:`txt`},()=>e.label))})),t.div({className:`flex-fill app-header-separator`}),w(),t.button({type:`button`,className:`header-link logged-user txt-normal`,"html-popovertarget":`logged-user-dropdown`},t.span({className:`superuser-name txt-ellipsis`},()=>app.store.superuser?.email),t.i({className:`ri-arrow-drop-down-line`,ariaHidden:!0})),t.div({pbEvent:`loggedUserDropdown`,id:`logged-user-dropdown`,className:`dropdown sm nowrap logged-user-dropdown`,popover:`auto`},t.a({className:`dropdown-item dropdown-item-manage`,href:`#/collections?collection=_superusers`,onclick:e=>{e.target.closest(`.dropdown`).hidePopover()}},t.i({className:`ri-group-line`,ariaHidden:!0}),t.span({className:`txt`},`Manage superusers`)),t.hr(),t.button({type:`button`,className:`dropdown-item txt-danger dropdown-item-logout`,onclick:()=>app.pb.authStore.clear()},t.i({className:`ri-logout-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Logout`))))}}function w(){let e=[{value:`light`,icon:`ri-sun-line`,label:`Light`},{value:`dark`,icon:`ri-moon-line`,label:`Dark`},{value:``,icon:`ri-subtract-line`,label:`Auto`}];return[t.button({type:`button`,className:`header-link color-scheme-picker`,"html-popovertarget":`color-scheme-dropdown`,title:`Color scheme`},t.i({className:()=>app.store.activeColorScheme==`dark`?`ri-moon-line`:`ri-sun-line`,ariaHidden:!0})),t.div({pbEvent:`colorSchemeDropdown`,id:`color-scheme-dropdown`,className:`dropdown sm nowrap color-scheme-dropdown`,popover:`auto`},()=>e.map(e=>t.button({type:`button`,className:()=>`dropdown-item dropdown-item-light ${app.store.userColorScheme==e.value?`active`:``}`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),app.store.userColorScheme=e.value}},t.i({className:e.icon,ariaHidden:!0}),t.span({className:`txt`},e.label))))]}document.addEventListener(`invalid`,e=>{let n=e.target.closest(`details`);n&&!n.open&&!e.target.closest(`summary`)&&(n.open=!0,e.target.reportValidity&&e.target.reportValidity())},!0);var T=`dropdown-item`;document.addEventListener(`toggle`,e=>{if(e.newState!=`open`||!e.target||e.target.__keyboardNavRegistered||!e.target.matches(`.dropdown`))return;e.target.__keyboardNavRegistered=!0;let n=e.target;function r(e){if(!n.isConnected){document.removeEventListener(`keydown`,r);return}let i;if(i=document.activeElement&&document.activeElement.classList.contains(T)?document.activeElement:n.querySelector(`.`+T+`:not([hidden]):not(.disabled)`),i){if(e.key==`ArrowUp`){e.preventDefault();let n=D(i,-1);i==document.activeElement&&n?.classList?.contains(T)?n?.focus():i.focus()}else if(e.key==`ArrowDown`){e.preventDefault();let n=D(i,1);i==document.activeElement&&n?.classList?.contains(T)?n?.focus():i.focus()}else if(e.keyCode>=65&&e.keyCode<=90||e.keyCode>=48&&e.keyCode<=57){let e=n.querySelectorAll(`input,textare,select`);e.length==1&&e[0].focus()}}}n.addEventListener(`toggle`,e=>{e.newState==`open`?(E(e.target.id,!0),document.addEventListener(`keydown`,r)):(E(e.target.id,!1),document.removeEventListener(`keydown`,r))})},!0);function E(e,n=!1){e&&document.querySelectorAll(`[popovertarget='`+e+`']`)?.forEach(e=>e.setAttribute(`data-popover-state`,n))}function D(e,n=-1){let r=n<0?e.previousElementSibling:e.nextElementSibling;return r&&(r.hidden||r.classList.contains(`disabled`)||!r.classList.contains(T))?D(r,n):r}var O=5,k=t.div({ariaHidden:!0,popover:`manual`,className:`pb-tooltip`});document.body.appendChild(k);function A(e,n){let r=e.getBoundingClientRect();k.setAttribute(`data-position`,n),k.style.top=`0px`,k.style.left=`0px`;let i=k.offsetHeight,a=k.offsetWidth,o=0,s=0;n==`left`?(o=r.top+r.height/2-i/2,s=r.left-a-O):n==`right`?(o=r.top+r.height/2-i/2,s=r.right+O):n==`top`?(o=r.top-i-O,s=r.left+r.width/2-a/2):n==`top-left`?(o=r.top-i-O,s=r.left):n==`top-right`?(o=r.top-i-O,s=r.right-a):n==`bottom-left`?(o=r.top+r.height+O,s=r.left):n==`bottom-right`?(o=r.top+r.height+O,s=r.right-a):(o=r.top+r.height+O,s=r.left+r.width/2-a/2),s+a>document.documentElement.clientWidth&&(s=document.documentElement.clientWidth-a),s=s>=0?s:0,o+i>document.documentElement.clientHeight&&(o=document.documentElement.clientHeight-i),o=o>=0?o:0,k.style.top=o+`px`,k.style.left=s+`px`}function j(){k.hidePopover()}function de(e,n,r){if(!e||!n){j();return}k.showPopover(),k.textContent=n,A(e,r)}document.body.addEventListener(`mouseleave`,()=>{j()});function fe(e,n=`top`){return r=>{if(!r._tooltipText){r._tooltipText=store({value:``});let e;function i(){e?.unwatch(),e=watch(()=>r._tooltipText.value,async e=>{de(r,e,n)})}async function a(){e?.unwatch(),e=null,j()}r.addEventListener(`mouseenter`,i),r.addEventListener(`focusin`,i),r.addEventListener(`mouseleave`,a),r.addEventListener(`focusout`,a),r.addEventListener(`blur`,a);let o=r.onunmount;r.onunmount=n=>{e?.unwatch(),n._tooltipText=null,n?.removeEventListener(`mouseenter`,i),n?.removeEventListener(`focusin`,i),n?.removeEventListener(`mouseleave`,a),n?.removeEventListener(`focusout`,a),n?.removeEventListener(`blur`,a),o(n)}}return typeof e==`function`?r._tooltipText.value=e():r._tooltipText.value=e,r._tooltipText.value}}window.app=window.app||{},window.app.attrs=window.app.attrs||{},window.app.attrs.tooltip=fe,window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.confirm=function(e,n,r,i={className:void 0,yesButton:``,noButton:``}){M.textOrElem=e,M.yesCallback=n,M.yesCallbackWaiting=!1,M.noCallback=r,M.noCallbackWaiting=!1,M.className=typeof i.className==`string`?i.className:`sm`,M.yesButton=i.yesButton||`Yes`,M.noButton=i.noButton||`No`,pe.isConnected||document.body.appendChild(pe),window.app.modals.open(pe)};var M=store({className:``,textOrElem:null,yesButton:``,yesCallback:null,yesCallbackWaiting:!1,noButton:``,noCallback:null,noCallbackWaiting:!1,get isBusy(){return M.yesCallbackWaiting||M.noCallbackWaiting}}),pe=t.div({className:()=>`modal popup manual ${M.className||``}`},t.div({className:`modal-content`},e=>typeof M.textOrElem==`string`?t.h6({className:`block txt-center`},M.textOrElem):typeof M.textOrElem==`function`?M.textOrElem(e):M.textOrElem),t.footer({className:`modal-footer p-sm`},t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.button({type:`button`,className:()=>`btn lg block secondary ${M.noCallbackWaiting?`loading`:``}`,disabled:()=>M.isBusy,onclick:async()=>{if(M.noCallback){M.noCallbackWaiting=!0;try{if(await M.noCallback()===!1)return}catch(e){console.log(`confirm noCallback error:`,e)}finally{M.noCallbackWaiting=!1}}window.app.modals.close(pe)}},()=>typeof M.noButton==`string`?t.span({className:`txt`},M.noButton):typeof M.noButton==`function`?M.noButton(el):M.noButton)),t.div({className:`col-sm-6`},t.button({type:`button`,className:()=>`btn lg block warning ${M.yesCallbackWaiting?`loading`:``}`,disabled:()=>M.isBusy,onclick:async()=>{if(M.yesCallback){M.yesCallbackWaiting=!0;try{if(await M.yesCallback()===!1)return}catch(e){console.log(`confirm yesCallback error:`,e)}finally{M.yesCallbackWaiting=!1}}window.app.modals.close(pe)}},()=>typeof M.yesButton==`string`?t.span({className:`txt`},M.yesButton):typeof M.yesButton==`function`?M.yesButton(el):M.yesButton)))));window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.dragline=function(e={}){let n,r=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,tolerance:0,ondragstart:function(e){},ondragstop:function(e){},ondragging:function(e,n,r){}}),i=app.utils.extendStore(r,e),a=store({dragStarted:!1}),o,s,c,l;function u(){document.addEventListener(`touchmove`,m),document.addEventListener(`mousemove`,m),document.addEventListener(`touchend`,p),document.addEventListener(`mouseup`,p)}function d(){document.removeEventListener(`touchmove`,m),document.removeEventListener(`mousemove`,m),document.removeEventListener(`touchend`,p),document.removeEventListener(`mouseup`,p)}function f(e){e.stopPropagation(),o=e.clientX,s=e.clientY,c=e.clientX-n.offsetLeft,l=e.clientY-n.offsetTop,u()}function p(e){a.dragStarted&&(e.preventDefault(),a.dragStarted=!1,r.ondragstop?.(e)),d()}function m(e){let i=e.clientX-o,u=e.clientY-s,d=e.clientX-c,f=e.clientY-l;!a.dragStarted&&Math.abs(d-n.offsetLeft)r.id,hidden:()=>r.hidden,inert:()=>r.inert,className:()=>`dragline ${a.dragStarted?`dragging`:``} ${r.className}`,onmousedown:e=>{e.button==0&&f(e)},ontouchstart:f,onunmount:()=>{d(),i.forEach(e=>e?.unwatch())}}),n},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.slide=function(e,...n){let r;return t.div({className:n=>`block slide-block ${e?.(n)?``:`hidden`}`,onmount:e=>{r=setTimeout(()=>{e?.setAttribute(`data-slide`,`1`)},200)},onunmount:()=>{clearTimeout(r)}},...n)},window.app=window.app||{},window.app.modals=window.app.modals||{};var N=`data-modal-state`,me=`manual`,he;window.app.modals.open=async function(e){if(!e?.isConnected){console.error(`modals.open requies an active DOM element`,e);return}let n;if(e.onbeforeopen&&(n=await e.onbeforeopen(e)),n===!1)return;if(e.onafteropen){let n=new ResizeObserver(r=>{for(let i of r)i.contentRect.height>0&&e?.onafteropen&&(e.onafteropen(e),n.disconnect(),n=null)});n.observe(e)}he=document.activeElement,ge(e),e._forceClose=()=>app.modals.close(e,!0),window.addEventListener(`popstate`,e._forceClose);let r=Math.max(_e(e)?.style.zIndex<<0,1e3);e.style.zIndex=r+1,e.setAttribute(N,`open`)},window.app.modals.close=async function(e=null,n=!1){if(e||=_e(),e){if(window.removeEventListener(`popstate`,e._forceClose),n)e.onbeforeclose?.(e,!0),e.setAttribute(N,`close`),e.onafterclose?.(e,!0);else{if(e.onbeforeclose&&await e.onbeforeclose(e,!1)===!1)return;if(e.onafterclose){let n=new ResizeObserver(r=>{for(let i of r)i.contentRect.height<=0&&e?.onafterclose&&(e.onafterclose(e,!1),n.disconnect(),n=null)});n.observe(e)}e.setAttribute(N,`close`)}he&&(he.focus?.(),setTimeout(()=>{he?.blur?.(),he=null},0))}};function ge(e){if(e.getAttribute(`tabindex`)||e.setAttribute(`tabindex`,`-1`),setTimeout(()=>{let n=e?.querySelector(`[autofocus]`);n?n.focus():e?.focus()},0),e.getAttribute(N))return;e.setAttribute(N,``),e.addEventListener(`keydown`,n=>{n.key!=`Escape`||e.classList.contains(me)||n.target!==e&&e.contains(n.target)||window.app.modals.close(e)});let n=!1,r=r=>{n=r.target!==e&&e.contains(r.target)};e.addEventListener(`mousedown`,r),e.addEventListener(`touchstart`,r);let i=!1,a=n=>{i=n.target!==e&&e.contains(n.target)};e.addEventListener(`mouseup`,a),e.addEventListener(`touchend`,a),e.addEventListener(`click`,r=>{n||i||e.classList.contains(me)||r.target!==e&&e.contains(r.target)||window.app.modals.close(e)})}function _e(e){let n=document.querySelectorAll(`[${N}="open"]`),r=0,i=0,a;for(let o of n)e&&o==e||(r=o.style.zIndex<<0,r>i&&(i=r,a=o));return a}var ve=new Map,ye=t.div({className:`toasts-container`});function be(e,n=!0){let r=ve.get(e);!r||!r.isConnected||(ve.delete(e),clearTimeout(r._removeTimeout),n?(r.classList.add(`removing`),setTimeout(()=>{r.remove()},300)):r.remove())}function xe(e=!0){ve.forEach((n,r)=>{window.app.toasts.remove(r,e)})}function Se(e,n={}){n.type=`info`,n.duration=n.duration||3e3,Te(e,n)}function Ce(e,n={}){n.type=`success`,n.duration=n.duration||3e3,Te(e,n)}function we(e,n={}){n.type=`error`,n.duration=n.duration||3500,Te(e,n)}function Te(e,n={}){n=Object.assign({duration:3e3,key:void 0,type:`info`},n),ye.isConnected||document.body.appendChild(ye);let r=n.key||e;ve.has(r)&&be(r,!1);function i(e){e?._removeTimeout&&clearTimeout(e?._removeTimeout),e._removeTimeout=setTimeout(()=>{be(r)},n.duration)}let a=t.div({className:`toast ${n.type||``}`,onmount:e=>{i(e)},onunmount:e=>{e?._removeTimeout&&(clearTimeout(e?._removeTimeout),a=null)},onmouseover:()=>{clearTimeout(a?._removeTimeout)},onmouseout:()=>{i(a)}},t.div({className:`toast-container`},t.div({className:`toast-icon`}),t.div({className:`toast-content`},e,t.button({type:`button`,className:`m-l-auto btn circle sm transparent secondary toast-remove`,title:`Clear`,onclick:()=>be(r)},t.i({className:`ri-close-line`,ariaHidden:!0})))));ve.set(r,a),ye.prepend(a)}window.app=window.app||{},window.app.toasts=window.app.toasts||{},window.app.toasts.info=Se,window.app.toasts.error=we,window.app.toasts.success=Ce,window.app.toasts.remove=be,window.app.toasts.removeAll=xe,window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.sortable=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,data:[],dataItem:function(e,n,r){return t.span(null,`Item `+n)},onchange:function(e,n,r){},handle:``,before:void 0,after:void 0}),r=app.utils.extendStore(n,e);function i(e){function r(){e.querySelectorAll(`:scope > [data-dragstart="true"]`)?.forEach(e=>{e.dataset.dragstart=!1}),e.querySelectorAll(`:scope > [data-dragover="true"]`)?.forEach(e=>{e.dataset.dragover=!1})}e.addEventListener(`dragstart`,r=>{if(n.handle&&!r.target.closest(n.handle)){r.preventDefault();return}let i=o(e,r.target);i&&(i.dataset.dragstart=!0)}),e.addEventListener(`dragenter`,n=>{for(let n of e.children)n.dataset.dragover&&(n.dataset.dragover=!1);let r=o(e,n.target);r&&(r.dataset.dragover=!0)}),e.addEventListener(`dragend`,e=>{r()}),e.addEventListener(`dragover`,e=>{e.preventDefault()}),e.addEventListener(`drop`,i=>{if(!n.onchange){r();return}let s=e.querySelector(`:scope > [data-dragstart="true"]`),c=o(e,i.target);if(r(),!s||!c||c==s)return;let l=a(s),u=a(c),d=n.data.slice(),f=d.splice(l,1);d.splice(u,0,f[0]),n.onchange(d,l,u)})}function a(e){if(!e?.parentNode)return-1;for(let n=0;nn.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>n.className,onmount:e=>{i(e)},onunmount:e=>{r.forEach(e=>e?.unwatch())}},e=>typeof n.before==`function`?n.before(e):n.before,e=>{let r=[];for(let i=0;itypeof n.after==`function`?n.after(e):n.after)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.copyButton=function(e,...n){let r=store({active:!1}),i;function a(){let n=e;typeof n==`function`&&(n=e()),app.utils.copyToClipboard(n),r.active=!0,clearTimeout(i),i=setTimeout(()=>{r.active=!1},500)}return t.button({tabIndex:-1,type:`button`,className:()=>`copy-to-clipboard ${r.active?`active`:``}`,title:`Copy`,ariaDescription:app.attrs.tooltip(()=>r.active?`Copied`:null),onclick:e=>{e.preventDefault(),e.stopPropagation(),a()}},t.i({hidden:n?.length,ariaHidden:!0,className:()=>`copy-icon ${r.active?`ri-check-double-line`:`ri-file-copy-line`}`}),...n)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeBlock=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,language:`js`,value:void 0,footnote:void 0}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`code-wrapper ${n.className}`,tabIndex:-1,onmount:e=>{e.addEventListener(`keydown`,n=>{(n.ctrlKey||n.metaKey)&&(n.key==`a`||n.key==`A`)&&(n.preventDefault(),window.getSelection().selectAllChildren(e))})},onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.code({className:`block`,innerHTML:()=>Ee(n.value,n.language)}),t.div({className:`footnote`},e=>typeof n.footnote==`function`?n.footnote(e):n.footnote))};function Ee(e,n){return e=typeof e==`string`?e:``,e=Prism.plugins.NormalizeWhitespace.normalize(e,{"remove-trailing":!0,"remove-indent":!0,"left-trim":!0,"right-trim":!0}),Prism.highlight(e,Prism.languages[n]||Prism.languages.js,n)}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeEditor=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,name:void 0,className:``,value:``,language:`js`,placeholder:``,disabled:!1,required:!1,singleLine:!1,autocomplete:void 0,oninput:function(e){},onfocus:function(e){},onblur:function(e){}}),r=app.utils.extendStore(n,e,`autocomplete`),i,a,o=!0;function s(e){c(),i=t.div({className:`dropdown autocomplete code-editor-dropdown`,onmount:e=>{e._updatePosition=()=>{o?Pe(i):c()},e._closeOnEsc=e=>{e.key==`Escape`&&(e.preventDefault(),c())},window.addEventListener(`scroll`,e._updatePosition,!0),window.addEventListener(`resize`,e._updatePosition),window.addEventListener(`keydown`,e._closeOnEsc),e._updatePosition()},onunmount:e=>{e&&(window.removeEventListener(`scroll`,e._updatePosition,!0),window.removeEventListener(`resize`,e._updatePosition),window.removeEventListener(`keydown`,e._closeOnEsc))}},e),document.body.appendChild(i),f&&(a?.disconnect(),a=new IntersectionObserver(([e])=>{o=e.isIntersecting},{root:null,threshold:.1}),a.observe(f))}function c(){i&&=(i.remove(),null),a&&=(a.disconnect(),null),o=!0}function l(e){n.value=e,n.oninput?.(e),f.dispatchEvent(new CustomEvent(`change`,{detail:e}))}let u=!1,d,f=t.div({contentEditable:()=>n.disabled?!1:`plaintext-only`,tabIndex:0,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,role:`textbox`,className:`editor-content`,"html-data-placeholder":()=>n.placeholder,onmount:e=>{d?.unwatch(),d=watch(()=>n.value,e=>{e!=f.textContent&&(f.textContent=e,c())})},onunmount:e=>{d?.unwatch(),c()},onfocus:()=>{n.onfocus?.(n.value)},onblur:e=>{i&&!i.contains(e.relatedTarget)&&c(),n.onblur?.(n.value)},oninput:e=>{if(c(),l(f.textContent),!n.value?.length){f.textContent=``;return}if(!f?.isConnected)return;let r=Ne(f),i=Ae(n.value,r);if(!i.word.length||r==i.start)return;let a=[];if(typeof n.autocomplete==`function`)a=n.autocomplete(i.word)||[];else if(!app.utils.isEmpty(n.autocomplete)){let e=i.word.toLowerCase();a=n.autocomplete.filter(n=>(typeof n==`object`&&(n=n?.value),n=n?.toLowerCase(),n&&n!=e&&n.includes(e)))}a?.length&&s(()=>a.map((e,n)=>t.button({type:`button`,className:`dropdown-item ${n==0?`active`:``}`,textContent:e.label||e.value||e,onclick:n=>{n.preventDefault(),f.focus();let r=e.value||e;f.textContent=f.textContent.substring(0,i.start)+r+f.textContent.substring(i.end+1),l(f.textContent);try{window.getSelection().setPosition(f.childNodes[0],i.start+r.length)}catch(e){console.warn(`failed to set caret position`,e)}c()}})))},onkeydown:e=>{if(u=e.ctrlKey||e.metaKey,(e.key==`Enter`||e.key==`Tab`)&&i?.isConnected){e.preventDefault(),i.querySelector(`.dropdown-item.active`)?.click();return}if(e.key==`ArrowUp`&&i?.isConnected){e.preventDefault();let n=i.querySelector(`.dropdown-item.active`);n?.previousElementSibling&&(n.classList.remove(`active`),n.previousElementSibling.classList.add(`active`),n.previousElementSibling.scrollIntoView(!1));return}if(e.key==`ArrowDown`&&i?.isConnected){e.preventDefault();let n=i.querySelector(`.dropdown-item.active`);n?.nextElementSibling&&(n.classList.remove(`active`),n.nextElementSibling.classList.add(`active`),n.nextElementSibling.scrollIntoView(!1));return}if(u&&e.key.toLowerCase()==`l`){e.preventDefault(),je(f);return}if(u&&e.key.toLowerCase()==`d`){e.preventDefault(),Me(f);return}if(!n.singleLine&&e.key==`Tab`){e.preventDefault();let n=window.getSelection();if(!n)return;if(e.shiftKey){n.modify(`extend`,`backward`,`character`),n.toString()[0]==` `?(n.deleteFromDocument(),l(f.textContent)):(n.modify(`extend`,`forward`,`character`),n.toString()[0]==` `&&(n.deleteFromDocument(),l(f.textContent)));return}let r=n.getRangeAt(0);r&&(r.deleteContents(),r.insertNode(document.createTextNode(` `)),r.collapse(),l(f.textContent));return}if(n.singleLine&&e.key==`Enter`){e.preventDefault(),m.click();return}},onscroll:()=>{c(),p&&(p.scrollLeft=f.scrollLeft,p.scrollTop=f.scrollTop)}}),p=t.div({className:`highlight-overlay`,innerHTML:()=>Oe(n.value,n.language),onscroll:()=>{f&&(f.scrollLeft=p.scrollLeft,f.scrollTop=p.scrollTop)}}),m=t.button({type:`submit`,className:`hidden`});return t.div({rid:n.rid,id:()=>n.id,inert:()=>n.inert,hidden:()=>n.hidden,"html-name":()=>n.name,"html-required":()=>n.required||void 0,className:()=>`input code-editor ${n.className} ${n.disabled?`disabled`:``} ${n.singleLine?`single-line`:``}`,onclick:()=>{f?.focus()},onunmount:()=>{r?.forEach(e=>e?.unwatch())}},t.div({className:`code-editor-container`},f,p,m))};var De=500;function Oe(e,n){return e=typeof e==`string`?e:``,e?((!Prism.languages[n]||e.length>De)&&(n=`plain`),Prism.highlight(e,Prism.languages[n],n)):``}var ke=new RegExp(/[\p{Alphabetic}\p{Number}_@:\."'{}]/,`u`);function Ae(e,n){let r=n;for(let i=n-1;i>=0&&ke.test(e[i]);i--)r=i;let i=r;for(let r=n-1;rdocument.documentElement.clientHeight&&(o=Math.max(n.top-r,0)),a+i>document.documentElement.clientWidth&&(a=Math.max(document.documentElement.clientWidth-i,0)),e.style.left=a+`px`,e.style.top=o+`px`}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeBlockTabs=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,activeTabIndex:0,historyKey:``,tabs:[],get activeTab(){return n.tabs[n.activeTabIndex]||n.tabs[0]}}),r=app.utils.extendStore(n,e);return r.push(watch(()=>n.activeTabIndex,(e,r)=>{r!=null&&n.historyKey&&localStorage.setItem(n.historyKey,e)})),t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden||!n.tabs.length,inert:()=>n.inert,className:()=>`code-block-tabs ${n.className}`,onmount:()=>{n.historyKey&&(n.activeTabIndex=localStorage.getItem(n.historyKey)<<0)},onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.header({className:`tabs-header`},()=>n.tabs.map((e,r)=>t.button({type:`button`,className:()=>`tab-item ${n.activeTabIndex==r?`active`:``}`,onclick:()=>n.activeTabIndex=r},n=>typeof e.title==`function`?e.title(n):e.title))),t.div({className:`code-block-tabs-content`},()=>{if(n.activeTab)return app.components.codeBlock(n.activeTab)}))},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.select=function(e={}){let n=store({rid:void 0,id:void 0,name:void 0,hidden:void 0,inert:void 0,className:``,value:void 0,options:[],before:null,after:null,max:1,searchThreshold:6,required:!1,disabled:!1,placeholder:`- Select -`,noItemsFoundText:`No items found`,onchange:function(e){},ondropdowntoggle:function(e){}}),r=app.utils.extendStore(n,e);n.max<=0&&(n.max=1);let i=store({selected:[],search:``,get hasSearch(){return i.search?.length>0},get allowRemove(){return!n.disabled&&(!n.required||n.max>1)}});function a(){if(n.value===void 0)return;let e=app.utils.toArray(n.value,!0),r=e.slice(0,n.max||1);e.length!=r.length&&(console.warn(`[select] the provided select values (${e.length}) are more than the allowed max selected options (${r.length}):`,e),n.value=n.max>1?r:r[0]),i.selected=e.map(e=>n.options.find(n=>n.value===e)).filter(Boolean)}r.push(watch(()=>n.value,()=>a()));async function o(e){let r=i.selected.findIndex(n=>n.value===e.value);if(r>=0){if(!i.allowRemove){f?.hidePopover();return}i.selected.splice(r,1)}else{let r=i.selected.length-n.max;for(;r>=0;)i.selected.pop(),r--;i.selected.push(e)}n.max<=1&&f?.hidePopover(),n.onchange&&(await n.onchange(i.selected),a()),p?.isConnected&&p.dispatchEvent(new CustomEvent(`change`,{detail:i.selected,bubbles:!0}))}function s(e){return i.selected.findIndex(n=>n.value===e.value)>=0}let c=t.input({type:`text`,placeholder:`Search...`,value:()=>i.search,oninput:e=>i.search=e.target.value});function l(e=!1){i.search=``,e&&c?.focus()}let u=t.div({className:`txt-hint txt-center m-0 p-5`,hidden:!0},n.noItemsFoundText);async function d(){f&&(await new Promise(e=>setTimeout(e,0)),f.querySelector(`.select-option:not([hidden])`)?u.hidden=!0:u.hidden=!1)}let f=t.div({tabIndex:-1,popover:`auto`,className:`dropdown`,onbeforetoggle:e=>(e.newState==`closed`&&l(),n.ondropdowntoggle?.(e))},t.div({className:`fields dropdown-search`,hidden:()=>n.options.length!i.hasSearch},t.button({type:`button`,title:`Clear`,className:`btn sm secondary transparent circle`,onclick:()=>l(!0)},t.i({className:`ri-close-line`,ariaHidden:!0})))),()=>n.before?.__raw||n.before,()=>n.options.map(e=>t.button({type:`button`,className:()=>`dropdown-item select-option ${s(e)?`active`:``}`,onclick:()=>(o(e),!1)},e.label||e.value)),u,()=>n.after?.__raw||n.after),p=t.button({type:`button`,id:()=>n.id,name:()=>n.name,disabled:()=>n.disabled,className:()=>`selected-container ${n.className}`,popoverTargetElement:f,onclick:e=>{e.stopPropagation()}},()=>i.selected.length?i.selected.map(e=>t.div({className:`selected-item`},e.selected||e.label||e.value,()=>{if(i.allowRemove)return t.i({tabIndex:-1,role:`button`,className:`ri-close-line link-hint btn-option-unset`,ariaLabel:app.attrs.tooltip(`Unset`),onclick:()=>(o(e),!1)})})):t.span({rid:`selected-placeholder`,className:`placeholder`},()=>n.placeholder));r.push(watch(()=>n.options,()=>{d()}));let m;return r.push(watch(()=>i.search,()=>{let e=i.search.toLowerCase().replaceAll(` `,``);clearTimeout(m),m=setTimeout(()=>{let n=f.querySelectorAll(`.select-option`);e.length?n.forEach(n=>{n.textContent.toLowerCase().replaceAll(` `,``).includes(e)?n.hidden=!1:n.hidden=!0}):n.forEach(e=>e.hidden=!1),d()},100)})),t.div({rid:n.rid,hidden:()=>n.hidden,inert:()=>n.inert,onmount:e=>{e.addEventListener(`focusout`,function(n){(!n.relatedTarget||!e.contains(n.relatedTarget))&&f?.hidePopover()})},onunmount:()=>{clearTimeout(m),r.forEach(e=>e.unwatch())},className:()=>[`input`,`select`,n.max>1?`multiple`:`single`,n.disabled?`disabled`:``,n.required?`required`:``].join(` `)},p,f)},window.app=window.app||{},window.app.components=window.app.components||{};var Fe=Intl.DateTimeFormat().resolvedOptions().timeZone;window.app.components.formattedDate=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,value:``,short:!1}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,ariaDescription:app.attrs.tooltip(()=>n.short&&n.value?app.utils.toLocalDatetime(n.value)+` `+Fe:null),"html-class":`formatted-date`,className:()=>`formatted-date ${n.short?`short`:`full`}`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(!n.value)return t.span({className:`missing-value`});if(n.short){let e=n.value.split(` `);return[t.span({className:`primary-date`},e[0]),t.span({className:`secondary-date`},e[1])]}return[t.span({className:`primary-date`},app.utils.toLocalDatetime(n.value)),t.span({className:`secondary-date`},n.value)]})},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.refreshButton=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,tooltip:`Refresh`,className:`btn transparent secondary circle rotate-btn`,disabled:!1,onclick:function(e){}}),r=app.utils.extendStore(n,e),i,a=t.button({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,type:`button`,ariaLabel:app.attrs.tooltip(()=>n.tooltip),disabled:()=>n.disabled,className:()=>n.className,onunmount:()=>{clearTimeout(i),r.forEach(e=>e?.unwatch())},onclick:e=>{e.preventDefault(),n.onclick&&n.onclick(e),a.classList.add(`rotate`),a.addEventListener(`animationend`,()=>{a.classList.remove(`rotate`)}),clearTimeout(i),i=setTimeout(()=>{clearTimeout(i),a.classList.remove(`rotate`)},500)}},t.i({className:`ri-refresh-line`,ariaHidden:!0}));return a},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.searchHistoryButton=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,value:void 0,historyKey:`default`,max:15,openInNewTabParam:`filter`,btnClassName:`btn sm pill secondary transparent p-r-5`,onselect:function(e){}}),r=app.utils.extendStore(n,e),i=store({items:app.utils.getLocalHistory(n.historyKey,[])});function a(e){o(e),i.items.unshift(e)}function o(e){app.utils.removeByValue(i.items,e)}let s=`history_dropdown_`+app.utils.randomString();r.push(watch(()=>n.value,e=>{e&&a(e)})),r.push(watch(()=>{i.items.length>n.max&&(i.items=i.items.slice(0,n.max)),app.utils.saveLocalHistory(n.historyKey,i.items)}));let c=t.div({id:s,className:`dropdown sm left nowrap history-searchbar-dropdown`,popover:`hint`,onclick:e=>(e.stopPropagation(),!1)},t.div({className:`block p-5`},t.small({className:`txt-hint`},`Search history`)),()=>i.items?.length?i.items.slice(0,n.max).map(e=>t.button({type:`button`,className:`dropdown-item txt-code`,onclick:()=>{c.hidePopover(),n.onselect?.(e),a(e)},onauxclick:()=>{if(n.openInNewTabParam){a(e),c.hidePopover();let r=app.utils.replaceHashQueryParams({[n.openInNewTabParam]:e},!1);window.open(r,`_blank`)}}},t.span({className:`txt-ellipsis`,title:e,textContent:e}),t.small({role:`button`,className:`remove-btn link-hint m-l-auto p-l-5 p-r-5`,title:`Clear`,onauxclick:e=>(e.stopPropagation(),!1),onclick:n=>(n.stopPropagation(),o(e),!1)},t.i({className:`ri-close-line`,ariaHidden:!0})))):t.div({rid:`no-history`,className:`block p-5`},t.span(null,`Your recent searches will show up here.`)));return t.button({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,type:`button`,title:`Search history`,className:()=>n.btnClassName,"html-popovertarget":s,onunmount:()=>{r?.forEach(e=>e?.unwatch())}},t.i({className:`ri-search-line`,ariaHidden:!0}),t.i({className:`ri-arrow-drop-down-line`,ariaHidden:!0}),c)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.s3Test=function(e={}){let n=`s3_test_request`,r=store({rid:void 0,config:null,label:`Use S3 storage`,testFilesystem:`storage`}),i=app.utils.extendStore(r,e),a=store({isTesting:!1,testError:null,get hasError(){return!app.utils.isEmpty(a.testError)}}),o,s;function c(e=150){if(!r.config.enabled){clearTimeout(o);return}a.isTesting=!0,clearTimeout(o),o=setTimeout(()=>{l()},e)}async function l(){if(a.isTesting=!0,!r.config.enabled||!r.testFilesystem){a.testError=null,a.isTesting=!1;return}app.pb.cancelRequest(n),clearTimeout(s),s=setTimeout(()=>{app.pb.cancelRequest(n),a.testError=Error(`S3 test connection timeout.`),a.isTesting=!1},3e4);try{await app.pb.props.testS3(r.testFilesystem,{requestKey:n}),a.testError=null,a.isTesting=!1}catch(e){e?.isAbort||(a.testError=e,a.isTesting=!1,clearTimeout(s))}}return i.push(watch(()=>r.testFilesystem&&r.config,()=>c())),t.div({pbEvent:`s3Test`,rid:r.rid,hidden:()=>!r.testFilesystem,className:()=>`label s3-test-label txt-nowrap ${a.hasError?`warning`:`success`}`,ariaDescription:app.attrs.tooltip(()=>a.testError?.data?.message),onunmount:()=>{clearTimeout(s),clearTimeout(o),i.forEach(e=>e?.unwatch())}},()=>a.isTesting?t.span({className:`loader sm`}):a.hasError?[t.i({className:`ri-error-warning-line txt-warning`,ariaHidden:!0}),t.span({className:`txt`},`Failed to establish S3 connection`)]:[t.i({className:`ri-checkbox-circle-line txt-success`,ariaHidden:!0}),t.span({className:`txt`},`S3 connected successfully`)])},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.s3ConfigFields=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,config:{},configKey:`s3`,toggleLabel:`Use S3 storage`,testFilesystem:`storage`,before:null,after:null}),r=app.utils.extendStore(n,e);n.configKey.endsWith(`.`)&&(n.configKey=n.configKey.substring(0,n.configKey.length-1));let i=store({originalHash:``,originalConfig:null});return r.push(watch(()=>n.config,e=>{i.originalHash=JSON.stringify(e),i.originalConfig=JSON.parse(i.originalHash)})),t.div({pbEvent:`s3ConfigFields`,rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`block s3-fields s3-config-${n.configKey} ${n.className}`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.div({className:`field`},t.input({id:()=>`${n.configKey}.enabled`,name:()=>`${n.configKey}.enabled`,type:`checkbox`,className:`switch`,checked:()=>n.config.enabled,onchange:e=>n.config.enabled=e.target.checked}),t.label({htmlFor:()=>`${n.configKey}.enabled`},()=>n.toggleLabel)),e=>typeof n.before==`function`?n.before(e):n.before,app.components.slide(()=>n.config.enabled,t.div({className:`grid m-t-base`},t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:()=>`${n.configKey}.endpoint`},`Endpoint`),t.input({id:()=>`${n.configKey}.endpoint`,name:()=>`${n.configKey}.endpoint`,type:`text`,required:()=>n.config.enabled,value:()=>n.config.endpoint||``,oninput:e=>n.config.endpoint=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:()=>`${n.configKey}.bucket`},`Bucket`),t.input({id:()=>`${n.configKey}.bucket`,name:()=>`${n.configKey}.bucket`,type:`text`,required:()=>n.config.enabled,value:()=>n.config.bucket||``,oninput:e=>n.config.bucket=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:()=>`${n.configKey}.region`},`Region`),t.input({id:()=>`${n.configKey}.region`,name:()=>`${n.configKey}.region`,type:`text`,required:()=>n.config.enabled,value:()=>n.config.region||``,oninput:e=>n.config.region=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:()=>`${n.configKey}.accessKey`},`Access key`),t.input({id:()=>`${n.configKey}.accessKey`,name:()=>`${n.configKey}.accessKey`,type:`text`,autocomplete:`off`,required:()=>n.config.enabled,value:()=>n.config.accessKey||``,oninput:e=>n.config.accessKey=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:()=>`field ${n.config.enabled?``:`required`}`},t.label({htmlFor:()=>`${n.configKey}.secret`},`Secret`),t.input({id:()=>`${n.configKey}.secret`,name:()=>`${n.configKey}.secret`,type:`password`,autocomplete:`new-password`,value:()=>n.config.secret||``,oninput:e=>n.config.secret=e.target.value,onkeyup:e=>{e.key==`Backspace`&&n.config.secret===void 0&&(n.config.secret=``)},placeholder:()=>n.config.secret===void 0?`* * * * * *`:``}))),t.div({className:`col-lg-6`,style:`min-height: 25px`},t.div({className:`field`},t.input({id:()=>`${n.configKey}.forcePathStyle`,name:()=>`${n.configKey}.forcePathStyle`,type:`checkbox`,checked:()=>n.config.forcePathStyle||!1,onchange:e=>n.config.forcePathStyle=e.target.checked}),t.label({htmlFor:()=>`${n.configKey}.forcePathStyle`},t.span({className:`txt`},`Force path-style addressing`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Forces the request to use path-style addressing, eg. "https://s3.amazonaws.com/BUCKET/KEY" instead of the default "https://BUCKET.s3.amazonaws.com/KEY".`)})))),t.div({className:`col-lg-6 txt-right`},()=>{if(!(!n.config?.enabled||i.originalHash!=JSON.stringify(n.config)))return app.components.s3Test({config:()=>n.config,testFilesystem:()=>n.testFilesystem})}))),e=>typeof n.after==`function`?n.after(e):n.after)};var Ie=p(d(((e,n)=>{(function(r,i){typeof e==`object`&&n!==void 0?i(e):typeof define==`function`&&define.amd?define([`exports`],i):(r=typeof globalThis<`u`?globalThis:r||self,i(r.leaflet={}))})(e,(function(e){var n=`1.9.4`;function r(e){var n,r,i,a;for(r=1,i=arguments.length;r`u`||!L||!L.Mixin)){e=v(e)?e:[e];for(var n=0;n0?Math.floor(e):Math.ceil(e)};C.prototype={clone:function(){return new C(this.x,this.y)},add:function(e){return this.clone()._add(w(e))},_add:function(e){return this.x+=e.x,this.y+=e.y,this},subtract:function(e){return this.clone()._subtract(w(e))},_subtract:function(e){return this.x-=e.x,this.y-=e.y,this},divideBy:function(e){return this.clone()._divideBy(e)},_divideBy:function(e){return this.x/=e,this.y/=e,this},multiplyBy:function(e){return this.clone()._multiplyBy(e)},_multiplyBy:function(e){return this.x*=e,this.y*=e,this},scaleBy:function(e){return new C(this.x*e.x,this.y*e.y)},unscaleBy:function(e){return new C(this.x/e.x,this.y/e.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},trunc:function(){return this.clone()._trunc()},_trunc:function(){return this.x=ue(this.x),this.y=ue(this.y),this},distanceTo:function(e){e=w(e);var n=e.x-this.x,r=e.y-this.y;return Math.sqrt(n*n+r*r)},equals:function(e){return e=w(e),e.x===this.x&&e.y===this.y},contains:function(e){return e=w(e),Math.abs(e.x)<=Math.abs(this.x)&&Math.abs(e.y)<=Math.abs(this.y)},toString:function(){return`Point(`+d(this.x)+`, `+d(this.y)+`)`}};function w(e,n,r){return e instanceof C?e:v(e)?new C(e[0],e[1]):e==null?e:typeof e==`object`&&`x`in e&&`y`in e?new C(e.x,e.y):new C(e,n,r)}function T(e,n){if(e)for(var r=n?[e,n]:e,i=0,a=r.length;i=this.min.x&&r.x<=this.max.x&&n.y>=this.min.y&&r.y<=this.max.y},intersects:function(e){e=E(e);var n=this.min,r=this.max,i=e.min,a=e.max,o=a.x>=n.x&&i.x<=r.x,s=a.y>=n.y&&i.y<=r.y;return o&&s},overlaps:function(e){e=E(e);var n=this.min,r=this.max,i=e.min,a=e.max,o=a.x>n.x&&i.xn.y&&i.y=n.lat&&a.lat<=r.lat&&i.lng>=n.lng&&a.lng<=r.lng},intersects:function(e){e=O(e);var n=this._southWest,r=this._northEast,i=e.getSouthWest(),a=e.getNorthEast(),o=a.lat>=n.lat&&i.lat<=r.lat,s=a.lng>=n.lng&&i.lng<=r.lng;return o&&s},overlaps:function(e){e=O(e);var n=this._southWest,r=this._northEast,i=e.getSouthWest(),a=e.getNorthEast(),o=a.lat>n.lat&&i.latn.lng&&i.lng1,Je=function(){var e=!1;try{var n=Object.defineProperty({},`passive`,{get:function(){e=!0}});window.addEventListener(`testPassiveEventSupport`,u,n),window.removeEventListener(`testPassiveEventSupport`,u,n)}catch{}return e}(),Ye=function(){return!!document.createElement(`canvas`).getContext}(),Xe=!!(document.createElementNS&&ge(`svg`).createSVGRect),Ze=!!Xe&&(function(){var e=document.createElement(`div`);return e.innerHTML=``,(e.firstChild&&e.firstChild.namespaceURI)===`http://www.w3.org/2000/svg`})(),Qe=!Xe&&function(){try{var e=document.createElement(`div`);e.innerHTML=``;var n=e.firstChild;return n.style.behavior=`url(#default#VML)`,n&&typeof n.adj==`object`}catch{return!1}}(),$e=navigator.platform.indexOf(`Mac`)===0,et=navigator.platform.indexOf(`Linux`)===0;function tt(e){return navigator.userAgent.toLowerCase().indexOf(e)>=0}var P={ie:ye,ielt9:be,edge:xe,webkit:Se,android:Ce,android23:we,androidStock:Ee,opera:De,chrome:Oe,gecko:ke,safari:Ae,phantom:je,opera12:Me,win:Ne,ie3d:Pe,webkit3d:Fe,gecko3d:Ie,any3d:Le,mobile:Re,mobileWebkit:ze,mobileWebkit3d:Be,msPointer:Ve,pointer:He,touch:We,touchNative:Ue,mobileOpera:Ge,mobileGecko:Ke,retina:qe,passiveEvents:Je,canvas:Ye,svg:Xe,vml:Qe,inlineSvg:Ze,mac:$e,linux:et},nt=P.msPointer?`MSPointerDown`:`pointerdown`,rt=P.msPointer?`MSPointerMove`:`pointermove`,F=P.msPointer?`MSPointerUp`:`pointerup`,it=P.msPointer?`MSPointerCancel`:`pointercancel`,at={touchstart:nt,touchmove:rt,touchend:F,touchcancel:it},ot={touchstart:gt,touchmove:ht,touchend:ht,touchcancel:ht},st={},ct=!1;function lt(e,n,r){return n===`touchstart`&&mt(),ot[n]?(r=ot[n].bind(this,r),e.addEventListener(at[n],r,!1),r):(console.warn(`wrong event specified:`,n),u)}function ut(e,n,r){if(!at[n]){console.warn(`wrong event specified:`,n);return}e.removeEventListener(at[n],r,!1)}function dt(e){st[e.pointerId]=e}function ft(e){st[e.pointerId]&&(st[e.pointerId]=e)}function pt(e){delete st[e.pointerId]}function mt(){ct||=(document.addEventListener(nt,dt,!0),document.addEventListener(rt,ft,!0),document.addEventListener(F,pt,!0),document.addEventListener(it,pt,!0),!0)}function ht(e,n){if(n.pointerType!==(n.MSPOINTER_TYPE_MOUSE||`mouse`)){for(var r in n.touches=[],st)n.touches.push(st[r]);n.changedTouches=[n],e(n)}}function gt(e,n){n.MSPOINTER_TYPE_TOUCH&&n.pointerType===n.MSPOINTER_TYPE_TOUCH&&q(n),ht(e,n)}function _t(e){var n={},r,i;for(i in e)r=e[i],n[i]=r&&r.bind?r.bind(e):r;return e=n,n.type=`dblclick`,n.detail=2,n.isTrusted=!1,n._simulated=!0,n}var vt=200;function yt(e,n){e.addEventListener(`dblclick`,n);var r=0,i;function a(e){if(e.detail!==1){i=e.detail;return}if(!(e.pointerType===`mouse`||e.sourceCapabilities&&!e.sourceCapabilities.firesTouchEvents)){var a=nn(e);if(!(a.some(function(e){return e instanceof HTMLLabelElement&&e.attributes.for})&&!a.some(function(e){return e instanceof HTMLInputElement||e instanceof HTMLSelectElement}))){var o=Date.now();o-r<=vt?(i++,i===2&&n(_t(e))):i=1,r=o}}}return e.addEventListener(`click`,a),{dblclick:n,simDblclick:a}}function bt(e,n){e.removeEventListener(`dblclick`,n.dblclick),e.removeEventListener(`click`,n.simDblclick)}var xt=Nt([`transform`,`webkitTransform`,`OTransform`,`MozTransform`,`msTransform`]),St=Nt([`webkitTransition`,`transition`,`OTransition`,`MozTransition`,`msTransition`]),Ct=St===`webkitTransition`||St===`OTransition`?St+`End`:`transitionend`;function wt(e){return typeof e==`string`?document.getElementById(e):e}function Tt(e,n){var r=e.style[n]||e.currentStyle&&e.currentStyle[n];if((!r||r===`auto`)&&document.defaultView){var i=document.defaultView.getComputedStyle(e,null);r=i?i[n]:null}return r===`auto`?null:r}function I(e,n,r){var i=document.createElement(e);return i.className=n||``,r&&r.appendChild(i),i}function R(e){var n=e.parentNode;n&&n.removeChild(e)}function Et(e){for(;e.firstChild;)e.removeChild(e.firstChild)}function Dt(e){var n=e.parentNode;n&&n.lastChild!==e&&n.appendChild(e)}function Ot(e){var n=e.parentNode;n&&n.firstChild!==e&&n.insertBefore(e,n.firstChild)}function kt(e,n){if(e.classList!==void 0)return e.classList.contains(n);var r=jt(e);return r.length>0&&RegExp(`(^|\\s)`+n+`(\\s|$)`).test(r)}function z(e,n){if(e.classList!==void 0)for(var r=p(n),i=0,a=r.length;i0?2*window.devicePixelRatio:1;function on(e){return P.edge?e.wheelDeltaY/2:e.deltaY&&e.deltaMode===0?-e.deltaY/an:e.deltaY&&e.deltaMode===1?-e.deltaY*20:e.deltaY&&e.deltaMode===2?-e.deltaY*60:e.deltaX||e.deltaZ?0:e.wheelDelta?(e.wheelDeltaY||e.wheelDelta)/2:e.detail&&Math.abs(e.detail)<32765?-e.detail*20:e.detail?e.detail/-32765*60:0}function sn(e,n){var r=n.relatedTarget;if(!r)return!0;try{for(;r&&r!==e;)r=r.parentNode}catch{return!1}return r!==e}var cn={__proto__:null,on:W,off:K,stopPropagation:Qt,disableScrollPropagation:$t,disableClickPropagation:en,preventDefault:q,stop:tn,getPropagationPath:nn,getMousePosition:rn,getWheelDelta:on,isExternalTarget:sn,addListener:W,removeListener:K},ln=le.extend({run:function(e,n,r,i){this.stop(),this._el=e,this._inProgress=!0,this._duration=r||.25,this._easeOutPower=1/Math.max(i||.5,.2),this._startPos=Ft(e),this._offset=n.subtract(this._startPos),this._startTime=+new Date,this.fire(`start`),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=b(this._animate,this),this._step()},_step:function(e){var n=+new Date-this._startTime,r=this._duration*1e3;nthis.options.maxZoom)?this.setZoom(e):this},panInsideBounds:function(e,n){this._enforcingBounds=!0;var r=this.getCenter(),i=this._limitCenter(r,this._zoom,O(e));return r.equals(i)||this.panTo(i,n),this._enforcingBounds=!1,this},panInside:function(e,n){n||={};var r=w(n.paddingTopLeft||n.padding||[0,0]),i=w(n.paddingBottomRight||n.padding||[0,0]),a=this.project(this.getCenter()),o=this.project(e),s=this.getPixelBounds(),c=E([s.min.add(r),s.max.subtract(i)]),l=c.getSize();if(!c.contains(o)){this._enforcingBounds=!0;var u=o.subtract(c.getCenter()),d=c.extend(o).getSize().subtract(l);a.x+=u.x<0?-d.x:d.x,a.y+=u.y<0?-d.y:d.y,this.panTo(this.unproject(a),n),this._enforcingBounds=!1}return this},invalidateSize:function(e){if(!this._loaded)return this;e=r({animate:!1,pan:!0},e===!0?{animate:!0}:e);var n=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var i=this.getSize(),o=n.divideBy(2).round(),s=i.divideBy(2).round(),c=o.subtract(s);return!c.x&&!c.y?this:(e.animate&&e.pan?this.panBy(c):(e.pan&&this._rawPanBy(c),this.fire(`move`),e.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,`moveend`),200)):this.fire(`moveend`)),this.fire(`resize`,{oldSize:n,newSize:i}))},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire(`viewreset`),this._stop()},locate:function(e){if(e=this._locateOptions=r({timeout:1e4,watch:!1},e),!(`geolocation`in navigator))return this._handleGeolocationError({code:0,message:`Geolocation not supported.`}),this;var n=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this);return e.watch?this._locationWatchId=navigator.geolocation.watchPosition(n,i,e):navigator.geolocation.getCurrentPosition(n,i,e),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(e){if(this._container._leaflet_id){var n=e.code,r=e.message||(n===1?`permission denied`:n===2?`position unavailable`:`timeout`);this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire(`locationerror`,{code:n,message:`Geolocation error: `+r+`.`})}},_handleGeolocationResponse:function(e){if(this._container._leaflet_id){var n=e.coords.latitude,r=e.coords.longitude,i=new k(n,r),a=i.toBounds(e.coords.accuracy*2),o=this._locateOptions;if(o.setView){var s=this.getBoundsZoom(a);this.setView(i,o.maxZoom?Math.min(s,o.maxZoom):s)}var c={latlng:i,bounds:a,timestamp:e.timestamp};for(var l in e.coords)typeof e.coords[l]==`number`&&(c[l]=e.coords[l]);this.fire(`locationfound`,c)}},addHandler:function(e,n){if(!n)return this;var r=this[e]=new n(this);return this._handlers.push(r),this.options[e]&&r.enable(),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off(`moveend`,this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw Error(`Map container is being reused by another instance`);try{delete this._container._leaflet_id,delete this._containerId}catch{this._container._leaflet_id=void 0,this._containerId=void 0}for(var e in this._locationWatchId!==void 0&&this.stopLocate(),this._stop(),R(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&=(x(this._resizeRequest),null),this._clearHandlers(),this._loaded&&this.fire(`unload`),this._layers)this._layers[e].remove();for(e in this._panes)R(this._panes[e]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(e,n){var r=I(`div`,`leaflet-pane`+(e?` leaflet-`+e.replace(`Pane`,``)+`-pane`:``),n||this._mapPane);return e&&(this._panes[e]=r),r},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var e=this.getPixelBounds();return new D(this.unproject(e.getBottomLeft()),this.unproject(e.getTopRight()))},getMinZoom:function(){return this.options.minZoom===void 0?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return this.options.maxZoom===void 0?this._layersMaxZoom===void 0?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(e,n,r){e=O(e),r=w(r||[0,0]);var i=this.getZoom()||0,a=this.getMinZoom(),o=this.getMaxZoom(),s=e.getNorthWest(),c=e.getSouthEast(),l=this.getSize().subtract(r),u=E(this.project(c,i),this.project(s,i)).getSize(),d=P.any3d?this.options.zoomSnap:1,f=l.x/u.x,p=l.y/u.y,m=n?Math.max(f,p):Math.min(f,p);return i=this.getScaleZoom(m,i),d&&(i=Math.round(i/(d/100))*(d/100),i=n?Math.ceil(i/d)*d:Math.floor(i/d)*d),Math.max(a,Math.min(o,i))},getSize:function(){return(!this._size||this._sizeChanged)&&(this._size=new C(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(e,n){var r=this._getTopLeftPoint(e,n);return new T(r,r.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(e){return this.options.crs.getProjectedBounds(e===void 0?this.getZoom():e)},getPane:function(e){return typeof e==`string`?this._panes[e]:e},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(e,n){var r=this.options.crs;return n=n===void 0?this._zoom:n,r.scale(e)/r.scale(n)},getScaleZoom:function(e,n){var r=this.options.crs;n=n===void 0?this._zoom:n;var i=r.zoom(e*r.scale(n));return isNaN(i)?1/0:i},project:function(e,n){return n=n===void 0?this._zoom:n,this.options.crs.latLngToPoint(A(e),n)},unproject:function(e,n){return n=n===void 0?this._zoom:n,this.options.crs.pointToLatLng(w(e),n)},layerPointToLatLng:function(e){var n=w(e).add(this.getPixelOrigin());return this.unproject(n)},latLngToLayerPoint:function(e){return this.project(A(e))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(e){return this.options.crs.wrapLatLng(A(e))},wrapLatLngBounds:function(e){return this.options.crs.wrapLatLngBounds(O(e))},distance:function(e,n){return this.options.crs.distance(A(e),A(n))},containerPointToLayerPoint:function(e){return w(e).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(e){return w(e).add(this._getMapPanePos())},containerPointToLatLng:function(e){var n=this.containerPointToLayerPoint(w(e));return this.layerPointToLatLng(n)},latLngToContainerPoint:function(e){return this.layerPointToContainerPoint(this.latLngToLayerPoint(A(e)))},mouseEventToContainerPoint:function(e){return rn(e,this._container)},mouseEventToLayerPoint:function(e){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e))},mouseEventToLatLng:function(e){return this.layerPointToLatLng(this.mouseEventToLayerPoint(e))},_initContainer:function(e){var n=this._container=wt(e);if(!n)throw Error(`Map container not found.`);if(n._leaflet_id)throw Error(`Map container is already initialized.`);W(n,`scroll`,this._onScroll,this),this._containerId=s(n)},_initLayout:function(){var e=this._container;this._fadeAnimated=this.options.fadeAnimation&&P.any3d,z(e,`leaflet-container`+(P.touch?` leaflet-touch`:``)+(P.retina?` leaflet-retina`:``)+(P.ielt9?` leaflet-oldie`:``)+(P.safari?` leaflet-safari`:``)+(this._fadeAnimated?` leaflet-fade-anim`:``));var n=Tt(e,`position`);n!==`absolute`&&n!==`relative`&&n!==`fixed`&&n!==`sticky`&&(e.style.position=`relative`),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var e=this._panes={};this._paneRenderers={},this._mapPane=this.createPane(`mapPane`,this._container),H(this._mapPane,new C(0,0)),this.createPane(`tilePane`),this.createPane(`overlayPane`),this.createPane(`shadowPane`),this.createPane(`markerPane`),this.createPane(`tooltipPane`),this.createPane(`popupPane`),this.options.markerZoomAnimation||(z(e.markerPane,`leaflet-zoom-hide`),z(e.shadowPane,`leaflet-zoom-hide`))},_resetView:function(e,n,r){H(this._mapPane,new C(0,0));var i=!this._loaded;this._loaded=!0,n=this._limitZoom(n),this.fire(`viewprereset`);var a=this._zoom!==n;this._moveStart(a,r)._move(e,n)._moveEnd(a),this.fire(`viewreset`),i&&this.fire(`load`)},_moveStart:function(e,n){return e&&this.fire(`zoomstart`),n||this.fire(`movestart`),this},_move:function(e,n,r,i){n===void 0&&(n=this._zoom);var a=this._zoom!==n;return this._zoom=n,this._lastCenter=e,this._pixelOrigin=this._getNewPixelOrigin(e),i?r&&r.pinch&&this.fire(`zoom`,r):((a||r&&r.pinch)&&this.fire(`zoom`,r),this.fire(`move`,r)),this},_moveEnd:function(e){return e&&this.fire(`zoomend`),this.fire(`moveend`)},_stop:function(){return x(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(e){H(this._mapPane,this._getMapPanePos().subtract(e))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw Error(`Set map center and zoom first.`)},_initEvents:function(e){this._targets={},this._targets[s(this._container)]=this;var n=e?K:W;n(this._container,`click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup`,this._handleDOMEvent,this),this.options.trackResize&&n(window,`resize`,this._onResize,this),P.any3d&&this.options.transform3DLimit&&(e?this.off:this.on).call(this,`moveend`,this._onMoveEnd)},_onResize:function(){x(this._resizeRequest),this._resizeRequest=b(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var e=this._getMapPanePos();Math.max(Math.abs(e.x),Math.abs(e.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(e,n){for(var r=[],i,a=n===`mouseout`||n===`mouseover`,o=e.target||e.srcElement,c=!1;o;){if(i=this._targets[s(o)],i&&(n===`click`||n===`preclick`)&&this._draggableMoved(i)){c=!0;break}if(i&&i.listens(n,!0)&&(a&&!sn(o,e)||(r.push(i),a))||o===this._container)break;o=o.parentNode}return!r.length&&!c&&!a&&this.listens(n,!0)&&(r=[this]),r},_isClickDisabled:function(e){for(;e&&e!==this._container;){if(e._leaflet_disable_click)return!0;e=e.parentNode}},_handleDOMEvent:function(e){var n=e.target||e.srcElement;if(!(!this._loaded||n._leaflet_disable_events||e.type===`click`&&this._isClickDisabled(n))){var r=e.type;r===`mousedown`&&Ut(n),this._fireDOMEvent(e,r)}},_mouseEvents:[`click`,`dblclick`,`mouseover`,`mouseout`,`contextmenu`],_fireDOMEvent:function(e,n,i){if(e.type===`click`){var a=r({},e);a.type=`preclick`,this._fireDOMEvent(a,a.type,i)}var o=this._findEventTargets(e,n);if(i){for(var s=[],c=0;c0?Math.round(e-n)/2:Math.max(0,Math.ceil(e))-Math.max(0,Math.floor(n))},_limitZoom:function(e){var n=this.getMinZoom(),r=this.getMaxZoom(),i=P.any3d?this.options.zoomSnap:1;return i&&(e=Math.round(e/i)*i),Math.max(n,Math.min(r,e))},_onPanTransitionStep:function(){this.fire(`move`)},_onPanTransitionEnd:function(){B(this._mapPane,`leaflet-pan-anim`),this.fire(`moveend`)},_tryAnimatedPan:function(e,n){var r=this._getCenterOffset(e)._trunc();return(n&&n.animate)!==!0&&!this.getSize().contains(r)?!1:(this.panBy(r,n),!0)},_createAnimProxy:function(){var e=this._proxy=I(`div`,`leaflet-proxy leaflet-zoom-animated`);this._panes.mapPane.appendChild(e),this.on(`zoomanim`,function(e){var n=xt,r=this._proxy.style[n];Pt(this._proxy,this.project(e.center,e.zoom),this.getZoomScale(e.zoom,1)),r===this._proxy.style[n]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on(`load moveend`,this._animMoveEnd,this),this._on(`unload`,this._destroyAnimProxy,this)},_destroyAnimProxy:function(){R(this._proxy),this.off(`load moveend`,this._animMoveEnd,this),delete this._proxy},_animMoveEnd:function(){var e=this.getCenter(),n=this.getZoom();Pt(this._proxy,this.project(e,n),this.getZoomScale(n,1))},_catchTransitionEnd:function(e){this._animatingZoom&&e.propertyName.indexOf(`transform`)>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName(`leaflet-zoom-animated`).length},_tryAnimatedZoom:function(e,n,r){if(this._animatingZoom)return!0;if(r||={},!this._zoomAnimated||r.animate===!1||this._nothingToAnimate()||Math.abs(n-this._zoom)>this.options.zoomAnimationThreshold)return!1;var i=this.getZoomScale(n),a=this._getCenterOffset(e)._divideBy(1-1/i);return r.animate!==!0&&!this.getSize().contains(a)?!1:(b(function(){this._moveStart(!0,r.noMoveStart||!1)._animateZoom(e,n,!0)},this),!0)},_animateZoom:function(e,n,r,i){this._mapPane&&(r&&(this._animatingZoom=!0,this._animateToCenter=e,this._animateToZoom=n,z(this._mapPane,`leaflet-zoom-anim`)),this.fire(`zoomanim`,{center:e,zoom:n,noUpdate:i}),this._tempFireZoomEvent||=this._zoom!==this._animateToZoom,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&B(this._mapPane,`leaflet-zoom-anim`),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire(`zoom`),delete this._tempFireZoomEvent,this.fire(`move`),this._moveEnd(!0))}});function un(e,n){return new J(e,n)}var Y=se.extend({options:{position:`topright`},initialize:function(e){m(this,e)},getPosition:function(){return this.options.position},setPosition:function(e){var n=this._map;return n&&n.removeControl(this),this.options.position=e,n&&n.addControl(this),this},getContainer:function(){return this._container},addTo:function(e){this.remove(),this._map=e;var n=this._container=this.onAdd(e),r=this.getPosition(),i=e._controlCorners[r];return z(n,`leaflet-control`),r.indexOf(`bottom`)===-1?i.appendChild(n):i.insertBefore(n,i.firstChild),this._map.on(`unload`,this.remove,this),this},remove:function(){return this._map?(R(this._container),this.onRemove&&this.onRemove(this._map),this._map.off(`unload`,this.remove,this),this._map=null,this):this},_refocusOnMap:function(e){this._map&&e&&e.screenX>0&&e.screenY>0&&this._map.getContainer().focus()}}),dn=function(e){return new Y(e)};J.include({addControl:function(e){return e.addTo(this),this},removeControl:function(e){return e.remove(),this},_initControlPos:function(){var e=this._controlCorners={},n=`leaflet-`,r=this._controlContainer=I(`div`,n+`control-container`,this._container);function i(i,a){var o=n+i+` `+n+a;e[i+a]=I(`div`,o,r)}i(`top`,`left`),i(`top`,`right`),i(`bottom`,`left`),i(`bottom`,`right`)},_clearControlPos:function(){for(var e in this._controlCorners)R(this._controlCorners[e]);R(this._controlContainer),delete this._controlCorners,delete this._controlContainer}});var fn=Y.extend({options:{collapsed:!0,position:`topright`,autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(e,n,r,i){return r1,this._baseLayersList.style.display=e?``:`none`),this._separator.style.display=n&&e?``:`none`,this},_onLayerChange:function(e){this._handlingClick||this._update();var n=this._getLayer(s(e.target)),r=n.overlay?e.type===`add`?`overlayadd`:`overlayremove`:e.type===`add`?`baselayerchange`:null;r&&this._map.fire(r,n)},_createRadioElement:function(e,n){var r=``,i=document.createElement(`div`);return i.innerHTML=r,i.firstChild},_addItem:function(e){var n=document.createElement(`label`),r=this._map.hasLayer(e.layer),i;e.overlay?(i=document.createElement(`input`),i.type=`checkbox`,i.className=`leaflet-control-layers-selector`,i.defaultChecked=r):i=this._createRadioElement(`leaflet-base-layers_`+s(this),r),this._layerControlInputs.push(i),i.layerId=s(e.layer),W(i,`click`,this._onInputClick,this);var a=document.createElement(`span`);a.innerHTML=` `+e.name;var o=document.createElement(`span`);return n.appendChild(o),o.appendChild(i),o.appendChild(a),(e.overlay?this._overlaysList:this._baseLayersList).appendChild(n),this._checkDisabledLayers(),n},_onInputClick:function(){if(!this._preventClick){var e=this._layerControlInputs,n,r,i=[],a=[];this._handlingClick=!0;for(var o=e.length-1;o>=0;o--)n=e[o],r=this._getLayer(n.layerId).layer,n.checked?i.push(r):n.checked||a.push(r);for(o=0;o=0;a--)n=e[a],r=this._getLayer(n.layerId).layer,n.disabled=r.options.minZoom!==void 0&&ir.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var e=this._section;this._preventClick=!0,W(e,`click`,q),this.expand();var n=this;setTimeout(function(){K(e,`click`,q),n._preventClick=!1})}}),pn=function(e,n,r){return new fn(e,n,r)},mn=Y.extend({options:{position:`topleft`,zoomInText:``,zoomInTitle:`Zoom in`,zoomOutText:``,zoomOutTitle:`Zoom out`},onAdd:function(e){var n=`leaflet-control-zoom`,r=I(`div`,n+` leaflet-bar`),i=this.options;return this._zoomInButton=this._createButton(i.zoomInText,i.zoomInTitle,n+`-in`,r,this._zoomIn),this._zoomOutButton=this._createButton(i.zoomOutText,i.zoomOutTitle,n+`-out`,r,this._zoomOut),this._updateDisabled(),e.on(`zoomend zoomlevelschange`,this._updateDisabled,this),r},onRemove:function(e){e.off(`zoomend zoomlevelschange`,this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(e){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(e.shiftKey?3:1))},_createButton:function(e,n,r,i,a){var o=I(`a`,r,i);return o.innerHTML=e,o.href=`#`,o.title=n,o.setAttribute(`role`,`button`),o.setAttribute(`aria-label`,n),en(o),W(o,`click`,tn),W(o,`click`,a,this),W(o,`click`,this._refocusOnMap,this),o},_updateDisabled:function(){var e=this._map,n=`leaflet-disabled`;B(this._zoomInButton,n),B(this._zoomOutButton,n),this._zoomInButton.setAttribute(`aria-disabled`,`false`),this._zoomOutButton.setAttribute(`aria-disabled`,`false`),(this._disabled||e._zoom===e.getMinZoom())&&(z(this._zoomOutButton,n),this._zoomOutButton.setAttribute(`aria-disabled`,`true`)),(this._disabled||e._zoom===e.getMaxZoom())&&(z(this._zoomInButton,n),this._zoomInButton.setAttribute(`aria-disabled`,`true`))}});J.mergeOptions({zoomControl:!0}),J.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new mn,this.addControl(this.zoomControl))});var hn=function(e){return new mn(e)},gn=Y.extend({options:{position:`bottomleft`,maxWidth:100,metric:!0,imperial:!0},onAdd:function(e){var n=`leaflet-control-scale`,r=I(`div`,n),i=this.options;return this._addScales(i,n+`-line`,r),e.on(i.updateWhenIdle?`moveend`:`move`,this._update,this),e.whenReady(this._update,this),r},onRemove:function(e){e.off(this.options.updateWhenIdle?`moveend`:`move`,this._update,this)},_addScales:function(e,n,r){e.metric&&(this._mScale=I(`div`,n,r)),e.imperial&&(this._iScale=I(`div`,n,r))},_update:function(){var e=this._map,n=e.getSize().y/2,r=e.distance(e.containerPointToLatLng([0,n]),e.containerPointToLatLng([this.options.maxWidth,n]));this._updateScales(r)},_updateScales:function(e){this.options.metric&&e&&this._updateMetric(e),this.options.imperial&&e&&this._updateImperial(e)},_updateMetric:function(e){var n=this._getRoundNum(e),r=n<1e3?n+` m`:n/1e3+` km`;this._updateScale(this._mScale,r,n/e)},_updateImperial:function(e){var n=e*3.2808399,r,i,a;n>5280?(r=n/5280,i=this._getRoundNum(r),this._updateScale(this._iScale,i+` mi`,i/r)):(a=this._getRoundNum(n),this._updateScale(this._iScale,a+` ft`,a/n))},_updateScale:function(e,n,r){e.style.width=Math.round(this.options.maxWidth*r)+`px`,e.innerHTML=n},_getRoundNum:function(e){var n=10**((Math.floor(e)+``).length-1),r=e/n;return r=r>=10?10:r>=5?5:r>=3?3:r>=2?2:1,n*r}}),_n=function(e){return new gn(e)},vn=Y.extend({options:{position:`bottomright`,prefix:``+(P.inlineSvg?` `:``)+`Leaflet`},initialize:function(e){m(this,e),this._attributions={}},onAdd:function(e){for(var n in e.attributionControl=this,this._container=I(`div`,`leaflet-control-attribution`),en(this._container),e._layers)e._layers[n].getAttribution&&this.addAttribution(e._layers[n].getAttribution());return this._update(),e.on(`layeradd`,this._addAttribution,this),this._container},onRemove:function(e){e.off(`layeradd`,this._addAttribution,this)},_addAttribution:function(e){e.layer.getAttribution&&(this.addAttribution(e.layer.getAttribution()),e.layer.once(`remove`,function(){this.removeAttribution(e.layer.getAttribution())},this))},setPrefix:function(e){return this.options.prefix=e,this._update(),this},addAttribution:function(e){return e?(this._attributions[e]||(this._attributions[e]=0),this._attributions[e]++,this._update(),this):this},removeAttribution:function(e){return e&&this._attributions[e]&&(this._attributions[e]--,this._update()),this},_update:function(){if(this._map){var e=[];for(var n in this._attributions)this._attributions[n]&&e.push(n);var r=[];this.options.prefix&&r.push(this.options.prefix),e.length&&r.push(e.join(`, `)),this._container.innerHTML=r.join(` `)}}});J.mergeOptions({attributionControl:!0}),J.addInitHook(function(){this.options.attributionControl&&new vn().addTo(this)}),Y.Layers=fn,Y.Zoom=mn,Y.Scale=gn,Y.Attribution=vn,dn.layers=pn,dn.zoom=hn,dn.scale=_n,dn.attribution=function(e){return new vn(e)};var yn=se.extend({initialize:function(e){this._map=e},enable:function(){return this._enabled?this:(this._enabled=!0,this.addHooks(),this)},disable:function(){return this._enabled?(this._enabled=!1,this.removeHooks(),this):this},enabled:function(){return!!this._enabled}});yn.addTo=function(e,n){return e.addHandler(n,this),this};var bn={Events:S},xn=P.touch?`touchstart mousedown`:`mousedown`,Sn=le.extend({options:{clickTolerance:3},initialize:function(e,n,r,i){m(this,i),this._element=e,this._dragStartTarget=n||e,this._preventOutline=r},enable:function(){this._enabled||=(W(this._dragStartTarget,xn,this._onDown,this),!0)},disable:function(){this._enabled&&(Sn._dragging===this&&this.finishDrag(!0),K(this._dragStartTarget,xn,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(e){if(this._enabled&&(this._moved=!1,!kt(this._element,`leaflet-zoom-anim`))){if(e.touches&&e.touches.length!==1){Sn._dragging===this&&this.finishDrag();return}if(!(Sn._dragging||e.shiftKey||e.which!==1&&e.button!==1&&!e.touches)&&(Sn._dragging=this,this._preventOutline&&Ut(this._element),zt(),It(),!this._moving)){this.fire(`down`);var n=e.touches?e.touches[0]:e,r=Gt(this._element);this._startPoint=new C(n.clientX,n.clientY),this._startPos=Ft(this._element),this._parentScale=Kt(r);var i=e.type===`mousedown`;W(document,i?`mousemove`:`touchmove`,this._onMove,this),W(document,i?`mouseup`:`touchend touchcancel`,this._onUp,this)}}},_onMove:function(e){if(this._enabled){if(e.touches&&e.touches.length>1){this._moved=!0;return}var n=e.touches&&e.touches.length===1?e.touches[0]:e,r=new C(n.clientX,n.clientY)._subtract(this._startPoint);!r.x&&!r.y||Math.abs(r.x)+Math.abs(r.y)o&&(s=c,o=l);o>r&&(n[s]=1,jn(e,n,r,i,s),jn(e,n,r,s,a))}function Mn(e,n){for(var r=[e[0]],i=1,a=0,o=e.length;in&&(r.push(e[i]),a=i);return an.max.x&&(r|=2),e.yn.max.y&&(r|=8),r}function Ln(e,n){var r=n.x-e.x,i=n.y-e.y;return r*r+i*i}function Rn(e,n,r,i){var a=n.x,o=n.y,s=r.x-a,c=r.y-o,l=s*s+c*c,u;return l>0&&(u=((e.x-a)*s+(e.y-o)*c)/l,u>1?(a=r.x,o=r.y):u>0&&(a+=s*u,o+=c*u)),s=e.x-a,c=e.y-o,i?s*s+c*c:new C(a,o)}function X(e){return!v(e[0])||typeof e[0][0]!=`object`&&e[0][0]!==void 0}function zn(e){return console.warn(`Deprecated use of _flat, please use L.LineUtil.isFlat instead.`),X(e)}function Bn(e,n){var r,i,a,o,s,c,l,u;if(!e||e.length===0)throw Error(`latlngs not passed`);X(e)||(console.warn(`latlngs are not flat! Only the first ring will be used`),e=e[0]);var d=A([0,0]),f=O(e);f.getNorthWest().distanceTo(f.getSouthWest())*f.getNorthEast().distanceTo(f.getNorthWest())<1700&&(d=Tn(e));var p=e.length,m=[];for(r=0;ri){l=(o-i)/a,u=[c.x-l*(c.x-s.x),c.y-l*(c.y-s.y)];break}var g=n.unproject(w(u));return A([g.lat+d.lat,g.lng+d.lng])}var Vn={__proto__:null,simplify:Dn,pointToSegmentDistance:On,closestPointOnSegment:kn,clipSegment:Pn,_getEdgeIntersection:Fn,_getBitCode:In,_sqClosestPointOnSegment:Rn,isFlat:X,_flat:zn,polylineCenter:Bn},Hn={project:function(e){return new C(e.lng,e.lat)},unproject:function(e){return new k(e.y,e.x)},bounds:new T([-180,-90],[180,90])},Un={R:6378137,R_MINOR:6356752.314245179,bounds:new T([-20037508.34279,-15496570.73972],[20037508.34279,18764656.23138]),project:function(e){var n=Math.PI/180,r=this.R,i=e.lat*n,a=this.R_MINOR/r,o=Math.sqrt(1-a*a),s=o*Math.sin(i),c=Math.tan(Math.PI/4-i/2)/((1-s)/(1+s))**(o/2);return i=-r*Math.log(Math.max(c,1e-10)),new C(e.lng*n*r,i)},unproject:function(e){for(var n=180/Math.PI,r=this.R,i=this.R_MINOR/r,a=Math.sqrt(1-i*i),o=Math.exp(-e.y/r),s=Math.PI/2-2*Math.atan(o),c=0,l=.1,u;c<15&&Math.abs(l)>1e-7;c++)u=a*Math.sin(s),u=((1-u)/(1+u))**(a/2),l=Math.PI/2-2*Math.atan(o*u)-s,s+=l;return new k(s*n,e.x*n/r)}},Wn={__proto__:null,LonLat:Hn,Mercator:Un,SphericalMercator:M},Gn=r({},de,{code:`EPSG:3395`,projection:Un,transformation:function(){var e=.5/(Math.PI*Un.R);return N(e,.5,-e,.5)}()}),Kn=r({},de,{code:`EPSG:4326`,projection:Hn,transformation:N(1/180,1,-1/180,.5)}),qn=r({},j,{projection:Hn,transformation:N(1,0,-1,0),scale:function(e){return 2**e},zoom:function(e){return Math.log(e)/Math.LN2},distance:function(e,n){var r=n.lng-e.lng,i=n.lat-e.lat;return Math.sqrt(r*r+i*i)},infinite:!0});j.Earth=de,j.EPSG3395=Gn,j.EPSG3857=me,j.EPSG900913=he,j.EPSG4326=Kn,j.Simple=qn;var Z=le.extend({options:{pane:`overlayPane`,attribution:null,bubblingMouseEvents:!0},addTo:function(e){return e.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(e){return e&&e.removeLayer(this),this},getPane:function(e){return this._map.getPane(e?this.options[e]||e:this.options.pane)},addInteractiveTarget:function(e){return this._map._targets[s(e)]=this,this},removeInteractiveTarget:function(e){return delete this._map._targets[s(e)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(e){var n=e.target;if(n.hasLayer(this)){if(this._map=n,this._zoomAnimated=n._zoomAnimated,this.getEvents){var r=this.getEvents();n.on(r,this),this.once(`remove`,function(){n.off(r,this)},this)}this.onAdd(n),this.fire(`add`),n.fire(`layeradd`,{layer:this})}}});J.include({addLayer:function(e){if(!e._layerAdd)throw Error(`The provided object is not a Layer.`);var n=s(e);return this._layers[n]?this:(this._layers[n]=e,e._mapToAdd=this,e.beforeAdd&&e.beforeAdd(this),this.whenReady(e._layerAdd,e),this)},removeLayer:function(e){var n=s(e);return this._layers[n]?(this._loaded&&e.onRemove(this),delete this._layers[n],this._loaded&&(this.fire(`layerremove`,{layer:e}),e.fire(`remove`)),e._map=e._mapToAdd=null,this):this},hasLayer:function(e){return s(e)in this._layers},eachLayer:function(e,n){for(var r in this._layers)e.call(n,this._layers[r]);return this},_addLayers:function(e){e=e?v(e)?e:[e]:[];for(var n=0,r=e.length;nthis._layersMaxZoom&&this.setZoom(this._layersMaxZoom),this.options.minZoom===void 0&&this._layersMinZoom&&this.getZoom()=2&&n[0]instanceof k&&n[0].equals(n[r-1])&&n.pop(),n},_setLatLngs:function(e){lr.prototype._setLatLngs.call(this,e),X(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return X(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var e=this._renderer._bounds,n=this.options.weight,r=new C(n,n);if(e=new T(e.min.subtract(r),e.max.add(r)),this._parts=[],!(!this._pxBounds||!this._pxBounds.intersects(e))){if(this.options.noClip){this._parts=this._rings;return}for(var i=0,a=this._rings.length,o;ie.y!=a.y>e.y&&e.x<(a.x-i.x)*(e.y-i.y)/(a.y-i.y)+i.x&&(n=!n);return n||lr.prototype._containsPoint.call(this,e,!0)}});function fr(e,n){return new dr(e,n)}var pr=Xn.extend({initialize:function(e,n){m(this,n),this._layers={},e&&this.addData(e)},addData:function(e){var n=v(e)?e:e.features,r,i,a;if(n){for(r=0,i=n.length;r0&&a.push(a[0].slice()),a}function br(e,n){return e.feature?r({},e.feature,{geometry:n}):xr(n)}function xr(e){return e.type===`Feature`||e.type===`FeatureCollection`?e:{type:`Feature`,properties:{},geometry:e}}var Sr={toGeoJSON:function(e){return br(this,{type:`Point`,coordinates:vr(this.getLatLng(),e)})}};nr.include(Sr),sr.include(Sr),ar.include(Sr),lr.include({toGeoJSON:function(e){var n=!X(this._latlngs),r=yr(this._latlngs,+!!n,!1,e);return br(this,{type:(n?`Multi`:``)+`LineString`,coordinates:r})}}),dr.include({toGeoJSON:function(e){var n=!X(this._latlngs),r=n&&!X(this._latlngs[0]),i=yr(this._latlngs,r?2:+!!n,!0,e);return n||(i=[i]),br(this,{type:(r?`Multi`:``)+`Polygon`,coordinates:i})}}),Jn.include({toMultiPoint:function(e){var n=[];return this.eachLayer(function(r){n.push(r.toGeoJSON(e).geometry.coordinates)}),br(this,{type:`MultiPoint`,coordinates:n})},toGeoJSON:function(e){var n=this.feature&&this.feature.geometry&&this.feature.geometry.type;if(n===`MultiPoint`)return this.toMultiPoint(e);var r=n===`GeometryCollection`,i=[];return this.eachLayer(function(n){if(n.toGeoJSON){var a=n.toGeoJSON(e);if(r)i.push(a.geometry);else{var o=xr(a);o.type===`FeatureCollection`?i.push.apply(i,o.features):i.push(o)}}}),r?br(this,{geometries:i,type:`GeometryCollection`}):{type:`FeatureCollection`,features:i}}});function Cr(e,n){return new pr(e,n)}var wr=Cr,Tr=Z.extend({options:{opacity:1,alt:``,interactive:!1,crossOrigin:!1,errorOverlayUrl:``,zIndex:1,className:``},initialize:function(e,n,r){this._url=e,this._bounds=O(n),m(this,r)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(z(this._image,`leaflet-interactive`),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){R(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(e){return this.options.opacity=e,this._image&&this._updateOpacity(),this},setStyle:function(e){return e.opacity&&this.setOpacity(e.opacity),this},bringToFront:function(){return this._map&&Dt(this._image),this},bringToBack:function(){return this._map&&Ot(this._image),this},setUrl:function(e){return this._url=e,this._image&&(this._image.src=e),this},setBounds:function(e){return this._bounds=O(e),this._map&&this._reset(),this},getEvents:function(){var e={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(e.zoomanim=this._animateZoom),e},setZIndex:function(e){return this.options.zIndex=e,this._updateZIndex(),this},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var e=this._url.tagName===`IMG`,n=this._image=e?this._url:I(`img`);if(z(n,`leaflet-image-layer`),this._zoomAnimated&&z(n,`leaflet-zoom-animated`),this.options.className&&z(n,this.options.className),n.onselectstart=u,n.onmousemove=u,n.onload=a(this.fire,this,`load`),n.onerror=a(this._overlayOnError,this,`error`),(this.options.crossOrigin||this.options.crossOrigin===``)&&(n.crossOrigin=this.options.crossOrigin===!0?``:this.options.crossOrigin),this.options.zIndex&&this._updateZIndex(),e){this._url=n.src;return}n.src=this._url,n.alt=this.options.alt},_animateZoom:function(e){var n=this._map.getZoomScale(e.zoom),r=this._map._latLngBoundsToNewLayerBounds(this._bounds,e.zoom,e.center).min;Pt(this._image,r,n)},_reset:function(){var e=this._image,n=new T(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),r=n.getSize();H(e,n.min),e.style.width=r.x+`px`,e.style.height=r.y+`px`},_updateOpacity:function(){V(this._image,this.options.opacity)},_updateZIndex:function(){this._image&&this.options.zIndex!==void 0&&this.options.zIndex!==null&&(this._image.style.zIndex=this.options.zIndex)},_overlayOnError:function(){this.fire(`error`);var e=this.options.errorOverlayUrl;e&&this._url!==e&&(this._url=e,this._image.src=e)},getCenter:function(){return this._bounds.getCenter()}}),Er=function(e,n,r){return new Tr(e,n,r)},Dr=Tr.extend({options:{autoplay:!0,loop:!0,keepAspectRatio:!0,muted:!1,playsInline:!0},_initImage:function(){var e=this._url.tagName===`VIDEO`,n=this._image=e?this._url:I(`video`);if(z(n,`leaflet-image-layer`),this._zoomAnimated&&z(n,`leaflet-zoom-animated`),this.options.className&&z(n,this.options.className),n.onselectstart=u,n.onmousemove=u,n.onloadeddata=a(this.fire,this,`load`),e){for(var r=n.getElementsByTagName(`source`),i=[],o=0;o0?i:[n.src];return}v(this._url)||(this._url=[this._url]),!this.options.keepAspectRatio&&Object.prototype.hasOwnProperty.call(n.style,`objectFit`)&&(n.style.objectFit=`fill`),n.autoplay=!!this.options.autoplay,n.loop=!!this.options.loop,n.muted=!!this.options.muted,n.playsInline=!!this.options.playsInline;for(var s=0;s