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 ¶
- func DeclareCapabilities(h Host, caps map[string]bool)
- func DeclareDoc(h Host, markdown, url string)
- type AuthChallenge
- type AuthHandlers
- type AuthHost
- type AuthState
- type CapabilityHost
- type CredentialHost
- type Ctx
- type DocHost
- type EventHost
- type File
- type Host
- type Invoke
- type Sink
- type SourceCtx
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DeclareCapabilities ¶
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 ¶
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 ¶
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 ¶
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.
type Host ¶
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.