// Package actor stores the calling user (tenant_id + uid) on a request // context so middleware can inject it once and any downstream layer // (handler / logic / usecase / repository) can read it without // re-parsing the JWT. // // The package lives under internal/library because it is depended on // by BOTH internal/middleware AND internal/logic/*. Defining the // context key here is the only way to keep a single key value across // packages (Go context.Value keys are typed by package, so each // package would otherwise get its own isolated slot). package actor import ( "context" "fmt" ) type contextKey struct{} // Actor identifies the calling tenant member, injected by the AuthJWT // middleware after a successful Bearer token parse. type Actor struct { TenantID string UID string } // WithActor stores tenant/uid on ctx. Returns the original ctx // unchanged when either field is empty. func WithActor(ctx context.Context, tenantID, uid string) context.Context { if tenantID == "" || uid == "" { return ctx } return context.WithValue(ctx, contextKey{}, Actor{TenantID: tenantID, UID: uid}) } // ActorFromContext returns the actor injected by AuthJWT. The error is // a plain error (no biz code) so callers can wrap it with their own // scope-specific Builder when needed. func ActorFromContext(ctx context.Context) (Actor, error) { v, ok := ctx.Value(contextKey{}).(Actor) if !ok || v.TenantID == "" || v.UID == "" { return Actor{}, fmt.Errorf("missing bearer token or X-Tenant-ID/X-UID headers") } return v, nil }