Documentation
¶
Overview ¶
Package xctx provides typed context helpers for request-scoped execution metadata. Context values are for cancellation, deadlines, and request metadata; application state should remain in explicit action parameters.
Index ¶
- Constants
- Variables
- func AddTrace(ctx context.Context, event string)
- func ApprovalTokenFrom(ctx context.Context) string
- func ClientIPFrom(ctx context.Context) string
- func CloneForAsync(ctx context.Context) context.Context
- func EndpointFrom(ctx context.Context) string
- func ExecutionIDFrom(ctx context.Context) string
- func FeaturesFrom(ctx context.Context) []string
- func FromClaims(scope *RequestScope, claims map[string]any)
- func HasAnyRole(ctx context.Context, allowed ...string) bool
- func HasFeature(ctx context.Context, feature string) bool
- func HasPermission(ctx context.Context, perm string) bool
- func HasRole(ctx context.Context, required string) bool
- func Now(ctx context.Context) time.Time
- func PermissionsFrom(ctx context.Context) []string
- func RandomBytes(ctx context.Context, destination []byte) error
- func ReportProgress(ctx context.Context, progress Progress)
- func RequestIDFrom(ctx context.Context) string
- func RolesFrom(ctx context.Context) []string
- func RootExecutionIDFrom(ctx context.Context) string
- func SpanIDFrom(ctx context.Context) string
- func TenantIDFrom(ctx context.Context) string
- func TraceIDFrom(ctx context.Context) string
- func UserIDFrom(ctx context.Context) string
- func WithApprovalToken(ctx context.Context, token string) context.Context
- func WithClientIP(ctx context.Context, ip string) context.Context
- func WithClock(ctx context.Context, clock Clock) context.Context
- func WithEndpoint(ctx context.Context, endpoint string) context.Context
- func WithEntropy(ctx context.Context, reader io.Reader) context.Context
- func WithEventPublisher(ctx context.Context, pub EventPublisher) context.Context
- func WithExecutionID(ctx context.Context, id string) context.Context
- func WithFeatures(ctx context.Context, features []string) context.Context
- func WithPermissions(ctx context.Context, perms []string) context.Context
- func WithProgressReporter(ctx context.Context, reporter ProgressReporter) context.Context
- func WithRequestID(ctx context.Context, id string) context.Context
- func WithRoles(ctx context.Context, roles []string) context.Context
- func WithRootExecutionID(ctx context.Context, id string) context.Context
- func WithScope(ctx context.Context, s *RequestScope) context.Context
- func WithSpanID(ctx context.Context, id string) context.Context
- func WithTenantID(ctx context.Context, id string) context.Context
- func WithTraceContext(ctx context.Context, traceID, spanID string) context.Context
- func WithTraceID(ctx context.Context, id string) context.Context
- func WithUserID(ctx context.Context, id string) context.Context
- type Clock
- type EventPublisher
- type Key
- type Progress
- type ProgressReporter
- type RequestScope
Constants ¶
const MaxTraceEvents = 128
MaxTraceEvents bounds the per-request trace ring. Once full, the oldest event is dropped to make room. Exported so callers can size assertions and load tests without a magic literal.
Variables ¶
var ApprovalTokenKey = NewKey[string]("nexss.approval.token")
ApprovalTokenKey is the single, framework-wide context key for the approval token. Every consumer — flow, agent/permission, agent/policy reads and writes through this one key so a token minted by one package is visible to all others.
var EventPublisherKey = NewKey[EventPublisher]("nexss.event.publisher")
var TenantDB = NewKey[any]("tenant_db")
TenantDB is the context key for the active tenant's DB connection or transaction handle.
Functions ¶
func AddTrace ¶
AddTrace appends a diagnostic event to the request's trace ring.
Safe for concurrent use: it is the only method that mutates TraceEvents while the request is in flight. Contention is limited to concurrent PublishEvent failures on the same request — an error path, not a hot path — so a plain mutex is the correct tool.
The generation check rejects writes to a scope that has already been returned to the pool, so a goroutine holding a stale context cannot corrupt a scope now serving a different request.
func ApprovalTokenFrom ¶ added in v0.8.0
ApprovalTokenFrom extracts the approval token, or "".
func ClientIPFrom ¶
func CloneForAsync ¶
CloneForAsync returns a context whose scope is a deep copy of ctx's, detached from ctx's cancellation. Use before handing ctx to a goroutine that outlives the request (background publish, batch flush, best-effort audit) so that canceling the parent does not abort the detached work and the detached work does not race the parent's pooled scope.
Execution identity keys (execution id, root execution id) are carried through automatically: context.WithoutCancel preserves all values, so the clone sees the same execution ids as the parent without an explicit copy. Only the mutable RequestScope is duplicated.
func EndpointFrom ¶
func ExecutionIDFrom ¶ added in v0.9.3
ExecutionIDFrom returns the active execution ID from context keys.
func FeaturesFrom ¶
FeaturesFrom returns a defensive copy of the scope's features.
func FromClaims ¶
func FromClaims(scope *RequestScope, claims map[string]any)
FromClaims populates a scope from a decoded JWT claim map. Recognized keys: sub, ten, jti, roles, features, perms. Unknown keys are ignored.
func HasAnyRole ¶
HasAnyRole reports whether the scope has any of the listed roles. Passing zero roles returns false.
func HasFeature ¶
HasFeature reports whether the scope has the given feature flag enabled. system_admin always passes; "all" and "*" are treated as wildcards.
func HasPermission ¶
HasPermission reports whether the scope grants perm or the wildcard "*".
func HasRole ¶
HasRole reports whether the scope has the given role, either as its primary Role or anywhere in the Roles slice.
func PermissionsFrom ¶
PermissionsFrom returns a defensive copy of the scope's permissions.
func ReportProgress ¶ added in v0.27.0
func RequestIDFrom ¶
func RolesFrom ¶ added in v0.16.0
RolesFrom returns a defensive copy of the scope's roles. Mutating the result has no effect on the scope.
func RootExecutionIDFrom ¶ added in v0.11.0
RootExecutionIDFrom returns the top-level execution ID recorded by WithRootExecutionID, or "" when none was set.
func SpanIDFrom ¶ added in v0.9.3
func TenantIDFrom ¶
func TraceIDFrom ¶
func UserIDFrom ¶
func WithApprovalToken ¶ added in v0.8.0
WithApprovalToken binds an approval token to ctx.
func WithEntropy ¶ added in v0.27.0
func WithEventPublisher ¶
func WithEventPublisher(ctx context.Context, pub EventPublisher) context.Context
func WithExecutionID ¶ added in v0.9.3
WithExecutionID stores the id in context keys, not in a RequestScope. The root id is set only when no root exists yet in the context tree.
func WithProgressReporter ¶ added in v0.27.0
func WithProgressReporter(ctx context.Context, reporter ProgressReporter) context.Context
func WithRoles ¶
WithRoles replaces the roles slice and sets Role to the first element. Passing nil clears both.
func WithRootExecutionID ¶ added in v0.11.0
func WithScope ¶
func WithScope(ctx context.Context, s *RequestScope) context.Context
WithScope binds s to ctx directly. Prefer NewScope for pooled scopes.
Safe for concurrent use on a fresh (never-bound) scope: two goroutines racing to bind the same fresh scope will agree on a single generation. Once a scope is bound, callers must not bind it to a second context concurrently — that is a programming error, not a race the runtime can detect.
func WithTraceContext ¶ added in v0.10.1
WithTraceContext sets TraceID and/or SpanID in one call. Empty strings are ignored, so passing ("trace", "") sets only the trace ID.
Types ¶
type EventPublisher ¶
type EventPublisher interface {
PublishEvent(ctx context.Context, subject string, payload any) error
}
func EventPublisherFrom ¶
func EventPublisherFrom(ctx context.Context) (EventPublisher, bool)
type Key ¶
type Key[T any] struct { // contains filtered or unexported fields }
Key is a typed context key. Two values are equal only when they came from the same NewKey. The zero value works in tests but allocates on With/From — use NewKey on hot paths.
func NewKey ¶
NewKey creates a typed context key. Every call returns a distinct key, even for the same name and the same type parameter.
func (Key[T]) From ¶
From returns the bound value and true, or the zero value and false. Safe on a nil context and on a zero-value Key.
type ProgressReporter ¶ added in v0.27.0
type ProgressReporter func(Progress)
type RequestScope ¶
type RequestScope struct {
RequestID string
TraceID string
SpanID string
Endpoint string
UserID string
TenantID string
Role string
ClientIP string
Roles []string
Permissions []string
Features []string
TraceEvents []string
// contains filtered or unexported fields
}
RequestScope carries per-request metadata.
Execution identity (execution id, root execution id) does not live here — it is stored in typed context keys by WithExecutionID. Only fields that are inherently mutable-per-request and cheap to reset live on the scope.
func NewScope ¶
func NewScope(parent context.Context) (context.Context, *RequestScope, func())
NewScope returns a pooled RequestScope bound to parent, plus a cleanup function that returns the scope to the pool. cleanup is idempotent.
func ScopeFrom ¶
func ScopeFrom(ctx context.Context) *RequestScope
ScopeFrom returns the RequestScope bound to ctx, or nil. Verifies the generation so a stale context fails closed.
func (*RequestScope) Reset ¶
func (s *RequestScope) Reset()
Reset clears every field, retaining slice capacity up to the trace ring size. Called by the pool before returning a scope for reuse. It does not touch generation; that is the pool's responsibility.