Hello from MCP server
// https://github.com/pocketbase/pocketbase/blob/master/examples/base/main.go
package main
import (
"log"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/pocketbase/dbx"
"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"
)
func main() {
app := pocketbase.New()
// ---------------------------------------------------------------
// Optional plugin flags:
// ---------------------------------------------------------------
var hooksDir string
app.RootCmd.PersistentFlags().StringVar(
&hooksDir,
"hooksDir",
"",
"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{})
registerHookNewOrg(app)
onPricebookChanges(app)
registerHookPreApprovedEmails(app)
// Role-based Access Control
app.OnRecordsListRequest().BindFunc(func(e *core.RecordsListRequestEvent) error {
publicResources := []string{"currencies", "currencyRateFixed", "currencyRates", "organizations"}
for _, resource := range publicResources {
if resource == e.Collection.Name {
return e.Next()
}
}
return authRecordsListRequest(e, "list")
})
app.OnRecordViewRequest().BindFunc(func(e *core.RecordRequestEvent) error {
return authRecordRequest(e, "view")
})
app.OnRecordCreateRequest().BindFunc(func(e *core.RecordRequestEvent) error {
return authRecordRequest(e, "create")
})
app.OnRecordUpdateRequest().BindFunc(func(e *core.RecordRequestEvent) error {
return authRecordRequest(e, "update")
})
app.OnRecordDeleteRequest().BindFunc(func(e *core.RecordRequestEvent) error {
return authRecordRequest(e, "delete")
})
app.OnServe().BindFunc(func(se *core.ServeEvent) error {
se.Router.POST("/api/join", func(e *core.RequestEvent) error {
data := struct {
OrgId string `json:"orgId"`
UserId string `json:"userId" `
}{}
if err := e.BindBody(&data); err != nil {
return e.BadRequestError("Failed to read request data", err)
}
// Check if profile already exists for this user and org
existingProfile, _ := e.App.FindFirstRecordByFilter(
"profiles",
"user = {:user} && org = {:org}",
dbx.Params{"user": e.Auth.Id, "org": data.OrgId},
)
if existingProfile != nil {
// Profile already exists - return friendly message without changing activeOrg
return e.JSON(http.StatusOK, map[string]interface{}{
"success": true,
"message": "You are already a member of this organization",
})
}
// Create new profile
collection, err := e.App.FindCollectionByNameOrId("profiles")
if err != nil {
return err
}
record := core.NewRecord(collection)
record.Set("user", e.Auth.Id)
record.Set("org", data.OrgId)
err = app.Save(record)
if err != nil {
return err
}
user, err := app.FindRecordById("users", e.Auth.Id)
if err != nil {
return err
}
// Get current profiles array
currentProfiles := user.Get("profiles")
var profileIds []string
// Handle existing profiles (could be nil or empty)
if currentProfiles != nil {
switch v := currentProfiles.(type) {
case []string:
profileIds = v
case []interface{}:
for _, id := range v {
if idStr, ok := id.(string); ok {
profileIds = append(profileIds, idStr)
}
}
}
}
// Add the new profile ID if not already present
newProfileId := record.Id
profileExists := false
for _, id := range profileIds {
if id == newProfileId {
profileExists = true
break
}
}
if !profileExists {
profileIds = append(profileIds, newProfileId)
}
// Update user with new profiles array and activeOrg
user.Set("profiles", profileIds)
user.Set("activeOrg", data.OrgId)
err = app.Save(user)
if err != nil {
return err
}
return e.JSON(http.StatusOK, map[string]interface{}{
"success": true,
"message": "Successfully joined organization",
})
}).Bind(apis.RequireAuth())
return se.Next()
})
// 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
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
// the default pb_public dir location is relative to the executable
func defaultPublicDir() string {
if strings.HasPrefix(os.Args[0], os.TempDir()) {
// most likely ran with go run
return "./pb_public"
}
return filepath.Join(os.Args[0], "../pb_public")
}