Documentation
¶
Overview ¶
Package nullusclient 는 nullus CLI(트랙 A)와 MCP 서버(트랙 B)가 공유하는 유일한 기반이다 — Nullus API 클라이언트와 설정·토큰 해석.
두 트랙은 이 패키지에만 의존하고 서로에게 의존하지 않는다 (CLI+MCP 구현 백로그 Phase 1). 여기에 명령 표면이나 tool 표면을 넣지 않는다.
Index ¶
- Constants
- Variables
- func DeleteSession() error
- func EnsureFreshToken(ctx context.Context, hc *http.Client) (string, error)
- func ReadToken() (string, error)
- func SaveSession(s Session) error
- func SaveToken(token string) error
- type APIError
- type AuthCodeFlow
- type Client
- type Config
- type Kind
- type OIDCConfig
- type OIDCEndpoints
- type Option
- type ServerInfo
- type Session
- type VersionSkew
Constants ¶
const ( EnvServer = "NULLUS_SERVER" EnvToken = "NULLUS_TOKEN" // EnvConfigDir 은 ~/.nullus 를 통째로 옮긴다. 테스트 격리용이면서, // 멀티 서버 컨텍스트(v2)가 들어올 자리이기도 하다. EnvConfigDir = "NULLUS_CONFIG_DIR" )
환경변수 이름. env 는 설정 파일보다 우선한다 — CI 에서 파일 없이 실행하기 위한 경로다 (Automation 계약 §5).
const MinServerVersion = "0.1.0-alpha"
MinServerVersion 은 이 클라이언트가 지원하는 최소 서버 버전이다 (백로그 S-4). 서버 API 에 breaking change 가 들어갈 때만 올린다 — 값의 출처는 cmd/api/main.go /health 의 version 필드.
Variables ¶
var ErrLoginRequired = errors.New("로그인이 필요하다 — nullus login 을 실행하라")
ErrLoginRequired 는 재로그인 없이는 진행할 수 없는 상태다 — refresh token 만료·폐기, 또는 만료된 세션에 refresh token 이 없는 경우. 호출측은 errors.Is 로 구분해 `nullus login` 안내를 낸다 (exit code 3, 계약 §1).
Functions ¶
func DeleteSession ¶
func DeleteSession() error
DeleteSession 은 로컬 자격(세션 + 토큰 파일)을 지운다. logout(A-3)용 — 지울 것이 없어도 오류가 아니다(멱등).
func EnsureFreshToken ¶
EnsureFreshToken 은 지금 쓸 수 있는 access token 을 돌려준다. 우선순위는 S-2 와 같다: NULLUS_TOKEN env → 로그인 세션(만료 임박 시 refresh 후 영속) → 정적 토큰 파일(bootstrap) → 빈 값. 자격 부재는 오류가 아니다 — dev 모드(auth.mode=session)는 토큰 없이 동작한다.
func ReadToken ¶
ReadToken 은 env → 토큰 파일 순으로 토큰을 찾는다. 파일이 없으면 빈 문자열을 반환한다 — 토큰 부재는 로그인 안내의 재료이지 오류가 아니다.
func SaveSession ¶
SaveSession 은 세션을 ~/.nullus/session 에 0600 으로 저장하고, access token 을 S-2 토큰 파일에도 함께 기록한다 — ReadToken/Load 만 아는 소비자(MCP 설계 §5 의 단일 토큰 캐시 경로)가 로그인 결과를 그대로 보게 하기 위해서다.
Types ¶
type APIError ¶
type APIError struct {
Kind Kind
StatusCode int // transport 실패면 0
Code string // 서버 error envelope 의 도메인 코드 (예: DEPLOY_COMPAT_WARN_UNACK)
Message string // envelope 의 message, 없으면 본문/원인 요약
TraceID string // 서버 request id — 지원 문의·로그 대조용
// contains filtered or unexported fields
}
APIError 는 실패한 API 호출 하나를 설명한다. HTTP 응답 실패와 transport 실패(연결 불가 등) 모두 이 타입으로 돌아온다 — 일반 분기는 Kind 로 하고, 같은 상태 코드 안에서 갈라야 하는 경우(예: 400 중 DEPLOY_COMPAT_WARN_UNACK 를 --ack-warnings 안내로 바꾸는 A-5)만 Code 를 본다.
type AuthCodeFlow ¶
type AuthCodeFlow struct {
// contains filtered or unexported fields
}
AuthCodeFlow 는 Authorization Code + PKCE 로그인 시도 하나다. verifier 와 state 는 생성 시 고정된다 — AuthURL 로 사용자를 보내고, 콜백으로 받은 code·state 를 Exchange 에 넘긴다.
func NewAuthCodeFlow ¶
func NewAuthCodeFlow(cfg OIDCConfig, ep OIDCEndpoints, redirectURI string) (*AuthCodeFlow, error)
NewAuthCodeFlow 는 로그인 시도를 만든다. redirectURI 는 콜백 수신 주소 (예: http://127.0.0.1:<port>/callback) — 리슨은 트랙 A 몫이다.
func (*AuthCodeFlow) AuthURL ¶
func (f *AuthCodeFlow) AuthURL() string
AuthURL 은 사용자를 보낼 인가 URL 이다 (PKCE S256 challenge + state 포함).
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client 는 /api/v1/* REST 의 얇은 클라이언트다. 비즈니스 로직도, 재시도도 없다 — 서버가 판정하고, 재시도 여부는 호출한 자동화(스크립트·에이전트)가 정한다 (컨셉 문서 §5, Automation 계약).
func New ¶
New 는 해석이 끝난 Config 로 클라이언트를 만든다. 서버 주소는 필수다. 토큰은 선택이다 — dev 모드(auth.mode=session)는 토큰 없이 동작한다.
func (*Client) CheckVersionSkew ¶
func (c *Client) CheckVersionSkew(ctx context.Context) (VersionSkew, error)
CheckVersionSkew 는 서버 버전을 조회해 최소 호환 버전과 비교한다. 서버 도달 실패는 *APIError, 버전 파싱 불능은 일반 오류로 돌아온다.
func (*Client) Do ¶
Do 는 API 를 한 번 호출한다. path 는 "/api/v1/..." 절대 경로. in 이 nil 이 아니면 JSON body 로 보내고, out 이 nil 이 아니면 응답 JSON 을 디코딩한다. 2xx 가 아니면 *APIError 를 반환한다.
func (*Client) ServerInfo ¶
func (c *Client) ServerInfo(ctx context.Context) (ServerInfo, error)
ServerInfo 는 서버 상태·버전을 조회한다.
type Config ¶
type Config struct {
Server string // API 서버 base URL (예: https://nullus.example.com)
Token string
}
Config 는 해석이 끝난 클라이언트 설정이다.
type Kind ¶
type Kind int
Kind 는 API 호출 실패의 분류다. 값은 Automation 계약 §1 의 exit code 와 일치한다 — CLI 는 Kind.ExitCode() 를 그대로 프로세스 종료 코드로 쓰고, MCP 는 isError 메시지의 카테고리로 쓴다.
type OIDCConfig ¶
type OIDCConfig struct {
Issuer string // 예: https://keycloak.example.com/realms/nullus
ClientID string // public client — PKCE 전제, client secret 없음
Scopes []string // 비면 ["openid"]
}
OIDCConfig 는 로그인에 필요한 IdP 좌표다. 서버는 이를 노출하는 API 가 없으므로(auth 모듈은 POST /auth/login 뿐) 트랙 A 가 플래그/env/설정 파일에서 모아 전달한다.
type OIDCEndpoints ¶
type OIDCEndpoints struct {
Authorization string `json:"authorization_endpoint"`
Token string `json:"token_endpoint"`
}
OIDCEndpoints 는 discovery 결과 중 이 라이브러리가 쓰는 것만 담는다.
func DiscoverOIDC ¶
DiscoverOIDC 는 issuer 의 /.well-known/openid-configuration 을 읽는다. hc 가 nil 이면 http.DefaultClient 를 쓴다.
type Option ¶
type Option func(*Client)
Option 은 Client 생성 옵션이다.
func WithHTTPClient ¶
WithHTTPClient 는 기본 http.Client 를 교체한다 (테스트·타임아웃 조정용).
type ServerInfo ¶
type ServerInfo struct {
Status string `json:"status"`
DB string `json:"db"`
Version string `json:"version"`
}
ServerInfo 는 GET /health 응답이다. /health 는 인증 없이 열려 있어 로그인 전 버전 검사에도 쓸 수 있다.
type Session ¶
type Session struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token,omitempty"`
Expiry time.Time `json:"expiry"` // access token 만료 시각
Issuer string `json:"issuer"`
ClientID string `json:"client_id"`
TokenEndpoint string `json:"token_endpoint"`
}
Session 은 nullus login(OIDC)이 남기는 로그인 상태다. access token 외에 refresh 에 필요한 재료(refresh token, token endpoint, client ID)까지 담아 다음 프로세스가 discovery 없이 갱신을 이어받는다.
bootstrap 토큰(무인 경로)은 세션을 만들지 않는다 — 그쪽은 S-2 의 토큰 파일만 쓰고 만료 관리는 외부(발급 스크립트) 책임이다.
func ReadSession ¶
ReadSession 은 저장된 세션을 읽는다. 부재는 (zero, false, nil) — 로그인 안내의 재료이지 오류가 아니다.
type VersionSkew ¶
type VersionSkew struct {
ServerVersion string // 서버가 보고한 원문 — 경고 문구용
MinSupported string // = MinServerVersion
Compatible bool // 서버 버전 >= 최소 호환 버전
}
VersionSkew 는 클라이언트-서버 버전 스큐 판정 결과다. 경고를 낼지(stderr) 중단할지(Automation 계약 §1, exit 5)는 호출측이 정한다.