plugin

package
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package plugin is the seam between a plugin's implementation and **its transport**.

A plugin's implementation — schema declarations plus handlers — should exist once and be carried by either transport:

server            an in-process call   — the platform is the host itself
plugin-builtin    sokel over NATS      — deployed separately on another machine

Only the transport differs, so an implementation should know nothing of *sokel.Plugin or sokel.Ctx — types that belong to the NATS side — and see only the interfaces below. Whoever implements them decides which route a call takes.

The interfaces are deliberately small: credentials, fetching a file, storing one and reporting status are all the runtime capability a real plugin uses. A large interface is hard for both transports to implement, and most of what makes it large would serve only one of them.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DeclareCapabilities

func DeclareCapabilities(h Host, caps map[string]bool)

DeclareCapabilities records the capability bits when the host supports them and silently skips otherwise, so the same code serves the in-process and remote cases.

func DeclareDoc

func DeclareDoc(h Host, markdown, url string)

DeclareDoc hands over the guide when the host supports one and silently skips otherwise, so the same code serves the in-process and remote cases.

Supply either markdown or url: write the text here, or point at an existing documentation site — a copy pasted in here will eventually disagree with the site.

Types

type AuthChallenge

type AuthChallenge struct {
	// AuthID identifies this authentication attempt; poll and submit come back carrying it. Leave it
	// empty and the SDK generates one.
	AuthID string
	// Kind defaults to the declared Kind when empty. Overriding it per attempt is needed only when one
	// plugin's credentials use different shapes.
	Kind string
	// QRImage is the QR code for kind=qr, as a data URI such as "data:image/png;base64,...".
	QRImage string
	// Prompt is one sentence for the user, which also serves as the input placeholder for kind=input.
	Prompt string
	// ExpiresIn is the lifetime in seconds; 0 tells the panel nothing.
	ExpiresIn int
}

AuthChallenge is the challenge start hands to the panel.

type AuthHandlers

type AuthHandlers struct {
	Start  func(Ctx) (*AuthChallenge, error)
	Poll   func(ctx Ctx, authID string) (*AuthState, error)
	Submit func(ctx Ctx, authID, input string) error
}

AuthHandlers is the implementation side of an auth flow. Which of them are non-nil follows from the declared Steps, and the generated RegisterAuth keeps the two aligned.

type AuthHost

type AuthHost interface {
	SetAuthFlow(meta contract.AuthMeta, h AuthHandlers)
}

AuthHost is a host that can accept a collaborative auth flow; the SDK's *sokel.Plugin implements it. As with CredentialHost it is a small, single-method interface, which is what keeps generated code free of any SDK import.

type AuthState

type AuthState struct {
	// Status is one of pending, scanned (the code was scanned and awaits confirmation), confirmed or
	// expired.
	Status string
	// Session is the session credential on confirmation, handed to **the platform** to write into the
	// credential row — it never goes back to the frontend, so no browser handles the plaintext.
	//
	// It must be a JSON **object**. A string gets another layer of quotes around it — double encoding —
	// and the plugin cannot decode it back the next time it reads the credential.
	Session []byte
}

AuthState is poll's answer.

type CapabilityHost

type CapabilityHost interface {
	SetCapabilities(caps map[string]bool)
}

CapabilityHost is a host that can accept self-reported optional capabilities.

Same pattern as DocHost. It answers the half of the question that "does this operation exist" leaves open: two implementations of the same operation can differ enormously in what they actually manage — storage plugins all offer keyword_query, but one backs it with a properly tokenised BM25 and another with an approximation by similarity. Unreported, the platform can only ignore the difference silently, so a user's field weighting has no effect whatsoever — which is worse than "unsupported".

type CredentialHost

type CredentialHost interface {
	SetCredentialContract(fields []contract.Field)
}

CredentialHost is a host that can accept a credential contract; the SDK's *sokel.Plugin implements it.

It is a separate small interface rather than part of Host because an in-process host has no such thing as "reporting a credential contract", while the generated code has to attach to both. That also keeps the generated code free of any SDK import — plugin-core depending on the SDK in return would form a cycle, since the kernel's own contract declarations live in plugin-core.

type Ctx

type Ctx interface {
	context.Context
	// Credential is this call's credential fields, resolved and sent by the platform; nil when there is
	// no credential.
	Credential() map[string]string
	// Upload stores bytes in the platform's file layer and returns a file reference, which may be handed
	// downstream as an output directly.
	Upload(name, mime string, data []byte) (*File, error)
	// UploadReader does the same but **streams while reading**: memory use is one chunk (1 MiB),
	// independent of the file's size.
	//
	// Anything above a few hundred MB — a video on a NAS, an archive — must go this way: Upload requires
	// the whole file in memory first, which is not "a bit slower" but the plugin process bursting.
	UploadReader(name, mime string, r io.Reader) (*File, error)
	// Fetch retrieves a file's bytes. File.Blob is the method form of it, and plugins usually write
	// f.Blob(ctx).
	Fetch(f *File) ([]byte, error)
}

Ctx is the runtime capability available during one call.

Each transport implements it differently but with identical semantics — Upload, for instance, streams chunks back to the platform over NATS and writes straight to the storage layer in-process. A handler need not know where it is running.

type DocHost

type DocHost interface {
	SetDoc(markdown, url string)
}

DocHost is a host that can accept a plugin's user guide.

Same pattern as the credential contract — a small, optionally implemented interface: the plugin hands over its own documentation and the platform renders it as-is. That way "where do I get this key" and "what should I watch out for" travel with the plugin's code, rather than being scattered across a hard-coded table in the platform frontend, a credential field's placeholder and the author's memory — which is exactly where they live today.

type EventHost

type EventHost interface {
	// DeclareEvent declares one event.
	DeclareEvent(e contract.Event)
	// DeclareEventsCommon declares the fields every event shares; the platform flattens them to the top
	// level of the trigger input.
	DeclareEventsCommon(fields []contract.Field, names []string)
}

EventHost is the host an event contract is declared to.

type File

type File struct {
	ID   string `json:"id,omitempty"`   // the platform file id (f_...)
	URL  string `json:"url,omitempty"`  // the platform download path (/api/v1/files/<id>)
	Name string `json:"name,omitempty"` // the file name
	Mime string `json:"mime,omitempty"` // the MIME type
	// Size must not be omitempty: zero bytes is a value that **has to be visible**. It used to disappear
	// entirely when size=0, leaving a downstream empty-file gate of "file.size > 0" with nothing to
	// reference — as observed, an empty download's output had no size key at all, so a user copying the
	// condition from a successful sample that did have one could never make it match.
	Size int64  `json:"size"`           // the byte count
	Data []byte `json:"data,omitempty"` // inline bytes as a fallback (small files and tests; empty on the normal path)
}

File is a platform file reference. It is **only data** — reading the bytes goes through Ctx, since that depends on the transport.

The json tags line up with the platform's file value shape, so it can be handed out as an output field directly.

func (*File) Blob

func (f *File) Blob(ctx Ctx) ([]byte, error)

Blob reads a file's bytes, preferring inline Data and otherwise asking the transport to pull them from the platform's file layer. Being a method is merely convenient — the work is ctx's, because reading bytes depends on the transport.

func (*File) FileRef

func (f *File) FileRef()

FileRef implements contract.FileRef, letting the contract package recognise this as a file field.

type Host

type Host interface {
	Register(op contract.Operation, fn Invoke)
}

Host is where a plugin registers its operations. sokel.Plugin and the platform's in-process host each implement it.

type Invoke

type Invoke func(ctx Ctx, raw json.RawMessage, out Sink) error

Invoke is one call. raw is the input JSON, which the generated code decodes into concrete types, and output goes through the Sink.

type Sink

type Sink interface {
	// Vars emits typed output variables for downstream nodes, named by their sokel tags.
	Vars(v any)
	// Text emits human-readable text for display and tracing; it does not become a downstream variable.
	Text(s string)
	// JSON emits a structured display value.
	JSON(v any)
}

Sink is the output. Calling it repeatedly produces multiple frames (streaming); for a non-streaming operation the transport buffers and merges them.

type SourceCtx

type SourceCtx interface {
	Ctx
	// Trigger pushes one event. eventID is what the platform deduplicates on, so pushing the same
	// upstream message twice triggers once.
	//
	// payload takes any rather than a map: the transport expands a struct into contract names by its sokel
	// tags, the same machinery as Sink.Vars, and type safety is guaranteed one layer out by the generated
	// TriggerXxx — narrowing it again here would only add a conversion to the generated code.
	Trigger(event, eventID string, payload any) error
	// UpdateCredential writes credential fields back, a refreshed token for instance.
	UpdateCredential(patch map[string]string) error
	// ReportStatus reports this source's status, carried back on the heartbeat and visible in the
	// credential list.
	ReportStatus(status, msg string)
}

SourceCtx is the runtime capability available to a long-running event source: Ctx plus two more, pushing an event and updating the credential.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL