diff --git a/apis/record_helpers.go b/apis/record_helpers.go index c9be32ce..e42f69be 100644 --- a/apis/record_helpers.go +++ b/apis/record_helpers.go @@ -138,10 +138,10 @@ func autoIgnoreAuthRecordsEmailVisibility( collection := records[0].Collection() mappedRecords := make(map[string]*models.Record, len(records)) - recordIds := make([]any, 0, len(records)) - for _, rec := range records { + recordIds := make([]any, len(records)) + for i, rec := range records { mappedRecords[rec.Id] = rec - recordIds = append(recordIds, rec.Id) + recordIds[i] = rec.Id } if requestData != nil && requestData.AuthRecord != nil && mappedRecords[requestData.AuthRecord.Id] != nil { diff --git a/core/base.go b/core/base.go index 208279a4..4169eb5c 100644 --- a/core/base.go +++ b/core/base.go @@ -714,7 +714,10 @@ func (app *BaseApp) createDaoWithHooks(db dbx.Builder) *daos.Dao { } dao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) { - app.OnModelAfterCreate().Trigger(&ModelEvent{eventDao, m}) + err := app.OnModelAfterCreate().Trigger(&ModelEvent{eventDao, m}) + if err != nil && app.isDebug { + log.Println(err) + } } dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error { @@ -722,7 +725,10 @@ func (app *BaseApp) createDaoWithHooks(db dbx.Builder) *daos.Dao { } dao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) { - app.OnModelAfterUpdate().Trigger(&ModelEvent{eventDao, m}) + err := app.OnModelAfterUpdate().Trigger(&ModelEvent{eventDao, m}) + if err != nil && app.isDebug { + log.Println(err) + } } dao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error { @@ -730,7 +736,10 @@ func (app *BaseApp) createDaoWithHooks(db dbx.Builder) *daos.Dao { } dao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) { - app.OnModelAfterDelete().Trigger(&ModelEvent{eventDao, m}) + err := app.OnModelAfterDelete().Trigger(&ModelEvent{eventDao, m}) + if err != nil && app.isDebug { + log.Println(err) + } } return dao diff --git a/daos/record_expand.go b/daos/record_expand.go index 4e081d07..b7e3c7e4 100644 --- a/daos/record_expand.go +++ b/daos/record_expand.go @@ -93,8 +93,8 @@ func (dao *Dao) expandRecords(records []*models.Record, expandPath string, fetch } recordIds := make([]any, len(records)) - for _, record := range records { - recordIds = append(recordIds, record.Id) + for i, record := range records { + recordIds[i] = record.Id } indirectRecords, err := dao.FindRecordsByExpr( diff --git a/examples/base/main.go b/examples/base/main.go index 41655c04..815ff4aa 100644 --- a/examples/base/main.go +++ b/examples/base/main.go @@ -2,42 +2,29 @@ package main import ( "log" - "os" - "path/filepath" - "strings" "github.com/pocketbase/pocketbase" - "github.com/pocketbase/pocketbase/apis" - "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/plugins/jsvm" + "github.com/pocketbase/pocketbase/plugins/migratecmd" + "github.com/pocketbase/pocketbase/plugins/publicdir" ) -func defaultPublicDir() string { - if strings.HasPrefix(os.Args[0], os.TempDir()) { - // most likely ran with go run - return "./pb_public" - } - - return filepath.Join(os.Args[0], "../pb_public") -} - func main() { app := pocketbase.New() - var publicDirFlag string + // load js pb_migrations + jsvm.MustRegisterMigrationsLoader(app, nil) - // add "--publicDir" option flag - app.RootCmd.PersistentFlags().StringVar( - &publicDirFlag, - "publicDir", - defaultPublicDir(), - "the directory to serve static files", - ) + // migrate command (with js templates) + migratecmd.MustRegister(app, app.RootCmd, &migratecmd.Options{ + TemplateLang: migratecmd.TemplateLangJS, + AutoMigrate: true, + }) - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { - // serves static files from the provided public dir (if exists) - e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS(publicDirFlag), true)) - - return nil + // pb_public dir + publicdir.MustRegister(app, &publicdir.Options{ + FlagsCmd: app.RootCmd, + IndexFallback: true, }) if err := app.Start(); err != nil { diff --git a/go.mod b/go.mod index 0fefaf13..243ffa65 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,8 @@ require ( github.com/aws/aws-sdk-go v1.44.141 github.com/disintegration/imaging v1.6.2 github.com/domodwyer/mailyak/v3 v3.3.4 + github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86 + github.com/dop251/goja_nodejs v0.0.0-20221009164102-3aa5028e57f6 github.com/fatih/color v1.13.0 github.com/gabriel-vasile/mimetype v1.4.1 github.com/ganigeorgiev/fexpr v0.1.1 @@ -45,6 +47,8 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.17.4 // indirect github.com/aws/smithy-go v1.13.4 // indirect + github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/uuid v1.3.0 // indirect diff --git a/go.sum b/go.sum index 9b4437f3..f572d6dd 100644 --- a/go.sum +++ b/go.sum @@ -47,18 +47,16 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5Jk4= cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0= +cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.6.0 h1:nsqQC88kT5Iwlm4MeNGTpfMWddp6NB/UOLFTH6m1QfQ= cloud.google.com/go/iam v0.7.0 h1:k4MuwOsS7zGJJ+QfZ5vBK8SgHBAvYN/23BWsiihJ1vs= cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/longrunning v0.1.1 h1:y50CXG4j0+qvEukslYFBCrzaXX0qpFbBzc3PchSu/LE= cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TElyanS95vIcl4= cloud.google.com/go/monitoring v1.5.0/go.mod h1:/o9y8NYX5j91JjD/JvGLYbi86kL11OjyJXq2XziLJu4= @@ -208,12 +206,6 @@ github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4 github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.45/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.68/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.44.126 h1:7HQJw2DNiwpxqMe2H7odGNT2rhO4SRrUe5/8dYXl0Jk= -github.com/aws/aws-sdk-go v1.44.126/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.44.127 h1:IoO2VfuIQg1aMXnl8l6OpNUKT4Qq5CnJMOyIWoTYXj0= -github.com/aws/aws-sdk-go v1.44.127/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.44.130 h1:a/qwOxmYJF47xTZvTjECSJXnfRbjegb3YxvCXfETtnY= -github.com/aws/aws-sdk-go v1.44.130/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.141 h1:kT/YIH9GUaKZa3yi8TEsZmVgvphwEzINJu19hYUzfGY= github.com/aws/aws-sdk-go v1.44.141/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= @@ -224,21 +216,15 @@ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXK github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 h1:RKci2D7tMwpvGpDNZnGQw9wk6v7o/xSwFcUAuNPoB8k= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9/go.mod h1:vCmV1q1VK8eoQJ5+aYE7PkK1K6v41qJ5pJdK3ggCDvg= github.com/aws/aws-sdk-go-v2/config v1.15.15/go.mod h1:A1Lzyy/o21I5/s2FbyX5AevQfSVXpvvIDCoVFD0BC4E= -github.com/aws/aws-sdk-go-v2/config v1.17.10 h1:zBy5QQ/mkvHElM1rygHPAzuH+sl8nsdSaxSWj0+rpdE= -github.com/aws/aws-sdk-go-v2/config v1.17.10/go.mod h1:/4np+UiJJKpWHN7Q+LZvqXYgyjgeXm5+lLfDI6TPZao= github.com/aws/aws-sdk-go-v2/config v1.18.2 h1:tRhTb3xMZsB0gW0sXWpqs9FeIP8iQp5SvnvwiPXzHwo= github.com/aws/aws-sdk-go-v2/config v1.18.2/go.mod h1:9XVoZTdD8ICjrgI5ddb8j918q6lEZkFYpb7uohgvU6c= github.com/aws/aws-sdk-go-v2/credentials v1.12.10/go.mod h1:g5eIM5XRs/OzIIK81QMBl+dAuDyoLN0VYaLP+tBqEOk= -github.com/aws/aws-sdk-go-v2/credentials v1.12.23 h1:LctvcJMIb8pxvk5hQhChpCu0WlU6oKQmcYb1HA4IZSA= -github.com/aws/aws-sdk-go-v2/credentials v1.12.23/go.mod h1:0awX9iRr/+UO7OwRQFpV1hNtXxOVuehpjVEzrIAYNcA= github.com/aws/aws-sdk-go-v2/credentials v1.13.2 h1:F/v1w0XcFDZjL0bCdi9XWJenoPKjGbzljBhDKcryzEQ= github.com/aws/aws-sdk-go-v2/credentials v1.13.2/go.mod h1:eAT5aj/WJ2UDIA0IVNFc2byQLeD89SDEi4cjzH/MKoQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9/go.mod h1:KDCCm4ONIdHtUloDcFvK2+vshZvx4Zmj7UMDfusuz5s= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.21/go.mod h1:iIYPrQ2rYfZiB/iADYlhj9HHZ9TTi6PqKQPAqygohbE= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37 h1:e1VtTBo+cLNjres0wTlMkmwCGGRjDEkkrz3frxxcaCs= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37/go.mod h1:kdAV1UMnCkyG6tZJUC4mHbPoRjPA3dIK0L8mnsHERiM= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.41 h1:ssgdsNm11dvFtO7F/AeiW4dAO3eGsDeg5fwpag/JP/I= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.41/go.mod h1:CS+AbDFAaPU9TQOo7U6mVV23YvqCOElnqmh0XQjgJ1g= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4= @@ -267,8 +253,6 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 h1:piDBAaWkaxkkV github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19/go.mod h1:BmQWRVkLTmyNzYPFAZgon53qKLWBNSvonugD1MrSWUs= github.com/aws/aws-sdk-go-v2/service/kms v1.18.1/go.mod h1:4PZMUkc9rXHWGVB5J9vKaZy3D7Nai79ORworQ3ASMiM= github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2/go.mod h1:u+566cosFI+d+motIz3USXEh6sN8Nq4GrNXSg2RXVMo= -github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1 h1:/EMdFPW/Ppieh0WUtQf1+qCGNLdsq5UWUyevBQ6vMVc= -github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0= github.com/aws/aws-sdk-go-v2/service/s3 v1.29.3 h1:F6wgg8aHGNyhaAy2ONnWBThiPdLa386qNA0j33FIuSM= github.com/aws/aws-sdk-go-v2/service/s3 v1.29.3/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.14/go.mod h1:xakbH8KMsQQKqzX87uyyzTHshc/0/Df8bsTneTS5pFU= @@ -281,8 +265,6 @@ github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vbo github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI= github.com/aws/aws-sdk-go-v2/service/sts v1.16.10/go.mod h1:cftkHYN6tCDNfkSasAmclSfl4l7cySoay8vz7p/ce0E= -github.com/aws/aws-sdk-go-v2/service/sts v1.17.1 h1:KRAix/KHvjGODaHAMXnxRk9t0D+4IJVUuS/uwXxngXk= -github.com/aws/aws-sdk-go-v2/service/sts v1.17.1/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4= github.com/aws/aws-sdk-go-v2/service/sts v1.17.4 h1:YNncBj5dVYd05i4ZQ+YicOotSXo0ufc9P8kTioi13EM= github.com/aws/aws-sdk-go-v2/service/sts v1.17.4/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4= github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= @@ -498,6 +480,9 @@ github.com/digitalocean/godo v1.81.0/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= @@ -521,6 +506,14 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/domodwyer/mailyak/v3 v3.3.4 h1:AG/pvcz2/ocFqZkPEG7lPAa0MhCq1warfUEKJt6Fagk= github.com/domodwyer/mailyak/v3 v3.3.4/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20220815083517-0c74f9139fd6/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86 h1:E2wycakfddWJ26v+ZyEY91Lb/HEZyaiZhbMX+KQcdmc= +github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= +github.com/dop251/goja_nodejs v0.0.0-20221009164102-3aa5028e57f6 h1:p3QZwRRfCN7Qr3GNBTMKBkLFjEm3DHR4MaJABvsiqgk= +github.com/dop251/goja_nodejs v0.0.0-20221009164102-3aa5028e57f6/go.mod h1:+CJy9V5cGycP5qwp6RM5jLg+TFEMyGtD7A9xUbU/BOQ= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -640,6 +633,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= @@ -816,8 +811,6 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= @@ -1379,7 +1372,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -1464,7 +1456,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -1567,8 +1558,6 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1613,8 +1602,6 @@ golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1694,7 +1681,6 @@ golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -1723,8 +1709,6 @@ golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7Lm golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220628200809-02e64fa58f26/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y= -golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= golang.org/x/oauth2 v0.2.0 h1:GtQkldQ9m7yvzCL1V+LrYow3Khe0eJH0w7RbX/VbaIU= golang.org/x/oauth2 v0.2.0/go.mod h1:Cwn6afJ8jrQwYMxQDTpISoXmXW9I6qF6vDeuuoX3Ibs= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1741,6 +1725,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1883,7 +1868,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1893,7 +1877,6 @@ golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1920,8 +1903,6 @@ golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2007,8 +1988,6 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2070,10 +2049,6 @@ google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6F google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= google.golang.org/api v0.91.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.101.0 h1:lJPPeEBIRxGpGLwnBTam1NPEM8Z2BmmXEd3z812pjwM= -google.golang.org/api v0.101.0/go.mod h1:CjxAAWWt3A3VrUE2IGDY2bgK5qhoG/OkyWVlYcP05MY= -google.golang.org/api v0.102.0 h1:JxJl2qQ85fRMPNvlZY/enexbxpCjLwGhZUtgfGeQ51I= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ= google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -2184,8 +2159,6 @@ google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljW google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c= google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -2229,8 +2202,6 @@ google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -2365,8 +2336,6 @@ lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8 h1:0+dsXf0zeLx9ixj4nilg6jKe5Bg1ilzBwSFq4kJmIUc= -modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= @@ -2379,15 +2348,11 @@ modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk= modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.19.3 h1:dIoagx6yIQT3V/zOSeAyZ8OqQyEr17YTgETOXTZNJMA= -modernc.org/sqlite v1.19.3/go.mod h1:xiyJD7FY8mTZXnQwE/gEL1STtFrrnDx03V8KhVQmcr8= modernc.org/sqlite v1.19.4 h1:nlPIDqumn6/mSvs7T5C8MNYEuN73sISzPdKtMdURpUI= modernc.org/sqlite v1.19.4/go.mod h1:x/yZNb3h5+I3zGQSlwIv4REL5eJhiRkUH5MReogAeIc= modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34= -modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE= diff --git a/plugins/jsvm/migrations.go b/plugins/jsvm/migrations.go new file mode 100644 index 00000000..2778a9c9 --- /dev/null +++ b/plugins/jsvm/migrations.go @@ -0,0 +1,110 @@ +package jsvm + +import ( + "os" + "path/filepath" + + "github.com/dop251/goja_nodejs/console" + "github.com/dop251/goja_nodejs/require" + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +// MigrationsLoaderOptions defines optional struct to customize the default plugin behavior. +type MigrationsLoaderOptions struct { + // Dir is the app migrations directory from where the js files will be loaded + // (default to pb_data/migrations) + Dir string +} + +// migrationsLoader is the plugin definition. +// Usually it is instantiated via RegisterMigrationsLoader or MustRegisterMigrationsLoader. +type migrationsLoader struct { + app core.App + options *MigrationsLoaderOptions +} + +// +// MustRegisterMigrationsLoader registers the plugin to the provided +// app instance and panics if it fails. +// +// It it calls RegisterMigrationsLoader(app, options) +// +// If options is nil, by default the js files from pb_data/migrations are loaded. +// Set custom options.Dir if you want to change it to some other directory. +func MustRegisterMigrationsLoader(app core.App, options *MigrationsLoaderOptions) { + if err := RegisterMigrationsLoader(app, options); err != nil { + panic(err) + } +} + +// RegisterMigrationsLoader registers the plugin to the provided app instance. +// +// If options is nil, by default the js files from pb_data/migrations are loaded. +// Set custom options.Dir if you want to change it to some other directory. +func RegisterMigrationsLoader(app core.App, options *MigrationsLoaderOptions) error { + l := &migrationsLoader{app: app} + + if options != nil { + l.options = options + } else { + l.options = &MigrationsLoaderOptions{} + } + + if l.options.Dir == "" { + l.options.Dir = filepath.Join(app.DataDir(), "../pb_migrations") + } + + files, err := readDirFiles(l.options.Dir) + if err != nil { + return err + } + + registry := new(require.Registry) // this can be shared by multiple runtimes + + for file, content := range files { + vm := NewBaseVM(l.app) + registry.Enable(vm) + console.Enable(vm) + + vm.Set("migrate", func(up, down func(db dbx.Builder) error) { + m.AppMigrations.Register(up, down, file) + }) + + _, err := vm.RunString(string(content)) + if err != nil { + return err + } + } + + return nil +} + +// readDirFiles returns a map with all directory files and their content. +// +// If directory with dirPath is missing, it returns an empty map and no error. +func readDirFiles(dirPath string) (map[string][]byte, error) { + files, err := os.ReadDir(dirPath) + if err != nil { + if os.IsNotExist(err) { + return map[string][]byte{}, nil + } + return nil, err + } + + result := map[string][]byte{} + + for _, f := range files { + if f.IsDir() { + continue + } + raw, err := os.ReadFile(filepath.Join(dirPath, f.Name())) + if err != nil { + return nil, err + } + result[f.Name()] = raw + } + + return result, nil +} diff --git a/plugins/jsvm/vm.go b/plugins/jsvm/vm.go new file mode 100644 index 00000000..2d8df2ac --- /dev/null +++ b/plugins/jsvm/vm.go @@ -0,0 +1,135 @@ +package jsvm + +import ( + "encoding/json" + + "github.com/dop251/goja" + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/apis" + "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/daos" + "github.com/pocketbase/pocketbase/models" +) + +func NewBaseVM(app core.App) *goja.Runtime { + vm := goja.New() + vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) + + vm.Set("$app", app) + + vm.Set("unmarshal", func(src map[string]any, dest any) (any, error) { + raw, err := json.Marshal(src) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(raw, &dest); err != nil { + return nil, err + } + + return dest, nil + }) + + collectionConstructor(vm) + recordConstructor(vm) + adminConstructor(vm) + daoConstructor(vm) + dbxBinds(vm) + + return vm +} + +func collectionConstructor(vm *goja.Runtime) { + vm.Set("Collection", func(call goja.ConstructorCall) *goja.Object { + instance := &models.Collection{} + instanceValue := vm.ToValue(instance).(*goja.Object) + instanceValue.SetPrototype(call.This.Prototype()) + return instanceValue + }) +} + +func recordConstructor(vm *goja.Runtime) { + vm.Set("Record", func(call goja.ConstructorCall) *goja.Object { + instance := &models.Record{} + instanceValue := vm.ToValue(instance).(*goja.Object) + instanceValue.SetPrototype(call.This.Prototype()) + return instanceValue + }) +} + +func adminConstructor(vm *goja.Runtime) { + vm.Set("Admin", func(call goja.ConstructorCall) *goja.Object { + instance := &models.Admin{} + instanceValue := vm.ToValue(instance).(*goja.Object) + instanceValue.SetPrototype(call.This.Prototype()) + return instanceValue + }) +} + +func daoConstructor(vm *goja.Runtime) { + vm.Set("Dao", func(call goja.ConstructorCall) *goja.Object { + db, ok := call.Argument(0).Export().(dbx.Builder) + if !ok || db == nil { + panic("missing required Dao(db) argument") + } + + instance := daos.New(db) + instanceValue := vm.ToValue(instance).(*goja.Object) + instanceValue.SetPrototype(call.This.Prototype()) + return instanceValue + }) +} + +func dbxBinds(vm *goja.Runtime) { + obj := vm.NewObject() + vm.Set("$dbx", obj) + + obj.Set("exp", dbx.NewExp) + obj.Set("hashExp", func(data map[string]any) dbx.HashExp { + exp := dbx.HashExp{} + for k, v := range data { + exp[k] = v + } + return exp + }) + obj.Set("not", dbx.Not) + obj.Set("and", dbx.And) + obj.Set("or", dbx.Or) + obj.Set("in", dbx.In) + obj.Set("notIn", dbx.NotIn) + obj.Set("like", dbx.Like) + obj.Set("orLike", dbx.OrLike) + obj.Set("notLike", dbx.NotLike) + obj.Set("orNotLike", dbx.OrNotLike) + obj.Set("exists", dbx.Exists) + obj.Set("notExists", dbx.NotExists) + obj.Set("between", dbx.Between) + obj.Set("notBetween", dbx.NotBetween) +} + +func apisBind(vm *goja.Runtime) { + obj := vm.NewObject() + vm.Set("$apis", obj) + + // middlewares + obj.Set("requireRecordAuth", apis.RequireRecordAuth) + obj.Set("requireRecordAuth", apis.RequireRecordAuth) + obj.Set("requireSameContextRecordAuth", apis.RequireSameContextRecordAuth) + obj.Set("requireAdminAuth", apis.RequireAdminAuth) + obj.Set("requireAdminAuthOnlyIfAny", apis.RequireAdminAuthOnlyIfAny) + obj.Set("requireAdminOrRecordAuth", apis.RequireAdminOrRecordAuth) + obj.Set("requireAdminOrOwnerAuth", apis.RequireAdminOrOwnerAuth) + obj.Set("activityLogger", apis.ActivityLogger) + + // api errors + obj.Set("notFoundError", apis.NewNotFoundError) + obj.Set("badRequestError", apis.NewBadRequestError) + obj.Set("forbiddenError", apis.NewForbiddenError) + obj.Set("unauthorizedError", apis.NewUnauthorizedError) + + // record helpers + obj.Set("getRequestData", apis.GetRequestData) + obj.Set("requestData", apis.RequestData) + obj.Set("enrichRecord", apis.EnrichRecord) + obj.Set("enrichRecords", apis.EnrichRecords) +} diff --git a/plugins/migratecmd/automigrate.go b/plugins/migratecmd/automigrate.go new file mode 100644 index 00000000..1fa83f72 --- /dev/null +++ b/plugins/migratecmd/automigrate.go @@ -0,0 +1,154 @@ +package migratecmd + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + "time" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" + "github.com/pocketbase/pocketbase/tools/list" +) + +const migrationsTable = "_migrations" + +// tidyMigrationsTable cleanups the migrations table by removing all +// entries with deleted migration files. +func (p *plugin) tidyMigrationsTable() error { + names, filesErr := p.getAllMigrationNames() + if filesErr != nil { + return fmt.Errorf("failed to fetch migration files list: %v", filesErr) + } + + _, tidyErr := p.app.Dao().DB().Delete(migrationsTable, dbx.NotIn("file", list.ToInterfaceSlice(names)...)).Execute() + if tidyErr != nil { + return fmt.Errorf("failed to delete last automigrates from the db: %v", tidyErr) + } + + return nil +} + +func (p *plugin) onCollectionChange() func(*core.ModelEvent) error { + return func(e *core.ModelEvent) error { + if e.Model.TableName() != "_collections" { + return nil // not a collection + } + + collections := []*models.Collection{} + if err := p.app.Dao().CollectionQuery().OrderBy("created ASC").All(&collections); err != nil { + return fmt.Errorf("failed to fetch collections list: %v", err) + } + if len(collections) == 0 { + return errors.New("missing collections to automigrate") + } + + names, err := p.getAllMigrationNames() + if err != nil { + return fmt.Errorf("failed to fetch migration files list: %v", err) + } + + // delete last consequitive automigrates + lastAutomigrates := []string{} + for i := len(names) - 1; i >= 0; i-- { + migrationFile := names[i] + if !strings.Contains(migrationFile, "_automigrate.") { + break + } + lastAutomigrates = append(lastAutomigrates, migrationFile) + } + if len(lastAutomigrates) > 0 { + // delete last automigrates from the db + _, err := p.app.Dao().DB().Delete(migrationsTable, dbx.In("file", list.ToInterfaceSlice(lastAutomigrates)...)).Execute() + if err != nil { + return fmt.Errorf("failed to delete last automigrates from the db: %v", err) + } + + // delete last automigrates from the filesystem + for _, f := range lastAutomigrates { + if err := os.Remove(filepath.Join(p.options.Dir, f)); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to delete last automigrates from the filesystem: %v", err) + } + } + } + + var template string + var templateErr error + if p.options.TemplateLang == TemplateLangJS { + template, templateErr = p.jsSnapshotTemplate(collections) + } else { + template, templateErr = p.goSnapshotTemplate(collections) + } + if templateErr != nil { + return fmt.Errorf("failed to resolve template: %v", templateErr) + } + + // add a comment to not edit the template + template = ("// Do not edit by hand since this file is autogenerated and may get overwritten.\n" + + "// If you want to do further changes, create a new non '_automigrate' file instead.\n" + template) + + appliedTime := time.Now().Unix() + fileDest := filepath.Join(p.options.Dir, fmt.Sprintf("%d_automigrate.%s", appliedTime, p.options.TemplateLang)) + + // ensure that the local migrations dir exist + if err := os.MkdirAll(p.options.Dir, os.ModePerm); err != nil { + return fmt.Errorf("failed to create migration dir: %v", err) + } + + return os.WriteFile(fileDest, []byte(template), 0644) + } +} + +// getAllMigrationNames return both applied and new local migration file names. +func (p *plugin) getAllMigrationNames() ([]string, error) { + names := []string{} + + for _, migration := range m.AppMigrations.Items() { + names = append(names, migration.File) + } + + localFiles, err := p.getLocalMigrationNames() + if err != nil { + return nil, err + } + for _, name := range localFiles { + if !list.ExistInSlice(name, names) { + names = append(names, name) + } + } + + sort.Slice(names, func(i int, j int) bool { + return names[i] < names[j] + }) + + return names, nil +} + +// getLocalMigrationNames returns a list with all local migration files +// +// Returns an empty slice if the migrations directory doesn't exist. +func (p *plugin) getLocalMigrationNames() ([]string, error) { + files, err := os.ReadDir(p.options.Dir) + if err != nil { + if os.IsNotExist(err) { + return []string{}, nil + } + return nil, err + } + + result := make([]string, 0, len(files)) + + for _, f := range files { + if f.IsDir() { + continue + } + result = append(result, f.Name()) + } + + return result, nil +} diff --git a/plugins/migratecmd/migratecmd.go b/plugins/migratecmd/migratecmd.go new file mode 100644 index 00000000..ecb678ab --- /dev/null +++ b/plugins/migratecmd/migratecmd.go @@ -0,0 +1,210 @@ +package migratecmd + +import ( + "fmt" + "log" + "os" + "path" + "path/filepath" + "time" + + "github.com/AlecAivazis/survey/v2" + "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" + "github.com/pocketbase/pocketbase/tools/inflector" + "github.com/pocketbase/pocketbase/tools/migrate" + "github.com/spf13/cobra" +) + +type Options struct { + Dir string // the directory with user defined migrations + AutoMigrate bool + TemplateLang string +} + +type plugin struct { + app core.App + options *Options +} + +func MustRegister(app core.App, rootCmd *cobra.Command, options *Options) { + if err := Register(app, rootCmd, options); err != nil { + panic(err) + } +} + +func Register(app core.App, rootCmd *cobra.Command, options *Options) error { + p := &plugin{app: app} + + if options != nil { + p.options = options + } else { + p.options = &Options{} + } + + if p.options.TemplateLang == "" { + p.options.TemplateLang = TemplateLangGo + } + + if p.options.Dir == "" { + if p.options.TemplateLang == TemplateLangJS { + p.options.Dir = filepath.Join(p.app.DataDir(), "../pb_migrations") + } else { + p.options.Dir = filepath.Join(p.app.DataDir(), "../migrations") + } + } + + // attach the migrate command + if rootCmd != nil { + rootCmd.AddCommand(p.createCommand()) + } + + // watch for collection changes + if p.options.AutoMigrate { + // @todo replace with AfterBootstrap + p.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + if err := p.tidyMigrationsTable(); err != nil && p.app.IsDebug() { + log.Println("Failed to tidy the migrations table.") + } + + return nil + }) + + p.app.OnModelAfterCreate().Add(p.onCollectionChange()) + p.app.OnModelAfterUpdate().Add(p.onCollectionChange()) + p.app.OnModelAfterDelete().Add(p.onCollectionChange()) + } + + return nil +} + +func (p *plugin) createCommand() *cobra.Command { + const cmdDesc = `Supported arguments are: +- up - runs all available migrations. +- down [number] - reverts the last [number] applied migrations. +- create name [folder] - creates new blank migration template file. +- collections [folder] - creates new migration file with the latest local collections snapshot (similar to the automigrate but allows editing). +` + + command := &cobra.Command{ + Use: "migrate", + Short: "Executes app DB migration scripts", + ValidArgs: []string{"up", "down", "create", "collections"}, + Long: cmdDesc, + Run: func(command *cobra.Command, args []string) { + cmd := "" + if len(args) > 0 { + cmd = args[0] + } + + // additional commands + // --- + if cmd == "create" { + if err := p.migrateCreateHandler("", args[1:]); err != nil { + log.Fatal(err) + } + return + } + + if cmd == "collections" { + if err := p.migrateCollectionsHandler(args[1:]); err != nil { + log.Fatal(err) + } + return + } + // --- + + runner, err := migrate.NewRunner(p.app.DB(), migrations.AppMigrations) + if err != nil { + log.Fatal(err) + } + + if err := runner.Run(args...); err != nil { + log.Fatal(err) + } + }, + } + + return command +} + +func (p *plugin) migrateCreateHandler(template string, args []string) error { + if len(args) < 1 { + return fmt.Errorf("Missing migration file name") + } + + name := args[0] + + var dir string + if len(args) == 2 { + dir = args[1] + } + if dir == "" { + dir = p.options.Dir + } + + resultFilePath := path.Join( + dir, + fmt.Sprintf("%d_%s.%s", time.Now().Unix(), inflector.Snakecase(name), p.options.TemplateLang), + ) + + confirm := false + prompt := &survey.Confirm{ + Message: fmt.Sprintf("Do you really want to create migration %q?", resultFilePath), + } + survey.AskOne(prompt, &confirm) + if !confirm { + fmt.Println("The command has been cancelled") + return nil + } + + // get default create template + if template == "" { + var templateErr error + if p.options.TemplateLang == TemplateLangJS { + template, templateErr = p.jsCreateTemplate() + } else { + template, templateErr = p.goCreateTemplate() + } + if templateErr != nil { + return fmt.Errorf("Failed to resolve create template: %v\n", templateErr) + } + } + + // ensure that the migrations dir exist + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return err + } + + // save the migration file + if err := os.WriteFile(resultFilePath, []byte(template), 0644); err != nil { + return fmt.Errorf("Failed to save migration file %q: %v\n", resultFilePath, err) + } + + fmt.Printf("Successfully created file %q\n", resultFilePath) + return nil +} + +func (p *plugin) migrateCollectionsHandler(args []string) error { + createArgs := []string{"collections_snapshot"} + createArgs = append(createArgs, args...) + + collections := []*models.Collection{} + if err := p.app.Dao().CollectionQuery().OrderBy("created ASC").All(&collections); err != nil { + return fmt.Errorf("Failed to fetch migrations list: %v", err) + } + + var template string + var templateErr error + if p.options.TemplateLang == TemplateLangJS { + template, templateErr = p.jsSnapshotTemplate(collections) + } else { + template, templateErr = p.goSnapshotTemplate(collections) + } + if templateErr != nil { + return fmt.Errorf("Failed to resolve template: %v", templateErr) + } + + return p.migrateCreateHandler(template, createArgs) +} diff --git a/plugins/migratecmd/templates.go b/plugins/migratecmd/templates.go new file mode 100644 index 00000000..5e6cfea8 --- /dev/null +++ b/plugins/migratecmd/templates.go @@ -0,0 +1,112 @@ +package migratecmd + +import ( + "encoding/json" + "fmt" + "path/filepath" + + "github.com/pocketbase/pocketbase/models" +) + +const ( + TemplateLangJS = "js" + TemplateLangGo = "go" +) + +// ------------------------------------------------------------------- +// JavaScript templates +// ------------------------------------------------------------------- + +func (p *plugin) jsCreateTemplate() (string, error) { + const template = `migrate((db) => { + // add up queries... +}, (db) => { + // add down queries... +}) +` + + return template, nil +} + +func (p *plugin) jsSnapshotTemplate(collections []*models.Collection) (string, error) { + jsonData, err := json.MarshalIndent(collections, " ", " ") + if err != nil { + return "", fmt.Errorf("failed to serialize collections list: %v", err) + } + + const template = `migrate((db) => { + const snapshot = %s; + + const collections = snapshot.map((item) => unmarshal(item, new Collection())); + + return Dao(db).importCollections(collections, true, null); +}, (db) => { + return null; +}) +` + + return fmt.Sprintf(template, string(jsonData)), nil +} + +// ------------------------------------------------------------------- +// Go templates +// ------------------------------------------------------------------- + +func (p *plugin) goCreateTemplate() (string, error) { + const template = `package %s + +import ( + "github.com/pocketbase/dbx" + m "github.com/pocketbase/pocketbase/migrations" +) + +func init() { + m.Register(func(db dbx.Builder) error { + // add up queries... + + return nil + }, func(db dbx.Builder) error { + // add down queries... + + return nil + }) +} +` + + return fmt.Sprintf(template, filepath.Base(p.options.Dir)), nil +} + +func (p *plugin) goSnapshotTemplate(collections []*models.Collection) (string, error) { + jsonData, err := json.MarshalIndent(collections, "\t", "\t\t") + if err != nil { + return "", fmt.Errorf("failed to serialize collections list: %v", err) + } + + const template = `package %s + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" +) + +func init() { + m.Register(func(db dbx.Builder) error { + jsonData := ` + "`%s`" + ` + + collections := []*models.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collections); err != nil { + return err + } + + return daos.New(db).ImportCollections(collections, true, nil) + }, func(db dbx.Builder) error { + return nil + }) +} +` + return fmt.Sprintf(template, filepath.Base(p.options.Dir), string(jsonData)), nil +} diff --git a/plugins/publicdir/publicdir.go b/plugins/publicdir/publicdir.go new file mode 100644 index 00000000..115c7931 --- /dev/null +++ b/plugins/publicdir/publicdir.go @@ -0,0 +1,84 @@ +// Example +// +// publicdir.MustRegister(app, &publicdir.Options{ +// FlagsCmd: app.RootCmd, +// IndexFallback: false, +// }) +package publicdir + +import ( + "os" + "path/filepath" + "strings" + + "github.com/pocketbase/pocketbase/apis" + "github.com/pocketbase/pocketbase/core" + "github.com/spf13/cobra" +) + +type Options struct { + Dir string + IndexFallback bool + FlagsCmd *cobra.Command +} + +type plugin struct { + app core.App + options *Options +} + +func MustRegister(app core.App, options *Options) { + if err := Register(app, options); err != nil { + panic(err) + } +} + +func Register(app core.App, options *Options) error { + p := &plugin{app: app} + + if options != nil { + p.options = options + } else { + p.options = &Options{} + } + + if options.Dir == "" { + options.Dir = defaultPublicDir() + } + + if options.FlagsCmd != nil { + // add "--publicDir" option flag + options.FlagsCmd.PersistentFlags().StringVar( + &options.Dir, + "publicDir", + options.Dir, + "the directory to serve static files", + ) + + // add "--indexFallback" option flag + options.FlagsCmd.PersistentFlags().BoolVar( + &options.IndexFallback, + "indexFallback", + options.IndexFallback, + "fallback the request to index.html on missing static path (eg. when pretty urls are used with SPA)", + ) + } + + p.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + // serves static files from the provided public dir (if exists) + e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS(options.Dir), options.IndexFallback)) + + return nil + }) + + return nil +} + +func defaultPublicDir() string { + if strings.HasPrefix(os.Args[0], os.TempDir()) { + // most likely ran with go run + return "./pb_public" + } + + return filepath.Join(os.Args[0], "../pb_public") +} diff --git a/pocketbase.go b/pocketbase.go index 6043ec0f..196ca7f7 100644 --- a/pocketbase.go +++ b/pocketbase.go @@ -127,7 +127,6 @@ func NewWithConfig(config Config) *PocketBase { func (pb *PocketBase) Start() error { // register system commands pb.RootCmd.AddCommand(cmd.NewServeCommand(pb, !pb.hideStartBanner)) - pb.RootCmd.AddCommand(cmd.NewMigrateCommand(pb)) pb.RootCmd.AddCommand(cmd.NewTempUpgradeCommand(pb)) return pb.Execute() diff --git a/tools/filesystem/filesystem_test.go b/tools/filesystem/filesystem_test.go index 69c27d05..3565437b 100644 --- a/tools/filesystem/filesystem_test.go +++ b/tools/filesystem/filesystem_test.go @@ -357,19 +357,19 @@ func createTestDir(t *testing.T) string { t.Fatal(err) } - file1, err := os.OpenFile(filepath.Join(dir, "test/sub1.txt"), os.O_WRONLY|os.O_CREATE, 0666) + file1, err := os.OpenFile(filepath.Join(dir, "test/sub1.txt"), os.O_WRONLY|os.O_CREATE, 0644) if err != nil { t.Fatal(err) } file1.Close() - file2, err := os.OpenFile(filepath.Join(dir, "test/sub2.txt"), os.O_WRONLY|os.O_CREATE, 0666) + file2, err := os.OpenFile(filepath.Join(dir, "test/sub2.txt"), os.O_WRONLY|os.O_CREATE, 0644) if err != nil { t.Fatal(err) } file2.Close() - file3, err := os.OpenFile(filepath.Join(dir, "image.png"), os.O_WRONLY|os.O_CREATE, 0666) + file3, err := os.OpenFile(filepath.Join(dir, "image.png"), os.O_WRONLY|os.O_CREATE, 0644) if err != nil { t.Fatal(err) } @@ -377,18 +377,18 @@ func createTestDir(t *testing.T) string { imgRect := image.Rect(0, 0, 1, 1) png.Encode(file3, imgRect) file3.Close() - err2 := os.WriteFile(filepath.Join(dir, "image.png.attrs"), []byte(`{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null}`), 0666) + err2 := os.WriteFile(filepath.Join(dir, "image.png.attrs"), []byte(`{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null}`), 0644) if err2 != nil { t.Fatal(err2) } - file4, err := os.OpenFile(filepath.Join(dir, "image.svg"), os.O_WRONLY|os.O_CREATE, 0666) + file4, err := os.OpenFile(filepath.Join(dir, "image.svg"), os.O_WRONLY|os.O_CREATE, 0644) if err != nil { t.Fatal(err) } file4.Close() - file5, err := os.OpenFile(filepath.Join(dir, "style.css"), os.O_WRONLY|os.O_CREATE, 0666) + file5, err := os.OpenFile(filepath.Join(dir, "style.css"), os.O_WRONLY|os.O_CREATE, 0644) if err != nil { t.Fatal(err) } diff --git a/tools/migrate/list.go b/tools/migrate/list.go index 858c13d7..65d24992 100644 --- a/tools/migrate/list.go +++ b/tools/migrate/list.go @@ -8,24 +8,24 @@ import ( "github.com/pocketbase/dbx" ) -type migration struct { - file string - up func(db dbx.Builder) error - down func(db dbx.Builder) error +type Migration struct { + File string + Up func(db dbx.Builder) error + Down func(db dbx.Builder) error } // MigrationsList defines a list with migration definitions type MigrationsList struct { - list []*migration + list []*Migration } // Item returns a single migration from the list by its index. -func (l *MigrationsList) Item(index int) *migration { +func (l *MigrationsList) Item(index int) *Migration { return l.list[index] } // Items returns the internal migrations list slice. -func (l *MigrationsList) Items() []*migration { +func (l *MigrationsList) Items() []*Migration { return l.list } @@ -47,13 +47,13 @@ func (l *MigrationsList) Register( file = filepath.Base(path) } - l.list = append(l.list, &migration{ - file: file, - up: up, - down: down, + l.list = append(l.list, &Migration{ + File: file, + Up: up, + Down: down, }) sort.Slice(l.list, func(i int, j int) bool { - return l.list[i].file < l.list[j].file + return l.list[i].File < l.list[j].File }) } diff --git a/tools/migrate/list_test.go b/tools/migrate/list_test.go index 4e96e4ee..5030e882 100644 --- a/tools/migrate/list_test.go +++ b/tools/migrate/list_test.go @@ -26,8 +26,8 @@ func TestMigrationsList(t *testing.T) { for i, name := range expected { item := l.Item(i) - if item.file != name { - t.Fatalf("Expected name %s for index %d, got %s", name, i, item.file) + if item.File != name { + t.Fatalf("Expected name %s for index %d, got %s", name, i, item.File) } } } diff --git a/tools/migrate/runner.go b/tools/migrate/runner.go index 57f30c0e..170c3dac 100644 --- a/tools/migrate/runner.go +++ b/tools/migrate/runner.go @@ -111,19 +111,19 @@ func (r *Runner) Up() ([]string, error) { err := r.db.Transactional(func(tx *dbx.Tx) error { for _, m := range r.migrationsList.Items() { // skip applied - if r.isMigrationApplied(tx, m.file) { + if r.isMigrationApplied(tx, m.File) { continue } - if err := m.up(tx); err != nil { - return fmt.Errorf("Failed to apply migration %s: %w", m.file, err) + if err := m.Up(tx); err != nil { + return fmt.Errorf("Failed to apply migration %s: %w", m.File, err) } - if err := r.saveAppliedMigration(tx, m.file); err != nil { - return fmt.Errorf("Failed to save applied migration info for %s: %w", m.file, err) + if err := r.saveAppliedMigration(tx, m.File); err != nil { + return fmt.Errorf("Failed to save applied migration info for %s: %w", m.File, err) } - applied = append(applied, m.file) + applied = append(applied, m.File) } return nil @@ -146,7 +146,7 @@ func (r *Runner) Down(toRevertCount int) ([]string, error) { m := r.migrationsList.Item(i) // skip unapplied - if !r.isMigrationApplied(tx, m.file) { + if !r.isMigrationApplied(tx, m.File) { continue } @@ -155,15 +155,15 @@ func (r *Runner) Down(toRevertCount int) ([]string, error) { break } - if err := m.down(tx); err != nil { - return fmt.Errorf("Failed to revert migration %s: %w", m.file, err) + if err := m.Down(tx); err != nil { + return fmt.Errorf("Failed to revert migration %s: %w", m.File, err) } - if err := r.saveRevertedMigration(tx, m.file); err != nil { - return fmt.Errorf("Failed to save reverted migration info for %s: %w", m.file, err) + if err := r.saveRevertedMigration(tx, m.File); err != nil { + return fmt.Errorf("Failed to save reverted migration info for %s: %w", m.File, err) } - reverted = append(reverted, m.file) + reverted = append(reverted, m.File) } return nil diff --git a/tools/migrate/runner_test.go b/tools/migrate/runner_test.go index 74091a5b..bd579ab0 100644 --- a/tools/migrate/runner_test.go +++ b/tools/migrate/runner_test.go @@ -79,7 +79,7 @@ func TestRunnerUpAndDown(t *testing.T) { } // simulate partially run migration - r.saveAppliedMigration(testDB, r.migrationsList.Item(0).file) + r.saveAppliedMigration(testDB, r.migrationsList.Item(0).File) // Up() // --- diff --git a/ui/.env b/ui/.env index 90c4c9ba..3acad62a 100644 --- a/ui/.env +++ b/ui/.env @@ -7,4 +7,4 @@ PB_FILE_UPLOAD_DOCS = "https://pocketbase.io/docs/files-handling/" 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.8.0" +PB_VERSION = "v0.9.0-rc"