feat: add plugin system (#1034)

* feat: add plugin system

* fix db docker build

* fix hammerhead readme, add strava subscription news to docs

* fixes and sdk improvements

* fix: reduce Meilisearch load, debounce federation sync (#1012)

* optimize meili trail index

* several fixes

---------

Co-authored-by: Flomp <Flomp@users.noreply.github.com>

* Bump svelte from 5.55.5 to 5.56.0 in /docs (#1032)

Bumps [svelte](https://github.com/sveltejs/svelte/tree/HEAD/packages/svelte) from 5.55.5 to 5.56.0.
- [Release notes](https://github.com/sveltejs/svelte/releases)
- [Changelog](https://github.com/sveltejs/svelte/blob/main/packages/svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/svelte/commits/svelte@5.56.0/packages/svelte)

---
updated-dependencies:
- dependency-name: svelte
  dependency-version: 5.56.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Flomp <Flomp@users.noreply.github.com>

* Release v0.19.2 (#1035)

* chore: release v0.19.2

* add changelog

---------

Co-authored-by: Flomp <26000991+Flomp@users.noreply.github.com>
Co-authored-by: Christian Beutel <>

* speed up plugin sync and several small fixes

* concepts for security improvements and process stability

* improve concept

* security concept implemented

* remove insecure TLS

* worker concept implemented

* fixes and cleanup

* fixes

* docu

* mermaid, namings

* WASM plugin host improvements, plugin logging

* fix db migration

* Improve plugin config and category mapping UI

* fixes

* further fixes

* remove manual test sync

* fix db migration and strava mapping

* type added, UI improvements

* fix plugin card toggle clickable area

* optimize synch status card layout

* plugin type 'trails' instead of 'integration'

* session auth validation in UI

* fix komoot date and waypoints

* improve category mapping

* fix send to hammerhead: trail name

* plugin setup error handling improved

* fix review findings

* re-mapping added

* rename remote_category

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Flomp <Flomp@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Flomp <26000991+Flomp@users.noreply.github.com>
This commit is contained in:
slothful-vassal
2026-06-22 15:00:44 +02:00
committed by GitHub
parent 2e3d8537b8
commit 485ec53f6d
196 changed files with 20947 additions and 5454 deletions

View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"log"
"os"
@@ -15,9 +16,7 @@ import (
"pocketbase/commands"
"pocketbase/hooks"
"pocketbase/integrations/hammerhead"
"pocketbase/integrations/komoot"
"pocketbase/integrations/strava"
"pocketbase/pluginsystem"
"pocketbase/routes"
_ "pocketbase/migrations"
@@ -56,6 +55,9 @@ func verifySettings(app core.App) {
}
func main() {
if len(os.Args) > 1 && os.Args[1] == "plugin-worker" {
os.Exit(pluginsystem.RunPluginWorker(context.Background(), os.Stdin, os.Stdout, os.Stderr))
}
app := pocketbase.New()
client := initializeMeilisearch()
@@ -124,11 +126,12 @@ func setupEventHandlers(app *pocketbase.PocketBase, client meilisearch.ServiceMa
app.OnRecordCreateRequest("follows").BindFunc(hooks.CreateFollowHandler())
app.OnRecordDeleteRequest("follows").BindFunc(hooks.DeleteFollowHandler())
app.OnRecordsListRequest("integrations").BindFunc(hooks.ListIntegrationHandler())
app.OnRecordCreate("integrations").BindFunc(hooks.CreateIntegrationHandler())
app.OnRecordAfterCreateSuccess("integrations").BindFunc(hooks.CreateUpdateIntegrationSuccessHandler())
app.OnRecordUpdate("integrations").BindFunc(hooks.UpdateIntegrationHandler())
app.OnRecordAfterUpdateSuccess("integrations").BindFunc(hooks.CreateUpdateIntegrationSuccessHandler())
app.OnRecordsListRequest("plugin_instances").BindFunc(hooks.ListPluginInstanceHandler())
app.OnRecordViewRequest("plugin_instances").BindFunc(hooks.ViewPluginInstanceHandler())
app.OnRecordCreate("plugin_instances").BindFunc(hooks.CreatePluginInstanceHandler())
app.OnRecordAfterCreateSuccess("plugin_instances").BindFunc(hooks.CreateUpdatePluginInstanceSuccessHandler())
app.OnRecordUpdate("plugin_instances").BindFunc(hooks.UpdatePluginInstanceHandler())
app.OnRecordAfterUpdateSuccess("plugin_instances").BindFunc(hooks.CreateUpdatePluginInstanceSuccessHandler())
app.OnRecordsListRequest("feed", "profile_feed").BindFunc(hooks.ListFeedHandler())
@@ -169,10 +172,14 @@ func registerRoutes(se *core.ServeEvent, client meilisearch.ServiceManager) {
se.Router.GET("/search/token", routes.SearchToken(client))
se.Router.POST("/integration/strava/token", routes.IntegrationStravaToken)
se.Router.POST("/integration/hammerhead/upload", routes.IntegrationHammerheadUpload)
se.Router.GET("/integration/hammerhead/login", routes.IntegrationHammerheadLogin)
se.Router.GET("/integration/komoot/login", routes.IntegrationKommotLogin)
se.Router.GET("/plugins", routes.PluginSystemPluginsList)
se.Router.POST("/plugins/trail-send", routes.PluginSystemTrailSend)
se.Router.POST("/plugins/auth/validate", routes.PluginSystemSessionAuthValidate)
se.Router.POST("/plugins/category-remap/preview", routes.PluginSystemCategoryRemapPreview)
se.Router.POST("/plugins/category-remap/apply", routes.PluginSystemCategoryRemapApply)
se.Router.POST("/plugins/oauth/start", routes.PluginSystemOAuthStart)
se.Router.POST("/plugins/oauth/callback", routes.PluginSystemOAuthCallback)
se.Router.POST("/plugins/oauth/revoke", routes.PluginSystemOAuthRevoke)
se.Router.POST("/activitypub/activity/process", routes.ActivitypubActivityProcess)
se.Router.GET("/activitypub/actor", routes.ActivitypubActor)
@@ -195,22 +202,9 @@ func registerCronJobs(app core.App, client meilisearch.ServiceManager) {
schedule = "0 2 * * *"
}
app.Cron().MustAdd("integrations", schedule, func() {
err := strava.SyncStrava(app, client)
if err != nil {
warning := fmt.Sprintf("Error syncing with strava: %v", err)
fmt.Println(warning)
app.Logger().Error(warning)
}
err = komoot.SyncKomoot(app, client)
if err != nil {
warning := fmt.Sprintf("Error syncing with komoot: %v", err)
fmt.Println(warning)
app.Logger().Error(warning)
}
err = hammerhead.SyncHammerhead(app, client)
if err != nil {
warning := fmt.Sprintf("Error syncing with hammerhead: %v", err)
app.Cron().MustAdd("plugin-sync", schedule, func() {
if err := routes.PluginSystemSyncConfigured(context.Background(), app, client); err != nil {
warning := fmt.Sprintf("Error syncing with WASM plugins: %v", err)
fmt.Println(warning)
app.Logger().Error(warning)
}
@@ -219,6 +213,7 @@ func registerCronJobs(app core.App, client meilisearch.ServiceManager) {
func initData(app core.App, client meilisearch.ServiceManager) error {
initCategories(app)
initPlugins(app)
initMeilisearchConfig(client)
go func() {
backfillPolylines(app)
@@ -227,6 +222,15 @@ func initData(app core.App, client meilisearch.ServiceManager) error {
return nil
}
func initPlugins(app core.App) {
manager := pluginsystem.NewManager(app, "")
if err := manager.SyncInstalledPlugins(context.Background()); err != nil {
warning := fmt.Sprintf("Error discovering WASM plugins: %v", err)
fmt.Println(warning)
app.Logger().Error(warning)
}
}
func backfillPolylines(app core.App) {
const pageSize int64 = 100
var lastID string
@@ -276,23 +280,28 @@ func initCategories(app core.App) error {
if err := query.All(&records); err != nil {
return err
}
if len(records) == 0 {
collection, _ := app.FindCollectionByNameOrId("categories")
if len(records) != 0 {
return nil
}
categories := []string{"Hiking", "Walking", "Climbing", "Skiing", "Canoeing", "Biking"}
for _, element := range categories {
record := core.NewRecord(collection)
record.Set("name", element)
record.Set("settings", map[string]any{
"wp_merge_enabled": true,
"wp_merge_radius": 50,
})
f, _ := filesystem.NewFileFromPath("migrations/initial_data/" + strings.ToLower(element) + ".jpg")
collection, err := app.FindCollectionByNameOrId("categories")
if err != nil {
return err
}
categories := []string{"Hiking", "Walking", "Climbing", "Skiing", "Canoeing", "Biking", "Other"}
for _, element := range categories {
record := core.NewRecord(collection)
record.Set("name", element)
record.Set("settings", map[string]any{
"wp_merge_enabled": true,
"wp_merge_radius": 50,
})
if f, err := filesystem.NewFileFromPath("migrations/initial_data/" + strings.ToLower(element) + ".jpg"); err == nil {
record.Set("img", f)
err := app.Save(record)
if err != nil {
return err
}
}
if err := app.Save(record); err != nil {
return err
}
}
return nil