@@ -10,14 +10,14 @@ import (
1010 "net/http"
1111 "net/url"
1212 "os"
13- "reflect"
14- "strings"
1513 "sync"
1614 "time"
1715
1816 "github.com/docker/docker/api/types"
1917 "github.com/docker/docker/api/types/container"
2018 "github.com/go-errors/errors"
19+ "github.com/olekukonko/tablewriter"
20+ "github.com/olekukonko/tablewriter/tw"
2121 "github.com/spf13/afero"
2222 "github.com/supabase/cli/internal/utils"
2323 "github.com/supabase/cli/internal/utils/flags"
@@ -26,9 +26,11 @@ import (
2626
2727type CustomName struct {
2828 ApiURL string `env:"api.url,default=API_URL"`
29+ RestURL string `env:"api.rest_url,default=REST_URL"`
2930 GraphqlURL string `env:"api.graphql_url,default=GRAPHQL_URL"`
3031 StorageS3URL string `env:"api.storage_s3_url,default=STORAGE_S3_URL"`
3132 McpURL string `env:"api.mcp_url,default=MCP_URL"`
33+ FunctionsURL string `env:"api.functions_url,default=FUNCTIONS_URL"`
3234 DbURL string `env:"db.url,default=DB_URL"`
3335 StudioURL string `env:"studio.url,default=STUDIO_URL"`
3436 InbucketURL string `env:"inbucket.url,default=INBUCKET_URL,deprecated"`
@@ -42,6 +44,24 @@ type CustomName struct {
4244 StorageS3SecretAccessKey string `env:"storage.s3_secret_access_key,default=S3_PROTOCOL_ACCESS_KEY_SECRET"`
4345 StorageS3Region string `env:"storage.s3_region,default=S3_PROTOCOL_REGION"`
4446}
47+ type OutputType string
48+
49+ const (
50+ Text OutputType = "text"
51+ Link OutputType = "link"
52+ Key OutputType = "key"
53+ )
54+
55+ type OutputItem struct {
56+ Label string
57+ Value string
58+ Type OutputType
59+ }
60+
61+ type OutputGroup struct {
62+ Name string
63+ Items []OutputItem
64+ }
4565
4666func (c * CustomName ) toValues (exclude ... string ) map [string ]string {
4767 values := map [string ]string {
@@ -56,7 +76,9 @@ func (c *CustomName) toValues(exclude ...string) map[string]string {
5676
5777 if apiEnabled {
5878 values [c .ApiURL ] = utils .Config .Api .ExternalUrl
79+ values [c .RestURL ] = utils .GetApiUrl ("/rest/v1" )
5980 values [c .GraphqlURL ] = utils .GetApiUrl ("/graphql/v1" )
81+ values [c .FunctionsURL ] = utils .GetApiUrl ("/functions/v1" )
6082 if studioEnabled {
6183 values [c .McpURL ] = utils .GetApiUrl ("/mcp" )
6284 }
@@ -210,43 +232,149 @@ func printStatus(names CustomName, format string, w io.Writer, exclude ...string
210232
211233func PrettyPrint (w io.Writer , exclude ... string ) {
212234 names := CustomName {
213- ApiURL : " " + utils .Aqua ("API URL" ),
214- GraphqlURL : " " + utils .Aqua ("GraphQL URL" ),
215- StorageS3URL : " " + utils .Aqua ("S3 Storage URL" ),
216- McpURL : " " + utils .Aqua ("MCP URL" ),
217- DbURL : " " + utils .Aqua ("Database URL" ),
218- StudioURL : " " + utils .Aqua ("Studio URL" ),
219- InbucketURL : " " + utils .Aqua ("Inbucket URL" ),
220- MailpitURL : " " + utils .Aqua ("Mailpit URL" ),
221- PublishableKey : " " + utils .Aqua ("Publishable key" ),
222- SecretKey : " " + utils .Aqua ("Secret key" ),
223- JWTSecret : " " + utils .Aqua ("JWT secret" ),
224- AnonKey : " " + utils .Aqua ("anon key" ),
225- ServiceRoleKey : "" + utils .Aqua ("service_role key" ),
226- StorageS3AccessKeyId : " " + utils .Aqua ("S3 Access Key" ),
227- StorageS3SecretAccessKey : " " + utils .Aqua ("S3 Secret Key" ),
228- StorageS3Region : " " + utils .Aqua ("S3 Region" ),
235+ ApiURL : "API_URL" ,
236+ RestURL : "REST_URL" ,
237+ GraphqlURL : "GRAPHQL_URL" ,
238+ FunctionsURL : "FUNCTIONS_URL" ,
239+ StorageS3URL : "STORAGE_S3_URL" ,
240+ McpURL : "MCP_URL" ,
241+ DbURL : "DB_URL" ,
242+ StudioURL : "STUDIO_URL" ,
243+ InbucketURL : "INBUCKET_URL" ,
244+ MailpitURL : "MAILPIT_URL" ,
245+ PublishableKey : "PUBLISHABLE_KEY" ,
246+ SecretKey : "SECRET_KEY" ,
247+ JWTSecret : "JWT_SECRET" ,
248+ AnonKey : "ANON_KEY" ,
249+ ServiceRoleKey : "SERVICE_ROLE_KEY" ,
250+ StorageS3AccessKeyId : "S3_PROTOCOL_ACCESS_KEY_ID" ,
251+ StorageS3SecretAccessKey : "S3_PROTOCOL_SECRET_ACCESS_KEY" ,
252+ StorageS3Region : "S3_PROTOCOL_REGION" ,
229253 }
230254 values := names .toValues (exclude ... )
231- // Iterate through map in order of declared struct fields
232- t := reflect .TypeOf (names )
233- val := reflect .ValueOf (names )
234- for i := 0 ; i < val .NumField (); i ++ {
235- k := val .Field (i ).String ()
236- if tag := t .Field (i ).Tag .Get ("env" ); isDeprecated (tag ) {
237- continue
255+
256+ groups := []OutputGroup {
257+ {
258+ Name : "🛠️ Development Tools" ,
259+ Items : []OutputItem {
260+ {Label : "Studio" , Value : values [names .StudioURL ], Type : Link },
261+ {Label : "Mailpit" , Value : values [names .MailpitURL ], Type : Link },
262+ {Label : "MCP" , Value : values [names .McpURL ], Type : Link },
263+ },
264+ },
265+ {
266+ Name : "🌐 APIs" ,
267+ Items : []OutputItem {
268+ {Label : "Project URL" , Value : values [names .ApiURL ], Type : Link },
269+ {Label : "REST" , Value : values [names .RestURL ], Type : Link },
270+ {Label : "GraphQL" , Value : values [names .GraphqlURL ], Type : Link },
271+ {Label : "Edge Functions" , Value : values [names .FunctionsURL ], Type : Link },
272+ },
273+ },
274+ {
275+ Name : "🗄️ Database" ,
276+ Items : []OutputItem {
277+ {Label : "URL" , Value : values [names .DbURL ], Type : Link },
278+ },
279+ },
280+ {
281+ Name : "🔑 Authentication Keys" ,
282+ Items : []OutputItem {
283+ {Label : "Publishable" , Value : values [names .PublishableKey ], Type : Key },
284+ {Label : "Secret" , Value : values [names .SecretKey ], Type : Key },
285+ },
286+ },
287+ {
288+ Name : "📦 Storage (S3)" ,
289+ Items : []OutputItem {
290+ {Label : "URL" , Value : values [names .StorageS3URL ], Type : Link },
291+ {Label : "Access Key" , Value : values [names .StorageS3AccessKeyId ], Type : Key },
292+ {Label : "Secret Key" , Value : values [names .StorageS3SecretAccessKey ], Type : Key },
293+ {Label : "Region" , Value : values [names .StorageS3Region ], Type : Text },
294+ },
295+ },
296+ }
297+
298+ for _ , group := range groups {
299+ // ensure at least one item in the group is non-empty
300+ shouldPrint := false
301+ for _ , item := range group .Items {
302+ if item .Value != "" {
303+ shouldPrint = true
304+ break
305+ }
238306 }
239- if v , ok := values [k ]; ok {
240- fmt .Fprintf (w , "%s: %s\n " , k , v )
307+ if shouldPrint {
308+ printTable (w , group .Name , group .Items )
309+ fmt .Fprintln (w )
241310 }
242311 }
312+
243313}
244314
245- func isDeprecated (tag string ) bool {
246- for part := range strings .SplitSeq (tag , "," ) {
247- if strings .EqualFold (part , "deprecated" ) {
248- return true
315+ func printTable (w io.Writer , title string , rows []OutputItem ) {
316+ table := tablewriter .NewTable (w ,
317+ // Rounded corners
318+ tablewriter .WithSymbols (tw .NewSymbols (tw .StyleRounded )),
319+
320+ // Table content formatting
321+ tablewriter .WithConfig (tablewriter.Config {
322+ Header : tw.CellConfig {
323+ Formatting : tw.CellFormatting {
324+ AutoFormat : tw .Off ,
325+ MergeMode : tw .MergeHorizontal ,
326+ },
327+ Alignment : tw.CellAlignment {
328+ Global : tw .AlignLeft ,
329+ },
330+ Filter : tw.CellFilter {
331+ Global : func (s []string ) []string {
332+ for i := range s {
333+ s [i ] = utils .Bold (s [i ])
334+ }
335+ return s
336+ },
337+ },
338+ },
339+ Row : tw.CellConfig {
340+ Alignment : tw.CellAlignment {
341+ Global : tw .AlignLeft ,
342+ },
343+ ColMaxWidths : tw.CellWidth {
344+ PerColumn : map [int ]int {0 : 16 },
345+ },
346+ Filter : tw.CellFilter {
347+ PerColumn : []func (string ) string {
348+ func (s string ) string {
349+ return utils .Green (s )
350+ },
351+ },
352+ },
353+ },
354+ Behavior : tw.Behavior {
355+ Compact : tw.Compact {
356+ Merge : tw .On ,
357+ },
358+ },
359+ }),
360+ )
361+
362+ // Set title as header (merged across all columns)
363+ table .Header (title , title )
364+
365+ // Add data rows with values colored based on type
366+ for _ , row := range rows {
367+ if row .Value != "" {
368+ switch row .Type {
369+ case Link :
370+ table .Append (row .Label , utils .Aqua (row .Value ))
371+ case Key :
372+ table .Append (row .Label , utils .Yellow (row .Value ))
373+ case Text :
374+ table .Append (row .Label , row .Value )
375+ }
249376 }
250377 }
251- return false
378+
379+ table .Render ()
252380}
0 commit comments