├── .gitignore ├── LICENSE ├── README.md ├── dns-example-service ├── .env.example ├── README.md ├── config.go ├── go.mod ├── go.sum └── main.go ├── docker-compose.yml ├── helm └── studio-chart │ ├── Chart.yaml │ ├── README.md │ ├── deploy.sh │ ├── docker │ └── Dockerfile │ ├── templates │ ├── dns-example-deployment.yaml │ ├── registry-deployment.yaml │ ├── registry-pvc.yaml │ ├── studio-build-configmap.yaml │ ├── studio-build-job.yaml │ ├── studio-deployment.yaml │ ├── studio-ingress.yaml │ ├── studio-service.yaml │ ├── supa-manager-configmap.yaml │ ├── supa-manager-deployment.yaml │ ├── supa-manager-ingress.yaml │ ├── supa-manager-service.yaml │ └── version-service-deployment.yaml │ └── values.yaml ├── studio ├── .env.example ├── README.md ├── build.sh ├── files │ └── apps │ │ └── studio │ │ └── public │ │ └── img │ │ ├── regions │ │ ├── JUPITER.svg │ │ └── MARS.svg │ │ └── twitter-profiles │ │ └── MpAMDXmc_400x400.jpg ├── patch.sh └── patches │ ├── 00-init.patch │ ├── 01-providers.patch │ ├── 02-providersfixes.patch │ ├── 03-removeoauthandsso.patch │ ├── 04-tweets.patch │ ├── 05-fixpatches.patch │ ├── 06-uifixes.patch │ ├── 07-hcaptcha.patch │ ├── 08-configcat.patch │ ├── 09-removebilling.patch │ ├── 10-removetelemetryreq.patch │ ├── 11-fixemptybilling.patch │ ├── 12-projectcreation.patch │ ├── 13-spacerace.patch │ ├── 14-juststoptelemetry.patch │ ├── 15-fixprojcreation.patch │ └── 16-removepropsprefix.patch ├── supa-manager ├── .env.example ├── Dockerfile ├── api │ ├── api.go │ ├── configCat.go │ ├── getIntegrationConnections.go │ ├── getOrganizationMembersReachedFreeProjectLimit.go │ ├── getOrganizations.go │ ├── getPlatformNotifications.go │ ├── getPlatformOrganizationSubscription.go │ ├── getPlatformOverdueInvoices.go │ ├── getPlatformProject.go │ ├── getPlatformProjectSettings.go │ ├── getPlatformProjects.go │ ├── getProfile.go │ ├── getProfilePermissions.go │ ├── getProjectApi.go │ ├── getProjectJwtSecretUpdateStatus.go │ ├── getProjectStatus.go │ ├── postGotrueToken.go │ ├── postPasswordCheck.go │ ├── postPlatformOrganizations.go │ ├── postPlatformProjects.go │ ├── postPlatformSignup.go │ └── projects.go ├── conf │ ├── config.go │ └── migrations.go ├── database │ ├── accounts.sql.go │ ├── db.go │ ├── migrations.sql.go │ ├── models.go │ ├── organization_membership.sql.go │ ├── organizations.sql.go │ └── projects.sql.go ├── go.mod ├── go.sum ├── main.go ├── migrations │ └── 00_init.sql ├── permisions │ └── org.go ├── queries │ ├── accounts.sql │ ├── migrations.sql │ ├── organization_membership.sql │ ├── organizations.sql │ └── projects.sql ├── sqlc.yaml └── utils │ └── sqlTypes.go └── version-service ├── .env.example ├── README.md ├── config.go ├── db.go ├── go.mod ├── go.sum ├── keys.go ├── main.go ├── models.go ├── queries.sql ├── queries.sql.go ├── schema.sql └── sqlc.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /studio/code-* 3 | /**/.env 4 | .DS_Store 5 | /**/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SupaManager 2 | A project by Harry Bairstow;
3 | Manage self-hosted Supabase instances using the Supabase studio. 4 | 5 |
6 | 7 | > [!WARNING] 8 | > The project is in active development and as such there are no docs for it, the best thing todo is wait for the project to become more stable. I am in the Supabase discord, however, the best way to reach me is via [my discord server](https://discord.gg/4k5HRe6YEp) or [twitter](https://twitter.com/TheHarryET) 9 | 10 | This project is only an API that has to be used in conjunction with the Supabase Studio or another UI. It is a fully functioning API which is based on what Supabase us in production and have as a mock in the Studio project. Please read the guides - when they are available - for information on how to start Supabase's Studio using this as the API. 11 | 12 | > [!NOTE] 13 | > We provide a way to patch a version of the Supabase Studio to use this API. Please refer to the `studio` folder for more information. 14 | 15 | ## Licence 16 | Copyright (C) 2024 Harry Bairstow 17 | 18 | This program is free software: you can redistribute it and/or modify 19 | it under the terms of the GNU General Public License as published by 20 | the Free Software Foundation, either version 3 of the License, or 21 | (at your option) any later version. 22 | 23 | This program is distributed in the hope that it will be useful, 24 | but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | GNU General Public License for more details. 27 | 28 | You should have received a copy of the GNU General Public License 29 | along with this program. If not, see . -------------------------------------------------------------------------------- /dns-example-service/.env.example: -------------------------------------------------------------------------------- 1 | TOKEN=secret-from-supamanager -------------------------------------------------------------------------------- /dns-example-service/README.md: -------------------------------------------------------------------------------- 1 | # Example DNS Service 2 | SupaManager needs a DNS service which can update the DNS records when each project is created. 3 | 4 | This is an example that can be used to make new services i.e. Cloudflare, Route53, etc. -------------------------------------------------------------------------------- /dns-example-service/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/joho/godotenv" 5 | "github.com/kelseyhightower/envconfig" 6 | "os" 7 | ) 8 | 9 | type Config struct { 10 | ListenAddress string `json:"listen_address" split_words:"true" default:"0.0.0.0:8082"` 11 | Token string `json:"token" split_words:"true" required:"true"` 12 | } 13 | 14 | func LoadConfig(filename string) (*Config, error) { 15 | if _, err := os.Stat("./.env"); !os.IsNotExist(err) { 16 | if err := loadEnvironment(filename); err != nil { 17 | return nil, err 18 | } 19 | } 20 | config := new(Config) 21 | if err := envconfig.Process("", config); err != nil { 22 | return nil, err 23 | } 24 | return config, nil 25 | } 26 | 27 | func loadEnvironment(filename string) error { 28 | var err error 29 | if filename != "" { 30 | err = godotenv.Load(filename) 31 | } else { 32 | err = godotenv.Load() 33 | // handle if .env file does not exist, this is OK 34 | if os.IsNotExist(err) { 35 | return nil 36 | } 37 | } 38 | return err 39 | } 40 | -------------------------------------------------------------------------------- /dns-example-service/go.mod: -------------------------------------------------------------------------------- 1 | module supamanager.io/dns-example-service 2 | 3 | go 1.21.0 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.10.0 7 | github.com/joho/godotenv v1.5.1 8 | github.com/kelseyhightower/envconfig v1.4.0 9 | ) 10 | 11 | require ( 12 | github.com/bytedance/sonic v1.11.6 // indirect 13 | github.com/bytedance/sonic/loader v0.1.1 // indirect 14 | github.com/cloudwego/base64x v0.1.4 // indirect 15 | github.com/cloudwego/iasm v0.2.0 // indirect 16 | github.com/gabriel-vasile/mimetype v1.4.3 // indirect 17 | github.com/gin-contrib/sse v0.1.0 // indirect 18 | github.com/go-playground/locales v0.14.1 // indirect 19 | github.com/go-playground/universal-translator v0.18.1 // indirect 20 | github.com/go-playground/validator/v10 v10.20.0 // indirect 21 | github.com/goccy/go-json v0.10.2 // indirect 22 | github.com/json-iterator/go v1.1.12 // indirect 23 | github.com/klauspost/cpuid/v2 v2.2.7 // indirect 24 | github.com/leodido/go-urn v1.4.0 // indirect 25 | github.com/mattn/go-isatty v0.0.20 // indirect 26 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 27 | github.com/modern-go/reflect2 v1.0.2 // indirect 28 | github.com/pelletier/go-toml/v2 v2.2.2 // indirect 29 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 30 | github.com/ugorji/go/codec v1.2.12 // indirect 31 | golang.org/x/arch v0.8.0 // indirect 32 | golang.org/x/crypto v0.23.0 // indirect 33 | golang.org/x/net v0.25.0 // indirect 34 | golang.org/x/sys v0.20.0 // indirect 35 | golang.org/x/text v0.15.0 // indirect 36 | google.golang.org/protobuf v1.34.1 // indirect 37 | gopkg.in/yaml.v3 v3.0.1 // indirect 38 | ) 39 | -------------------------------------------------------------------------------- /dns-example-service/go.sum: -------------------------------------------------------------------------------- 1 | github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= 2 | github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= 3 | github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= 4 | github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= 5 | github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= 6 | github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= 7 | github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= 8 | github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= 13 | github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= 14 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 15 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 16 | github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= 17 | github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= 18 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 19 | github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 20 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 21 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 22 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 23 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 24 | github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= 25 | github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= 26 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 27 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 28 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 29 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 30 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 31 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 32 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 33 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 34 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 35 | github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= 36 | github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= 37 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 38 | github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= 39 | github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 40 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= 41 | github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= 42 | github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= 43 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 44 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 45 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 46 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 47 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 48 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 49 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 50 | github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= 51 | github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= 52 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 53 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 54 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 55 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 56 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 57 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 58 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 59 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 60 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 61 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 62 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 63 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 64 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 65 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 66 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 67 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 68 | github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= 69 | github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 70 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 71 | golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= 72 | golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 73 | golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= 74 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 75 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= 76 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 77 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 78 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 79 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= 80 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 81 | golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= 82 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 83 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 84 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 85 | google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= 86 | google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 87 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 88 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 89 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 90 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 91 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 92 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= 93 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 94 | -------------------------------------------------------------------------------- /dns-example-service/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | ) 7 | 8 | type DNSUpdateType string 9 | 10 | const ( 11 | DNSUpdateTypeCreate DNSUpdateType = "CREATE" 12 | DNSUpdateTypeDelete DNSUpdateType = "DELETE" 13 | ) 14 | 15 | type RequestBody struct { 16 | Type DNSUpdateType `json:"type"` 17 | Hostname string `json:"hostname"` 18 | ProjectRef string `json:"project_ref"` 19 | } 20 | 21 | func main() { 22 | config, err := LoadConfig(".env") 23 | if err != nil { 24 | println("Failed to load configuration, ensure the required environment variables are set.") 25 | return 26 | } 27 | 28 | r := gin.Default() 29 | 30 | r.POST("/", func(c *gin.Context) { 31 | tokenHeader := c.GetHeader("x-api-key") 32 | if tokenHeader != config.Token { 33 | c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) 34 | return 35 | } 36 | 37 | var body RequestBody 38 | if err := c.BindJSON(&body); err != nil { 39 | c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) 40 | return 41 | } 42 | 43 | // TODO: DNS Work Here 44 | 45 | c.AbortWithStatus(http.StatusAccepted) 46 | }) 47 | 48 | r.Run(config.ListenAddress) 49 | } 50 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | database: 4 | image: supabase/postgres:latest 5 | ports: 6 | - "5432:5432" 7 | environment: 8 | POSTGRES_USER: postgres 9 | POSTGRES_PASSWORD: postgres 10 | POSTGRES_DB: supabase 11 | studio: 12 | image: supa-manager/studio:v1.24.04 13 | ports: 14 | - "3000:3000" 15 | environment: 16 | PLATFORM_PG_META_URL: http://localhost:8080/pg 17 | NEXT_PUBLIC_SITE_URL: http://localhost:3000 18 | NEXT_PUBLIC_GOTRUE_URL: http://localhost:8080/auth 19 | NEXT_PUBLIC_API_URL: http://localhost:8080 20 | NEXT_PUBLIC_API_ADMIN_URL: http://localhost:8080 -------------------------------------------------------------------------------- /helm/studio-chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: studio-chart 3 | description: Helm chart for Studio and related services 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0.0" -------------------------------------------------------------------------------- /helm/studio-chart/README.md: -------------------------------------------------------------------------------- 1 | # Studio Helm Chart 2 | 3 | This Helm chart deploys Supabase Studio along with its required services including Supa-manager API and PostgreSQL. 4 | 5 | ## Overview 6 | 7 | The chart deploys the following components: 8 | - Supabase Studio UI 9 | - Supa-manager API 10 | - PostgreSQL database 11 | - DNS Example Service (optional) 12 | - Version Service (optional) 13 | 14 | ## Prerequisites 15 | 16 | - Kubernetes 1.19+ 17 | - Helm 3.2.0+ 18 | - Ingress controller (e.g., nginx-ingress) 19 | - cert-manager (optional, for TLS) 20 | - Docker registry accessible from the cluster (when building in-cluster) 21 | 22 | ## Installation 23 | 24 | There are two ways to deploy Studio: using the in-cluster build process or providing your own pre-built image. 25 | 26 | ### Option 1: In-Cluster Build (Recommended) 27 | 28 | This option will build the Studio UI directly in your cluster using the official Supabase repository. 29 | 30 | 1. Create a values file (e.g., `my-values.yaml`): -------------------------------------------------------------------------------- /helm/studio-chart/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if domain is provided 4 | if [ -z "$1" ]; then 5 | echo "Usage: $0 [build_params]" 6 | echo "Example: $0 example.com '--param1 value1 --param2 value2'" 7 | exit 1 8 | fi 9 | 10 | DOMAIN=$1 11 | BUILD_PARAMS=${2:-""} 12 | 13 | # Determine if we need to deploy registry 14 | if [ -z "$REGISTRY" ]; then 15 | REGISTRY_DEPLOY="true" 16 | else 17 | REGISTRY_DEPLOY="false" 18 | fi 19 | 20 | # Install/upgrade the Helm chart 21 | helm upgrade --install studio-release . \ 22 | --namespace studio \ 23 | --create-namespace \ 24 | --set global.domain=$DOMAIN \ 25 | --set global.registry.deploy=$REGISTRY_DEPLOY \ 26 | --set postgresql.enabled=true \ 27 | --set studio.image.build.params="$BUILD_PARAMS" -------------------------------------------------------------------------------- /helm/studio-chart/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | WORKDIR /app 4 | 5 | COPY studio/ . 6 | COPY studio/patch.sh /app/patch.sh 7 | COPY studio/build.sh /app/build.sh 8 | 9 | RUN chmod +x /app/patch.sh /app/build.sh 10 | RUN ./patch.sh && ./build.sh 11 | 12 | EXPOSE 3000 13 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /helm/studio-chart/templates/dns-example-deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.dnsExample.enabled }} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: dns-example 6 | namespace: {{ .Values.global.namespace }} 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: dns-example 12 | template: 13 | metadata: 14 | labels: 15 | app: dns-example 16 | spec: 17 | containers: 18 | - name: dns-example 19 | image: "{{ .Values.global.imageRegistry }}/{{ .Values.dnsExample.image.repository }}:{{ .Values.dnsExample.image.tag }}" 20 | imagePullPolicy: {{ .Values.dnsExample.image.pullPolicy }} 21 | resources: 22 | {{- toYaml .Values.dnsExample.resources | nindent 12 }} 23 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/registry-deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.global.registry.deploy }} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: registry 6 | namespace: {{ .Values.global.namespace }} 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: registry 12 | template: 13 | metadata: 14 | labels: 15 | app: registry 16 | spec: 17 | containers: 18 | - name: registry 19 | image: registry:2 20 | ports: 21 | - containerPort: 5000 22 | volumeMounts: 23 | - name: registry-data 24 | mountPath: /var/lib/registry 25 | volumes: 26 | - name: registry-data 27 | {{- if .Values.global.registry.persistence.enabled }} 28 | persistentVolumeClaim: 29 | claimName: registry-pvc 30 | {{- else }} 31 | emptyDir: {} 32 | {{- end }} 33 | --- 34 | apiVersion: v1 35 | kind: Service 36 | metadata: 37 | name: registry 38 | namespace: {{ .Values.global.namespace }} 39 | spec: 40 | selector: 41 | app: registry 42 | ports: 43 | - port: 5000 44 | targetPort: 5000 45 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/registry-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.global.registry.deploy .Values.global.registry.persistence.enabled }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: registry-pvc 6 | namespace: {{ .Values.global.namespace }} 7 | spec: 8 | {{- if .Values.global.registry.persistence.storageClass }} 9 | storageClassName: {{ .Values.global.registry.persistence.storageClass }} 10 | {{- end }} 11 | accessModes: 12 | - ReadWriteOnce 13 | resources: 14 | requests: 15 | storage: {{ .Values.global.registry.persistence.size }} 16 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/studio-build-configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.studio.image.build.enabled }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: studio-build-context 6 | namespace: {{ .Values.global.namespace }} 7 | data: 8 | "build.sh": | 9 | {{ .Files.Get "studio/build.sh" | indent 4 }} 10 | "patch.sh": | 11 | {{ .Files.Get "studio/patch.sh" | indent 4 }} 12 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/studio-build-job.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.studio.image.build.enabled }} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: studio-build-{{ .Release.Revision }} 6 | namespace: {{ .Values.global.namespace }} 7 | annotations: 8 | "helm.sh/hook": pre-install,pre-upgrade 9 | "helm.sh/hook-weight": "-5" 10 | "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded 11 | spec: 12 | template: 13 | spec: 14 | containers: 15 | - name: builder 16 | image: docker:20.10-dind 17 | securityContext: 18 | privileged: true 19 | command: 20 | - /bin/sh 21 | - -c 22 | - | 23 | set -e 24 | mkdir -p /workspace 25 | cd /workspace 26 | 27 | # Configure insecure registry if using in-cluster registry 28 | {{- if .Values.global.registry.deploy }} 29 | echo '{"insecure-registries": ["registry:5000"]}' > /etc/docker/daemon.json 30 | {{- end }} 31 | 32 | # Copy build context from configmap 33 | cp -r /build-context/* . 34 | 35 | # Create .env file 36 | cat > .env << EOL 37 | PLATFORM_PG_META_URL=http://api.{{ .Values.global.domain }}/pg 38 | NEXT_PUBLIC_SITE_URL=https://studio.{{ .Values.global.domain }} 39 | NEXT_PUBLIC_SUPABASE_URL=http://api.{{ .Values.global.domain }} 40 | NEXT_PUBLIC_GOTRUE_URL=http://api.{{ .Values.global.domain }}/auth 41 | NEXT_PUBLIC_API_URL=http://api.{{ .Values.global.domain }} 42 | NEXT_PUBLIC_API_ADMIN_URL=http://api.{{ .Values.global.domain }} 43 | NEXT_PUBLIC_HCAPTCHA_SITE_KEY=10000000-ffff-ffff-ffff-000000000001 44 | EOL 45 | 46 | # Run build script with correct parameters 47 | chmod +x build.sh 48 | ./build.sh "v1.24.04" "{{ if .Values.global.registry.deploy }}registry:5000{{ else }}{{ .Values.global.imageRegistry }}{{ end }}/{{ .Values.studio.image.repository }}:{{ .Release.Revision }}" .env 49 | volumeMounts: 50 | - name: build-context 51 | mountPath: /build-context 52 | - name: docker-socket 53 | mountPath: /var/run/docker.sock 54 | volumes: 55 | - name: build-context 56 | configMap: 57 | name: studio-build-context 58 | - name: docker-socket 59 | hostPath: 60 | path: /var/run/docker.sock 61 | restartPolicy: Never 62 | backoffLimit: 1 63 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/studio-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: studio 5 | namespace: {{ .Values.global.namespace }} 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: studio 11 | template: 12 | metadata: 13 | labels: 14 | app: studio 15 | spec: 16 | {{- if .Values.studio.image.build.enabled }} 17 | initContainers: 18 | - name: wait-for-build 19 | image: bitnami/kubectl:latest 20 | command: 21 | - /bin/sh 22 | - -c 23 | - | 24 | echo "Waiting for build job to complete..." 25 | while ! kubectl get job studio-build-{{ .Release.Revision }} -n {{ .Values.global.namespace }} -o jsonpath='{.status.succeeded}' 2>/dev/null | grep -q "1"; do 26 | sleep 5 27 | done 28 | echo "Build job completed successfully" 29 | {{- end }} 30 | containers: 31 | - name: studio 32 | image: "{{ if .Values.global.registry.deploy }}registry:5000{{ else }}{{ .Values.global.imageRegistry }}{{ end }}/{{ .Values.studio.image.repository }}:{{ if .Values.studio.image.build.enabled }}{{ .Release.Revision }}{{ else }}{{ .Values.studio.image.tag }}{{ end }}" 33 | imagePullPolicy: {{ .Values.studio.image.pullPolicy }} 34 | resources: 35 | {{- toYaml .Values.studio.resources | nindent 12 }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/studio-ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.studio.ingress.enabled }} 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: studio 6 | namespace: {{ .Values.global.namespace }} 7 | {{- with .Values.studio.ingress.annotations }} 8 | annotations: 9 | {{- toYaml . | nindent 4 }} 10 | {{- end }} 11 | spec: 12 | {{- if .Values.studio.ingress.tls.enabled }} 13 | tls: 14 | - hosts: 15 | - {{ .Values.studio.ingress.host }} 16 | secretName: studio-tls 17 | {{- end }} 18 | rules: 19 | - host: {{ .Values.studio.ingress.host }} 20 | http: 21 | paths: 22 | - path: / 23 | pathType: Prefix 24 | backend: 25 | service: 26 | name: studio 27 | port: 28 | number: {{ .Values.studio.service.port }} 29 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/studio-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: studio 5 | namespace: {{ .Values.global.namespace }} 6 | spec: 7 | selector: 8 | app: studio 9 | ports: 10 | - protocol: TCP 11 | port: {{ .Values.studio.service.port }} 12 | targetPort: 3000 -------------------------------------------------------------------------------- /helm/studio-chart/templates/supa-manager-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: supa-manager-config 5 | namespace: {{ .Values.global.namespace }} 6 | data: 7 | {{- if .Values.postgresql.enabled }} 8 | DATABASE_URL: "postgresql://{{ .Values.postgresql.auth.username }}:{{ .Values.postgresql.auth.password }}@{{ .Release.Name }}-postgresql:5432/{{ .Values.postgresql.auth.database }}?sslmode=disable" 9 | POSTGRES_HOST: {{ .Release.Name }}-postgresql 10 | POSTGRES_PORT: "5432" 11 | POSTGRES_DB: {{ .Values.postgresql.auth.database }} 12 | POSTGRES_USER: {{ .Values.postgresql.auth.username }} 13 | POSTGRES_PASSWORD: {{ .Values.postgresql.auth.password }} 14 | {{- else }} 15 | DATABASE_URL: {{ required "A valid database URL is required when postgresql.enabled is false" .Values.externalDatabase.url | quote }} 16 | POSTGRES_HOST: {{ default (.Values.externalDatabase.host) (regexReplaceAll "^.*@([^:]+):?[0-9]*/.+$" .Values.externalDatabase.url "${1}") }} 17 | POSTGRES_PORT: {{ default (.Values.externalDatabase.port) (regexReplaceAll "^.*@[^:]+:([0-9]+)/.+$" .Values.externalDatabase.url "${1}") }} 18 | POSTGRES_DB: {{ default (.Values.externalDatabase.database) (regexReplaceAll "^.*@[^:]+:?[0-9]*/(.+)(?:\\?.+)?$" .Values.externalDatabase.url "${1}") }} 19 | POSTGRES_USER: {{ default (.Values.externalDatabase.user) (regexReplaceAll "^.*://([^:]+):.*@.+$" .Values.externalDatabase.url "${1}") }} 20 | POSTGRES_PASSWORD: {{ default (.Values.externalDatabase.password) (regexReplaceAll "^.*://[^:]+:([^@]+)@.+$" .Values.externalDatabase.url "${1}") }} 21 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/supa-manager-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: supa-manager 5 | namespace: {{ .Values.global.namespace }} 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: supa-manager 11 | template: 12 | metadata: 13 | labels: 14 | app: supa-manager 15 | spec: 16 | containers: 17 | - name: supa-manager 18 | image: "{{ .Values.global.imageRegistry }}/{{ .Values.supaManager.image.repository }}:{{ .Values.supaManager.image.tag }}" 19 | imagePullPolicy: {{ .Values.supaManager.image.pullPolicy }} 20 | resources: 21 | {{- toYaml .Values.supaManager.resources | nindent 12 }} 22 | envFrom: 23 | - configMapRef: 24 | name: supa-manager-config -------------------------------------------------------------------------------- /helm/studio-chart/templates/supa-manager-ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.supaManager.ingress.enabled }} 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: supa-manager 6 | namespace: {{ .Values.global.namespace }} 7 | {{- with .Values.supaManager.ingress.annotations }} 8 | annotations: 9 | {{- toYaml . | nindent 4 }} 10 | {{- end }} 11 | spec: 12 | {{- if .Values.supaManager.ingress.tls.enabled }} 13 | tls: 14 | - hosts: 15 | - {{ .Values.supaManager.ingress.host }} 16 | secretName: supa-manager-tls 17 | {{- end }} 18 | rules: 19 | - host: {{ .Values.supaManager.ingress.host }} 20 | http: 21 | paths: 22 | - path: / 23 | pathType: Prefix 24 | backend: 25 | service: 26 | name: supa-manager 27 | port: 28 | number: {{ .Values.supaManager.service.port }} 29 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/templates/supa-manager-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: supa-manager 5 | namespace: {{ .Values.global.namespace }} 6 | spec: 7 | selector: 8 | app: supa-manager 9 | ports: 10 | - protocol: TCP 11 | port: {{ .Values.supaManager.service.port }} 12 | targetPort: 8080 -------------------------------------------------------------------------------- /helm/studio-chart/templates/version-service-deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.versionService.enabled }} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: version-service 6 | namespace: {{ .Values.global.namespace }} 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: version-service 12 | template: 13 | metadata: 14 | labels: 15 | app: version-service 16 | spec: 17 | containers: 18 | - name: version-service 19 | image: "{{ .Values.global.imageRegistry }}/{{ .Values.versionService.image.repository }}:{{ .Values.versionService.image.tag }}" 20 | imagePullPolicy: {{ .Values.versionService.image.pullPolicy }} 21 | resources: 22 | {{- toYaml .Values.versionService.resources | nindent 12 }} 23 | {{- end }} -------------------------------------------------------------------------------- /helm/studio-chart/values.yaml: -------------------------------------------------------------------------------- 1 | # Global settings 2 | global: 3 | namespace: studio 4 | imageRegistry: "" 5 | domain: "example.com" # Base domain for services 6 | registry: 7 | deploy: false # Will be set to true automatically if imageRegistry is empty and build is enabled 8 | persistence: 9 | enabled: true 10 | size: 10Gi 11 | storageClass: "" # Empty string means use cluster default 12 | 13 | # Studio settings 14 | studio: 15 | image: 16 | repository: studio 17 | tag: latest 18 | pullPolicy: IfNotPresent 19 | build: 20 | enabled: true 21 | params: "" 22 | resources: 23 | requests: 24 | cpu: 100m 25 | memory: 128Mi 26 | limits: 27 | cpu: 500m 28 | memory: 512Mi 29 | service: 30 | port: 3000 31 | ingress: 32 | enabled: true 33 | annotations: 34 | kubernetes.io/ingress.class: nginx 35 | cert-manager.io/cluster-issuer: letsencrypt-prod 36 | host: "studio.{{ .Values.global.domain }}" 37 | tls: 38 | enabled: true 39 | 40 | # DNS Example Service settings 41 | dnsExample: 42 | enabled: true 43 | image: 44 | repository: dns-example 45 | tag: latest 46 | pullPolicy: IfNotPresent 47 | resources: 48 | requests: 49 | cpu: 100m 50 | memory: 128Mi 51 | limits: 52 | cpu: 500m 53 | memory: 512Mi 54 | 55 | # Version Service settings 56 | versionService: 57 | enabled: false 58 | image: 59 | repository: version-service 60 | tag: latest 61 | pullPolicy: IfNotPresent 62 | resources: 63 | requests: 64 | cpu: 100m 65 | memory: 128Mi 66 | limits: 67 | cpu: 500m 68 | memory: 512Mi 69 | 70 | # Supa Manager settings 71 | supaManager: 72 | image: 73 | repository: supa-manager 74 | tag: latest 75 | pullPolicy: IfNotPresent 76 | resources: 77 | requests: 78 | cpu: 100m 79 | memory: 128Mi 80 | limits: 81 | cpu: 500m 82 | memory: 512Mi 83 | service: 84 | port: 8080 85 | ingress: 86 | enabled: true 87 | annotations: 88 | kubernetes.io/ingress.class: nginx 89 | cert-manager.io/cluster-issuer: letsencrypt-prod 90 | host: "api.{{ .Values.global.domain }}" 91 | tls: 92 | enabled: true 93 | 94 | # PostgreSQL settings 95 | postgresql: 96 | enabled: true 97 | auth: 98 | username: postgres 99 | password: postgres 100 | database: studio 101 | persistence: 102 | enabled: true 103 | size: 10Gi 104 | storageClass: "" 105 | primary: 106 | persistence: 107 | enabled: true 108 | size: 10Gi 109 | storageClass: "" 110 | 111 | # External PostgreSQL configuration (used when postgresql.enabled is false) 112 | externalDatabase: 113 | url: "" # Full DATABASE_URL for external PostgreSQL 114 | host: "" # Optional: Individual connection parameters 115 | port: "5432" 116 | database: "" 117 | user: "" 118 | password: "" 119 | -------------------------------------------------------------------------------- /studio/.env.example: -------------------------------------------------------------------------------- 1 | PLATFORM_PG_META_URL=http://localhost:8080/pg 2 | NEXT_PUBLIC_SITE_URL=http://localhost:3000 3 | NEXT_PUBLIC_SUPABASE_URL=http://localhost:8080 4 | NEXT_PUBLIC_SUPABASE_ANON_KEY=aaa.bbb.ccc 5 | NEXT_PUBLIC_GOTRUE_URL=http://localhost:8080/auth 6 | NEXT_PUBLIC_API_URL=http://localhost:8080 7 | NEXT_PUBLIC_API_ADMIN_URL=http://localhost:8080 8 | NEXT_PUBLIC_HCAPTCHA_SITE_KEY=10000000-ffff-ffff-ffff-000000000001 -------------------------------------------------------------------------------- /studio/README.md: -------------------------------------------------------------------------------- 1 | # Supabase Studio 2 | For Supa-Manager to keep the UI everyone is used to we have a patched version of the Supabase studio. 3 | This folder has the script we use to build that automatically applies all the patches. To add or update a patch please refer to the `patches` folder. 4 | 5 | > [!Note] 6 | > Currently the Supabase Studio image needs certain variables set at build time. As such you must run the command yourself to produce a "patched" image for your environment. 7 | > Please refer to the .env.example file for the required variables 8 | 9 | ## Usage 10 | `./build.sh [branch] [docker tag] [.env file (optional)]` - This will build the patched version of the Supabase Studio and tag it with the specified tag 11 | 12 | `./patch.sh [branch]` - This will apply the patches to the specified branch 13 | 14 | ## Creating new Patches 15 | 1. Download a version of the Studio and patch it using `./patch.sh` 16 | 2. `git add . && git commit -m "checkpoint"` - Create a checkpoint so patches are applied incrementally 17 | 3. Make your changes to the studio codebase 18 | 4. `git diff > patches/00-yourpatch.patch` - Create a patch file and increment the number based on the last patch 19 | -------------------------------------------------------------------------------- /studio/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | BRANCH=$1 5 | IMAGE_TAG=$2 6 | ENV_FILE=${3:-".env"} # Use the third argument or default to ".env" 7 | 8 | # Check if .env file exists 9 | if [ ! -f $ENV_FILE ]; then 10 | echo ".env file not found!" 11 | exit 1 12 | fi 13 | 14 | # Clone the repository and apply patches 15 | ./patch.sh $BRANCH 16 | 17 | cd ./code-$BRANCH || exit 18 | 19 | if [ -f ../$ENV_FILE ]; then 20 | if [ -f ./apps/studio/.env ]; then 21 | rm ./apps/studio/.env 22 | fi 23 | cp ../$ENV_FILE ./apps/studio/.env 24 | fi 25 | 26 | # Build and push for amd64 27 | docker build \ 28 | --file apps/studio/Dockerfile \ 29 | --target production \ 30 | --tag ${IMAGE_TAG} \ 31 | . 32 | 33 | # Cleanup 34 | cd ../../.. 35 | # rm -rf ./code-$BRANCH 36 | echo "Produced a patched docker image ${IMAGE_TAG} from branch ${BRANCH}." 37 | -------------------------------------------------------------------------------- /studio/files/apps/studio/public/img/regions/JUPITER.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /studio/files/apps/studio/public/img/regions/MARS.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /studio/files/apps/studio/public/img/twitter-profiles/MpAMDXmc_400x400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarryET/supa-manager/b97bf28e97b8cae3268aad5928b78e2e44aee83e/studio/files/apps/studio/public/img/twitter-profiles/MpAMDXmc_400x400.jpg -------------------------------------------------------------------------------- /studio/patch.sh: -------------------------------------------------------------------------------- 1 | BRANCH=$1 2 | 3 | # Clone the repository and apply patches 4 | if [ -d "code-$BRANCH" ]; then 5 | cd ./code-$BRANCH || exit 6 | git stash 7 | git checkout $BRANCH 8 | cd .. 9 | else 10 | git clone --depth 1 --branch $BRANCH https://github.com/supabase/supabase.git ./code-$BRANCH || exit 11 | fi 12 | 13 | for file in ./patches/*.patch; do 14 | patch -d ./code-$BRANCH -p1 < $file 15 | done 16 | 17 | find ./files -type f | while read -r file; do 18 | dest="./code-$BRANCH/${file#./files/}" 19 | mkdir -p "$(dirname "$dest")" 20 | cp "$file" "$dest" 21 | done -------------------------------------------------------------------------------- /studio/patches/02-providersfixes.patch: -------------------------------------------------------------------------------- 1 | diff --git a/apps/studio/components/interfaces/Billing/Subscription/Subscription.utils.ts b/apps/studio/components/interfaces/Billing/Subscription/Subscription.utils.ts 2 | index c21278b..79107c6 100644 3 | --- a/apps/studio/components/interfaces/Billing/Subscription/Subscription.utils.ts 4 | +++ b/apps/studio/components/interfaces/Billing/Subscription/Subscription.utils.ts 5 | @@ -23,6 +23,8 @@ export const billingPartnerLabel = (billingPartner?: string) => { 6 | return 'Fly.io' 7 | case 'aws': 8 | return 'AWS' 9 | + case 'k8s': 10 | + return 'Kubernetes' 11 | default: 12 | return billingPartner 13 | } 14 | diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/EnterpriseCard.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/EnterpriseCard.tsx 15 | index d85e884..40fe94a 100644 16 | --- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/EnterpriseCard.tsx 17 | +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/EnterpriseCard.tsx 18 | @@ -6,7 +6,7 @@ import { pickFeatures } from 'shared-data/plans' 19 | export interface EnterpriseCardProps { 20 | plan: PricingInformation 21 | isCurrentPlan: boolean 22 | - billingPartner: 'fly' | 'aws' | undefined 23 | + billingPartner: 'fly' | 'aws' | 'k8s' | undefined 24 | } 25 | 26 | const EnterpriseCard = ({ plan, isCurrentPlan, billingPartner }: EnterpriseCardProps) => { 27 | diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx 28 | index b0b2dd3..64d9fde 100644 29 | --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx 30 | +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx 31 | @@ -91,7 +91,7 @@ const DeployNewReplicaPanel = ({ 32 | const canDeployReplica = 33 | !reachedMaxReplicas && 34 | currentPgVersion >= 15 && 35 | - project?.cloud_provider === 'AWS' && 36 | + project?.cloud_provider === 'K8S' && 37 | !isFreePlan && 38 | isWalgEnabled && 39 | currentComputeAddon !== undefined 40 | diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/MapView.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/MapView.tsx 41 | index a5c8c30..27f8682 100644 42 | --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/MapView.tsx 43 | +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/MapView.tsx 44 | @@ -264,7 +264,7 @@ const MapView = ({ onSelectDeployNewReplica, onSelectDropReplica }: MapViewProps 45 | Unhealthy 46 | )} 47 |

48 | -

AWS • {database.size}

49 | +

K8S • {database.size}

50 | {database.identifier !== ref && ( 51 |

Created on: {created}

52 | )} 53 | diff --git a/apps/studio/data/misc/get-default-region-query.ts b/apps/studio/data/misc/get-default-region-query.ts 54 | index 2ccea10..bd3842f 100644 55 | --- a/apps/studio/data/misc/get-default-region-query.ts 56 | +++ b/apps/studio/data/misc/get-default-region-query.ts 57 | @@ -7,7 +7,7 @@ import { K8S_REGIONS, K8S_REGIONS_DEFAULT } from 'lib/constants' 58 | const RESTRICTED_POOL = ['WEST_US', 'CENTRAL_EU', 'SOUTHEAST_ASIA'] 59 | 60 | export type DefaultRegionVariables = { 61 | - cloudProvider?: 'AWS' | 'FLY' 62 | + cloudProvider?: 'K8S' 63 | useRestrictedPool?: boolean 64 | } 65 | 66 | diff --git a/apps/studio/data/projects/project-create-mutation.ts b/apps/studio/data/projects/project-create-mutation.ts 67 | index dd46ed8..a2b4de0 100644 68 | --- a/apps/studio/data/projects/project-create-mutation.ts 69 | +++ b/apps/studio/data/projects/project-create-mutation.ts 70 | @@ -29,7 +29,7 @@ export async function createProject({ 71 | dbPass, 72 | dbRegion, 73 | dbSql, 74 | - cloudProvider = PROVIDERS.AWS.id, 75 | + cloudProvider = PROVIDERS.K8S.id, 76 | configurationId, 77 | authSiteUrl, 78 | customSupabaseRequest, 79 | diff --git a/apps/studio/data/read-replicas/replica-setup-mutation.ts b/apps/studio/data/read-replicas/replica-setup-mutation.ts 80 | index 6fc0f28..49cd3d2 100644 81 | --- a/apps/studio/data/read-replicas/replica-setup-mutation.ts 82 | +++ b/apps/studio/data/read-replicas/replica-setup-mutation.ts 83 | @@ -72,7 +72,7 @@ export const useReadReplicaSetUpMutation = ({ 84 | region, 85 | inserted_at: new Date().toISOString(), 86 | status: 'COMING_UP', 87 | - cloud_provider: 'AWS', 88 | + cloud_provider: 'K8S', 89 | } 90 | return [...old, scaffoldNewDatabase] 91 | }) 92 | diff --git a/apps/studio/lib/cloudprovider-utils.ts b/apps/studio/lib/cloudprovider-utils.ts 93 | index e40898f..d0cf4da 100644 94 | --- a/apps/studio/lib/cloudprovider-utils.ts 95 | +++ b/apps/studio/lib/cloudprovider-utils.ts 96 | @@ -2,9 +2,7 @@ import { PROVIDERS } from './constants' 97 | 98 | export function getCloudProviderArchitecture(cloudProvider: string | undefined) { 99 | switch (cloudProvider) { 100 | - case PROVIDERS.AWS.id: 101 | - return 'ARM' 102 | - case PROVIDERS.FLY.id: 103 | + case PROVIDERS.K8S.id: 104 | return 'x86 64-bit' 105 | default: 106 | return '' 107 | diff --git a/apps/studio/pages/api/props/project/[ref]/settings.ts b/apps/studio/pages/api/props/project/[ref]/settings.ts 108 | index 20eebfd..1d286fe 100644 109 | --- a/apps/studio/pages/api/props/project/[ref]/settings.ts 110 | +++ b/apps/studio/pages/api/props/project/[ref]/settings.ts 111 | @@ -22,8 +22,8 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { 112 | const response = { 113 | project: { 114 | ...DEFAULT_PROJECT, 115 | - cloud_provider: 'AWS', 116 | - region: 'ap-southeast-1', 117 | + cloud_provider: 'K8S', 118 | + region: 'MARS-1', 119 | db_dns_name: '-', 120 | db_host: 'localhost', 121 | db_name: 'postgres', 122 | diff --git a/apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx b/apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx 123 | index 7af4c27..0050ab7 100644 124 | --- a/apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx 125 | +++ b/apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx 126 | @@ -60,7 +60,7 @@ const CreateProject = () => { 127 | const [passwordStrengthMessage, setPasswordStrengthMessage] = useState('') 128 | const [passwordStrengthScore, setPasswordStrengthScore] = useState(-1) 129 | const [shouldRunMigrations, setShouldRunMigrations] = useState(true) 130 | - const [dbRegion, setDbRegion] = useState(PROVIDERS.AWS.default_region) 131 | + const [dbRegion, setDbRegion] = useState(PROVIDERS.K8S.default_region) 132 | 133 | const snapshot = useIntegrationInstallationSnapshot() 134 | 135 | diff --git a/apps/studio/pages/vercel/setupProject.tsx b/apps/studio/pages/vercel/setupProject.tsx 136 | index e01897f..8e5ead7 100644 137 | --- a/apps/studio/pages/vercel/setupProject.tsx 138 | +++ b/apps/studio/pages/vercel/setupProject.tsx 139 | @@ -150,7 +150,7 @@ const CreateProject = observer(() => { 140 | const [dbPass, setDbPass] = useState('') 141 | const [passwordStrengthMessage, setPasswordStrengthMessage] = useState('') 142 | const [passwordStrengthScore, setPasswordStrengthScore] = useState(-1) 143 | - const [dbRegion, setDbRegion] = useState(PROVIDERS.AWS.default_region) 144 | + const [dbRegion, setDbRegion] = useState(PROVIDERS.K8S.default_region) 145 | 146 | const delayedCheckPasswordStrength = useRef( 147 | debounce((value: string) => checkPasswordStrength(value), 300) 148 | @@ -228,7 +228,7 @@ const CreateProject = observer(() => { 149 | VERCEL_INTEGRATION_CONFIGS.find((x) => x.id == _store.externalId)?.template?.sql || '' 150 | 151 | createProject({ 152 | - cloudProvider: PROVIDERS.AWS.id, 153 | + cloudProvider: PROVIDERS.K8S.id, 154 | organizationId: Number(_store.supabaseOrgId), 155 | name: projectName, 156 | dbPass: dbPass, 157 | diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts 158 | index f05b737..9db41b6 100644 159 | --- a/packages/api-types/types/api.d.ts 160 | +++ b/packages/api-types/types/api.d.ts 161 | @@ -3908,7 +3908,7 @@ export interface components { 162 | | 'INIT_READ_REPLICA' 163 | | 'INIT_READ_REPLICA_FAILED' 164 | /** @enum {string} */ 165 | - cloud_provider: 'AWS' | 'FLY' 166 | + cloud_provider: 'AWS' | 'FLY' | 'K8S' 167 | db_port: number 168 | db_name: string 169 | db_user: string 170 | -------------------------------------------------------------------------------- /studio/patches/03-removeoauthandsso.patch: -------------------------------------------------------------------------------- 1 | diff --git a/apps/studio/pages/sign-in.tsx b/apps/studio/pages/sign-in.tsx 2 | index a2f7d2b..4c94b82 100644 3 | --- a/apps/studio/pages/sign-in.tsx 4 | +++ b/apps/studio/pages/sign-in.tsx 5 | @@ -1,22 +1,16 @@ 6 | import Link from 'next/link' 7 | 8 | import SignInForm from 'components/interfaces/SignIn/SignInForm' 9 | -import SignInWithGitHub from 'components/interfaces/SignIn/SignInWithGitHub' 10 | -import SignInWithSSO from 'components/interfaces/SignIn/SignInWithSSO' 11 | import { SignInLayout } from 'components/layouts' 12 | import { useRouter } from 'next/router' 13 | import type { NextPageWithLayout } from 'types' 14 | 15 | const SignInPage: NextPageWithLayout = () => { 16 | const router = useRouter() 17 | - const searchParams = new URLSearchParams(router.query as Record).toString() 18 | 19 | return ( 20 | <> 21 |
22 | - 23 | - 24 | - 25 |
26 |
27 |
28 | diff --git a/apps/studio/pages/sign-up.tsx b/apps/studio/pages/sign-up.tsx 29 | index 4dc6e50..c243efa 100644 30 | --- a/apps/studio/pages/sign-up.tsx 31 | +++ b/apps/studio/pages/sign-up.tsx 32 | @@ -1,4 +1,3 @@ 33 | -import SignInWithGitHub from 'components/interfaces/SignIn/SignInWithGitHub' 34 | import SignUpForm from 'components/interfaces/SignIn/SignUpForm' 35 | import { SignInLayout } from 'components/layouts' 36 | import Link from 'next/link' 37 | @@ -8,8 +7,6 @@ const SignUpPage: NextPageWithLayout = () => { 38 | return ( 39 | <> 40 |
41 | - 42 | - 43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /studio/patches/04-tweets.patch: -------------------------------------------------------------------------------- 1 | diff --git a/packages/shared-data/tweets.ts b/packages/shared-data/tweets.ts 2 | index 842800d..f6e20a9 100644 3 | --- a/packages/shared-data/tweets.ts 4 | +++ b/packages/shared-data/tweets.ts 5 | @@ -1,231 +1,9 @@ 6 | const tweets = [ 7 | { 8 | - text: "Working with @supabase has been one of the best dev experiences I've had lately. Incredibly easy to set up, great documentation, and so many fewer hoops to jump through than the competition. I definitely plan to use it on any and all future projects.", 9 | - url: 'https://twitter.com/thatguy_tex/status/1497602628410388480', 10 | - handle: 'thatguy_tex', 11 | - img_url: '/images/twitter-profiles/09HouOSt_400x400.jpg', 12 | - }, 13 | - { 14 | - text: '@supabase is just 🤯 Now I see why a lot of people love using it as a backend for their applications. I am really impressed with how easy it is to set up an Auth and then just code it together for the frontend. @IngoKpp now I see your joy with Supabase #coding #fullstackwebdev', 15 | - url: 'https://twitter.com/IxoyeDesign/status/1497473731777728512', 16 | - handle: 'IxoyeDesign', 17 | - img_url: '/images/twitter-profiles/C8opIL-g_400x400.jpg', 18 | - }, 19 | - { 20 | - text: "I've been using @supabase for two personal projects and it has been amazing being able to use the power of Postgres and don't have to worry about the backend", 21 | - url: 'https://twitter.com/varlenneto/status/1496595780475535366', 22 | - handle: 'varlenneto', 23 | - img_url: '/images/twitter-profiles/wkXN0t_F_400x400.jpg', 24 | - }, 25 | - { 26 | - text: "Y'all @supabase + @nextjs is amazing! 🙌 Barely an hour into a proof-of-concept and already have most of the functionality in place. 🤯🤯🤯", 27 | - url: 'https://twitter.com/justinjunodev/status/1500264302749622273', 28 | - handle: 'justinjunodev', 29 | - img_url: '/images/twitter-profiles/9k_ZB9OO_400x400.jpg', 30 | - }, 31 | - { 32 | - text: 'And thanks to @supabase, I was able to go from idea to launched feature in a matter of hours. Absolutely amazing!', 33 | - url: 'https://twitter.com/BraydonCoyer/status/1511071369731137537', 34 | - handle: 'BraydonCoyer', 35 | - img_url: '/images/twitter-profiles/8YxkpW8f_400x400.jpg', 36 | - }, 37 | - { 38 | - text: 'Contributing to open-source projects and seeing merged PRs gives enormous happiness! Special thanks to @supabase, for giving this opportunity by staying open-source and being junior-friendly✌🏼', 39 | - url: 'https://twitter.com/damlakoksal/status/1511436907984662539', 40 | - handle: 'damlakoksal', 41 | - img_url: '/images/twitter-profiles/N8EfTFs7_400x400.jpg', 42 | - }, 43 | - { 44 | - text: "Holy crap. @supabase is absolutely incredible. Most elegant backend as a service I've ever used. This is a dream.", 45 | - url: 'https://twitter.com/kentherogers/status/1512609587110719488', 46 | - handle: 'KenTheRogers', 47 | - img_url: '/images/twitter-profiles/9l9Td-Fz_400x400.jpg', 48 | - }, 49 | - { 50 | - text: "Over the course of a few weeks, we migrated 125.000 users (email/pw, Gmail, Facebook, Apple logins) from Auth0 to @supabase and have now completed the migration. I'm just glad the migration is done 😅 Went well, besides a few edge cases (duplicate emails/linked accounts)", 51 | - url: 'https://twitter.com/kevcodez/status/1518548401587204096', 52 | - handle: 'kevcodez', 53 | - img_url: '/images/twitter-profiles/t6lpcRcn_400x400.jpg', 54 | - }, 55 | - { 56 | - text: "Using @supabase I'm really pleased on the power of postgres (and sql in general). Despite being a bit dubious about the whole backend as a service thing I have to say I really don't miss anything. The whole experience feel very robust and secure.", 57 | - url: 'https://twitter.com/paoloricciuti/status/1497691838597066752', 58 | - handle: 'PaoloRicciuti', 59 | - img_url: '/images/twitter-profiles/OCDKFUOp_400x400.jpg', 60 | - }, 61 | - { 62 | - text: '@supabase is lit. It took me less than 10 minutes to setup, the DX is just amazing.', 63 | - url: 'https://twitter.com/saxxone/status/1500812171063828486', 64 | - handle: 'saxxone', 65 | - img_url: '/images/twitter-profiles/BXi6z1M7_400x400.jpg', 66 | - }, 67 | - { 68 | - text: 'I’m not sure what magic @supabase is using but we’ve migrated @happyteamsdotio database to @supabase from @heroku and it’s much much faster at half the cost.', 69 | - url: 'https://twitter.com/michaelcdever/status/1524753565599690754', 70 | - handle: 'michaelcdever', 71 | - img_url: '/images/twitter-profiles/rWX8Jzp5_400x400.jpg', 72 | - }, 73 | - { 74 | - text: 'There are a lot of indie hackers building in public, but it’s rare to see a startup shipping as consistently and transparently as Supabase. Their upcoming March releases look to be 🔥 Def worth a follow! also opened my eyes as to how to value add in open source.', 75 | - url: 'https://twitter.com/swyx/status/1366685025047994373', 76 | - handle: 'swyx', 77 | - img_url: '/images/twitter-profiles/qhvO9V6x_400x400.jpg', 78 | - }, 79 | - { 80 | - text: 'This weekend I made a personal record 🥇 on the less time spent creating an application with social login / permissions, database, cdn, infinite scaling, git push to deploy and for free. Thanks to @supabase and @vercel', 81 | - url: 'https://twitter.com/jperelli/status/1366195769657720834', 82 | - handle: 'jperelli', 83 | - img_url: '/images/twitter-profiles/_ki30kYo_400x400.jpg', 84 | - }, 85 | - { 86 | - text: 'Badass! Supabase is amazing. literally saves our small team a whole engineer’s worth of work constantly. The founders and everyone I’ve chatted with at supabase are just awesome people as well :)', 87 | - url: 'https://twitter.com/KennethCassel/status/1524359528619384834', 88 | - handle: 'KennethCassel', 89 | - img_url: '/images/twitter-profiles/pmQj3TX-_400x400.jpg', 90 | - }, 91 | - { 92 | - text: 'Working with Supabase is just fun. It makes working with a DB so much easier.', 93 | - url: 'https://twitter.com/the_BrianB/status/1524716498442276864', 94 | - handle: 'the_BrianB', 95 | - img_url: '/images/twitter-profiles/7NITI8Z3_400x400.jpg', 96 | - }, 97 | - { 98 | - text: 'This community is STRONG and will continue to be the reason why developers flock to @supabase over an alternative. Keep up the good work! ⚡️', 99 | - url: 'https://twitter.com/_wilhelm__/status/1524074865107488769', 100 | - handle: '_wilhelm__', 101 | - img_url: '/images/twitter-profiles/CvqDy6YF_400x400.jpg', 102 | - }, 103 | - { 104 | - text: "Working on my next SaaS app and I want this to be my whole job because I'm just straight out vibing putting it together. @supabase and chill, if you will", 105 | - url: 'https://twitter.com/drewclemcr8/status/1523843155484942340', 106 | - handle: 'drewclemcr8', 107 | - img_url: '/images/twitter-profiles/bJlKtSxz_400x400.jpg', 108 | - }, 109 | - { 110 | - text: '@supabase Putting a ton of well-explained example API queries in a self-building documentation is just a classy move all around. I also love having GraphQL-style nested queries with traditional SQL filtering. This is pure DX delight. A+++. #backend', 111 | - url: 'https://twitter.com/CodiferousCoder/status/1522233113207836675', 112 | - handle: 'CodiferousCoder', 113 | - img_url: '/images/twitter-profiles/t37cVLwy_400x400.jpg', 114 | - }, 115 | - { 116 | - text: 'Me using @supabase for the first time right now 🤯', 117 | - url: 'https://twitter.com/nasiscoe/status/1365140856035024902', 118 | - handle: 'nasiscoe', 119 | - img_url: '/images/twitter-profiles/nc2Ms5hH_400x400.jpg', 120 | - }, 121 | - { 122 | - text: "I'm trying @supabase, Firebase alternative that uses PostgreSQL (and you can use GraphQL too) in the cloud. It's incredible 😍", 123 | - url: 'https://twitter.com/JP__Gallegos/status/1365699468109242374', 124 | - handle: 'JP__Gallegos', 125 | - img_url: '/images/twitter-profiles/1PH2mt6v_400x400.jpg', 126 | - }, 127 | - { 128 | - text: 'Check out this amazing product @supabase. A must give try #newidea #opportunity', 129 | - url: 'https://twitter.com/digitaldaswani/status/1364447219642814464', 130 | - handle: 'digitaldaswani', 131 | - img_url: '/images/twitter-profiles/w8HLdlC7_400x400.jpg', 132 | - }, 133 | - { 134 | - text: "I gave @supabase a try this weekend and I was able to create a quick dashboard to visualize the data from the PostgreSQL instance. It's super easy to use Supabase's API or the direct DB connection. Check out the tutorial 📖", 135 | - url: 'https://twitter.com/razvanilin/status/1363770020581412867', 136 | - handle: 'razvanilin', 137 | - img_url: '/images/twitter-profiles/AiaH9vJ2_400x400.jpg', 138 | - }, 139 | - { 140 | - text: "Tried @supabase for the first time yesterday. Amazing tool! I was able to get my Posgres DB up in no time and their documentation on operating on the DB is super easy! 👏 Can't wait for Cloud functions to arrive! It's gonna be a great Firebase alternative!", 141 | - url: 'https://twitter.com/chinchang457/status/1363347740793524227', 142 | - handle: 'chinchang457', 143 | - img_url: '/images/twitter-profiles/LTw5OCnv_400x400.jpg', 144 | - }, 145 | - { 146 | - text: '10/100 All day i was migrating my project from firebase to @supabase Because it is perfect and simple!!! I like design and API for understandable. There are in BETA now. Just try!🧪', 147 | - url: 'https://twitter.com/roomahhka/status/1363155396391763971', 148 | - handle: 'roomahhka', 149 | - img_url: '/images/twitter-profiles/e_2eQt6C_400x400.jpg', 150 | - }, 151 | - { 152 | - text: 'I gave @supabase a try today and I was positively impressed! Very quick setup to get a working remote database with API access and documentation generated automatically for you 👌 10/10 will play more', 153 | - url: 'https://twitter.com/razvanilin/status/1363002398738800640', 154 | - handle: 'razvanilin', 155 | - img_url: '/images/twitter-profiles/AiaH9vJ2_400x400.jpg', 156 | - }, 157 | - { 158 | - text: "Wait. Is it so easy to write queries for @supabase ? It's like simple SQL stuff!", 159 | - url: 'https://twitter.com/T0ny_Boy/status/1362911838908911617', 160 | - handle: 'T0ny_Boy', 161 | - img_url: '/images/twitter-profiles/UCBhUBZl_400x400.jpg', 162 | - }, 163 | - { 164 | - text: 'Jeez, and @supabase have native support for magic link login?! I was going to use http://magic.link for this But if I can get my whole DB + auth + magic link support in one... Awesome', 165 | - url: 'https://twitter.com/louisbarclay/status/1362016666868154371', 166 | - handle: 'louisbarclay', 167 | - img_url: '/images/twitter-profiles/6f1O8ZOW_400x400.jpg', 168 | - }, 169 | - { 170 | - text: 'Where has @supabase been all my life? 😍', 171 | - url: 'https://twitter.com/Elsolo244/status/1360257201911320579', 172 | - handle: 'Elsolo244', 173 | - img_url: '/images/twitter-profiles/v6citnk33y2wpeyzrq05_400x400.jpeg', 174 | - }, 175 | - { 176 | - text: 'Honestly Supabase is such a killer Firebase alternative.', 177 | - url: 'https://twitter.com/XPCheese/status/1360229397735895043', 178 | - handle: 'XPCheese', 179 | - img_url: '/images/twitter-profiles/eYP6YXr7_400x400.jpg', 180 | - }, 181 | - { 182 | - text: "I think you'll love @supabase :-) Open-source, PostgreSQL-based & zero magic.", 183 | - url: 'https://twitter.com/zippoxer/status/1360021315852328961', 184 | - handle: 'zippoxer', 185 | - img_url: '/images/twitter-profiles/6rd3xub9_400x400.png', 186 | - }, 187 | - { 188 | - text: '@supabase is insane.', 189 | - url: 'https://twitter.com/codewithbhargav/status/1357647840911126528', 190 | - handle: 'codewithbhargav', 191 | - img_url: '/images/twitter-profiles/LQYfHXBp_400x400.jpg', 192 | - }, 193 | - { 194 | - text: 'It’s fun, feels lightweight, and really quick to spin up user auth and a few tables. Almost too easy! Highly recommend.', 195 | - url: 'https://twitter.com/nerdburn/status/1356857261495214085', 196 | - handle: 'nerdburn', 197 | - img_url: '/images/twitter-profiles/66VSV9Mm_400x400.png', 198 | - }, 199 | - { 200 | - text: 'Now things are starting to get interesting! Firebase has long been the obvious choice for many #flutter devs for the ease of use. But their databases are NoSQL, which has its downsides... Seems like @supabase is working on something interesting here!', 201 | - url: 'https://twitter.com/RobertBrunhage/status/1356973695865085953', 202 | - handle: 'RobertBrunhage', 203 | - img_url: '/images/twitter-profiles/5LMWEACf_400x400.jpg', 204 | - }, 205 | - { 206 | - text: "Honestly, I really love what @supabase is doing, you don't need to own a complete backend, just write your logic within your app and you'll get a powerful Postgresql at your disposal.", 207 | - url: 'https://twitter.com/NavicsteinR/status/1356927229217959941', 208 | - handle: 'NavicsteinR', 209 | - img_url: '/images/twitter-profiles/w_zNZAs7_400x400.jpg', 210 | - }, 211 | - { 212 | - text: "I've really enjoyed the DX! Extremely fun to use, which is odd to say about a database at least for me.", 213 | - url: 'https://twitter.com/Soham_Asmi/status/1373086068132745217', 214 | - handle: 'Soham_Asmi', 215 | - img_url: '/images/twitter-profiles/Os4nhKIr_400x400.jpg', 216 | - }, 217 | - { 218 | - text: 'Supabase team is doing some awesome stuff #supabase #facts @supabase', 219 | - url: 'https://twitter.com/_strawbird/status/1372607500499841025', 220 | - handle: '_strawbird', 221 | - img_url: '/images/twitter-profiles/iMBvvQdn_400x400.jpg', 222 | - }, 223 | - { 224 | - text: "Did a website with @supabase last week with no prior experience with it. Up and running in 20 minutes. It's awesome to use. Thumbs up", 225 | - url: 'https://twitter.com/michael_webdev/status/1352885366928404481?s=20', 226 | - handle: 'michael_webdev', 227 | - img_url: '/images/twitter-profiles/SvAyLaWV_400x400.jpg', 228 | - }, 229 | - { 230 | - text: 'I just learned about @supabase and im in love 😍 Supabase is an open source Firebase alternative! EarListen (& react) to database changes 💁 Manage users & permissions 🔧 Simple UI for database interaction', 231 | - url: 'https://twitter.com/0xBanana/status/1373677301905362948', 232 | - handle: '0xBanana', 233 | - img_url: '/images/twitter-profiles/pgHIGqZ0_400x400.jpg', 234 | + text: "Self-hosted version of @supabase, powered by SupaManager.", 235 | + url: 'https://twitter.com/theharryet', 236 | + handle: 'theharryet', 237 | + img_url: '/img/twitter-profiles/MpAMDXmc_400x400.jpg', 238 | }, 239 | ] 240 | 241 | -------------------------------------------------------------------------------- /studio/patches/05-fixpatches.patch: -------------------------------------------------------------------------------- 1 | diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx 2 | index 64d9fde..899d86c 100644 3 | --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx 4 | +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx 5 | @@ -112,10 +112,7 @@ const DeployNewReplicaPanel = ({ 6 | const [selectedCompute, setSelectedCompute] = useState(defaultCompute) 7 | const selectedComputeMeta = computeAddons.find((addon) => addon.identifier === selectedCompute) 8 | 9 | - const availableRegions = 10 | - process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging' 11 | - ? AVAILABLE_REPLICA_REGIONS.filter((x) => x.key === 'SOUTHEAST_ASIA') 12 | - : AVAILABLE_REPLICA_REGIONS 13 | + const availableRegions = AVAILABLE_REPLICA_REGIONS 14 | 15 | const onSubmit = async () => { 16 | const regionKey = K8S_REGIONS_VALUES[selectedRegion] 17 | -------------------------------------------------------------------------------- /studio/patches/06-uifixes.patch: -------------------------------------------------------------------------------- 1 | diff --git a/apps/studio/components/layouts/SignInLayout/SignInLayout.tsx b/apps/studio/components/layouts/SignInLayout/SignInLayout.tsx 2 | index c1b2b53..df65ada 100644 3 | --- a/apps/studio/components/layouts/SignInLayout/SignInLayout.tsx 4 | +++ b/apps/studio/components/layouts/SignInLayout/SignInLayout.tsx 5 | @@ -70,7 +70,7 @@ const SignInLayout = ({ 6 | return 7 | } 8 | }) 9 | - .catch(() => {}) // catch all errors thrown by auth methods 10 | + .catch(() => { }) // catch all errors thrown by auth methods 11 | }, []) 12 | 13 | const [quote, setQuote] = useState<{ 14 | @@ -90,9 +90,8 @@ const SignInLayout = ({ 15 | <> 16 |
17 |
24 |