contracts

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: May 31, 2026 License: GPL-3.0 Imports: 6 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EventClusterNodeJoined    = "cluster.node.joined"
	EventClusterNodeLeft      = "cluster.node.left"
	EventClusterNodeDegraded  = "cluster.node.degraded"
	EventClusterLeaderChanged = "cluster.leader.changed"
)

Cluster event types for the event bus.

View Source
const (
	EventModuleRegistered   = "module.registered"
	EventModuleUnregistered = "module.unregistered"
	EventModuleDegraded     = "module.degraded"
)

Module-lifecycle event types — the only domain event types core knows about. Cluster events are in cluster.go. All other event types are in contract repos.

View Source
const (
	SafeContentTypeJSON     = "application/json"
	SafeContentTypeProtobuf = "application/x-protobuf"
	SafeContentTypeMsgpack  = "application/msgpack"
)

SafeSerializationTypes enumerates content types that are considered safe for deserialization. These formats do not support code-execution gadgets or type-confusion attacks in their standard Go implementations.

Formats NOT in this list (e.g., "application/yaml", "application/gob", "application/x-java-serialized-object") MUST NOT be supported by SerializationProvider implementations unless explicit sandboxing is applied and documented.

View Source
const (
	EventTapestryStarted   = "tapestry.started"
	EventTapestryCompleted = "tapestry.completed"
	EventTapestryFailed    = "tapestry.failed"
	EventTapestryCancelled = "tapestry.cancelled"
	EventTapestryPaused    = "tapestry.paused"
	EventTapestryResumed   = "tapestry.resumed"
	EventStepStarted       = "tapestry.step.started"
	EventStepCompleted     = "tapestry.step.completed"
	EventStepFailed        = "tapestry.step.failed"
)

Tapestry lifecycle event types — defined here so both core and modules can reference them without a separate contract repo for workflow.

View Source
const EventSchemaVersion = "v1"

EventSchemaVersion is the current schema version for all event payloads. RESERVED: defined for future typed-payload support. Currently the event bus uses raw []byte Payload and this constant is not consumed at runtime.

View Source
const EventStorageTierTransition = "storage.tier.transition"

EventStorageTierTransition is emitted when an object moves between tiers.

Variables

View Source
var ErrCallDenied = errors.New("call policy: access denied")

ErrCallDenied is returned when a call policy provider denies access. This is distinct from ErrCallNoPolicy which means no provider is registered.

View Source
var ErrCallNoPolicy = errors.New("call policy: no provider registered — calls are denied by default")

ErrCallNoPolicy is returned when no CallPolicyProvider is registered. In production, the mesh MUST reject cross-module calls when no provider is present rather than defaulting to open mode. This error signals that the deployment is missing a required security component.

View Source
var ErrCircuitOpen = errors.New("circuit breaker is open")

ErrCircuitOpen is returned by CircuitBreaker.Execute when the circuit is open and the call is rejected without execution.

View Source
var ErrDatabaseCredentialExposure = errors.New("database: credential passed as raw string — use OpenSecure with DatabaseParams instead")

ErrDatabaseCredentialExposure is a sentinel error that OpenSecure implementations SHOULD return if they detect that credentials were passed as a raw connection string (e.g., via the deprecated Open method). This enables CI lint rules to detect unsafe database initialization.

View Source
var ErrLockHeld = errors.New("distributed lock: key is already held")

ErrLockHeld is returned by DistributedLockProvider.Acquire when the requested key is already locked by another client.

View Source
var ErrNotFound = errors.New("object not found")

ErrNotFound is returned by storage providers when a key does not exist. Use errors.Is(err, contracts.ErrNotFound) to check.

View Source
var SensitiveLogFieldNames = []string{
	"password", "passwd", "secret", "token", "api_key", "apikey",
	"credential", "private_key", "ssh_key", "access_key", "auth",
	"authorization", "cookie", "jwt", "session", "signature",
	"credit_card", "ssn", "social_security", "passport",
}

SensitiveLogFieldNames is a curated list of field name prefixes that commonly carry credentials, tokens, or PII. Redaction providers and logging implementations SHOULD use this list as a default deny-set.

This list is not exhaustive — implementations may extend it based on their domain. The convention is lowercase field names as they appear in structured log fields.

Functions

func CallerIDFromContext added in v0.4.0

func CallerIDFromContext(ctx context.Context) string

CallerIDFromContext extracts the caller module ID from context, or "" if none was set.

func Register deprecated

func Register(factory ModuleFactory)

Deprecated: Use gRPC sidecar registration instead.

func WithCallerID deprecated added in v0.4.0

func WithCallerID(ctx context.Context, moduleID string) context.Context

WithCallerID returns a context carrying the given module ID as the caller. Modules use this before calling Mesh.Call() so the call policy provider can identify the caller.

SECURITY: Only use this for in-process (local) dispatch where the caller is part of the same trusted process. For gRPC mesh calls, the server extracts the caller ID from the authenticated connection metadata.

Deprecated: The gRPC mesh server now reads caller identity from the authenticated connection. This function remains for local dispatch only and will be removed when all modules have migrated to the sidecar model.

Types

type Action added in v0.4.0

type Action string

Action represents an operation a caller wants to perform. Standard verbs: "create", "read", "update", "delete", "list", "execute".

const (
	ActionCreate  Action = "create"
	ActionRead    Action = "read"
	ActionUpdate  Action = "update"
	ActionDelete  Action = "delete"
	ActionList    Action = "list"
	ActionExecute Action = "execute"
)

type AtomicMovable

type AtomicMovable interface {
	AtomicMove(ctx context.Context, src, dst string) error
}

type AuditEntry

type AuditEntry struct {
	ID         string
	Timestamp  time.Time
	Actor      string            // user ID, "system", or module ID
	Action     string            // e.g., "http.request", "module.registered", "media.requested"
	Resource   string            // e.g., "/api/movies", "admin-ui", "Inception"
	ResourceID string            // UUID of the affected resource, if applicable
	Details    map[string]string // arbitrary context — MUST NOT contain credentials or PII
	TraceID    string
	NodeID     string
	// PrevEntryHash is the SHA-256 hash of the chronologically previous audit entry.
	// This forms a tamper-evident hash chain. Zero value for the first entry in a log.
	PrevEntryHash string
	// Signature is an optional HMAC-SHA256 over the entry fields using a root key.
	// Enables verification that the entry was produced by an authorized audit logger.
	// Empty if the audit logger does not support cryptographic signing.
	Signature string
}

AuditEntry is a single audit log record.

type AuditFilter

type AuditFilter struct {
	Actor    string
	Action   string
	Resource string
	From     time.Time
	To       time.Time
	TraceID  string
	// VerifyChain, when true, instructs Query to validate the hash chain
	// of returned entries and exclude or flag entries with broken links.
	VerifyChain bool
}

AuditFilter narrows audit queries.

type AuditLogger

type AuditLogger interface {
	// Log records an audit entry.
	//
	// SECURITY: Details MUST NOT contain credentials, tokens, or PII.
	// The caller is responsible for redacting sensitive data before
	// calling Log. Use DataRedactionProvider if the details map is
	// built from untrusted input.
	Log(ctx context.Context, entry AuditEntry) error

	// Query returns entries matching the filter.
	Query(ctx context.Context, filter AuditFilter) ([]AuditEntry, error)

	// Export writes all entries in the given format (json, csv).
	Export(ctx context.Context, format string) (io.ReadCloser, error)

	// VerifyChainIntegrity performs a standalone integrity check on the
	// audit log hash chain in the given time range. Unlike Query with
	// VerifyChain=true, this method does not return entry data — it only
	// returns the verification result. This enables independent integrity
	// audits without exposing audit content to the verifier.
	//
	// If the provider does not support hash chains, this method returns
	// a result with Valid=true and TotalEntries=0 (no chain to verify).
	VerifyChainIntegrity(ctx context.Context, from, to time.Time) (ChainVerificationResult, error)
}

AuditLogger records and queries audit entries.

type AuthProvider

type AuthProvider interface {
	// Authenticate verifies credentials and returns a session if valid.
	// The returned Session.Token is the bearer token for subsequent
	// Validate calls.
	Authenticate(ctx context.Context, credentials Credentials) (Session, error)

	// Validate checks whether a token is still valid and returns the
	// associated session. Returns an error if the token is expired,
	// revoked, or malformed.
	//
	// SECURITY: The token parameter MUST NOT be logged. Use a
	// cryptographically safe prefix (first 8 chars of SHA-256) for
	// audit trail references.
	Validate(ctx context.Context, token string) (Session, error)

	// Revoke invalidates a token so it can no longer be used for
	// Validate calls. Already-established sessions are not affected
	// until their next Validate.
	Revoke(ctx context.Context, token string) error
}

AuthProvider authenticates callers and validates existing sessions.

SECURITY: Implementations MUST NOT log tokens. The token parameter on Validate and the Token field on Session are sensitive material. If you need to log authentication events, use AuditLogger with redacted token references (e.g., a SHA-256 prefix of the token).

type Authorizer

type Authorizer interface {
	// Can performs a permission check using a flat (action, resource) pair.
	//
	// SECURITY: The session parameter contains a raw token. Authorizer
	// implementations MUST NOT log or store the full Session struct.
	// Use session.Safe() if identity information is needed for audit.
	Can(ctx context.Context, session Session, action string, resource string) (bool, error)
}

Authorizer checks whether a session is permitted to perform an action on a resource.

For resource-level checks with ABAC support, implement the optional ResourceAuthorizer interface alongside Authorizer. Callers that need resource-level authorization type-assert to ResourceAuthorizer and fall back to Authorizer.Can if it's not supported.

type BackupInfo

type BackupInfo struct {
	ID        string
	Timestamp time.Time
	Size      int64
	Modules   []string // module IDs included in the backup
}

BackupInfo describes a completed backup.

type BackupProvider

type BackupProvider interface {
	// CreateBackup captures state from all registered Backupable modules.
	CreateBackup(ctx context.Context) (BackupInfo, error)
	// Restore restores state from a previous backup.
	Restore(ctx context.Context, backupID string) error
	// ListBackups returns all available backups.
	ListBackups(ctx context.Context) ([]BackupInfo, error)
	// DeleteBackup removes a stored backup.
	DeleteBackup(ctx context.Context, backupID string) error
}

BackupProvider is implemented by backup modules (backup-local, backup-s3, etc.)

type Backupable

type Backupable interface {
	// ExportState returns serialized state for backup.
	ExportState(ctx context.Context) ([]byte, error)
	// ImportState restores state from a backup.
	ImportState(ctx context.Context, data []byte) error
}

Backupable is implemented by modules that have state to back up.

type CacheLayer added in v0.1.1

type CacheLayer interface {
	// Get returns cached data for the given key. The bool indicates a cache hit.
	Get(ctx context.Context, key string) ([]byte, bool)
	// Set caches data for the given key.
	Set(ctx context.Context, key string, data []byte) error
	// Invalidate removes all cached entries whose key has the given prefix.
	Invalidate(ctx context.Context, prefix string) error
}

CacheLayer is an optional read-through cache for the storage orchestrator. Unlike CacheProvider (distributed caches for application state), CacheLayer provides local caching for storage objects. Implemented by cache-memory and similar modules. Core discovers a CacheLayer at bootstrap; if none is found, the orchestrator operates without a cache.

type CacheProvider

type CacheProvider interface {
	// Get retrieves a value by key. Returns nil, nil if the key does not exist.
	Get(ctx context.Context, key string) ([]byte, error)
	// Set stores a value with an optional TTL. Zero TTL means no expiration.
	Set(ctx context.Context, key string, value []byte, ttl time.Duration) error
	// Delete removes one or more keys.
	Delete(ctx context.Context, keys ...string) error
	// Exists checks whether a key exists.
	Exists(ctx context.Context, key string) (bool, error)
	// Incr atomically increments an integer key by delta and returns the new value.
	Incr(ctx context.Context, key string, delta int64) (int64, error)
	// CompareAndSwap atomically replaces oldValue with newValue at key.
	// Returns true if the swap succeeded (key held oldValue), false otherwise.
	// A nil oldValue matches a non-existent key.
	CompareAndSwap(ctx context.Context, key string, oldValue, newValue []byte) (bool, error)
	// Lock acquires a distributed lock on a key. Returns a Lock handle.
	// If the key is already locked, returns an error immediately (non-blocking).
	Lock(ctx context.Context, key string, ttl time.Duration) (LockHandle, error)
	// Publish sends a message on a pub/sub channel.
	Publish(ctx context.Context, channel string, msg []byte) error
	// Subscribe returns a channel that receives messages published on the given channel.
	Subscribe(ctx context.Context, channel string) (<-chan []byte, error)
}

CacheProvider is implemented by cache modules (cache-redis, cache-valkey, etc.) to provide ephemeral state, distributed locks, and pub/sub. Core defines the contract; modules provide the driver.

type CallPolicyProvider added in v0.4.0

type CallPolicyProvider interface {
	// AllowCall returns (true, nil) if caller is permitted to invoke method on target.
	// Returns (false, nil) if access is denied, or (false, error) if the policy engine
	// encountered an error (transient failure, configuration issue, etc.).
	AllowCall(ctx context.Context, callerModuleID, targetModuleID, method string) (bool, error)
}

CallPolicyProvider determines whether one module is allowed to call another. Implemented by modules that define inter-module access control. The mesh client consults this before dispatching calls.

SECURITY: When no CallPolicyProvider is registered, the mesh MUST deny all cross-module calls and return ErrCallNoPolicy. This is a change from the previous behavior where the default was open mode. Deployments that want open mode must register an explicit permissive policy provider.

Discovered via FindByCapability("call.policy"). Only one policy provider is consulted — if multiple register, the first found wins.

type ChainVerificationResult added in v0.4.0

type ChainVerificationResult struct {
	// Valid is true if the entire chain is intact with no broken links.
	Valid bool
	// TotalEntries is the number of entries in the verified range.
	TotalEntries int
	// BrokenLinks is the list of entry IDs where the PrevEntryHash does
	// not match the computed hash of the previous entry.
	BrokenLinks []string
	// FirstBrokenAt is the timestamp of the first detected break, or
	// the zero time if no breaks were found.
	FirstBrokenAt time.Time
}

ChainVerificationResult reports the outcome of a hash-chain integrity check.

type CircuitBreaker added in v0.4.0

type CircuitBreaker interface {
	// Execute runs fn within the circuit identified by key.
	// If the circuit is open, returns ErrCircuitOpen immediately.
	// If fn returns an error, the failure is recorded against the circuit.
	Execute(ctx context.Context, key string, fn func(context.Context) error) error

	// State returns the current state of the circuit identified by key.
	State(key string) CircuitState
}

CircuitBreaker protects downstream calls from cascading failures. When a downstream module degrades, the circuit opens and calls fail fast instead of waiting for timeouts. After a configurable cooldown (module-defined), the circuit transitions to half-open to test recovery.

Modules that call other modules via Mesh.Call() wrap those calls in Execute() to gain circuit breaking without implementing it themselves.

type CircuitState added in v0.4.0

type CircuitState string

CircuitState represents the current state of a circuit breaker.

const (
	// CircuitClosed — normal operation, requests flow through.
	CircuitClosed CircuitState = "closed"
	// CircuitOpen — failing, requests are rejected immediately with ErrCircuitOpen.
	CircuitOpen CircuitState = "open"
	// CircuitHalfOpen — testing if the downstream has recovered.
	// A single success transitions back to closed; a failure re-opens.
	CircuitHalfOpen CircuitState = "half_open"
)

type Cluster

type Cluster interface {
	// Start joins or forms a cluster. If no seed nodes are reachable,
	// the node starts a new single-node cluster.
	Start(ctx context.Context) error

	// Stop gracefully leaves the cluster.
	Stop(ctx context.Context) error

	// Members returns all current cluster members.
	Members() []NodeInfo

	// Leader returns the current leader, or nil if unknown.
	Leader() *NodeInfo

	// LocalNode returns information about this node.
	LocalNode() NodeInfo

	// Events returns a channel that emits cluster membership changes.
	Events() <-chan ClusterEvent

	// Health checks whether the cluster is operational.
	Health(ctx context.Context) error

	// FindNodesByLabel returns all nodes with the given label value.
	FindNodesByLabel(ctx context.Context, label, value string) []NodeInfo

	// FindNodesByModule returns all nodes running the given module.
	FindNodesByModule(ctx context.Context, moduleID string) []NodeInfo
}

Cluster manages node membership, leader election, and peer discovery.

type ClusterEvent

type ClusterEvent struct {
	Type     ClusterEventType
	Node     NodeInfo
	LeaderID string
}

ClusterEvent is emitted when cluster membership changes.

type ClusterEventType

type ClusterEventType string

ClusterEventType describes the kind of membership change.

const (
	ClusterNodeJoined    ClusterEventType = "node.joined"
	ClusterNodeLeft      ClusterEventType = "node.left"
	ClusterNodeDegraded  ClusterEventType = "node.degraded"
	ClusterLeaderChanged ClusterEventType = "leader.changed"
)

type ConfigWatcher added in v0.4.0

type ConfigWatcher interface {
	// OnChange registers a handler that fires when modules matching the
	// given capability string are added or removed. Returns a cancel
	// function to stop watching. The handler receives no arguments —
	// the module is expected to re-query the registry for current state.
	OnChange(ctx context.Context, capability string, handler func()) (cancel func())
}

ConfigWatcher notifies modules when infrastructure services change at runtime. Modules subscribe by capability string; when a new module registers or an existing one disappears, registered handlers fire.

Modules use this instead of polling the registry. Example:

watcher.OnChange(ctx, "secrets", func() {
    entries := reg.FindByCapability("secrets")
    if len(entries) > 0 {
        secrets = entries[0].Module.(contracts.SecretsProvider)
    }
})

ConfigWatcher is discovered via FindByCapability("config.watcher"). If no module implements it, modules fall back to polling or subscribe to module.registered/module.unregistered events directly.

type ContractDeclaration added in v0.4.0

type ContractDeclaration struct {
	Repo      string // Go module path of the contract package
	Version   string // semantic version tag (e.g. "v1.0.0")
	Interface string // Go interface name the module implements (e.g. "Downloader")
}

ContractDeclaration describes a typed contract that a module implements. Modules declare these in their Info() so consumers can verify compatibility before attempting type assertions. The marketplace uses these to detect incompatibilities between installed modules and prospective modules.

type Counter added in v0.4.0

type Counter interface {
	Inc()
	Add(delta float64)
}

Counter is a monotonically increasing metric.

type CredentialType added in v0.4.0

type CredentialType string

CredentialType enumerates well-known authentication schemes. Implementations MUST validate the type against this set to prevent credential-type confusion attacks (e.g., an attacker sending a password in a "token"-typed credential).

const (
	CredentialTypePassword CredentialType = "password"
	CredentialTypeToken    CredentialType = "token"
	CredentialTypeCert     CredentialType = "cert"
	CredentialTypeAPIKey   CredentialType = "api-key"
)

type Credentials added in v0.4.0

type Credentials struct {
	Type string
	Data []byte
}

Credentials carries authentication material to the AuthProvider. Type identifies the credential scheme and Data holds the opaque credential payload.

SECURITY: Implementations MUST NOT log the Data field. Callers MUST NOT include credentials in structured log fields, audit entries, or event payloads. Use the SecretsProvider contract to store and retrieve credentials instead of passing them through application code.

Backward-compat: Credentials.Type remains string (not CredentialType) so existing providers that use custom type strings continue to work. New implementations SHOULD validate against the CredentialType constants.

type DataRedactionProvider added in v0.4.0

type DataRedactionProvider interface {
	// Redact returns a new map with sensitive values replaced according
	// to the given rules. The input map is not modified. Rules are
	// provider-specific identifiers; the provider silently ignores
	// rules it doesn't recognize.
	Redact(ctx context.Context, data map[string]any, rules []string) (map[string]any, error)
}

DataRedactionProvider redacts sensitive data from structured payloads before they are logged, audited, or stored. This contract exists so modules never write PII (emails, IP addresses, tokens, personal data) to plaintext logs or audit trails.

Modules call Redact on any map[string]any before passing it to StructuredLogger, AuditLogger, or any persistent storage. The provider applies configured rules to replace sensitive values with redacted placeholders.

The rules parameter is an opaque list of rule identifiers that the provider interprets. Common patterns: field-name matching ("email", "password"), path expressions ("user.address.street"), regex patterns ("/\\d{3}-\\d{2}-\\d{4}/"), or category tags ("pii", "phi"). The provider documents which rule syntax it supports.

This contract is provider-agnostic: a module that calls Redact works identically whether the backend uses regex, field-name allowlists, an external DLP service, or a future redaction engine.

If no DataRedactionProvider is registered, Redact returns the input unchanged — modules degrade without nil checks but SHOULD document that redaction is inactive.

type DatabaseParams added in v0.4.0

type DatabaseParams struct {
	// Driver is the database driver name (e.g., "postgres", "sqlite3").
	Driver string
	// Host is the database server address (host:port or socket path).
	Host string
	// Database is the database name.
	Database string
	// User is the database username.
	User string
	// Password is the database password. Leave empty for passwordless auth.
	//
	// SECURITY: Never log this field. Fetch the password from
	// SecretsProvider at connection time rather than storing it in
	// application state.
	Password string
	// Extra carries driver-specific connection parameters (e.g., sslmode,
	// connect_timeout). These are appended to the DSN after the core params.
	// Keys and values in Extra must not contain credentials.
	Extra map[string]string
}

DatabaseParams separates connection parameters from credentials. Use this struct with OpenSecure instead of passing a raw connection string to Open. This prevents accidental credential exposure in logs, stack traces, and configuration serialization.

SECURITY: The Password field is a plain string — implementations MUST NOT log DatabaseParams or any field within it. If the database driver supports credential-free authentication (IAM, workload identity, certificate-based auth), prefer those methods and leave Password empty.

type DatabaseProvider

type DatabaseProvider interface {
	// Open initializes the database connection from a raw connection string.
	//
	// Deprecated: Use OpenSecure with DatabaseParams instead. Raw connection
	// strings often contain embedded credentials that are easily leaked in
	// logs and error messages. This method is retained for backward
	// compatibility with existing modules.
	Open(ctx context.Context, connString string) error

	// Close gracefully shuts down the database connection.
	Close(ctx context.Context) error
	// Health checks whether the database is reachable.
	Health(ctx context.Context) error
	// Exec runs a statement that modifies data (INSERT, UPDATE, DELETE, DDL).
	//
	// SECURITY: Callers MUST use parameterized queries. Never concatenate
	// user input into the query string. The args ...any parameter supports
	// standard SQL placeholders ($1, ?, :name). Consider using
	// InputValidator with "sql:<param-count>" schema for additional
	// injection protection.
	Exec(ctx context.Context, query string, args ...any) (int64, error)
	// Query runs a read query and returns a row iterator.
	//
	// SECURITY: Same parameterization requirement as Exec. All user
	// input MUST be passed via args, never interpolated into query.
	Query(ctx context.Context, query string, args ...any) (Rows, error)
	// Transaction runs fn inside a database transaction, committing on success and rolling back on error.
	Transaction(ctx context.Context, fn func(Tx) error) error
	// Migrate applies ordered schema migrations. Implementations track which migrations
	// have already been applied and skip those.
	//
	// SECURITY: Migration SQL (Up/Down strings) is trusted schema code.
	// Implementations SHOULD verify migration content against a known
	// checksum or signature before execution when operating in production.
	Migrate(ctx context.Context, migrations []Migration) error
}

DatabaseProvider is implemented by database modules (database-postgres, database-sqlite, etc.) to provide persistent storage for modules. Core defines the contract; modules provide the driver.

type DeadLetterEntry added in v0.4.0

type DeadLetterEntry struct {
	Event       Event
	HandlerName string
	Error       string
	FailedAt    time.Time
	RetryCount  int
}

DeadLetterEntry stores a failed event with its error context.

type DeadLetterProvider added in v0.4.0

type DeadLetterProvider interface {
	// Store records a failed event delivery. Called by the event bus
	// or by modules that want explicit dead-letter handling.
	Store(ctx context.Context, event Event, handlerName string, err error) error

	// Replay returns failed events for the given handler since the given time.
	// Sorted by FailedAt ascending.
	Replay(ctx context.Context, handlerName string, since time.Time) ([]DeadLetterEntry, error)

	// Discard removes a failed event from the dead letter store after
	// the issue has been resolved.
	Discard(ctx context.Context, eventID string) error
}

DeadLetterProvider stores events that failed to process so they can be inspected, replayed, or discarded. Modules that handle critical events (workflow steps, downloads, imports) can configure a dead letter provider to prevent silent data loss when a handler transiently fails.

DeadLetterProvider is discovered via FindByCapability("deadletter"). If no module implements it, failed events are logged and dropped.

type DistributedLockHandle added in v0.4.0

type DistributedLockHandle interface {
	// Unlock releases the lock. Safe to call multiple times.
	Unlock(ctx context.Context) error

	// Renew extends the lock's TTL without releasing and re-acquiring.
	// Useful for long-running operations where the initial TTL would expire
	// before completion. Returns ErrLockHeld if the lock was lost (e.g.,
	// network partition caused the backend to expire it).
	Renew(ctx context.Context, ttl time.Duration) error
}

DistributedLockHandle represents an acquired distributed lock. Callers must call Unlock when done, or Renew to extend the lease for long-running operations.

type DistributedLockProvider added in v0.4.0

type DistributedLockProvider interface {
	// Acquire attempts to acquire a lock for the given key with a TTL.
	// Returns (nil, ErrLockHeld) if the key is already locked.
	// Returns (nil, ctx.Err()) if the context is cancelled before acquisition.
	// The returned handle must be Unlock()ed when the critical section completes.
	Acquire(ctx context.Context, key string, ttl time.Duration) (DistributedLockHandle, error)
}

DistributedLockProvider provides standalone distributed locking. This is distinct from CacheProvider.Lock which ties locking to a cache instance. Modules that need coordination (leader election, singleton workers, migration gating, split-brain fencing) use this contract without needing to stand up a cache.

This contract is provider-agnostic: a module that calls Acquire works identically whether the backend is Redis, etcd, Consul, Postgres advisory locks, or a future coordination service.

Acquire is non-blocking by design. If the lock is held, it returns ErrLockHeld immediately. Callers that want blocking behavior compose this with RetryProvider.Execute.

If no DistributedLockProvider is registered, Acquire always succeeds (single-node mode) — modules degrade gracefully without nil checks.

type EncryptionProvider added in v0.4.0

type EncryptionProvider interface {
	// Encrypt encrypts plaintext and returns self-describing ciphertext.
	// The returned bytes include key version metadata so Decrypt can
	// identify the correct key even after rotation.
	Encrypt(ctx context.Context, plaintext []byte) ([]byte, error)

	// Decrypt decrypts ciphertext that was produced by Encrypt.
	// The provider reads key metadata from the ciphertext to select
	// the correct decryption key, including keys from previous rotations.
	Decrypt(ctx context.Context, ciphertext []byte) ([]byte, error)

	// RotateKey initiates key rotation. After rotation, new Encrypt calls
	// use the new key. Old keys remain available for Decrypt indefinitely —
	// previously encrypted data does not need re-encryption.
	//
	// SECURITY: Implementations that do NOT support rotation (static-key
	// implementations) MUST return an error from this method. Production
	// deployments SHOULD use a provider that supports rotation.
	RotateKey(ctx context.Context) error

	// Available reports whether encryption is configured and operational.
	// Returns false if no provider is registered or the provider is in a
	// degraded state. The fabric SHOULD use this to enforce encryption
	// requirements at startup.
	Available() bool
}

EncryptionProvider handles envelope encryption for sensitive data at rest. Modules call Encrypt before storing sensitive data and Decrypt after retrieving it. The provider manages key material, rotation, and versioning internally — modules never touch raw keys.

The ciphertext produced by Encrypt is self-describing: it carries key metadata so Decrypt can identify which key was used, even after rotation.

This contract is provider-agnostic: a module that calls Encrypt/Decrypt works identically whether the backend uses AES-GCM with local keys, a cloud KMS (AWS KMS, GCP KMS), HashiCorp Vault transit engine, or a future encryption service. The security posture is determined by the provider implementation, not by module code.

SECURITY: Production deployments MUST register an EncryptionProvider. If no EncryptionProvider is registered, the fabric SHOULD refuse to start in production mode. Development and CI environments may operate without encryption. Use the Available() method to check at runtime.

type Event

type Event struct {
	ID        string
	Type      string
	Source    string
	TraceID   string
	Payload   []byte
	Metadata  map[string]string
	Timestamp time.Time
}

Event is the envelope for all inter-module communication. Type is a dotted string like "module.registered" or "media.requested". Event type constants and payload schemas are defined by contract repos, not by core. Core only defines the module-lifecycle event types (below). Cluster-lifecycle events are defined in cluster.go.

type EventBus

type EventBus interface {
	Publish(ctx context.Context, event Event) error
	Subscribe(ctx context.Context, eventType string, handler EventHandler) error
	Unsubscribe(ctx context.Context, eventType string, handler EventHandler) error
	// Request publishes an event and waits for a reply on event.Type + ".reply".
	Request(ctx context.Context, event Event, timeout time.Duration) (Event, error)

	// SubscribeModule registers a handler tagged with a module identifier.
	// This enables UnsubscribeAll for clean module lifecycle management —
	// when a module shuts down, all its subscriptions are removed at once.
	SubscribeModule(ctx context.Context, moduleID, eventType string, handler EventHandler) error

	// UnsubscribeAll removes all subscriptions tagged with the given module ID.
	// If moduleID is empty, this is a no-op. Used by module lifecycle management
	// during shutdown to prevent handlers from receiving events after the
	// module has stopped.
	UnsubscribeAll(ctx context.Context, moduleID string) error
}

EventBus is the core message bus. All module communication flows through it.

type EventHandler

type EventHandler func(ctx context.Context, event Event) error

EventHandler is a callback invoked when a matching event is published.

type EventStore added in v0.4.0

type EventStore interface {
	// Append writes events to a stream and returns their assigned sequence
	// numbers. Events in a single Append call are atomic — either all
	// are written or none are. Returns the starting sequence number for
	// the batch and an error if the write fails.
	//
	// The first event in a new stream gets sequence 1.
	Append(ctx context.Context, stream string, events []Event) (firstSequence int64, err error)

	// Read returns events from a stream starting at fromSequence (inclusive).
	// limit caps the number of events returned. Pass 0 for no limit
	// (provider default). Returns events in ascending sequence order.
	// Returns an empty slice if fromSequence is beyond the stream end.
	Read(ctx context.Context, stream string, fromSequence int64, limit int) ([]EventStoreEntry, error)

	// Subscribe returns a channel that receives new events appended to
	// the stream starting from fromSequence. The channel closes when ctx
	// is cancelled. Events are delivered in sequence order.
	//
	// To catch up on existing events before live ones, call Read first
	// to get historical events, then Subscribe from the last sequence + 1.
	Subscribe(ctx context.Context, stream string, fromSequence int64) (<-chan EventStoreEntry, error)

	// Streams returns the names of all known streams.
	Streams(ctx context.Context) ([]string, error)
}

EventStore provides a durable, append-only event log. This is distinct from EventBus which handles fire-and-forget pub/sub. EventStore is for event sourcing: state is reconstructed by replaying all events in a stream from the beginning.

Streams are logical partitions — typically one per aggregate or entity type ("user-abc123", "order-456", "module.metrics"). Append guarantees that events within a stream are ordered by sequence number.

This contract is provider-agnostic: a module that calls Append/Read works identically whether the backend is PostgreSQL, Kafka, NATS JetStream, an in-memory log, or a future event store.

If no EventStore is registered, Append is a no-op (returns nil sequence) and Read/Subscribe return empty — modules that only need pub/sub use EventBus; modules that need event sourcing require an EventStore.

type EventStoreEntry added in v0.4.0

type EventStoreEntry struct {
	// Stream is the logical partition this event belongs to.
	Stream string

	// Sequence is the monotonically increasing position within the stream.
	// The first event in a stream has sequence 1.
	Sequence int64

	// Event is the stored event with type, source, payload, and metadata.
	Event Event

	// StoredAt is when the event was appended to the store.
	StoredAt time.Time

	// Extra carries provider-specific extensions (e.g., partition info,
	// checksum, storage tier).
	Extra map[string]any
}

EventStoreEntry is a persisted event with its stream position.

type Executor

type Executor interface {
	CanHandle(taskType string) bool
	Execute(ctx context.Context, task WorkerTask) (result []byte, err error)
}

Executor is implemented by modules that can run tasks of a given type.

type Fabric added in v0.4.0

type Fabric struct {
	Registry   Registry
	EventBus   EventBus
	Routes     RouteRegistrar
	Cluster    Cluster
	Storage    StorageOrchestrator
	WorkerPool WorkerPool
	Audit      AuditLogger
	Mesh       ModuleMeshClient
}

Fabric provides modules with the core fabric services they need during construction. Domain-specific services (SecretsProvider, DatabaseProvider, etc.) are discovered at runtime via the Registry — they are not pre-wired here.

type FeatureFlagProvider added in v0.4.0

type FeatureFlagProvider interface {
	// IsEnabled checks whether a feature flag is enabled for the caller
	// in the given context. The context carries identity for percentage-based
	// rollouts and targeting rules. defaultValue is returned when no provider
	// is registered or the flag is not defined.
	IsEnabled(ctx context.Context, flag string, defaultValue bool) bool

	// GetVariant returns the assigned variant for a multivariate flag.
	// Useful for A/B testing where a flag has more than two states.
	// defaultValue is returned when no provider is registered or the
	// flag is not defined.
	GetVariant(ctx context.Context, flag string, defaultValue string) string
}

FeatureFlagProvider evaluates feature flags for gradual rollouts, kill switches, and A/B testing. Modules call IsEnabled before activating new code paths; the provider evaluates the flag against the caller's identity (via context) and any configured rules.

This contract is provider-agnostic: a module that calls IsEnabled works identically whether the backend is a config file, LaunchDarkly, a database table, or a future feature flag service.

If no FeatureFlagProvider is registered, IsEnabled returns defaultValue and GetVariant returns defaultValue — modules degrade gracefully without nil checks.

type Gauge added in v0.4.0

type Gauge interface {
	Set(value float64)
	Inc()
	Dec()
	Add(delta float64)
}

Gauge is a metric that can increase and decrease.

type Hardlinkable

type Hardlinkable interface {
	Hardlink(ctx context.Context, src, dst string) error
}

type HealthMonitor added in v0.1.1

type HealthMonitor interface {
	// StartMonitoring begins periodic health checking. The monitor calls Health()
	// on every registered module at the configured interval and publishes
	// events on the bus for any degraded modules.
	StartMonitoring(ctx context.Context, reg Registry, bus EventBus) error

	// Stop gracefully stops the health monitor.
	Stop(ctx context.Context) error
}

HealthMonitor runs periodic health checks on all registered modules and publishes module.degraded events for unhealthy modules. Core starts the HealthMonitor at bootstrap if one is discovered from the registry. If no module implements this contract, periodic health monitoring is skipped (modules still report via /health endpoint).

type Histogram added in v0.4.0

type Histogram interface {
	Observe(value float64)
}

Histogram observes values and tracks distribution.

type IdempotencyProvider added in v0.4.0

type IdempotencyProvider interface {
	// Store records that a key has been processed and caches the result.
	// Returns (true, nil) if the key was new — this is the first occurrence.
	// Returns (false, nil) if the key was already stored — this is a duplicate.
	// The result is cached for ttl; after expiry the key may be evicted.
	Store(ctx context.Context, key string, result []byte, ttl time.Duration) (bool, error)

	// Exists checks whether a key has been previously stored and not yet expired.
	// Returns true if the key exists, false otherwise.
	Exists(ctx context.Context, key string) (bool, error)

	// Result retrieves the cached result for a previously stored key.
	// Returns (nil, nil) if the key does not exist or has expired.
	// This allows a duplicate request to receive the same response
	// as the original without re-executing the operation.
	Result(ctx context.Context, key string) ([]byte, error)
}

IdempotencyProvider prevents duplicate processing of requests. When a module receives a request that must not be processed more than once (e.g., payment capture, order creation), it generates an idempotency key and checks this provider before acting.

This contract is provider-agnostic: a module that calls Store/Exists works identically whether the backend is in-memory, Redis, a database table, or a future storage mechanism.

If no IdempotencyProvider is registered, Store always returns true (treated as first occurrence) and Exists always returns false — modules degrade gracefully without needing nil checks.

This contract pairs with RetryProvider. Retries may deliver the same logical request multiple times; IdempotencyProvider ensures the side effects only happen once.

type Identity added in v0.4.0

type Identity struct {
	// ID is the unique identifier for this caller (user ID, service account ID).
	ID string

	// Kind describes the type of identity (e.g., "user", "service", "api-key").
	Kind string

	// Roles are the authorization roles assigned to this identity.
	Roles []string

	// Claims carries provider-specific claims extracted from the auth token.
	// For JWT this is the decoded payload. For API keys this may be scopes.
	//
	// SECURITY: May contain sensitive data. Redact before logging.
	Claims map[string]any

	// Extra carries provider-specific extensions that consumers can interpret.
	//
	// SECURITY: May contain sensitive data. Redact before logging.
	Extra map[string]any
}

Identity represents the caller extracted from an authentication context. Fields are intentionally broad — the identity provider populates whatever it can determine, and downstream consumers interpret what they understand.

SECURITY: Claims and Extra carry provider-specific data that may include sensitive information from auth tokens (JWT payloads, API key metadata). These fields MUST be treated as potentially sensitive:

  • NEVER serialize a full Identity to logs without redaction.
  • NEVER include Identity in event payloads unless the event is explicitly an auth/identity event with access controls.
  • Use SafeInfo() when passing identity data to subsystems that do not need provider-specific claims.

The SafeInfo method strips Claims and Extra, retaining only the typed fields that Authorizer needs for permission checks.

func (Identity) SafeInfo added in v0.4.0

func (id Identity) SafeInfo() Identity

SafeInfo returns a copy of the Identity with Claims and Extra stripped. Use this when passing identity to subsystems that do not need provider-specific data (logging, metrics, events, workflows).

type IdentityProvider added in v0.4.0

type IdentityProvider interface {
	// ExtractIdentity extracts the caller identity from the given context.
	// Returns (nil, nil) if no identity is present (unauthenticated request).
	// Returns an error only if identity extraction itself fails (e.g., invalid
	// token format), not if the request is simply unauthenticated.
	ExtractIdentity(ctx context.Context) (*Identity, error)
}

IdentityProvider extracts caller identity from context. Modules call this to determine who is making a request before passing that identity to the Authorizer for permission checks.

This contract is provider-agnostic: a module that calls ExtractIdentity works identically whether the backend is JWT validation, API key lookup, mTLS certificate extraction, or a future protocol.

SECURITY: When no IdentityProvider is registered, the system MUST apply a deny-by-default access policy. Anonymous access (no identity) should only be permitted for explicitly public endpoints. The fabric should refuse to start in production mode without an IdentityProvider — see EnforcedIdentityProvider.

Discovered via FindByCapability("identity"). If no module implements this contract, the fabric treats all requests as unauthenticated (nil identity). Modules MUST check for nil identity and apply their own access policy. The recommended safe default is to deny access when identity is nil unless the endpoint is explicitly marked as public.

type InfrastructureAware added in v0.4.0

type InfrastructureAware interface {
	SetInfrastructure(cluster Cluster, workerPool WorkerPool, audit AuditLogger)
}

InfrastructureAware is implemented by modules that need late-bound infrastructure services (Cluster, WorkerPool, AuditLogger).

type InputValidator added in v0.4.0

type InputValidator interface {
	// Validate checks the given data against the named schema and returns
	// a result indicating pass/fail plus any sanitized output.
	//
	// The schema parameter follows the conventions above. If the schema is
	// not recognised, implementations should return a ValidationResult with
	// Valid=false and an error entry explaining the unknown schema, rather
	// than returning an error — this allows callers to fall back gracefully.
	//
	// SECURITY: The schema string MUST be validated before use (see type docs).
	Validate(ctx context.Context, data []byte, schema string) (ValidationResult, error)

	// SupportedSchemas returns the list of schema identifiers this validator
	// can handle. Used for capability discovery so callers can determine at
	// registration time whether a validator meets their needs.
	SupportedSchemas() []string
}

InputValidator performs centralized input validation for the MuxCore fabric. Modules implement this contract to provide schema-aware validation that other modules can delegate to, rather than duplicating validation logic.

Schema conventions:

"json:<schema-name>"   — JSON Schema validation (e.g., "json:user-create")
"regex:<pattern>"      — Regex-based validation (e.g., "regex:^[a-z]+$")
"sql:<param-count>"    — SQL injection-safe parameter binding (e.g., "sql:3")

SECURITY: The schema parameter is caller-controlled. Implementations MUST:

  • Validate the schema string format before interpretation.
  • Reject schemas with path-traversal characters (../, /, etc.) to prevent access to unintended schema files or namespaces.
  • Apply a limit on schema name length to prevent resource exhaustion.
  • Never treat the schema string as a file path without sanitization.

Schema names should match the pattern: ^[a-z][a-z0-9_.:-]{0,127}$

Modules discover registered validators via the registry and call SupportedSchemas() to check which schemas are available before calling Validate. If no InputValidator is registered, modules handle validation themselves (degrade gracefully).

Discovered via FindByCapability("input.validate"). If multiple validators register, the first found is consulted. Validators may internally delegate to other validators for schemas they do not support.

type LeaderChangedPayload

type LeaderChangedPayload struct {
	PreviousLeader string `json:"previous_leader"`
	NewLeader      string `json:"new_leader"`
}

LeaderChangedPayload is the payload for cluster.leader.changed events.

type LockHandle

type LockHandle interface {
	// Unlock releases the lock.
	Unlock(ctx context.Context) error
}

LockHandle represents an acquired distributed lock.

type LogLevel added in v0.4.0

type LogLevel string

LogLevel describes the severity of a log message.

const (
	LogLevelDebug LogLevel = "debug"
	LogLevelInfo  LogLevel = "info"
	LogLevelWarn  LogLevel = "warn"
	LogLevelError LogLevel = "error"
)

type MeshHandler added in v0.3.0

type MeshHandler interface {
	// HandleCall processes a cross-module method invocation.
	// method is an arbitrary string the caller and handler agree on.
	// payload is the JSON-encoded request body.
	// Returns the JSON-encoded response or an error.
	HandleCall(ctx context.Context, method string, payload []byte) ([]byte, error)
}

MeshHandler is implemented by modules that want to receive cross-module gRPC calls. The mesh server routes incoming Call(targetModule, method, payload) requests to the target module's HandleCall method.

Modules register themselves as handlers during Start():

deps.Mesh.RegisterHandler("my-module", myHandler)

type MetricsProvider added in v0.4.0

type MetricsProvider interface {
	// Counter creates or returns a counter with the given name and labels.
	Counter(name string, labels map[string]string) Counter
	// Gauge creates or returns a gauge with the given name and labels.
	Gauge(name string, labels map[string]string) Gauge
	// Histogram creates or returns a histogram with the given name, labels, and buckets.
	Histogram(name string, labels map[string]string, buckets []float64) Histogram
}

MetricsProvider exposes application metrics. Modules implement this to provide Prometheus, Datadog, or other metrics backends. Modules that want to expose metrics call these methods to register and update metrics. If no MetricsProvider is registered, metric calls are no-ops.

type Migration

type Migration struct {
	Version int
	Name    string
	Up      string // SQL to apply
	// Down is SQL to roll back.
	// RESERVED — DatabaseProvider.Migrate does not yet support rollback;
	// will be wired when Rollback is added.
	Down string
}

Migration represents a versioned schema migration.

type Module

type Module interface {
	Info() ModuleInfo
	Init(ctx context.Context) error
	Start(ctx context.Context) error
	Stop(ctx context.Context) error
	Health(ctx context.Context) error
}

func LoadRegistered deprecated

func LoadRegistered(deps Fabric) []Module

Deprecated: Use gRPC sidecar registration instead.

type ModuleDegradedPayload

type ModuleDegradedPayload struct {
	ModuleID string `json:"module_id"`
	Error    string `json:"error"`
}

ModuleDegradedPayload is the payload for module.degraded events.

type ModuleEntry

type ModuleEntry struct {
	Info   ModuleInfo
	State  ModuleState
	Module Module
}

type ModuleFactory

type ModuleFactory func(deps Fabric) Module

type ModuleInfo

type ModuleInfo struct {
	ID           string
	Name         string
	Version      string
	Roles        []string // module-defined role strings; core imposes no taxonomy
	Description  string
	Author       string
	Capabilities []string              // granular capability strings for routing/discovery
	Contracts    []ContractDeclaration // typed contracts this module implements
	DependsOn    []string              // module IDs that must be initialized before this module starts. Cycles detected by Registry.StartupOrder().
	// MinCoreVersion is the minimum core version required by this module.
	// Uses SemVer (e.g., "1.2.0"). Empty means compatible with any version.
	// Core rejects modules whose MinCoreVersion is greater than the running
	// core version or targets a different major version.
	MinCoreVersion string
}

type ModuleKind

type ModuleKind string

ModuleKind is a user-defined string that categorizes a module's role. Core has no opinion about what kinds exist — modules and consumers define them. Common conventions (defined in contract repos, not here): "auth", "downloader", "indexer", "media_manager", "playback", "storage", "workflow", "transcoder". The WorkflowEngine is discovered via "workflow.engine".

type ModuleMeshClient added in v0.3.0

type ModuleMeshClient interface {
	// Call invokes a method on the target module. If the target is registered
	// locally, the call is dispatched in-process with zero network overhead.
	// If the target is on a remote node, the call goes over gRPC.
	Call(ctx context.Context, targetModule, method string, payload []byte) ([]byte, error)

	// RegisterHandler registers a local module to receive incoming Call requests.
	// Only call this during module Start(). Modules that don't receive calls
	// don't need to register.
	RegisterHandler(moduleID string, handler MeshHandler)
}

ModuleMeshClient is the interface modules use to call other modules. It abstracts whether the target is local (in-process) or remote (gRPC network call). Modules receive this via Fabric.Mesh.

type ModuleRegisteredPayload

type ModuleRegisteredPayload struct {
	ModuleID string `json:"module_id"`
	Version  string `json:"version"`
}

ModuleRegisteredPayload is the payload for module.registered events.

type ModuleState

type ModuleState string
const (
	ModuleStateRegistered ModuleState = "registered"
	ModuleStateStarting   ModuleState = "starting"
	ModuleStateRunning    ModuleState = "running"
	ModuleStateDegraded   ModuleState = "degraded"
	ModuleStateStopping   ModuleState = "stopping"
	ModuleStateStopped    ModuleState = "stopped"
)

type ModuleUnregisteredPayload

type ModuleUnregisteredPayload struct {
	ModuleID string `json:"module_id"`
}

ModuleUnregisteredPayload is the payload for module.unregistered events.

type NodeInfo

type NodeInfo struct {
	ID        string
	GRPCAddr  string
	HTTPAddr  string
	Labels    map[string]string
	ModuleIDs []string
}

NodeInfo describes a node in the cluster.

type NodeJoinedPayload

type NodeJoinedPayload struct {
	NodeID   string `json:"node_id"`
	GRPCAddr string `json:"grpc_addr"`
	HTTPAddr string `json:"http_addr"`
}

NodeJoinedPayload is the payload for cluster.node.joined events.

type NodeLeftPayload

type NodeLeftPayload struct {
	NodeID string `json:"node_id"`
}

NodeLeftPayload is the payload for cluster.node.left events.

type ObjectInfo

type ObjectInfo struct {
	Key          string
	Size         int64
	ContentType  string
	ETag         string
	LastModified time.Time
	Metadata     map[string]string
}

type Permission added in v0.4.0

type Permission string

Permission represents a named permission in the authorization system. The string format is "<domain>.<verb>" or "<domain>.<resource>.<verb>", e.g. "storage.read", "media.movies.delete", "admin.*".

Wildcard support:

  • "*" matches all permissions (superuser)
  • "domain.*" matches all permissions within a domain
  • "domain.resource.*" matches all permissions on a specific resource

type PublishPolicyProvider added in v0.4.0

type PublishPolicyProvider interface {
	// CanPublish returns (true, nil) if the caller is permitted to publish
	// events of the given type. Returns (false, nil) if publishing is denied.
	CanPublish(ctx context.Context, callerID, eventType string) (bool, error)
}

PublishPolicyProvider determines whether a caller is authorized to publish events of a given type. Implemented by modules that define event-level access control. The event bus consults this before dispatching.

SECURITY: When no PublishPolicyProvider is registered, the event bus MUST deny all event publication. This is a change from the previous behavior where the default was open mode. Deployments that want open mode must register an explicit permissive policy provider.

For resource-level event authorization, implement the optional ResourcePublishPolicyProvider interface. The event bus will type-assert and use the richer interface when available.

type RateLimiterProvider added in v0.1.1

type RateLimiterProvider interface {
	// Allow checks whether a request from the given key (typically IP) is allowed.
	// Returns true if the request should proceed, false if it should be rate-limited.
	Allow(ctx context.Context, key string) bool

	// Enabled returns whether rate limiting is active.
	Enabled() bool
}

RateLimiterProvider is implemented by rate limiter modules (ratelimit-tokenbucket, etc.) to provide request rate limiting to the API server middleware chain. Core discovers a RateLimiterProvider at bootstrap and injects it into the middleware. If no module implements this contract, rate limiting is disabled (open mode).

type RedactingLogger added in v0.4.0

type RedactingLogger interface {
	StructuredLogger

	// IsRedacting reports whether this logger automatically applies
	// redaction to all fields before writing to sinks.
	IsRedacting() bool
}

RedactingLogger is an optional extension that guarantees all log output is redacted. Implementations that embed automatic redaction can declare this interface so that callers can skip manual redaction.

Modules MAY type-assert their StructuredLogger to RedactingLogger to determine if manual redaction is necessary.

type Registry added in v0.4.0

type Registry interface {
	FindByRole(role string) []ModuleEntry
	FindByCapability(cap string) []ModuleEntry
	SupportsCapability(moduleID, cap string) bool
	Resolve(id string) (ModuleEntry, error)
	ListAll() []ModuleEntry

	// StartupOrder returns module IDs in dependency-respecting order.
	// Modules listed in DependsOn appear before the module that depends on them.
	// Returns an error if a dependency cycle is detected.
	StartupOrder() ([]string, error)

	// DependencyGraph returns modules that list the given ID in their DependsOn.
	// Useful for understanding the impact of stopping or removing a module.
	DependencyGraph(id string) ([]string, error)
}

Registry provides runtime discovery of registered modules.

type ResourceAuthorizer added in v0.4.0

type ResourceAuthorizer interface {
	Authorizer

	// CanWithResource performs a permission check with resource context.
	// The resource descriptor enables hierarchical checks, ABAC policies,
	// and resource-ownership gating. When ResourceDescriptor.ID is empty,
	// the check is scoped to the resource type.
	CanWithResource(ctx context.Context, session Session, action Action, resource ResourceDescriptor) (bool, error)
}

ResourceAuthorizer is an optional extension to Authorizer that enables resource-level permission checks with ABAC support. Implement this alongside Authorizer when your policy engine supports hierarchical resource permissions.

Callers that need resource-level authorization type-assert to this interface and fall back to Authorizer.Can() if not supported.

type ResourceDescriptor added in v0.4.0

type ResourceDescriptor struct {
	// Type is the resource kind, e.g. "media", "storage", "module".
	Type string
	// ID is the resource identifier, e.g. a UUID or key path.
	// Empty means the check is at the resource-type level.
	ID string
	// Attributes carries additional resource properties that
	// policy engines can use for ABAC decisions (owner, labels, tier).
	// MUST NOT contain credentials or PII.
	Attributes map[string]string
}

ResourceDescriptor carries the resource identifier and optional attributes for attribute-based access decisions.

type ResourcePublishPolicyProvider added in v0.4.0

type ResourcePublishPolicyProvider interface {
	PublishPolicyProvider

	// CanPublishEvent performs event-level authorization with access to
	// the full event payload. This enables resource-level checks beyond
	// the type-level check in CanPublish.
	CanPublishEvent(ctx context.Context, callerID string, event Event) (bool, error)
}

ResourcePublishPolicyProvider is an optional extension that enables resource-level event authorization with access to the full event payload. Implement this alongside PublishPolicyProvider to enable checks like "can this caller publish media.updated events for media item X?".

When a provider implements this interface, the event bus calls CanPublishEvent before CanPublish, giving the provider full event context.

type RetryPolicy added in v0.4.0

type RetryPolicy struct {
	// MaxAttempts is the maximum number of attempts, including the first.
	// A value of 0 means the provider's default (typically 3).
	MaxAttempts int

	// InitialDelay is the delay before the first retry.
	// A value of 0 means the provider's default (typically 100ms).
	InitialDelay time.Duration

	// MaxDelay is the maximum delay between retries. The backoff caps at this.
	// A value of 0 means no cap (provider default).
	MaxDelay time.Duration

	// BackoffFactor is multiplied against the delay on each retry.
	// Typical values: 2.0 (exponential), 1.0 (fixed delay).
	// A value of 0 means the provider's default (typically 2.0).
	BackoffFactor float64

	// Jitter, when true, adds random jitter to the delay to avoid thundering herd.
	Jitter bool

	// Extra carries provider-specific extensions.
	Extra map[string]any
}

RetryPolicy configures how a RetryProvider retries failed operations. Zero values mean "use the provider's default."

type RetryProvider added in v0.4.0

type RetryProvider interface {
	// Execute runs fn with retry semantics based on the given policy.
	// Returns nil if fn succeeds on any attempt. Returns the last error
	// if all attempts are exhausted. The context is passed to each attempt;
	// if ctx is cancelled, retries stop immediately.
	Execute(ctx context.Context, policy RetryPolicy, fn func(ctx context.Context) error) error
}

RetryProvider executes operations with configurable retry semantics. This contract is provider-agnostic: a module that wraps a call in RetryProvider.Execute works identically whether the backend uses simple backoff, exponential backoff with jitter, or a future retry strategy.

RetryProvider is complementary to CircuitBreaker. CircuitBreaker prevents cascading failures by opening the circuit when errors exceed a threshold. RetryProvider handles transient failures (network blips, temporary unavailability) by retrying individual calls with backoff. A robust module uses both.

If no RetryProvider is registered, Execute runs fn exactly once with no retries — modules don't need nil checks.

type RouteRegistrar

type RouteRegistrar interface {
	Handle(pattern string, handler http.Handler)
	HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
}

type Rows

type Rows interface {
	Next() bool
	Scan(dest ...any) error
	Close() error
}

Rows is an iterator over query result rows.

type Scheduler

type Scheduler interface {
	Schedule(ctx context.Context, task SchedulerTask) (string, error)
	Cancel(ctx context.Context, taskID string) error
	Status(ctx context.Context, taskID string) (SchedulerTaskStatus, error)
}

Scheduler is implemented by scheduler modules (scheduler-cron, etc.) to provide task scheduling. Core defines the contract; modules provide the driver.

type SchedulerTask added in v0.4.0

type SchedulerTask struct {
	ID       string
	Name     string
	CronExpr string
	Payload  []byte
	Timeout  time.Duration
	Meta     map[string]any
}

SchedulerTask is a unit of scheduled work. Payload carries the task data. Meta carries scheduler-specific or task-type-specific context that the scheduler module can interpret.

type SchedulerTaskStatus added in v0.4.0

type SchedulerTaskStatus string

SchedulerTaskStatus represents the lifecycle of a scheduled task.

const (
	SchedulerTaskScheduled SchedulerTaskStatus = "scheduled"
	SchedulerTaskRunning   SchedulerTaskStatus = "running"
	SchedulerTaskCompleted SchedulerTaskStatus = "completed"
	SchedulerTaskFailed    SchedulerTaskStatus = "failed"
	SchedulerTaskCancelled SchedulerTaskStatus = "cancelled"
)

type SecretsProvider added in v0.4.0

type SecretsProvider interface {
	// Get retrieves a secret by key. Returns an error if not found.
	Get(ctx context.Context, key string) (string, error)
	// Set stores a secret. Implementations may be read-only (e.g., env-backed)
	// and return an error for Set calls.
	Set(ctx context.Context, key, value string) error
	// Delete removes a secret. May not be supported by all backends.
	Delete(ctx context.Context, key string) error
	// List returns all known keys. Values are NOT included — only key names.
	List(ctx context.Context) ([]string, error)
}

SecretsProvider manages sensitive configuration values (API keys, tokens, passwords). Modules implement this to back secrets from environment variables, HashiCorp Vault, encrypted files, or external secret managers.

This contract exists so modules never read raw env vars for credentials. A module that needs a Jackett API key calls deps.Secrets.Get("jackett_api_key") instead of os.Getenv("JACKETT_API_KEY"). This enables audit logging, rotation, and centralized secret management without changing module code.

type SecureDatabaseProvider added in v0.4.0

type SecureDatabaseProvider interface {
	DatabaseProvider

	// OpenSecure initializes the database connection using separated
	// connection parameters. This isolates credentials from connection
	// metadata, reducing the risk of accidental credential exposure.
	//
	// Implementations SHOULD return ErrDatabaseCredentialExposure if
	// the caller attempts to embed credentials in Extra.
	OpenSecure(ctx context.Context, params DatabaseParams) error
}

SecureDatabaseProvider is an optional extension that enables credential-safe database initialization via separated DatabaseParams. Implement this alongside DatabaseProvider when your database module supports parameter-based connection.

Callers SHOULD type-assert DatabaseProvider to SecureDatabaseProvider and use OpenSecure instead of Open to prevent credential leakage through connection strings.

type Seekable

type Seekable interface {
	Seek(ctx context.Context, key string, offset int64) (int64, error)
}

type SerializationProvider added in v0.4.0

type SerializationProvider interface {
	// Marshal serializes v to bytes using the specified content type.
	// Common content types: "application/json", "application/x-protobuf",
	// "application/msgpack".
	Marshal(contentType string, v any) ([]byte, error)

	// Unmarshal deserializes data into v using the specified content type.
	// v must be a pointer to a concrete target type.
	//
	// SECURITY: The content type and data originate from untrusted sources
	// (the wire or another module). Implementations MUST validate the
	// content type against a safelist before deserializing.
	Unmarshal(contentType string, data []byte, v any) error

	// SupportedTypes returns the content types this provider can handle.
	// Callers can negotiate format by intersecting their needs with this list.
	//
	// SECURITY: The returned list MUST only include types that have been
	// vetted for safe deserialization. See SafeSerializationTypes above.
	SupportedTypes() []string
}

SerializationProvider handles marshaling and unmarshaling of data with content-type negotiation. Modules use this to serialize/deserialize payloads without knowing which format the other side expects.

A module producing protobuf can call Marshal("application/json", v) and the provider handles the conversion. A module consuming JSON can call Unmarshal(contentType, data, v) regardless of the wire format.

This contract is provider-agnostic: a module that calls Marshal/Unmarshal works identically whether the backend uses encoding/json + protobuf, msgpack, or a future serialization format.

SECURITY: Unmarshal deserializes untrusted data into an arbitrary target type. Implementations MUST:

  • Reject content types that support code execution (YAML v1, gob, etc.) unless sandboxed with strict decoding modes.
  • Enforce type safety — the target 'v' must be a concrete Go type, and the implementation must not instantiate types based on the serialized payload's type hints (no polymorphic deserialization).
  • Reject payloads that exceed a reasonable size limit to prevent memory-exhaustion DoS. A minimum of 10 MB per payload is recommended.

If no SerializationProvider is registered, modules handle serialization themselves — this is acceptable for simple deployments where all modules agree on a single format.

type Session

type Session struct {
	UserID      string
	Username    string
	Roles       []string
	Permissions []string
	Token       string // SECURITY: zero before logging or serializing
}

Session represents an authenticated session.

SECURITY WARNING: The Token field carries the raw bearer token. Session structs flow through the authorization path (Authorizer.Can), and can be inadvertently serialized in logs, audit entries, or event payloads. Consumers that pass Session to loggers or serializers MUST zero the Token field first. Use the Safe() method when passing session identity to non-security subsystems.

func (Session) Safe added in v0.4.0

func (s Session) Safe() Session

Safe returns a copy of the Session with the Token field zeroed. Use this when passing session information to subsystems that do not need the raw token (logging, metrics, events, workflows).

type SettingDef

type SettingDef struct {
	Key         string // env var or config key, e.g. "MUXCORE_JACKETT_URL"
	Label       string // human-readable label, e.g. "Jackett Server URL"
	Type        SettingType
	Default     string // default value as a string
	Description string // help text
	Required    bool
	Options     []string // for SettingTypeSelect: allowed values
	Group       string   // settings group, e.g. "Connection", "Downloads"
}

SettingDef describes one configuration setting that a module exposes.

type SettingType

type SettingType string

SettingType enumerates the supported setting types.

const (
	SettingTypeString SettingType = "string"
	SettingTypeInt    SettingType = "int"
	SettingTypeBool   SettingType = "bool"
	SettingTypeSelect SettingType = "select"
	SettingTypeSecret SettingType = "secret" // masked in UI, redacted in logs
)

type SettingsProvider

type SettingsProvider interface {
	Settings() []SettingDef
}

SettingsProvider is an optional interface modules implement to expose their configuration to the admin UI. The admin UI discovers all modules that implement this interface and renders their settings automatically.

type Span added in v0.4.0

type Span interface {
	// SetAttribute records a key-value pair on the span. Attributes appear
	// in trace visualizations and can be searched.
	SetAttribute(key string, value string)

	// SetStatus records the outcome of the span. Call before End().
	SetStatus(code SpanStatusCode, description string)

	// End marks the span as complete and sends it to the tracing backend.
	End()
}

Span represents a single unit of work in a distributed trace.

type SpanStatusCode added in v0.4.0

type SpanStatusCode int

SpanStatusCode indicates success or failure of a span.

const (
	SpanStatusOK    SpanStatusCode = 0
	SpanStatusError SpanStatusCode = 1
)

type StepCompletedPayload added in v0.4.0

type StepCompletedPayload struct {
	RunID    string         `json:"run_id"`
	StepName string         `json:"step_name"`
	Duration string         `json:"duration"`
	Output   map[string]any `json:"output"`
}

type StepFailedPayload added in v0.4.0

type StepFailedPayload struct {
	RunID    string `json:"run_id"`
	StepName string `json:"step_name"`
	Attempt  int    `json:"attempt"`
	MaxRetry int    `json:"max_retry"`
	Error    string `json:"error"`
}

type StepResult

type StepResult struct {
	StepName   string
	Status     string // "success", "failed", "skipped"
	StartedAt  time.Time
	EndedAt    time.Time
	Attempt    int
	MaxRetries int
	Output     map[string]any // step output data passed to subsequent steps
	Error      string
}

StepResult captures the outcome of one tapestry step.

type StepStartedPayload added in v0.4.0

type StepStartedPayload struct {
	RunID    string `json:"run_id"`
	StepName string `json:"step_name"`
	Handler  string `json:"handler"`
	Attempt  int    `json:"attempt"`
}

type StorageEvent

type StorageEvent struct {
	Type StorageEventType
	Key  string
}

type StorageEventType

type StorageEventType string
const (
	StorageEventCreated  StorageEventType = "created"
	StorageEventDeleted  StorageEventType = "deleted"
	StorageEventModified StorageEventType = "modified"
)

type StorageOrchestrator

type StorageOrchestrator interface {
	Get(ctx context.Context, key string) (io.ReadCloser, error)
	Put(ctx context.Context, key string, data io.Reader, size int64) error
	Delete(ctx context.Context, key string) error
	Move(ctx context.Context, src, dst string) error
	Exists(ctx context.Context, key string) (bool, error)
	Stat(ctx context.Context, key string) (ObjectInfo, error)
	List(ctx context.Context, prefix string) ([]ObjectInfo, error)
	ProviderCount() int
	// Stream reads a byte range from a storage object. Uses provider-side
	// streaming when the routed provider implements Streamable; otherwise
	// falls back to a full Get with client-side slicing.
	Stream(ctx context.Context, key string, offset, length int64) (io.ReadCloser, error)
	// CapabilityCheck returns which capability interfaces the routed provider
	// supports for the given key (streamable, seekable, watchable, etc.).
	// Modules use this to negotiate behavior at runtime.
	CapabilityCheck(ctx context.Context, key string) ([]string, error)
}

StorageOrchestrator is the high-level storage interface exposed to modules. It handles provider routing, caching, and capability negotiation internally.

type StorageProvider

type StorageProvider interface {
	Put(ctx context.Context, key string, data io.Reader, size int64) error
	Get(ctx context.Context, key string) (io.ReadCloser, error)
	Delete(ctx context.Context, key string) error
	Move(ctx context.Context, src, dst string) error
	Exists(ctx context.Context, key string) (bool, error)
	Stat(ctx context.Context, key string) (ObjectInfo, error)
	List(ctx context.Context, prefix string) ([]ObjectInfo, error)
}

Core blob storage interface — all storage providers implement this.

type StorageTier

type StorageTier string

Storage tier constants.

const (
	StorageTierHot     StorageTier = "hot"
	StorageTierWarm    StorageTier = "warm"
	StorageTierCold    StorageTier = "cold"
	StorageTierArchive StorageTier = "archive"
)

type Streamable

type Streamable interface {
	Stream(ctx context.Context, key string, offset, length int64) (io.ReadCloser, error)
}

type StructuredLogger added in v0.4.0

type StructuredLogger interface {
	// Debug logs at debug level with structured fields.
	// SECURITY: fields may contain sensitive data — redact before calling.
	Debug(ctx context.Context, msg string, fields map[string]any)

	// Info logs at info level with structured fields.
	// SECURITY: fields may contain sensitive data — redact before calling.
	Info(ctx context.Context, msg string, fields map[string]any)

	// Warn logs at warning level with structured fields.
	// SECURITY: fields may contain sensitive data — redact before calling.
	Warn(ctx context.Context, msg string, fields map[string]any)

	// Error logs at error level with structured fields.
	// SECURITY: fields may contain sensitive data — redact before calling.
	Error(ctx context.Context, msg string, fields map[string]any)

	// Level returns the configured minimum log level. Messages below this
	// level are silently dropped by the provider.
	Level() LogLevel
}

StructuredLogger provides leveled, structured logging for modules. This is the general-purpose logger — distinct from AuditLogger which handles security-relevant audit events specifically.

Modules call StructuredLogger instead of importing a specific logging library. This makes the logging backend swappable (slog, zap, zerolog, or a future standard) without changing module code.

SECURITY: All log methods accept fields as map[string]any. This map can inadvertently contain credentials, tokens, PII, or other sensitive data. Callers MUST:

  • Apply DataRedactionProvider.Redact() to the fields map before passing it to any log method if the map contains untrusted data.
  • Never log full Identity structs — use Identity.SafeInfo().
  • Never log Session structs — use Session.Safe().
  • Avoid logging raw request bodies, query parameters, or headers.

Implementations SHOULD apply automatic field-name-based redaction for keys matching SensitiveLogFieldNames before writing to any sink.

If no StructuredLogger is registered, log calls are no-ops — modules do not need nil checks.

type TapestryCompletedPayload added in v0.4.0

type TapestryCompletedPayload struct {
	RunID        string `json:"run_id"`
	DefinitionID string `json:"definition_id"`
	Duration     string `json:"duration"`
}

type TapestryDefinition added in v0.4.0

type TapestryDefinition struct {
	ID          string
	Name        string
	Description string
	Steps       []TapestryStep
	Version     string
	Meta        map[string]any
}

TapestryDefinition is a registered, reusable workflow template.

type TapestryFailedPayload added in v0.4.0

type TapestryFailedPayload struct {
	RunID        string `json:"run_id"`
	DefinitionID string `json:"definition_id"`
	StepName     string `json:"step_name"`
	Error        string `json:"error"`
}

type TapestryRun added in v0.4.0

type TapestryRun struct {
	ID           string
	DefinitionID string
	Status       TapestryStatus
	CurrentStep  string
	StepResults  []StepResult
	Input        map[string]any
	StartedAt    time.Time
	EndedAt      time.Time
	Error        string
	Meta         map[string]any
}

TapestryRun represents a single execution of a tapestry.

type TapestryRunFilter added in v0.4.0

type TapestryRunFilter struct {
	Status       TapestryStatus
	DefinitionID string
}

TapestryRunFilter narrows ListRuns queries.

type TapestryStartedPayload added in v0.4.0

type TapestryStartedPayload struct {
	RunID        string `json:"run_id"`
	DefinitionID string `json:"definition_id"`
}

Tapestry event payloads.

type TapestryStatus added in v0.4.0

type TapestryStatus string

TapestryStatus tracks the lifecycle of a running workflow.

const (
	TapestryPending   TapestryStatus = "pending"
	TapestryRunning   TapestryStatus = "running"
	TapestryCompleted TapestryStatus = "completed"
	TapestryFailed    TapestryStatus = "failed"
	TapestryCancelled TapestryStatus = "cancelled"
	TapestryPaused    TapestryStatus = "paused"
)

type TapestryStep added in v0.4.0

type TapestryStep struct {
	Name         string
	Handler      string // module ID or capability to handle this step
	Retry        int    // max retry attempts (0 = no retry)
	Timeout      time.Duration
	DependsOn    []string          // step names that must complete before this one
	InputMapping map[string]string // maps step output keys to this step's input keys
	Meta         map[string]any
}

TapestryStep defines one step in a tapestry definition.

type TierTransitionPayload

type TierTransitionPayload struct {
	Key      string      `json:"key"`
	FromTier StorageTier `json:"from_tier"`
	ToTier   StorageTier `json:"to_tier"`
	Reason   string      `json:"reason"`
}

TierTransitionPayload is the payload for storage.tier.transition events.

type TieredProvider

type TieredProvider interface {
	StorageProvider

	// Tier returns which tier this provider handles.
	Tier() StorageTier

	// Promote moves an object from this tier to a higher one.
	Promote(ctx context.Context, key string) error

	// Relegate moves an object from this tier to a lower one.
	Relegate(ctx context.Context, key string) error
}

TieredProvider extends StorageProvider with tiering support. Storage modules that support multiple tiers implement this.

type TracingProvider added in v0.4.0

type TracingProvider interface {
	// StartSpan begins a new span with the given name as a child of any
	// span in ctx. Returns the context carrying the new span and the span
	// itself. Call span.End() when the operation completes.
	StartSpan(ctx context.Context, name string) (context.Context, Span)
}

TracingProvider creates spans for distributed tracing. Modules call this to wrap operations in spans; the provider handles export to whatever backend is configured (Jaeger, Zipkin, OTLP, or future protocols).

If no TracingProvider is registered, StartSpan returns the context unchanged and a no-op span — modules don't need nil checks.

This contract is provider-agnostic by design. A module that creates spans through TracingProvider works identically whether the backend is OpenTelemetry, a proprietary APM, or a future standard.

type Tx

type Tx interface {
	// SECURITY: Same SQL parameterization requirements as DatabaseProvider.Exec/Query.
	Exec(ctx context.Context, query string, args ...any) (int64, error)
	Query(ctx context.Context, query string, args ...any) (Rows, error)
}

Tx is a database transaction handle.

type ValidationResult added in v0.4.0

type ValidationResult struct {
	// Valid is true if the input passed all schema checks without errors.
	// When Valid is true, Sanitized holds the (possibly cleaned) data
	// that should be used in place of the original.
	Valid bool

	// Sanitized is the cleaned/sanitized version of the input data.
	// When Valid is true, callers should use this instead of the raw input.
	// When Valid is false, Sanitized may be nil or partial.
	Sanitized []byte

	// Errors is the list of validation failures. Empty when Valid is true.
	// Each entry describes a specific failure (e.g., "field email must
	// match pattern ^[^@]+@[^@]+$").
	Errors []string
}

ValidationResult carries the outcome of an input validation call. Modules use this to decide whether to accept, reject, or sanitize incoming data before processing.

type Watchable

type Watchable interface {
	Watch(ctx context.Context, prefix string) (<-chan StorageEvent, error)
}

type WorkerPool

type WorkerPool interface {
	Submit(ctx context.Context, task WorkerTask) (string, error)
	Status(ctx context.Context, taskID string) (WorkerTask, error)
	Cancel(ctx context.Context, taskID string) error
	List(ctx context.Context, filter *WorkerTaskFilter) ([]WorkerTask, error)

	// Reassign moves a task from a dead or unresponsive node to a new one.
	// If the task is already completed or cancelled, Reassign returns an error.
	// The new node should re-execute the task from scratch unless the executor
	// checks IdempotencyKey against an IdempotencyProvider.
	Reassign(ctx context.Context, taskID, newNode string) error
}

WorkerPool schedules tasks across cluster nodes and tracks their lifecycle.

type WorkerTask

type WorkerTask struct {
	ID            string
	Type          string
	Payload       []byte
	AssignedNode  string
	Status        WorkerTaskStatus
	MaxRetries    int
	RetryCount    int
	Capabilities  []string
	CreatedAt     time.Time
	StartedAt     time.Time
	CompletedAt   time.Time
	LastHeartbeat time.Time
	Error         string
	Meta          map[string]any

	// IdempotencyKey is an optional key that executors use with
	// IdempotencyProvider to prevent duplicate execution. When a task
	// is reassigned after a node failure, the new executor checks this
	// key before re-executing. If empty, no idempotency guard is applied.
	IdempotencyKey string
}

WorkerTask is a unit of work scheduled across the cluster. Meta carries task-type-specific context that executors interpret.

type WorkerTaskFilter

type WorkerTaskFilter struct {
	Status       WorkerTaskStatus
	Type         string
	AssignedNode string
}

WorkerTaskFilter narrows task queries.

type WorkerTaskStatus

type WorkerTaskStatus string

WorkerTaskStatus represents the lifecycle of a distributed task.

const (
	WorkerTaskStatusPending   WorkerTaskStatus = "pending"
	WorkerTaskStatusAssigned  WorkerTaskStatus = "assigned"
	WorkerTaskStatusRunning   WorkerTaskStatus = "running"
	WorkerTaskStatusCompleted WorkerTaskStatus = "completed"
	WorkerTaskStatusFailed    WorkerTaskStatus = "failed"
	WorkerTaskStatusCancelled WorkerTaskStatus = "cancelled"
)

type WorkflowEngine

type WorkflowEngine interface {
	// RegisterDefinition stores a tapestry template for later execution.
	// definition.ID is the key used by Run.
	RegisterDefinition(ctx context.Context, definition TapestryDefinition) error

	// RemoveDefinition removes a previously registered definition.
	RemoveDefinition(ctx context.Context, definitionID string) error

	// GetDefinition returns a registered definition, or nil if not found.
	GetDefinition(ctx context.Context, definitionID string) (*TapestryDefinition, error)

	// ListDefinitions returns all registered definitions.
	ListDefinitions(ctx context.Context) ([]TapestryDefinition, error)

	// Run starts a tapestry execution. input carries the initial
	// data passed to the first step(s).
	Run(ctx context.Context, definitionID string, input map[string]any) (string, error)

	// Status returns the current state of a run.
	Status(ctx context.Context, runID string) (*TapestryRun, error)

	// Cancel stops a running tapestry. Already-completed steps
	// are not rolled back.
	Cancel(ctx context.Context, runID string) error

	// Pause suspends a running tapestry at the next step boundary.
	Pause(ctx context.Context, runID string) error

	// Resume continues a paused tapestry.
	Resume(ctx context.Context, runID string) error

	// ListRuns returns all runs, optionally filtered by status or definitionID.
	ListRuns(ctx context.Context, filter *TapestryRunFilter) ([]TapestryRun, error)
}

WorkflowEngine orchestrates multi-step tapestry executions. Discovered via FindByCapability("workflow.engine"). If no module implements this contract, individual Scheduler tasks can still run independently — tapestry execution is an optional layer.

Jump to

Keyboard shortcuts

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