Documentation
¶
Overview ¶
Package interactiveclient — use-cases of InternalInteractiveClientService (IAM-INT-1): the lifecycle of the OAuth2 client through which a HUMAN completes an interactive sign-in ceremony.
Clean Architecture: this package defines the narrow ports below and depends on nothing but domain + the corelib operation envelope. Concrete adapters (pgx, the identity provider's admin API) live in internal/repo and internal/clients and are wired in cmd/kaname/wiring.go.
Index ¶
- type CreateUseCase
- type DeleteUseCase
- type GetUseCase
- type Handler
- func (h *Handler) Create(ctx context.Context, req *iamv1.CreateInteractiveClientRequest) (*operationpb.Operation, error)
- func (h *Handler) Delete(ctx context.Context, req *iamv1.DeleteInteractiveClientRequest) (*operationpb.Operation, error)
- func (h *Handler) Get(ctx context.Context, req *iamv1.GetInteractiveClientRequest) (*iamv1.InteractiveClient, error)
- func (h *Handler) List(ctx context.Context, req *iamv1.ListInteractiveClientsRequest) (*iamv1.ListInteractiveClientsResponse, error)
- func (h *Handler) Update(ctx context.Context, req *iamv1.UpdateInteractiveClientRequest) (*operationpb.Operation, error)
- type ListResult
- type ListUseCase
- type ProviderClient
- type ProviderClientSpec
- type UpdateUseCase
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CreateUseCase ¶
type CreateUseCase struct {
// contains filtered or unexported fields
}
CreateUseCase — registers the client at the identity provider, then records it.
func NewCreateUseCase ¶
func NewCreateUseCase(r clientRepo, p providerClients, ops operations.Repo, audiences []string, logger *slog.Logger) *CreateUseCase
NewCreateUseCase — constructor. `audiences` comes from iam's own configuration (Р2): the caller never supplies it and it is echoed output-only.
func (*CreateUseCase) Execute ¶
func (uc *CreateUseCase) Execute(ctx context.Context, req *iamv1.CreateInteractiveClientRequest) (*operationpb.Operation, error)
Execute — validate → persist Operation → register at provider → insert row.
WHY THE PROVIDER IS CONTACTED BEFORE THE ROW IS WRITTEN, AND WHAT PAYS FOR IT. The row must carry the provider's client id, so registration comes first. If the insert then fails — most often because the name is taken — the client that was just registered is deregistered again. Without that compensation an orphan would remain at the provider that the platform has no record of and no way to name: nothing would ever remove it, and it would keep accepting ceremonies.
The Operation row is persisted BEFORE either side effect, so the id the caller receives is always pollable; a failure is recorded on it as a terminal error rather than leaving the caller polling a row that does not exist.
func (*CreateUseCase) WithCompensationEmitter ¶
func (uc *CreateUseCase) WithCompensationEmitter(c providerCompensationEmitter) *CreateUseCase
WithCompensationEmitter wires the durable sink for compensating intents. Composition-root only.
type DeleteUseCase ¶
type DeleteUseCase struct {
// contains filtered or unexported fields
}
DeleteUseCase — removes the client at the provider and its row.
func NewDeleteUseCase ¶
func NewDeleteUseCase(r clientRepo, p providerClients, ops operations.Repo, logger *slog.Logger) *DeleteUseCase
NewDeleteUseCase — constructor.
func (*DeleteUseCase) Execute ¶
func (uc *DeleteUseCase) Execute(ctx context.Context, id string) (*operationpb.Operation, error)
Execute — idempotent by construction.
Deleting an already-absent client succeeds and reports the same code as the first delete: the caller asked for the client to be gone, and it is. The row is removed first and the provider-side deregistration follows only when a row was actually taken — otherwise a repeated Delete would keep asking the provider to remove something already removed.
type GetUseCase ¶
type GetUseCase struct {
// contains filtered or unexported fields
}
GetUseCase — sync read of one client.
func (*GetUseCase) Execute ¶
func (uc *GetUseCase) Execute(ctx context.Context, id string) (domain.InteractiveClient, error)
Execute — direct-read lane: a well-formed id with no row is NOT_FOUND.
type Handler ¶
type Handler struct {
iamv1.UnimplementedInternalInteractiveClientServiceServer
// contains filtered or unexported fields
}
Handler implements iamv1.InternalInteractiveClientServiceServer.
func NewHandler ¶
func NewHandler(g *GetUseCase, l *ListUseCase, c *CreateUseCase, u *UpdateUseCase, d *DeleteUseCase) *Handler
NewHandler assembles the Handler. Composition root: cmd/kaname/wiring.go.
func (*Handler) Create ¶
func (h *Handler) Create(ctx context.Context, req *iamv1.CreateInteractiveClientRequest) (*operationpb.Operation, error)
Create — async; returns the Operation envelope.
func (*Handler) Delete ¶
func (h *Handler) Delete(ctx context.Context, req *iamv1.DeleteInteractiveClientRequest) (*operationpb.Operation, error)
Delete — async; returns the Operation envelope.
func (*Handler) Get ¶
func (h *Handler) Get(ctx context.Context, req *iamv1.GetInteractiveClientRequest) (*iamv1.InteractiveClient, error)
Get — sync read of one client.
func (*Handler) List ¶
func (h *Handler) List(ctx context.Context, req *iamv1.ListInteractiveClientsRequest) (*iamv1.ListInteractiveClientsResponse, error)
List — sync cursor-paginated read.
func (*Handler) Update ¶
func (h *Handler) Update(ctx context.Context, req *iamv1.UpdateInteractiveClientRequest) (*operationpb.Operation, error)
Update — async; returns the Operation envelope.
type ListResult ¶
type ListResult struct {
Clients []domain.InteractiveClient
NextPageToken string
}
ListResult — one page plus the cursor for the next.
type ListUseCase ¶
type ListUseCase struct {
// contains filtered or unexported fields
}
ListUseCase — sync cursor-paginated read.
func (*ListUseCase) Execute ¶
func (uc *ListUseCase) Execute(ctx context.Context, pageSize int64, pageToken, filter string) (ListResult, error)
Execute — pagination format is validated FIRST, so a garbage token or an out-of-range page size is INVALID_ARGUMENT independently of what the caller holds and of what the store contains. `page_size` out of range is REJECTED, never clamped: silent clamping returns a different page than the one asked for and the caller never learns of it.
type ProviderClient ¶
type ProviderClient struct {
ClientID string
GrantTypes []string
TokenEndpointAuthMethod string
Audiences []string
}
ProviderClient — what the provider gives back.
type ProviderClientSpec ¶
type ProviderClientSpec struct {
Name string
RedirectURIs []string
PostLogoutRedirectURIs []string
Audiences []string
// GrantTypes — decided by the use-case, forwarded verbatim. The adapter does
// not choose: this resource exists to register exactly one shape, and a
// default living in the adapter is how the other three registration paths
// ended up all meaning `client_credentials`.
GrantTypes []string
}
ProviderClientSpec — what iam asks the provider to register. The caller of the RPC supplies only the first two fields' worth of intent; everything else is iam's decision (Р2 — the audience is stamped, never accepted).
type UpdateUseCase ¶
type UpdateUseCase struct {
// contains filtered or unexported fields
}
UpdateUseCase — applies the mutable fields.
func NewUpdateUseCase ¶
func NewUpdateUseCase(r clientRepo, ops operations.Repo, logger *slog.Logger) *UpdateUseCase
NewUpdateUseCase — constructor.
func (*UpdateUseCase) Execute ¶
func (uc *UpdateUseCase) Execute(ctx context.Context, req *iamv1.UpdateInteractiveClientRequest) (*operationpb.Operation, error)
Execute — mask discipline, then the write.