Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions cmd/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cmd

import (
"github.com/spf13/cobra"
"github.com/supabase/cli/internal/gen/types/typescript"
)

var (
genCmd = &cobra.Command{
Use: "gen",
}

genTypesCmd = &cobra.Command{
Use: "types",
}

genTypesTypescriptCmd = &cobra.Command{
Use: "typescript",
Short: "Generate types for TypeScript. Must either specify --local, or --db-url, or be in a linked project (with supabase link)",
RunE: func(cmd *cobra.Command, args []string) error {
isLocal, err := cmd.Flags().GetBool("local")
if err != nil {
return err
}
dbUrl, err := cmd.Flags().GetString("db-url")
if err != nil {
return err
}

return typescript.Run(isLocal, dbUrl)
},
}
)

func init() {
genTypesTypescriptCmd.Flags().Bool("local", false, "Generate types from the local dev database")
genTypesTypescriptCmd.Flags().String("db-url", "", "Generate types from a database url")
genTypesCmd.AddCommand(genTypesTypescriptCmd)
genCmd.AddCommand(genTypesCmd)
rootCmd.AddCommand(genCmd)
}
6 changes: 3 additions & 3 deletions cmd/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ var (
}

projectsCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a new project.",
Args: cobra.ExactArgs(1),
Use: "create",
Short: "Create a new project.",
Args: cobra.ExactArgs(1),
Example: `supabase projects create my-project --org-id 12345 --db-password ******** --region us-east-1`,
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
Expand Down
193 changes: 193 additions & 0 deletions internal/gen/types/typescript/typescript.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package typescript

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stdcopy"
"github.com/supabase/cli/internal/utils"
)

var ctx = context.Background()

func Run(isLocal bool, dbUrl string) error {
if isLocal && dbUrl != "" {
return errors.New("Cannot specify both --local and --db-url")
}

if isLocal {
if err := utils.AssertSupabaseStartIsRunning(); err != nil {
return err
}

exec, err := utils.Docker.ContainerExecCreate(
ctx,
utils.PgmetaId,
types.ExecConfig{
Env: []string{
"PG_META_DB_HOST=" + utils.DbId,
},
Cmd: []string{
"node", "bin/src/server/app.js", "gen", "types", "typescript", "--exclude-schemas", "auth,extensions,graphql,graphql_public,realtime,storage,supabase_functions,supabase_migrations",
},
AttachStderr: true,
AttachStdout: true,
},
)
if err != nil {
return err
}

resp, err := utils.Docker.ContainerExecAttach(ctx, exec.ID, types.ExecStartCheck{})
if err != nil {
return err
}
var genBuf, errBuf bytes.Buffer
if _, err := stdcopy.StdCopy(&genBuf, &errBuf, resp.Reader); err != nil {
return err
}
if errBuf.Len() > 0 {
return errors.New(errBuf.String())
}

fmt.Print(genBuf.String())
return nil
}

// determine db url if in a linked project
if dbUrl == "" {
var accessToken string
var projectRef string
{
if err := utils.AssertSupabaseCliIsSetUp(); err != nil {
return err
}
_accessToken, err := utils.LoadAccessToken()
if err != nil {
return err
}
if err := utils.AssertIsLinked(); err != nil {
return err
}
projectRefBytes, err := os.ReadFile("supabase/.temp/project-ref")
if err != nil {
return err
}
_projectRef := string(projectRefBytes)

accessToken = _accessToken
projectRef = _projectRef
}

req, err := http.NewRequest("GET", "https://api.supabase.io/v1/projects", nil)
if err != nil {
return err
}
req.Header.Add("Authorization", "Bearer "+string(accessToken))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("Unexpected error retrieving projects: %w", err)
}

return errors.New("Unexpected error retrieving projects: " + string(body))
}

body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}

var projects []struct {
Ref string `json:"ref"`
DbPass string `json:"db_pass"`
}
if err := json.Unmarshal(body, &projects); err != nil {
return err
}

var dbPass string
for _, project := range projects {
if project.Ref == projectRef {
dbPass = project.DbPass
}
}
if dbPass == "" {
return errors.New("Could not find the linked project for the logged-in user. Try running supabase link again")
}

dbUrl = "postgresql://postgres:" + url.QueryEscape(dbPass) + "@db." + projectRef + ".supabase.co:5432/postgres"
}

// run typegen on the dbUrl
{
if err := utils.AssertDockerIsRunning(); err != nil {
return err
}

defer utils.DockerRemoveAll()

if _, _, err := utils.Docker.ImageInspectWithRaw(ctx, "docker.io/"+utils.PgmetaImage); err != nil {
fmt.Fprintln(os.Stderr, "Downloading type generator...")
out, err := utils.Docker.ImagePull(
ctx,
"docker.io/"+utils.PgmetaImage,
types.ImagePullOptions{},
)
if err != nil {
return err
}
if _, err := io.ReadAll(out); err != nil {
return err
}
if err := out.Close(); err != nil {
return err
}
fmt.Fprintln(os.Stderr, "Done downloading type generator")
}

out, err := utils.DockerRun(
ctx,
"supabase_gen_types_typescript",
&container.Config{
Image: utils.PgmetaImage,
Env: []string{
"PG_META_DB_URL=" + dbUrl,
},
Cmd: []string{
"node", "bin/src/server/app.js", "gen", "types", "typescript", "--exclude-schemas", "auth,extensions,graphql,graphql_public,realtime,storage,supabase_functions,supabase_migrations",
},
},
&container.HostConfig{},
)
if err != nil {
return err
}
var genBuf, errBuf bytes.Buffer
if _, err := stdcopy.StdCopy(&genBuf, &errBuf, out); err != nil {
return err
}
if errBuf.Len() > 0 {
return errors.New(errBuf.String())
}

fmt.Print(genBuf.String())
}

return nil
}
6 changes: 4 additions & 2 deletions internal/projects/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ func Run(name string, orgId uint, dbPassword string, region string, plan string)
}

// TODO: Prompt missing args.
{}
{
}

// POST request, check errors
var project struct {
Expand Down Expand Up @@ -71,7 +72,8 @@ func Run(name string, orgId uint, dbPassword string, region string, plan string)
}

// TODO: Poll until PostgREST is reachable.
{}
{
}

fmt.Printf(`Created a new project %s at %s\n`, utils.Aqua(project.Name), utils.Aqua("https://app.supabase.com/project/"+project.Ref))
return nil
Expand Down
2 changes: 1 addition & 1 deletion internal/utils/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const (
InbucketImage = "inbucket/inbucket:stable"
PostgrestImage = "postgrest/postgrest:v9.0.0.20220211"
DifferImage = "supabase/pgadmin-schema-diff:cli-0.0.4"
PgmetaImage = "supabase/postgres-meta:v0.33.2"
PgmetaImage = "supabase/postgres-meta:v0.40.0"
// TODO: Hardcode version once provided upstream.
StudioImage = "supabase/studio:latest"
DenoRelayImage = "supabase/deno-relay:v1.2.0"
Expand Down