Documentation
¶
Overview ¶
Package tailorclient is an UNOFFICIAL Go client library for the Tailor Platform that runs on the access tokens the official Tailor SDK already holds.
It implements no login flow of its own. Authentication piggybacks on the Tailor SDK (https://github.com/tailor-platform/sdk): the user logs in once with `npx tailor-sdk login`, and this package reuses the access and refresh tokens the SDK stores in ~/.config/tailor-platform/config.yaml, or in the OS keyring when the user is configured for keyring storage. Running that login is therefore a prerequisite, not a suggestion.
New picks its credentials from one of three sources.
- WithClientCredentials: an OAuth2 client_credentials grant for a platform machine user. This is the option for CI and other unattended callers, and it never touches the SDK config.
- WithTokens: tokens the caller manages itself.
- Otherwise: the current user's tokens from the SDK config.
Whichever source is used, New returns a connect-go OperatorServiceClient wired with bearer-token authentication that refreshes on Unauthenticated errors. Refreshed tokens stay in memory unless WithTokenPersist writes them back to the SDK config.
Token handling follows the SDK rather than reimplementing it. The config user key is platform-scoped the way the SDK scopes it, the OAuth2 client_id defaults to the SDK's own and honors the same environment variables, and the platform endpoint is taken from the SDK config when the caller names none, so a dev or self-hosted login is never refreshed against production.
Example ¶
Example builds an authenticated client from the SDK config and calls an OperatorService RPC. The RPC method is promoted from the embedded tailorv1connect.OperatorServiceClient, so it is callable directly on *Client.
package main
import (
"context"
"fmt"
"log"
tailorv1 "buf.build/gen/go/tailor-inc/tailor/protocolbuffers/go/tailor/v1"
"connectrpc.com/connect"
tailorclient "github.com/k1LoW/tailor-client-go"
)
func main() {
ctx := context.Background()
c, err := tailorclient.New(ctx)
if err != nil {
log.Fatal(err)
}
res, err := c.GetApplication(ctx, connect.NewRequest(&tailorv1.GetApplicationRequest{
WorkspaceId: "ws_xxx",
ApplicationName: "my-app",
}))
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Msg.GetApplication().GetName())
}
Output:
Index ¶
- Constants
- func IsTokenExpired(expiresAt string) bool
- func ResolveOAuth2ClientID(oauth2ClientID string) string
- func ResolvePlatformURL(platformURL string) string
- func WriteSDKTokens(userKey, accessToken, refreshToken, tokenExpiresAt string) error
- type Client
- type Option
- func WithClientCredentials(clientID, clientSecret string) Option
- func WithHTTPClient(h connect.HTTPClient) Option
- func WithInterceptors(ics ...connect.Interceptor) Option
- func WithOAuth2ClientID(id string) Option
- func WithPlatformURL(u string) Option
- func WithTokenPersist() Option
- func WithTokens(accessToken, refreshToken string) Option
- type SDKConfig
- type SDKTokens
- type SDKUserTokens
- type TokenResponse
- type UploadFileParams
Examples ¶
Constants ¶
const DefaultOAuth2ClientID = "cpoc_0Iudir72fqSpqC6GQ58ri1cLAqcq5vJl" //nostyle:repetition
DefaultOAuth2ClientID is the public OAuth2 client_id the Tailor SDK uses for the refresh_token grant. The SDK ships a single client_id for every platform and lets the environment override it, so this package must not invent per-platform IDs of its own.
const DefaultPlatformURL = "https://api.tailor.tech"
DefaultPlatformURL is the production Tailor Platform endpoint.
const DefaultUploadChunkSize = 256 * 1024
DefaultUploadChunkSize is the default chunk size used by Client.UploadFileFromReader when UploadFileParams.ChunkSize is not set.
Variables ¶
This section is empty.
Functions ¶
func IsTokenExpired ¶
IsTokenExpired checks if a token_expires_at string indicates an expired token.
func ResolveOAuth2ClientID ¶ added in v0.4.0
ResolveOAuth2ClientID mirrors the SDK's getOAuth2ClientId: an explicit value wins, then TAILOR_PLATFORM_OAUTH2_CLIENT_ID, then PLATFORM_OAUTH2_CLIENT_ID, then the SDK default. The client_id is not derived from the platform URL, because a self-hosted platform is configured through the same environment variables rather than through a table of known hosts.
func ResolvePlatformURL ¶ added in v0.4.0
ResolvePlatformURL mirrors the SDK's getPlatformBaseUrl: an explicit value wins, then TAILOR_PLATFORM_URL, then PLATFORM_URL. It returns "" when none is set so callers can apply their own fallback.
func WriteSDKTokens ¶
WriteSDKTokens updates the tokens stored under userKey, which is the value SDKTokens.UserKey carries. Taking the resolved key rather than re-deriving one keeps a writeback on a legacy bare-key entry from silently creating a second, platform-scoped entry beside it.
Tokens go to the keyring or the config file depending on the entry's storage mode.
Types ¶
type Client ¶
type Client struct {
tailorv1connect.OperatorServiceClient
// contains filtered or unexported fields
}
Client is an authenticated Tailor Platform client.
It embeds OperatorServiceClient, so RPC methods can be called directly (e.g. c.GetApplication). The auto-refresh interceptor is wired into the embedded client at construction time.
func New ¶
New builds an authenticated client.
Authentication source is determined by which options are supplied:
- WithClientCredentials: fetch an access token via the OAuth2 client_credentials grant using a platform machine user.
- WithTokens: use the supplied access/refresh tokens directly.
- Otherwise: read the current user's tokens from the Tailor SDK config, and proactively refresh them if expired. The platform is taken from the config user key unless WithPlatformURL or the environment names one, so a dev or self-hosted login is not refreshed against production.
Token refresh on unauthenticated unary RPCs is always enabled (using the refresh_token for SDK-config / WithTokens flows, or re-fetching with the stored client_credentials for machine-user flows). SDK config writeback is opt-in via WithTokenPersist and applies only to tokens sourced from that config, since the other two flows have no config entry to write back to.
Example (ClientCredentials) ¶
ExampleNew_clientCredentials authenticates as a platform machine user via the OAuth2 client_credentials grant. This is the option for CI and other unattended callers: it needs no `npx tailor-sdk login` and never touches the SDK config.
package main
import (
"context"
"log"
"os"
tailorclient "github.com/k1LoW/tailor-client-go"
)
func main() { //nostyle:repetition
ctx := context.Background()
_, err := tailorclient.New(ctx,
tailorclient.WithClientCredentials(os.Getenv("TAILOR_CLIENT_ID"), os.Getenv("TAILOR_CLIENT_SECRET")),
)
if err != nil {
log.Fatal(err)
}
}
Output:
Example (ExplicitTokens) ¶
ExampleNew_explicitTokens passes tokens explicitly instead of reading the SDK config.
package main
import (
"context"
"log"
tailorclient "github.com/k1LoW/tailor-client-go"
)
func main() {
ctx := context.Background()
_, err := tailorclient.New(ctx,
tailorclient.WithTokens("access-token", "refresh-token"),
tailorclient.WithPlatformURL(tailorclient.DefaultPlatformURL),
)
if err != nil {
log.Fatal(err)
}
}
Output:
Example (PersistTokens) ¶
ExampleNew_persistTokens enables SDK config writeback on token refresh. Disabled by default.
package main
import (
"context"
"log"
tailorclient "github.com/k1LoW/tailor-client-go"
)
func main() {
ctx := context.Background()
_, err := tailorclient.New(ctx, tailorclient.WithTokenPersist())
if err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) HTTPClient ¶
func (c *Client) HTTPClient() connect.HTTPClient
HTTPClient returns the underlying HTTP client.
func (*Client) PlatformURL ¶
PlatformURL returns the configured Tailor Platform endpoint.
func (*Client) UploadFileFromReader ¶ added in v0.2.0
func (c *Client) UploadFileFromReader(ctx context.Context, params UploadFileParams, r io.Reader) error
UploadFileFromReader streams r to the Tailor Platform as a single file. It sends one InitialMetadata message followed by ChunkData messages until r returns io.EOF, then closes the stream.
This wraps the generated streaming UploadFile RPC so callers do not have to manage the metadata/chunk oneof, the chunk loop, or stream close themselves. The raw streaming RPC is still reachable as c.OperatorServiceClient.UploadFile.
type Option ¶
type Option func(*options)
Option configures New.
func WithClientCredentials ¶ added in v0.3.0
WithClientCredentials configures OAuth2 client_credentials grant authentication using a platform machine user. New() will fetch an access token at construction time, and the interceptor re-fetches with the same credentials whenever the token is rejected as Unauthenticated (machine user grants do not issue refresh tokens, so the helper holds on to the client_id/client_secret rather than a refresh_token).
Mutually exclusive with WithTokens and WithTokenPersist.
func WithHTTPClient ¶
func WithHTTPClient(h connect.HTTPClient) Option
WithHTTPClient overrides the underlying HTTP client.
func WithInterceptors ¶
func WithInterceptors(ics ...connect.Interceptor) Option
WithInterceptors appends additional connect interceptors. The auto-refresh interceptor is always installed first.
func WithOAuth2ClientID ¶ added in v0.4.0
WithOAuth2ClientID overrides the OAuth2 client_id used for the refresh_token grant. Defaults to TAILOR_PLATFORM_OAUTH2_CLIENT_ID, PLATFORM_OAUTH2_CLIENT_ID, then DefaultOAuth2ClientID.
func WithPlatformURL ¶
WithPlatformURL overrides the Tailor Platform endpoint. Without it the endpoint comes from TAILOR_PLATFORM_URL, PLATFORM_URL, the platform recorded on the SDK config user key, and finally DefaultPlatformURL.
func WithTokenPersist ¶
func WithTokenPersist() Option
WithTokenPersist enables writing refreshed tokens back to the SDK config. Disabled by default.
Only tokens sourced from the SDK config can be written back, so this is mutually exclusive with WithTokens and WithClientCredentials.
func WithTokens ¶
WithTokens uses the supplied tokens instead of reading the SDK config. Mutually exclusive with WithTokenPersist, which has no config entry to write back to in this flow.
type SDKConfig ¶
type SDKConfig struct {
Version int `yaml:"version"`
MinSDKVersion string `yaml:"min_sdk_version,omitempty"`
LatestVersion *int `yaml:"latest_version,omitempty"`
LatestMinSDKVersion string `yaml:"latest_min_sdk_version,omitempty"`
Users map[string]*SDKUserTokens `yaml:"users"`
Profiles yaml.MapSlice `yaml:"profiles,omitempty"`
CurrentUser *string `yaml:"current_user"`
}
SDKConfig represents the Tailor SDK config.yaml (v1, v2 and v3 formats).
type SDKTokens ¶ added in v0.4.0
type SDKTokens struct {
AccessToken string
RefreshToken string
TokenExpiresAt string
// PlatformURL is the platform the tokens belong to, either the one the
// caller asked for or the one recovered from the config user key.
PlatformURL string
// UserKey is the key the entry lives under in the config users map. It is
// also the OS keyring account name, and the handle WriteSDKTokens takes.
UserKey string
}
SDKTokens holds the credentials resolved from the Tailor SDK config for one user, together with the platform they were issued for.
func ReadSDKTokens ¶
ReadSDKTokens reads the current_user's credentials from the SDK config.
platformURL selects which of the current_user's platform entries to read; pass "" to let the platform be inferred from the config. Both file-based (v1) and keyring-based (v2, v3) storage are supported.
type SDKUserTokens ¶
type SDKUserTokens struct {
AccessToken string `yaml:"access_token,omitempty"`
RefreshToken string `yaml:"refresh_token,omitempty"`
TokenExpiresAt string `yaml:"token_expires_at"`
Storage *string `yaml:"storage,omitempty"`
// Email is carried so that a writeback does not strip the field the v3
// SDK relies on to match a user across platforms.
Email string `yaml:"email,omitempty"`
}
type TokenResponse ¶
type TokenResponse struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"`
Error string `json:"error,omitempty"`
}
TokenResponse is the response from the OAuth2 token endpoint.
func FetchClientCredentialsToken ¶ added in v0.3.0
func FetchClientCredentialsToken(ctx context.Context, httpClient connect.HTTPClient, platformURL, clientID, clientSecret string) (*TokenResponse, error)
FetchClientCredentialsToken obtains an access token via the OAuth2 client_credentials grant using a platform machine user's clientID and clientSecret.
ctx is propagated to the underlying HTTP request so callers can apply deadlines and cancellation to the token round-trip. httpClient overrides the HTTP transport (e.g. for custom CAs or proxies on self-hosted platforms); pass nil to use http.DefaultClient.
Unlike RefreshAccessToken, the response does not carry a refresh_token — machine user tokens are short-lived and re-fetched with the same credentials when they expire or are rejected.
func RefreshAccessToken ¶
func RefreshAccessToken(ctx context.Context, httpClient connect.HTTPClient, platformURL, oauth2ClientID, refreshToken string) (*TokenResponse, error)
RefreshAccessToken exchanges a refresh_token for a new access_token.
oauth2ClientID selects the OAuth2 client the grant is made against; pass "" to fall back to the environment and then to DefaultOAuth2ClientID, the same way the SDK resolves it.
ctx is propagated to the underlying HTTP request so callers can apply deadlines and cancellation to the token round-trip. httpClient overrides the HTTP transport (e.g. for custom CAs or proxies on self-hosted platforms); pass nil to use http.DefaultClient.
type UploadFileParams ¶ added in v0.2.0
type UploadFileParams struct {
WorkspaceID string
DeploymentID string
FilePath string
ContentType string
// ChunkSize controls the size in bytes of each ChunkData message. When
// zero or negative, DefaultUploadChunkSize is used.
ChunkSize int
}
UploadFileParams configures Client.UploadFileFromReader.