package ports import ( "context" "fmt" "galaxy/authsession/internal/domain/challenge" "galaxy/authsession/internal/domain/common" ) // ChallengeStore provides source-of-truth persistence for auth confirmation // challenges without exposing storage-specific primitives. type ChallengeStore interface { // Get returns the stored challenge for challengeID. Implementations must // wrap ErrNotFound when challengeID does not exist. Get(ctx context.Context, challengeID common.ChallengeID) (challenge.Challenge, error) // Create persists record as a new challenge. Implementations must wrap // ErrConflict when record.ID already exists. Create(ctx context.Context, record challenge.Challenge) error // CompareAndSwap replaces previous with next when the currently stored // challenge matches previous exactly. Implementations must wrap ErrConflict // when the stored challenge differs from previous and wrap ErrNotFound when // previous.ID does not exist. CompareAndSwap(ctx context.Context, previous challenge.Challenge, next challenge.Challenge) error } // ValidateComparableChallenges reports whether previous and next are suitable // for one ChallengeStore compare-and-swap call. func ValidateComparableChallenges(previous challenge.Challenge, next challenge.Challenge) error { if err := previous.Validate(); err != nil { return fmt.Errorf("previous challenge: %w", err) } if err := next.Validate(); err != nil { return fmt.Errorf("next challenge: %w", err) } if previous.ID != next.ID { return fmt.Errorf("challenge compare-and-swap ids must match: %q != %q", previous.ID, next.ID) } return nil }