client

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ExitOK          = 0
	ExitGeneric     = 1
	ExitUsage       = 2
	ExitAuth        = 3
	ExitNotFound    = 4
	ExitValidation  = 5
	ExitRateLimited = 6
	ExitServer      = 7
)

Documented CLI exit-code scheme (see docs/api-reference.md and the architecture). The cmd layer maps outcomes to these and os.Exit()s with them.

Variables

This section is empty.

Functions

func ExitCode

func ExitCode(err error) int

ExitCode maps a Client error to the documented exit-code scheme. A nil error is success (0); an *APIError maps by HTTP status (401→auth, 404→not-found, 429→rate-limited, other 4xx→validation, 5xx→server, 0→generic); any other error is generic (1). Wrapped *APIErrors are unwrapped via errors.As.

Types

type APIError

type APIError struct {
	StatusCode int
	Code       string
	Message    string
}

APIError is returned by Client methods when the request fails or the server returns an error envelope. StatusCode carries the HTTP status (0 for a transport-level failure); Code/Message come from the server's error object.

func (*APIError) Error

func (e *APIError) Error() string

Error implements the error interface.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a typed HTTP client over the /api/v1 surface. It depends only on the JSON contract (stdlib) — it imports no server internals — which is what lets a future MCP server reuse it. Construct it with New.

func New

func New(baseURL, apiKey string) (*Client, error)

New builds a Client targeting baseURL authenticated with apiKey. The base URL is normalized (trailing slash trimmed) and must be an http(s) scheme + host with no userinfo and no path (the client appends /api/v1/...); rejecting a path avoids a silent double-prefix when callers proxy under a path. The returned Client follows redirects but strips the API key on cross-host hops. A default 30s per-request timeout is applied so a hung server cannot block the CLI indefinitely.

func (*Client) CreateContent

func (c *Client) CreateContent(
	ctx context.Context,
	req CreateContentRequest,
) (json.RawMessage, json.RawMessage, error)

CreateContent POSTs a content-create request to /api/v1/content and returns the decoded data and meta payloads, or an *APIError on failure.

func (*Client) DeleteContent

func (c *Client) DeleteContent(
	ctx context.Context,
	id int,
) (json.RawMessage, json.RawMessage, error)

DeleteContent sends DELETE /api/v1/content/{id}. A 204 No Content success returns (nil, nil, nil); a 404 or other 4xx/5xx returns an *APIError.

func (*Client) GetContent

func (c *Client) GetContent(
	ctx context.Context,
	id int,
) (json.RawMessage, json.RawMessage, error)

GetContent sends GET /api/v1/content/{id} and returns the decoded data and meta payloads, or an *APIError on failure.

func (*Client) GetMedia

func (c *Client) GetMedia(
	ctx context.Context,
	id int,
) (json.RawMessage, json.RawMessage, error)

GetMedia sends GET /api/v1/media/{id} and returns the decoded data and meta payloads, or an *APIError on failure.

func (*Client) ListContent

func (c *Client) ListContent(
	ctx context.Context,
	limit int,
	cursor string,
	filters ListContentFilters,
) (json.RawMessage, json.RawMessage, error)

ListContent sends GET /api/v1/content?limit=&cursor=&tag=&language=&status=&post_type=&author=&search= and returns the decoded data (a bare array of content projections) and meta (with pagination), or an *APIError on failure. A limit of 0 (or negative) is passed as "no limit" (the server uses its default); an empty cursor is passed as "no cursor" (the first page). Each non-empty filter field emits its query key; an empty field is omitted entirely so the wire stays minimal. Tags is expanded into repeated ?tag= keys (one per tag) so the server can AND-of-tags.

func (*Client) ListMedia

func (c *Client) ListMedia(
	ctx context.Context,
	limit int,
	cursor string,
) (json.RawMessage, json.RawMessage, error)

ListMedia sends GET /api/v1/media?limit=&cursor= and returns the decoded data (a bare array of media projections) and meta (with pagination), or an *APIError on failure. A limit of 0 (or negative) is passed as "no limit" (the server uses its default); an empty cursor is passed as "no cursor" (the first page).

func (*Client) PublishContent

func (c *Client) PublishContent(
	ctx context.Context,
	id int,
) (json.RawMessage, json.RawMessage, error)

PublishContent sends POST /api/v1/content/{id}/publish with an empty body and returns the decoded data and meta payloads, or an *APIError on failure. The server endpoint is idempotent: publishing an already-published post returns 200 with the current projection. Ownership is enforced server-side; a non-admin non-owner call returns 404 (not 403, no disclosure).

func (*Client) UnpublishContent

func (c *Client) UnpublishContent(
	ctx context.Context,
	id int,
) (json.RawMessage, json.RawMessage, error)

UnpublishContent sends POST /api/v1/content/{id}/unpublish with an empty body and returns the decoded data and meta payloads, or an *APIError on failure. The server endpoint is idempotent: unpublishing an already-draft post returns 200 with the current projection. Same ownership contract as PublishContent.

func (*Client) UpdateContent

func (c *Client) UpdateContent(
	ctx context.Context,
	id int,
	req UpdateContentRequest,
) (json.RawMessage, json.RawMessage, error)

UpdateContent sends PUT /api/v1/content/{id} with the given request body and returns the decoded data and meta payloads, or an *APIError on failure. The request body is the same shape as CreateContent. The server's update handler preserves the server-managed fields (SEO metadata — metaDescription / ogTitle / ogDescription, allowComments, translationGroupId) from the existing item, so a partial update that omits them is safe; postType / tags / language are now settable and forwarded as-given (the server validates them).

func (*Client) UploadMedia

func (c *Client) UploadMedia(
	ctx context.Context,
	req UploadMediaRequest,
) (json.RawMessage, json.RawMessage, error)

UploadMedia sends POST /api/v1/media as multipart/form-data with a `file` part and an optional `metadata` JSON part, then returns the decoded data and meta payloads (the server returns 200 with the media projection in the data envelope) or an *APIError on failure.

The multipart body is buffered in memory; the server enforces its own size limit at r.ParseMultipartForm. The 204/304+envelope defenses from doRequest apply unchanged.

type CreateContentRequest

type CreateContentRequest struct {
	Title       string   `json:"title"`
	Body        string   `json:"body"`
	Format      string   `json:"format,omitempty"`
	PostType    string   `json:"postType,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	Language    string   `json:"language,omitempty"`
	IsPublished bool     `json:"isPublished,omitempty"`
}

CreateContentRequest is the agent content-create payload. It mirrors the {data, error, meta} contract documented in docs/api-reference.md — the client hard-codes it (it cannot import the server's DTO types).

All metadata fields (PostType, Tags, Language) use `omitempty` so an unset value is identical on the wire to a default-zero request. Tags must already be normalized by the caller (the CLI's normalizeTags helper trims, drops empties, and dedupes); the server re-validates via contentdomain.ValidateTags. Language is forwarded as-given — the server is the single source of truth for the configured-languages list (it returns ErrInvalidLanguage for an unknown code, mapped to 400 VALIDATION_ERROR by the CLI's exit code map).

type ListContentFilters

type ListContentFilters struct {
	Tags     []string
	Language string
	Status   string
	PostType string
	Author   string
	Search   string
}

ListContentFilters is the cmd-layer projection of contentdomain.ContentFilters for the agent List endpoint. The CLI re-declares the shape (it cannot import server-internal types) so the wire contract is the source of truth, and only the fields used by the agent v1 surface are exposed here. Tags is intentionally a slice — the wire format uses repeated ?tag= keys (one per tag, AND-of-tags on the server). An empty / zero struct produces a no-filter call (server returns the unfiltered list).

type UpdateContentRequest

type UpdateContentRequest struct {
	Title       string   `json:"title"`
	Body        string   `json:"body"`
	Format      string   `json:"format,omitempty"`
	PostType    string   `json:"postType,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	Language    string   `json:"language,omitempty"`
	IsPublished bool     `json:"isPublished,omitempty"`
}

UpdateContentRequest is the agent content-update payload. It carries the same fields as CreateContentRequest because the server's PUT /api/v1/content/{id} accepts the same ContentRequest shape. The server preserves the server-managed fields (SEO metadata — metaDescription / ogTitle / ogDescription, allowComments, translationGroupId) from the existing item; the client does not surface flags for them. The client cannot import the server's DTO types so the subset is re-declared here.

type UploadMediaRequest

type UploadMediaRequest struct {
	File     io.Reader
	Filename string
	Metadata map[string]string
}

UploadMediaRequest is the multipart payload sent to POST /api/v1/media. It is built in memory by UploadMedia — callers supply the file reader + filename and an optional metadata map (the server reads `altText` today; the map type allows future expansion without a client signature change). The client validates that File is non-nil and Filename is non-empty so a bad call site fails fast with a clear error instead of a runtime panic.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL