confluence

package
v0.18.1 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package confluence is a thin REST client for Confluence Cloud: enough of the API to fill the page mirror, plus the user-initiated page writes that go through the origin (create / update). It never writes to gadak's SQLite mirror — after a write, callers re-read from the origin (and, on a later surface, SyncPage the same way SyncIssue follows a Jira write).

The token lives only in the Authorization header. It is never put in an error, a log line or a URL (constitution article 8).

Index

Constants

This section is empty.

Variables

View Source
var ErrAuth = atlhttp.Auth("confluence")

ErrAuth is the Confluence-named rejected credential. It unwraps to atlhttp.ErrAuth so Watch detects it without a per-source branch. Error() keeps the "confluence:" prefix so last_error names the source. Callers keep using errors.Is(err, confluence.ErrAuth).

View Source
var ErrConflict = &APIError{Status: http.StatusConflict}

ErrConflict is a 409. On update, that is a stale version.number: the caller refetches and decides. This client does not retry a 409.

View Source
var ErrNotFound = errors.New("confluence: content not found")

ErrNotFound marks a 404 on a specific content id. A page can vanish (or get view-restricted) between the CQL listing and the per-page fetch on a busy site; callers skip that page instead of aborting the run.

Functions

This section is empty.

Types

type APIError added in v0.16.0

type APIError struct {
	Status int
	Body   string
}

APIError is a non-2xx Confluence answer with its HTTP status. Callers distinguish a stale version (409) from other rejections with Status or errors.Is(err, ErrConflict) — not by matching a human-readable substring. The shape follows jira.APIError.

func (*APIError) Error added in v0.16.0

func (e *APIError) Error() string

func (*APIError) Is added in v0.16.0

func (e *APIError) Is(target error) bool

Is reports whether target is an APIError with the same Status. That is how ErrConflict matches any 409, including a wrapped one.

type BodyADF

type BodyADF struct {
	Value          string `json:"value"`
	Representation string `json:"representation"`
}

BodyADF holds body.atlas_doc_format; Value is the ADF document as a JSON string.

type Client

type Client struct {
	HTTP *http.Client
	// Retries is the total number of attempts per request; Backoff is the first
	// wait, doubling per attempt and capped at 30 s.
	Retries int
	Backoff time.Duration
	// PauseBetween is slept after each Page fetch (rate politeness). Zero in tests.
	PauseBetween time.Duration
	// contains filtered or unexported fields
}

Client talks to Confluence Cloud under <site>/wiki.

func New

func New(site, email, token string) *Client

New builds a client. site is the Atlassian origin (no /wiki suffix).

func (*Client) AddPageComment added in v0.16.1

func (c *Client) AddPageComment(ctx context.Context, pageID, adf string) (Comment, error)

AddPageComment POSTs a top-level comment on a page (v1 content with type=comment and the page as container). ADF is the atlas_doc_format value as a JSON string, same as CreatePage.

func (*Client) BaseURL

func (c *Client) BaseURL() string

BaseURL is the wiki origin (…/wiki), used to build deep links.

func (*Client) Comments

func (c *Client) Comments(ctx context.Context, pageID string) ([]Comment, error)

Comments returns every comment on a page plus one level of replies (start/limit paging on each parent).

func (*Client) CreatePage added in v0.16.0

func (c *Client) CreatePage(ctx context.Context, spaceKey, title, adf string, parentID string) (Page, error)

CreatePage POSTs a page to the origin. ADF is the atlas_doc_format value as a JSON string (the same representation the read path already handles). parentID, when non-empty, is sent as ancestors[0].id.

The returned page is a GET of the new id, not the request body and not the POST envelope — the origin is the record.

func (*Client) Page

func (c *Client) Page(ctx context.Context, id string) (Page, error)

Page fetches one content id with ADF body, version, space, ancestors, and labels. metadata.labels is the first page only (≤25 results); see LabelNames.

func (*Client) PageVersions added in v0.16.0

func (c *Client) PageVersions(ctx context.Context, id string) ([]Version, error)

PageVersions lists every history stamp for a content id (GET /content/{id}/version). Bodies are not requested. Pagination follows _links.next the same way SearchPages does. The server's order is not trusted: results are sorted by Number ascending before return.

func (*Client) Raw

func (c *Client) Raw(ctx context.Context, method, path string, body []byte, mutating bool) (status int, out []byte, err error)

Raw sends a request and returns the HTTP status and response body without JSON decoding. Path is relative to the wiki origin (e.g. /rest/api/… or /api/v2/… — not the /wiki prefix). Absolute URLs are rejected. mutating selects the write retry policy (429/503 only).

A completed HTTP response always returns err == nil with the status and body (including non-2xx). err is reserved for transport failures and bad paths.

func (*Client) SearchPages

func (c *Client) SearchPages(ctx context.Context, cql string, fn func([]Page) error) error

SearchPages runs a CQL search with expand=version,space and follows _links.next. fn is called once per page of results (may be empty only on the final empty page).

func (*Client) SiteURL

func (c *Client) SiteURL() string

SiteURL is the Atlassian origin without /wiki.

func (*Client) Space

func (c *Client) Space(ctx context.Context, key string) (Space, error)

Space fetches one space by key with expand=homepage. 404 wraps ErrNotFound (same as Page); callers that tolerate a missing/restricted space skip it.

func (*Client) Spaces

func (c *Client) Spaces(ctx context.Context) ([]Space, error)

Spaces lists every space the credential can see (start/limit paging). expand=homepage fills Space.Homepage so callers can store the root page id.

func (*Client) TakeUsage

func (c *Client) TakeUsage() Usage

TakeUsage returns the current counters and zeroes the numeric fields so a flusher can accumulate into daily totals without double-counting.

LastThrottledAt is a timestamp, not a counter: it is included in the snapshot but is NOT cleared.

func (*Client) UpdatePage added in v0.16.0

func (c *Client) UpdatePage(ctx context.Context, id, title, adf string, nextVersion int) (Page, error)

UpdatePage PUTs a page. nextVersion must be the origin's current version.number + 1. A stale number is a 409 / ErrConflict — the caller refetches and decides; this method does not retry.

The returned page is a GET after the write, same as CreatePage.

func (*Client) Usage

func (c *Client) Usage() Usage

Usage returns the current counters without resetting them.

type Comment

type Comment struct {
	ID      string      `json:"id"`
	Title   string      `json:"title"`
	Body    ContentBody `json:"body"`
	Version Version     `json:"version"`
}

Comment is a child comment (or reply) on a page.

type ContentBody

type ContentBody struct {
	AtlasDocFormat *BodyADF `json:"atlas_doc_format"`
}

ContentBody is the expand=body.atlas_doc_format payload.

func (ContentBody) ADFRaw

func (b ContentBody) ADFRaw() json.RawMessage

ADFRaw returns the atlas_doc_format value as json.RawMessage for storage/FTS. Value is a JSON string of the ADF document.

type Label

type Label struct {
	Name   string `json:"name"`
	Prefix string `json:"prefix"`
	ID     string `json:"id"`
}

Label is one entry under metadata.labels.results (Confluence REST v1).

type LabelsPage

type LabelsPage struct {
	Results []Label `json:"results"`
	Size    int     `json:"size"`
	Limit   int     `json:"limit"`
	Start   int     `json:"start"`
}

LabelsPage is the expanded metadata.labels object. expand=metadata.labels returns only the first page (default limit 25). Real wiki pages almost always have single-digit labels, so paging is intentionally not followed.

type Page

type Page struct {
	ID      string      `json:"id"`
	Type    string      `json:"type"`
	Status  string      `json:"status"`
	Title   string      `json:"title"`
	Space   SpaceRef    `json:"space"`
	Version Version     `json:"version"`
	Body    ContentBody `json:"body"`
	// Metadata is present when expand includes metadata.labels (full Page fetch).
	Metadata PageMetadata `json:"metadata"`
	// Ancestors, when expanded, lists the parent chain; the last entry is the direct parent.
	Ancestors []struct {
		ID string `json:"id"`
	} `json:"ancestors"`
	Links struct {
		WebUI string `json:"webui"`
	} `json:"_links"`
}

Page is a content row (search hit or full fetch).

func (Page) LabelNames

func (p Page) LabelNames() []string

LabelNames returns label names from metadata.labels.results in API order. Always returns a non-nil empty slice when none are present. Does not sort — callers that need determinism (sync → store) sort themselves.

Limit: expand=metadata.labels only includes the first results page (≤25). Pages with more labels than that will be truncated; paging is not followed because production pages typically have single-digit labels.

type PageMetadata

type PageMetadata struct {
	Labels LabelsPage `json:"labels"`
}

PageMetadata is the expand=metadata.* payload on a content row.

type Space

type Space struct {
	Key      string `json:"key"`
	Name     string `json:"name"`
	Type     string `json:"type"`
	Homepage *struct {
		ID string `json:"id"`
	} `json:"homepage"`
}

Space is one space listing row. Homepage is present when expand=homepage was requested; its id is the content id of the space's root page (same id scheme as Page.ID / pages.parent_id).

type SpaceRef

type SpaceRef struct {
	Key  string `json:"key"`
	Name string `json:"name"`
}

SpaceRef is the embedded space on a content row.

type Usage

type Usage = atlhttp.Usage

Usage is a point-in-time snapshot of this client's outbound Confluence traffic. Counters are process-local until a caller persists them (see store.api_usage).

Requests counts every HTTP attempt, including retries: that is the unit that draws from Confluence's rate budget.

type User

type User struct {
	AccountID   string `json:"accountId"`
	DisplayName string `json:"displayName"`
}

User is a Confluence account reference on version.by.

type Version

type Version struct {
	Number    int    `json:"number"`
	When      string `json:"when"`
	Message   string `json:"message"`
	MinorEdit bool   `json:"minorEdit"`
	By        User   `json:"by"`
}

Version is the content version stamp. Message and MinorEdit are filled on GET /content/{id}/version rows; the expand=version object on a Page fetch typically omits them.

Jump to

Keyboard shortcuts

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