diff --git a/cmd/seed.go b/cmd/seed.go index 760a9424d..c36b70741 100644 --- a/cmd/seed.go +++ b/cmd/seed.go @@ -4,6 +4,7 @@ import ( "os" "os/signal" + "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/supabase/cli/internal/seed/buckets" "github.com/supabase/cli/internal/utils" @@ -27,7 +28,7 @@ var ( Short: "Seed buckets declared in [storage.buckets]", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - return buckets.Run(cmd.Context(), flags.ProjectRef, utils.NewConsole()) + return buckets.Run(cmd.Context(), flags.ProjectRef, true, afero.NewOsFs()) }, } ) diff --git a/docs/main.go b/docs/main.go index b791dedcf..bfacba311 100644 --- a/docs/main.go +++ b/docs/main.go @@ -185,7 +185,7 @@ func GenYamlDoc(cmd *cobra.Command, root *SpecDoc) CmdDoc { Subcommands: subcommands, } - names := strings.Split(cmd.CommandPath(), " ") + names := strings.Fields(cmd.CommandPath()) if len(names) > 3 { base := strings.Join(names[2:], "-") names = append(names[:2], base) diff --git a/go.mod b/go.mod index df5e501f0..c654a19d1 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/go-xmlfmt/xmlfmt v1.1.2 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golangci/golangci-lint v1.59.1 + github.com/google/go-cmp v0.6.0 github.com/google/go-github/v62 v62.0.0 github.com/google/go-querystring v1.1.0 github.com/google/uuid v1.6.0 @@ -48,7 +49,7 @@ require ( github.com/stripe/pg-schema-diff v0.7.0 github.com/withfig/autocomplete-tools/packages/cobra v1.2.0 github.com/zalando/go-keyring v0.2.5 - golang.org/x/mod v0.19.0 + golang.org/x/mod v0.20.0 golang.org/x/oauth2 v0.21.0 golang.org/x/term v0.22.0 google.golang.org/grpc v1.65.0 @@ -168,7 +169,6 @@ require ( github.com/golangci/plugin-module-register v0.1.1 // indirect github.com/golangci/revgrep v0.5.3 // indirect github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gordonklaus/ineffassign v0.1.0 // indirect github.com/gorilla/css v1.0.0 // indirect diff --git a/go.sum b/go.sum index 9dd3bac96..ca3d61989 100644 --- a/go.sum +++ b/go.sum @@ -1146,8 +1146,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go index cb8568996..599365ece 100644 --- a/internal/db/reset/reset.go +++ b/internal/db/reset/reset.go @@ -8,6 +8,7 @@ import ( "os" "strconv" "strings" + "time" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" @@ -21,6 +22,7 @@ import ( "github.com/supabase/cli/internal/gen/keys" "github.com/supabase/cli/internal/migration/apply" "github.com/supabase/cli/internal/migration/repair" + "github.com/supabase/cli/internal/seed/buckets" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/migration" ) @@ -43,17 +45,21 @@ func Run(ctx context.Context, version string, config pgconn.Config, fsys afero.F } return resetRemote(ctx, version, config, fsys, options...) } - // Config file is loaded before parsing --linked or --local flags if err := utils.AssertSupabaseDbIsRunning(); err != nil { return err } - // Reset postgres database because extensions (pg_cron, pg_net) require postgres if err := resetDatabase(ctx, version, fsys, options...); err != nil { return err } - + // Seed objects from supabase/buckets directory + if err := start.WaitForHealthyService(ctx, 30*time.Second, utils.StorageId); err != nil { + return err + } + if err := buckets.Run(ctx, "", false, fsys); err != nil { + return err + } branch := keys.GetGitBranch(fsys) fmt.Fprintln(os.Stderr, "Finished "+utils.Aqua("supabase db reset")+" on branch "+utils.Aqua(branch)+".") return nil diff --git a/internal/link/diff.go b/internal/link/diff.go new file mode 100644 index 000000000..84f2e3494 --- /dev/null +++ b/internal/link/diff.go @@ -0,0 +1,261 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package link + +import ( + "bytes" + "fmt" + "sort" + "strings" +) + +// A pair is a pair of values tracked for both the x and y side of a diff. +// It is typically a pair of line indexes. +type pair struct{ x, y int } + +// Diff returns an anchored diff of the two texts old and new +// in the “unified diff” format. If old and new are identical, +// Diff returns a nil slice (no output). +// +// Unix diff implementations typically look for a diff with +// the smallest number of lines inserted and removed, +// which can in the worst case take time quadratic in the +// number of lines in the texts. As a result, many implementations +// either can be made to run for a long time or cut off the search +// after a predetermined amount of work. +// +// In contrast, this implementation looks for a diff with the +// smallest number of “unique” lines inserted and removed, +// where unique means a line that appears just once in both old and new. +// We call this an “anchored diff” because the unique lines anchor +// the chosen matching regions. An anchored diff is usually clearer +// than a standard diff, because the algorithm does not try to +// reuse unrelated blank lines or closing braces. +// The algorithm also guarantees to run in O(n log n) time +// instead of the standard O(n²) time. +// +// Some systems call this approach a “patience diff,” named for +// the “patience sorting” algorithm, itself named for a solitaire card game. +// We avoid that name for two reasons. First, the name has been used +// for a few different variants of the algorithm, so it is imprecise. +// Second, the name is frequently interpreted as meaning that you have +// to wait longer (to be patient) for the diff, meaning that it is a slower algorithm, +// when in fact the algorithm is faster than the standard one. +func Diff(oldName string, old []byte, newName string, new []byte) []byte { + if bytes.Equal(old, new) { + return nil + } + x := lines(old) + y := lines(new) + + // Print diff header. + var out bytes.Buffer + fmt.Fprintf(&out, "diff %s %s\n", oldName, newName) + fmt.Fprintf(&out, "--- %s\n", oldName) + fmt.Fprintf(&out, "+++ %s\n", newName) + + // Loop over matches to consider, + // expanding each match to include surrounding lines, + // and then printing diff chunks. + // To avoid setup/teardown cases outside the loop, + // tgs returns a leading {0,0} and trailing {len(x), len(y)} pair + // in the sequence of matches. + var ( + done pair // printed up to x[:done.x] and y[:done.y] + chunk pair // start lines of current chunk + count pair // number of lines from each side in current chunk + ctext []string // lines for current chunk + ) + for _, m := range tgs(x, y) { + if m.x < done.x { + // Already handled scanning forward from earlier match. + continue + } + + // Expand matching lines as far as possible, + // establishing that x[start.x:end.x] == y[start.y:end.y]. + // Note that on the first (or last) iteration we may (or definitely do) + // have an empty match: start.x==end.x and start.y==end.y. + start := m + for start.x > done.x && start.y > done.y && x[start.x-1] == y[start.y-1] { + start.x-- + start.y-- + } + end := m + for end.x < len(x) && end.y < len(y) && x[end.x] == y[end.y] { + end.x++ + end.y++ + } + + // Emit the mismatched lines before start into this chunk. + // (No effect on first sentinel iteration, when start = {0,0}.) + for _, s := range x[done.x:start.x] { + ctext = append(ctext, "-"+s) + count.x++ + } + for _, s := range y[done.y:start.y] { + ctext = append(ctext, "+"+s) + count.y++ + } + + // If we're not at EOF and have too few common lines, + // the chunk includes all the common lines and continues. + const C = 3 // number of context lines + if (end.x < len(x) || end.y < len(y)) && + (end.x-start.x < C || (len(ctext) > 0 && end.x-start.x < 2*C)) { + for _, s := range x[start.x:end.x] { + ctext = append(ctext, " "+s) + count.x++ + count.y++ + } + done = end + continue + } + + // End chunk with common lines for context. + if len(ctext) > 0 { + n := end.x - start.x + if n > C { + n = C + } + for _, s := range x[start.x : start.x+n] { + ctext = append(ctext, " "+s) + count.x++ + count.y++ + } + done = pair{start.x + n, start.y + n} + + // Format and emit chunk. + // Convert line numbers to 1-indexed. + // Special case: empty file shows up as 0,0 not 1,0. + if count.x > 0 { + chunk.x++ + } + if count.y > 0 { + chunk.y++ + } + fmt.Fprintf(&out, "@@ -%d,%d +%d,%d @@\n", chunk.x, count.x, chunk.y, count.y) + for _, s := range ctext { + out.WriteString(s) + } + count.x = 0 + count.y = 0 + ctext = ctext[:0] + } + + // If we reached EOF, we're done. + if end.x >= len(x) && end.y >= len(y) { + break + } + + // Otherwise start a new chunk. + chunk = pair{end.x - C, end.y - C} + for _, s := range x[chunk.x:end.x] { + ctext = append(ctext, " "+s) + count.x++ + count.y++ + } + done = end + } + + return out.Bytes() +} + +// lines returns the lines in the file x, including newlines. +// If the file does not end in a newline, one is supplied +// along with a warning about the missing newline. +func lines(x []byte) []string { + l := strings.SplitAfter(string(x), "\n") + if l[len(l)-1] == "" { + l = l[:len(l)-1] + } else { + // Treat last line as having a message about the missing newline attached, + // using the same text as BSD/GNU diff (including the leading backslash). + l[len(l)-1] += "\n\\ No newline at end of file\n" + } + return l +} + +// tgs returns the pairs of indexes of the longest common subsequence +// of unique lines in x and y, where a unique line is one that appears +// once in x and once in y. +// +// The longest common subsequence algorithm is as described in +// Thomas G. Szymanski, “A Special Case of the Maximal Common +// Subsequence Problem,” Princeton TR #170 (January 1975), +// available at https://research.swtch.com/tgs170.pdf. +func tgs(x, y []string) []pair { + // Count the number of times each string appears in a and b. + // We only care about 0, 1, many, counted as 0, -1, -2 + // for the x side and 0, -4, -8 for the y side. + // Using negative numbers now lets us distinguish positive line numbers later. + m := make(map[string]int) + for _, s := range x { + if c := m[s]; c > -2 { + m[s] = c - 1 + } + } + for _, s := range y { + if c := m[s]; c > -8 { + m[s] = c - 4 + } + } + + // Now unique strings can be identified by m[s] = -1+-4. + // + // Gather the indexes of those strings in x and y, building: + // xi[i] = increasing indexes of unique strings in x. + // yi[i] = increasing indexes of unique strings in y. + // inv[i] = index j such that x[xi[i]] = y[yi[j]]. + var xi, yi, inv []int + for i, s := range y { + if m[s] == -1+-4 { + m[s] = len(yi) + yi = append(yi, i) + } + } + for i, s := range x { + if j, ok := m[s]; ok && j >= 0 { + xi = append(xi, i) + inv = append(inv, j) + } + } + + // Apply Algorithm A from Szymanski's paper. + // In those terms, A = J = inv and B = [0, n). + // We add sentinel pairs {0,0}, and {len(x),len(y)} + // to the returned sequence, to help the processing loop. + J := inv + n := len(xi) + T := make([]int, n) + L := make([]int, n) + for i := range T { + T[i] = n + 1 + } + for i := 0; i < n; i++ { + k := sort.Search(n, func(k int) bool { + return T[k] >= J[i] + }) + T[k] = J[i] + L[i] = k + 1 + } + k := 0 + for _, v := range L { + if k < v { + k = v + } + } + seq := make([]pair, 2+k) + seq[1+k] = pair{len(x), len(y)} // sentinel at end + lastj := n + for i := n - 1; i >= 0; i-- { + if L[i] == k && J[i] < lastj { + seq[k] = pair{xi[i], yi[J[i]]} + k-- + } + } + seq[0] = pair{0, 0} // sentinel at start + return seq +} diff --git a/internal/link/link.go b/internal/link/link.go index 172ea09f7..9113f5434 100644 --- a/internal/link/link.go +++ b/internal/link/link.go @@ -11,7 +11,6 @@ import ( "github.com/BurntSushi/toml" "github.com/go-errors/errors" - "github.com/google/go-cmp/cmp" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -26,7 +25,7 @@ import ( ) func Run(ctx context.Context, projectRef string, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { - original := toTomlLines(map[string]interface{}{ + original := toTomlBytes(map[string]interface{}{ "api": utils.Config.Api, "db": utils.Config.Db, }) @@ -56,25 +55,26 @@ func Run(ctx context.Context, projectRef string, fsys afero.Fs, options ...func( fmt.Fprintln(os.Stdout, "Finished "+utils.Aqua("supabase link")+".") // 4. Suggest config update - updated := toTomlLines(map[string]interface{}{ + updated := toTomlBytes(map[string]interface{}{ "api": utils.Config.Api, "db": utils.Config.Db, }) - if lineDiff := cmp.Diff(original, updated); len(lineDiff) > 0 { + // if lineDiff := cmp.Diff(original, updated); len(lineDiff) > 0 { + if lineDiff := Diff(utils.ConfigPath, original, projectRef, updated); len(lineDiff) > 0 { fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "Local config differs from linked project. Try updating", utils.Bold(utils.ConfigPath)) - fmt.Println(lineDiff) + fmt.Println(string(lineDiff)) } return nil } -func toTomlLines(config any) []string { +func toTomlBytes(config any) []byte { var buf bytes.Buffer enc := toml.NewEncoder(&buf) enc.Indent = "" if err := enc.Encode(config); err != nil { fmt.Fprintln(utils.GetDebugLogger(), "failed to marshal toml config:", err) } - return strings.Split(buf.String(), "\n") + return buf.Bytes() } func LinkServices(ctx context.Context, projectRef, anonKey string, fsys afero.Fs) { diff --git a/internal/seed/buckets/buckets.go b/internal/seed/buckets/buckets.go index 2801405af..55ec4ee65 100644 --- a/internal/seed/buckets/buckets.go +++ b/internal/seed/buckets/buckets.go @@ -3,18 +3,22 @@ package buckets import ( "context" "fmt" + "path/filepath" + "github.com/spf13/afero" "github.com/supabase/cli/internal/storage/client" + "github.com/supabase/cli/internal/storage/cp" "github.com/supabase/cli/internal/utils" ) -func Run(ctx context.Context, projectRef string, console *utils.Console) error { +func Run(ctx context.Context, projectRef string, interactive bool, fsys afero.Fs) error { api, err := client.NewStorageAPI(ctx, projectRef) if err != nil { return err } - if console == nil { - return api.UpsertBuckets(ctx, utils.Config.Storage.Buckets) + console := utils.NewConsole() + if !interactive { + console.IsTTY = false } filter := func(bucketId string) bool { label := fmt.Sprintf("Bucket %s already exists. Do you want to overwrite its properties?", utils.Bold(bucketId)) @@ -24,5 +28,14 @@ func Run(ctx context.Context, projectRef string, console *utils.Console) error { } return shouldOverwrite } - return api.UpsertBuckets(ctx, utils.Config.Storage.Buckets, filter) + if err := api.UpsertBuckets(ctx, utils.Config.Storage.Buckets, filter); err != nil { + return err + } + for _, bucket := range utils.Config.Storage.Buckets { + localPath := filepath.Join(utils.SupabaseDirPath, bucket.ObjectsPath) + if err := cp.UploadStorageObjectAll(ctx, api, "", localPath, 5, fsys); err != nil { + return err + } + } + return nil } diff --git a/internal/seed/buckets/buckets_test.go b/internal/seed/buckets/buckets_test.go index 1d0e5f5e9..e14a40e74 100644 --- a/internal/seed/buckets/buckets_test.go +++ b/internal/seed/buckets/buckets_test.go @@ -3,10 +3,12 @@ package buckets import ( "context" "net/http" + "path/filepath" "testing" "github.com/BurntSushi/toml" "github.com/h2non/gock" + "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/supabase/cli/internal/testing/apitest" @@ -23,6 +25,10 @@ public = true [private] public = false` require.NoError(t, toml.Unmarshal([]byte(config), &utils.Config.Storage.Buckets)) + // Setup in-memory fs + fsys := afero.NewMemMapFs() + bucketPath := filepath.Join(utils.SupabaseDirPath, "images") + require.NoError(t, fsys.Mkdir(bucketPath, 0755)) // Setup mock api gock.New(utils.Config.Api.ExternalUrl). Get("/storage/v1/bucket"). @@ -40,7 +46,7 @@ public = false` Reply(http.StatusOK). JSON(storage.CreateBucketResponse{Name: "private"}) // Run test - err := Run(context.Background(), "", utils.NewConsole()) + err := Run(context.Background(), "", false, fsys) // Check error assert.NoError(t, err) assert.Empty(t, apitest.ListUnmatchedRequests()) @@ -53,7 +59,7 @@ public = false` Reply(http.StatusOK). JSON([]storage.BucketResponse{}) // Run test - err := Run(context.Background(), "", nil) + err := Run(context.Background(), "", false, afero.NewMemMapFs()) // Check error assert.NoError(t, err) assert.Empty(t, apitest.ListUnmatchedRequests()) diff --git a/internal/start/start.go b/internal/start/start.go index 4d4a50b4c..014e70883 100644 --- a/internal/start/start.go +++ b/internal/start/start.go @@ -1075,7 +1075,7 @@ EOF return err } // Disable prompts when seeding - if err := buckets.Run(ctx, "", nil); err != nil { + if err := buckets.Run(ctx, "", false, fsys); err != nil { return err } } diff --git a/internal/storage/cp/cp.go b/internal/storage/cp/cp.go index 9719a7262..b41c58b38 100644 --- a/internal/storage/cp/cp.go +++ b/internal/storage/cp/cp.go @@ -94,16 +94,19 @@ func UploadStorageObjectAll(ctx context.Context, api storage.StorageAPI, remoteP // Check if directory exists on remote dirExists := false fileExists := false - if err := ls.IterateStoragePaths(ctx, api, noSlash, func(objectName string) error { - if objectName == path.Base(noSlash) { - fileExists = true + if len(noSlash) > 0 { + callback := func(objectName string) error { + if objectName == path.Base(noSlash) { + fileExists = true + } + if objectName == path.Base(noSlash)+"/" { + dirExists = true + } + return nil } - if objectName == path.Base(noSlash)+"/" { - dirExists = true + if err := ls.IterateStoragePaths(ctx, api, noSlash, callback); err != nil { + return err } - return nil - }); err != nil { - return err } baseName := filepath.Base(localPath) jq := utils.NewJobQueue(maxJobs) diff --git a/internal/storage/cp/cp_test.go b/internal/storage/cp/cp_test.go index a310a3512..fe988c21c 100644 --- a/internal/storage/cp/cp_test.go +++ b/internal/storage/cp/cp_test.go @@ -311,7 +311,7 @@ func TestUploadAll(t *testing.T) { Get("/storage/v1/bucket"). Reply(http.StatusServiceUnavailable) // Run test - err := UploadStorageObjectAll(context.Background(), mockApi, "", ".", 1, fsys) + err := UploadStorageObjectAll(context.Background(), mockApi, "missing", ".", 1, fsys) // Check error assert.ErrorContains(t, err, "Error status 503:") assert.Empty(t, apitest.ListUnmatchedRequests()) diff --git a/internal/utils/api.go b/internal/utils/api.go index 90e6a2610..3dc63d30d 100644 --- a/internal/utils/api.go +++ b/internal/utils/api.go @@ -264,7 +264,7 @@ func GetSupabaseDashboardURL() string { case DefaultApiHost, DeprecatedApiHost: return "https://supabase.com/dashboard" case "https://api.supabase.green": - return "https://app.supabase.green" + return "https://supabase.green/dashboard" default: return "http://127.0.0.1:8082" } diff --git a/internal/utils/flags/db_url.go b/internal/utils/flags/db_url.go index 629e0332a..c183aa1ad 100644 --- a/internal/utils/flags/db_url.go +++ b/internal/utils/flags/db_url.go @@ -107,6 +107,8 @@ func getPassword(projectRef string) string { if password, err := credentials.Get(projectRef); err == nil { return password } + resetUrl := fmt.Sprintf("%s/project/%s/settings/database", utils.GetSupabaseDashboardURL(), projectRef) + fmt.Fprintln(os.Stderr, "Forgot your password? Reset it from the Dashboard:", utils.Bold(resetUrl)) fmt.Fprint(os.Stderr, "Enter your database password: ") return credentials.PromptMasked(os.Stdin) } diff --git a/internal/utils/tenant/postgrest.go b/internal/utils/tenant/postgrest.go index 3872dffef..cb8c96d28 100644 --- a/internal/utils/tenant/postgrest.go +++ b/internal/utils/tenant/postgrest.go @@ -34,6 +34,6 @@ func (t *TenantAPI) GetPostgrestVersion(ctx context.Context) (string, error) { if len(data.Info.Version) == 0 { return "", errors.New(errPostgrestVersion) } - parts := strings.Split(data.Info.Version, " ") + parts := strings.Fields(data.Info.Version) return "v" + parts[0], nil } diff --git a/pkg/config/config.go b/pkg/config/config.go index 3877f32f6..cb52dce63 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -211,6 +211,7 @@ type ( Public *bool `toml:"public"` FileSizeLimit sizeInBytes `toml:"file_size_limit"` AllowedMimeTypes []string `toml:"allowed_mime_types"` + ObjectsPath string `toml:"objects_path"` } imageTransformation struct { diff --git a/pkg/config/constants.go b/pkg/config/constants.go index f81b3b409..f1be3f2bc 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -12,11 +12,11 @@ const ( pgmetaImage = "supabase/postgres-meta:v0.83.2" studioImage = "supabase/studio:20240729-ce42139" imageProxyImage = "darthsim/imgproxy:v3.8.0" - edgeRuntimeImage = "supabase/edge-runtime:v1.55.2" + edgeRuntimeImage = "supabase/edge-runtime:v1.56.0" vectorImage = "timberio/vector:0.28.1-alpine" supavisorImage = "supabase/supavisor:1.1.56" gotrueImage = "supabase/gotrue:v2.158.1" - realtimeImage = "supabase/realtime:v2.29.15" + realtimeImage = "supabase/realtime:v2.30.23" storageImage = "supabase/storage-api:v1.0.6" logflareImage = "supabase/logflare:1.4.0" // Append to JobImages when adding new dependencies below diff --git a/pkg/config/templates/config.toml b/pkg/config/templates/config.toml index e9545a6da..573982798 100644 --- a/pkg/config/templates/config.toml +++ b/pkg/config/templates/config.toml @@ -78,6 +78,7 @@ enabled = true # public = false # file_size_limit = "50MiB" # allowed_mime_types = ["image/png", "image/jpeg"] +# objects_path = "./images" [auth] enabled = true diff --git a/pkg/config/testdata/config.toml b/pkg/config/testdata/config.toml index 02d8c37bd..b08879b72 100644 --- a/pkg/config/testdata/config.toml +++ b/pkg/config/testdata/config.toml @@ -78,6 +78,7 @@ enabled = false public = false file_size_limit = "50MiB" allowed_mime_types = ["image/png", "image/jpeg"] +objects_path = "./images" [auth] enabled = true