The wasip1 half of the ABI: bn_alloc/bn_invoke/bn_free exports with a live-pin map so the GC never frees host-visible buffers, the generic `blockninja.host_call` import (single import decided over per-family symbols; recorded in wasm-abi.md), and a dispatch table adapting an unmodified plugin.PluginRegistration to all nine v1 hooks. Panics inside plugin hooks come back as ABI_ERROR_CODE_INTERNAL — the instance stays callable; traps stay reserved for runtime corruption. DESCRIBE builds the PluginManifest from the registration's static funcs plus a capture-only Register pass (block metas via the same PluginBlockRegistry prefixing the .so loader applies, template/system/ page-template/email-wrapper keys), probes JobHandlers/ServiceHandlers/ Load with capture-only services for job types, RBAC roles, core-service bindings, and RAG fetcher types. RenderContext values are rehydrated through the exact core/blocks context keys, so existing block code reading from ctx works unchanged. Plugins build in REACTOR mode (go build -buildmode=c-shared): init() calls wasmguest.Serve (non-blocking), main is never called, and the host runs _initialize before any bn_invoke. Command mode deadlocks or exits (verified against wazero v1.12.0) — documented prominently in wasm-abi.md, which also now reconciles the import module namespace to `blockninja` and requires bn_alloc'd buffers on both directions. Dispatch/describe/context logic is buildable on every GOOS; only exports.go and hostcalls.go carry the wasip1 tag. dispatch_test.go covers describe, hook routing, envelope mismatch, decode failures, template-override resolution, panic recovery, and lifecycle hooks natively. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
47 lines
1.9 KiB
Go
47 lines
1.9 KiB
Go
// Package wasmguest is the guest half of the BlockNinja wasm plugin ABI:
|
|
// the go:wasmexport entry points (bn_alloc / bn_invoke / bn_free), guest
|
|
// memory pinning, the generic host-call import, and the dispatch table that
|
|
// adapts an unmodified plugin.PluginRegistration to ABI hook calls.
|
|
//
|
|
// The wire contract lives in core/docs/wasm-abi.md; the messages in
|
|
// git.dev.alexdunmow.com/block/core/abi/v1.
|
|
//
|
|
// # Plugin boilerplate
|
|
//
|
|
// A plugin becomes a wasm plugin by adding one main file next to its
|
|
// Registration:
|
|
//
|
|
// //go:build wasip1
|
|
//
|
|
// package main
|
|
//
|
|
// import "git.dev.alexdunmow.com/block/core/plugin/wasmguest"
|
|
//
|
|
// func init() { wasmguest.Serve(Registration) }
|
|
// func main() {} // never called — reactor mode
|
|
//
|
|
// and compiling in REACTOR mode (Go >= 1.24 toolchain; this repo's floor is
|
|
// higher):
|
|
//
|
|
// GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o plugin.wasm .
|
|
//
|
|
// Reactor modules export `_initialize` instead of `_start`: the host runs
|
|
// `_initialize` once per instance — which runs the init func above, hence
|
|
// Serve — before any bn_invoke. Serve is non-blocking: it stores the
|
|
// registration, runs the Register pass against capture registries, and
|
|
// returns; all work then arrives through bn_invoke.
|
|
//
|
|
// Command mode (plain `go build`) does NOT work and must not be used: its
|
|
// `_start` runs main synchronously, so a blocking main deadlocks the Go
|
|
// runtime ("all goroutines are asleep") and a returning main exits and
|
|
// closes the module — either way the exports are never callable
|
|
// (empirically verified against wazero v1.12.0; see wasm-abi.md).
|
|
//
|
|
// # Build shape
|
|
//
|
|
// Dispatch, describe, capture-registry, and context-reconstruction logic is
|
|
// plain Go and builds on every GOOS so it stays natively testable. Only
|
|
// exports.go (go:wasmexport, memory pinning) and hostcalls.go
|
|
// (go:wasmimport blockninja host_call) carry the wasip1 build tag.
|
|
package wasmguest
|