package main import ( "log" "net/http" "os" "path/filepath" "github.com/joho/godotenv" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/apis" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/plugins/ghupdate" "github.com/pocketbase/pocketbase/plugins/jsvm" "github.com/pocketbase/pocketbase/plugins/migratecmd" "github.com/pocketbase/pocketbase/tools/hook" "github.com/pocketbase/pocketbase/tools/osutils" // Import migrations to ensure they are registered _ "github.com/pocketbase/pocketbase/migrations" ) // EncryptionEnvName is the name of the environment variable that holds the 32-char encryption key const EncryptionEnvName = "PB_ENCRYPTION_KEY" func main() { // Load .env file if it exists // This allows configuration through a .env file godotenv.Load() // Get database configuration from environment variables dbConfig := GetDBConfigFromEnv() // Print the configuration (useful for debugging) if os.Getenv("PB_DEBUG") == "true" { dbConfig.PrintConfig() } // Build PocketBase configuration pbConfig := pocketbase.Config{ DefaultEncryptionEnv: EncryptionEnvName, DefaultDataDir: dbConfig.GetDataDir(), DBConnect: dbConfig.GetDBConnectFunc(), } // If using PostgreSQL or MySQL, also set the auxiliary settings if dbConfig.Type == DBTypePostgres { pbConfig.DefaultPostgresURL = dbConfig.PostgresURL pbConfig.DefaultPostgresDataDb = dbConfig.PostgresDataDB pbConfig.DefaultPostgresAuxDb = dbConfig.PostgresAuxDB } else if dbConfig.Type == DBTypeMysql { // Pass MySQL DB names via the existing structure fields pbConfig.DefaultPostgresDataDb = dbConfig.MysqlDataDB pbConfig.DefaultPostgresAuxDb = dbConfig.MysqlAuxDB } // Initialize app with the configuration app := pocketbase.NewWithConfig(pbConfig) // --------------------------------------------------------------- // Optional plugin flags: // --------------------------------------------------------------- var hooksDir string app.RootCmd.PersistentFlags().StringVar( &hooksDir, "hooksDir", os.Getenv("PB_HOOKS_DIR"), "the directory with the JS app hooks", ) var hooksWatch bool app.RootCmd.PersistentFlags().BoolVar( &hooksWatch, "hooksWatch", true, "auto restart the app on pb_hooks file change; it has no effect on Windows", ) var hooksPool int app.RootCmd.PersistentFlags().IntVar( &hooksPool, "hooksPool", 15, "the total prewarm goja.Runtime instances for the JS app hooks execution", ) var migrationsDir string app.RootCmd.PersistentFlags().StringVar( &migrationsDir, "migrationsDir", "", "the directory with the user defined migrations", ) var automigrate bool app.RootCmd.PersistentFlags().BoolVar( &automigrate, "automigrate", true, "enable/disable auto migrations", ) var publicDir string app.RootCmd.PersistentFlags().StringVar( &publicDir, "publicDir", defaultPublicDir(), "the directory to serve static files", ) var indexFallback bool app.RootCmd.PersistentFlags().BoolVar( &indexFallback, "indexFallback", true, "fallback the request to index.html on missing static path, e.g. when pretty urls are used with SPA", ) app.RootCmd.ParseFlags(os.Args[1:]) // --------------------------------------------------------------- // Plugins and hooks: // --------------------------------------------------------------- // load jsvm (pb_hooks and pb_migrations) jsvm.MustRegister(app, jsvm.Config{ MigrationsDir: migrationsDir, HooksDir: hooksDir, HooksWatch: hooksWatch, HooksPoolSize: hooksPool, }) // migrate command (with js templates) migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{ TemplateLang: migratecmd.TemplateLangJS, Automigrate: automigrate, Dir: migrationsDir, }) // GitHub selfupdate ghupdate.MustRegister(app, app.RootCmd, ghupdate.Config{}) // static route to serves files from the provided public dir // (if publicDir exists and the route path is not already defined) app.OnServe().Bind(&hook.Handler[*core.ServeEvent]{ Func: func(e *core.ServeEvent) error { if !e.Router.HasRoute(http.MethodGet, "/{path...}") { e.Router.GET("/{path...}", apis.Static(os.DirFS(publicDir), indexFallback)) } return e.Next() }, Priority: 999, // execute as latest as possible to allow users to provide their own route }) // Print database info on startup app.OnServe().Bind(&hook.Handler[*core.ServeEvent]{ Func: func(e *core.ServeEvent) error { log.Printf("Starting with database type: %s", dbConfig.Type) return e.Next() }, Priority: -999, }) if err := app.Start(); err != nil { log.Fatal(err) } } // the default pb_public dir location is relative to the executable func defaultPublicDir() string { if os.Getenv("PB_PUBLIC_DIR") != "" { return os.Getenv("PB_PUBLIC_DIR") } if osutils.IsProbablyGoRun() { return "./pb_public" } return filepath.Join(os.Args[0], "../pb_public") }