Defines the host<->guest wire contract for the .so -> wazero migration as a repo-local buf module (abi/proto/v1, generated Go in abi/v1): - manifest.proto: PluginManifest mirroring every static field of plugin.PluginRegistration (abi_version, deps, block/template registrations, admin pages, settings schema, theme presets, fonts, master pages, AI actions, RBAC method roles, CSS manifest, icon packs, directory extensions, job types, RAG fetcher types, settings panel, hook flags, core service bindings) - invoke.proto: bn_invoke envelope, Hook catalog (RENDER_BLOCK, RENDER_TEMPLATE, HANDLE_HTTP, JOB, LOAD, UNLOAD, RAG_FETCH, MEDIA_HOOK, DESCRIBE), AbiError, and job/lifecycle/rag/media/describe payloads - render.proto: RenderBlock/RenderTemplate payloads + RenderContext enumerating every ctx value from blocks/context.go (incl. BlockContext 1:1) - http.proto: buffered HttpRequest/HttpResponse for HANDLE_HTTP - db.proto: guest sql-driver messages (DbValue oneof over pgx-mappable types, query/exec/tx with host-side tx handles, SQLSTATE-carrying DbError) - capability.proto: HostCall envelope + one request/response pair per CoreServices interface method (content, settings+update, gating, crypto, menus, datasources, users, subscriptions, media.deposit, email.send, ai.text_call, ai.tools.register, bridge, jobs.submit, embeddings, rag, reviews, badges.refresh) The abi/ buf module is deliberately separate from the repo-root config: proto/ is the shared block/proto submodule (service API contracts); the ABI is SDK-internal and versions in lockstep with the guest shim. New `make abi` target runs buf lint + generate. docs/wasm-abi.md documents the ptr+len calling convention (bn_alloc, bn_invoke, packed u64), hook catalog, error semantics, abi_version evolution rules, and the full registration/ CoreServices coverage tables. Verified: `cd abi && buf lint` exit 0; `go build ./...` exit 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
190 lines
5.5 KiB
Protocol Buffer
190 lines
5.5 KiB
Protocol Buffer
// invoke.proto — the bn_invoke envelope, hook catalog, and the job/lifecycle
|
|
// hook payloads (WO-WZ-001).
|
|
//
|
|
// Every host→guest call crosses the wasm boundary as one guest export:
|
|
//
|
|
// bn_invoke(hook_id, ptr, len) → packed(ptr, len)
|
|
//
|
|
// where (ptr, len) frames a serialized InvokeRequest and the packed return
|
|
// frames a serialized InvokeResponse. Hook-specific payloads (render.proto,
|
|
// http.proto, and the messages below) travel inside InvokeRequest.payload /
|
|
// InvokeResponse.payload. See core/docs/wasm-abi.md.
|
|
|
|
syntax = "proto3";
|
|
|
|
package abi.v1;
|
|
|
|
import "v1/manifest.proto";
|
|
|
|
option go_package = "git.dev.alexdunmow.com/block/core/abi/v1;abiv1";
|
|
|
|
// Hook identifies the guest entry point being invoked.
|
|
enum Hook {
|
|
HOOK_UNSPECIFIED = 0;
|
|
// Render one block: payload = RenderBlockRequest / RenderBlockResponse.
|
|
HOOK_RENDER_BLOCK = 1;
|
|
// Render one template: payload = RenderTemplateRequest / RenderTemplateResponse.
|
|
HOOK_RENDER_TEMPLATE = 2;
|
|
// Forward a buffered HTTP request to the guest's mux:
|
|
// payload = HttpRequest / HttpResponse.
|
|
HOOK_HANDLE_HTTP = 3;
|
|
// Run a background job handler: payload = JobRequest / JobResponse.
|
|
HOOK_JOB = 4;
|
|
// Plugin load lifecycle: payload = LoadRequest / LoadResponse.
|
|
HOOK_LOAD = 5;
|
|
// Plugin unload lifecycle: payload = UnloadRequest / UnloadResponse.
|
|
HOOK_UNLOAD = 6;
|
|
// Re-fetch content for RAG re-indexing:
|
|
// payload = RagFetchRequest / RagFetchResponse.
|
|
HOOK_RAG_FETCH = 7;
|
|
// Media lifecycle event delivery: payload = MediaHookRequest / MediaHookResponse.
|
|
HOOK_MEDIA_HOOK = 8;
|
|
// Capture the static manifest at publish time:
|
|
// payload = DescribeRequest / DescribeResponse.
|
|
HOOK_DESCRIBE = 9;
|
|
}
|
|
|
|
// InvokeRequest is the host→guest call envelope.
|
|
message InvokeRequest {
|
|
Hook hook = 1;
|
|
// Serialized hook-specific request message (see Hook value comments).
|
|
bytes payload = 2;
|
|
// Milliseconds the guest has to answer; the host also enforces this
|
|
// deadline on the wasm instance (WithCloseOnContextDone).
|
|
int64 deadline_ms = 3;
|
|
}
|
|
|
|
// InvokeResponse is the guest→host return envelope.
|
|
message InvokeResponse {
|
|
// Serialized hook-specific response message; empty when error is set.
|
|
bytes payload = 1;
|
|
// Set when the hook failed; the host treats decode failures and traps as
|
|
// implicit ABI_ERROR_CODE_INTERNAL.
|
|
AbiError error = 2;
|
|
}
|
|
|
|
// AbiErrorCode classifies boundary-crossing failures.
|
|
enum AbiErrorCode {
|
|
ABI_ERROR_CODE_UNSPECIFIED = 0;
|
|
// The handler ran and failed; message carries the Go error text.
|
|
ABI_ERROR_CODE_INTERNAL = 1;
|
|
// The payload could not be decoded.
|
|
ABI_ERROR_CODE_DECODE = 2;
|
|
// The hook/capability is not implemented by the callee.
|
|
ABI_ERROR_CODE_UNIMPLEMENTED = 3;
|
|
// The call exceeded its deadline; the instance is considered poisoned.
|
|
ABI_ERROR_CODE_DEADLINE_EXCEEDED = 4;
|
|
// The caller is not entitled to this capability.
|
|
ABI_ERROR_CODE_PERMISSION_DENIED = 5;
|
|
}
|
|
|
|
// AbiError is the structured error carried by InvokeResponse and
|
|
// HostCallResponse.
|
|
message AbiError {
|
|
AbiErrorCode code = 1;
|
|
string message = 2;
|
|
}
|
|
|
|
// --- DESCRIBE ---
|
|
|
|
// DescribeRequest asks the guest for its static manifest (publish time only).
|
|
message DescribeRequest {
|
|
// ABI major version of the calling host/publish tool.
|
|
uint32 host_abi_version = 1;
|
|
}
|
|
|
|
// DescribeResponse returns the static manifest.
|
|
message DescribeResponse {
|
|
PluginManifest manifest = 1;
|
|
}
|
|
|
|
// --- LOAD / UNLOAD ---
|
|
|
|
// LoadRequest carries the static host configuration the .so world exposed as
|
|
// CoreServices.AppURL / CoreServices.MediaPath.
|
|
message LoadRequest {
|
|
HostConfig host_config = 1;
|
|
}
|
|
|
|
// HostConfig mirrors the plain-value CoreServices fields.
|
|
message HostConfig {
|
|
string app_url = 1; // CoreServices.AppURL
|
|
string media_path = 2; // CoreServices.MediaPath
|
|
}
|
|
|
|
message LoadResponse {}
|
|
|
|
message UnloadRequest {}
|
|
|
|
message UnloadResponse {}
|
|
|
|
// --- JOB ---
|
|
|
|
// JobRequest dispatches one background job to the guest handler registered
|
|
// for job_type (manifest.job_types).
|
|
message JobRequest {
|
|
string job_type = 1;
|
|
// JSON job configuration (json.RawMessage in JobHandlerFunc).
|
|
bytes config_json = 2;
|
|
}
|
|
|
|
// JobResponse returns the handler's JSON result.
|
|
message JobResponse {
|
|
bytes result_json = 1;
|
|
}
|
|
|
|
// --- RAG_FETCH ---
|
|
|
|
// RagFetchRequest asks the guest's registered content fetcher
|
|
// (manifest.rag_content_fetcher_types) for a content item's text.
|
|
message RagFetchRequest {
|
|
string content_type = 1;
|
|
string content_id = 2; // UUID
|
|
}
|
|
|
|
// RagFetchResponse mirrors plugin.ContentFetcher's return values.
|
|
message RagFetchResponse {
|
|
string title = 1;
|
|
string text = 2;
|
|
}
|
|
|
|
// --- MEDIA_HOOK ---
|
|
|
|
// MediaHookRequest delivers one media lifecycle event
|
|
// (plugin.MediaHooksProvider).
|
|
message MediaHookRequest {
|
|
oneof event {
|
|
MediaAnalyzedEvent media_analyzed = 1; // OnMediaAnalyzed
|
|
ModerationDecisionEvent moderation_decision = 2; // OnModerationDecision
|
|
}
|
|
}
|
|
|
|
message MediaHookResponse {}
|
|
|
|
// MediaAnalyzedEvent mirrors plugin.MediaAnalyzedEvent (UUIDs as strings).
|
|
message MediaAnalyzedEvent {
|
|
string media_id = 1;
|
|
string analysis_id = 2;
|
|
string content_hash = 3;
|
|
string status = 4;
|
|
string source_plugin = 5;
|
|
string source_type = 6;
|
|
string source_ref_id = 7;
|
|
string safe_adult = 8;
|
|
string safe_violence = 9;
|
|
string safe_racy = 10;
|
|
}
|
|
|
|
// ModerationDecisionEvent mirrors plugin.ModerationDecisionEvent.
|
|
message ModerationDecisionEvent {
|
|
string media_id = 1;
|
|
string analysis_id = 2;
|
|
string status = 3;
|
|
string previous_status = 4;
|
|
string source_plugin = 5;
|
|
string source_type = 6;
|
|
string source_ref_id = 7;
|
|
string moderated_by = 8;
|
|
string note = 9;
|
|
}
|