// Package main is the WO-WZ-002 acceptance fixture: a minimal plugin with // one block, one template, and one admin page, compiled to wasm with only // the wasmguest boilerplate (main.go). package main import ( "context" "fmt" "io" "strings" "git.dev.alexdunmow.com/block/core/blocks" "git.dev.alexdunmow.com/block/core/plugin" "git.dev.alexdunmow.com/block/core/templates" ) // capReport is populated by the Load hook from capability calls, then // surfaced through the greeting block ({"report": true}). It is the runtime // proof that deps.Content / deps.Settings / deps.Bridge cross the wasm ABI // end-to-end through the guest capability stubs (WO-WZ-003 acceptance). var capReport string // Registration is the fixture's plugin registration — the same shape a .so // plugin exports, untouched by the wasm migration. var Registration = plugin.PluginRegistration{ Name: "wasmfixture", Version: "0.0.1", Register: func(tr templates.TemplateRegistry, br blocks.BlockRegistry) error { br.Register(blocks.BlockMeta{ Key: "greeting", Title: "Greeting", Description: "Renders a greeting", Category: blocks.CategoryContent, }, func(ctx context.Context, content map[string]any) string { if boom, _ := content["boom"].(bool); boom { panic("fixture kaboom") } if report, _ := content["report"].(bool); report { return "

capreport:" + capReport + "

" } name, _ := content["name"].(string) if name == "" { name = "world" } if powered, _ := content["powered"].(bool); powered { // Powered path: hand the host a template + data instead of final // HTML, so the host renders it (pongo2) after this call returns. return blocks.PoweredBlock("

hello {{ name }}

", map[string]any{"name": name}) } return fmt.Sprintf("

hello %s

", name) }) // Custom template tag + filter the host wires from manifest.declared_tags // / declared_filters, invoked via HOOK_RENDER_TAG / HOOK_APPLY_FILTER. blocks.RegisterTag("shout", func(args map[string]any, rctx blocks.RenderContext) (string, error) { msg, _ := args["msg"].(string) return "" + strings.ToUpper(msg) + "", nil }) blocks.RegisterFilter("exclaim", func(input string, args map[string]any) (string, error) { return input + "!", nil }) return tr.Register("wasmfixture-page", func(ctx context.Context, doc map[string]any) templates.HTMLComponent { title, _ := doc["title"].(string) return htmlString("" + title + "") }) }, // Load exercises the guest capability stubs exactly as a real plugin's // service code does — unchanged calls against deps.Content / deps.Settings // / deps.Bridge — proving they compile and cross the ABI for wasip1. Load: func(deps plugin.CoreServices) error { page, err := deps.Content.GetPage(context.Background(), "about") if err != nil { capReport = "content-err:" + err.Error() return nil } site, err := deps.Settings.GetSiteSettings(context.Background()) if err != nil { capReport = "settings-err:" + err.Error() return nil } svc := deps.Bridge.GetService("other", "search") // cannot cross; expected nil capReport = fmt.Sprintf("page=%s site=%v bridge_nil=%t", page.Title, site["site_name"], svc == nil) return nil }, AdminPages: func() []plugin.AdminPage { return []plugin.AdminPage{{ Key: "wasmfixture", Title: "Wasm Fixture", Icon: "flask", Route: "/admin/wasmfixture", }} }, } type htmlString string func (s htmlString) Render(_ context.Context, w io.Writer) error { _, err := io.WriteString(w, string(s)) return err }