client

package
v0.30.23 Latest Latest
Warning

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

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

Documentation

Overview

Package client provides an HTTP client for the xolu REST API server.

xolu is a graph-enhanced document store that provides:

  • Entity CRUD operations
  • Graph relationships via REF objects
  • OQL (SQL-like) queries
  • Sulpher (graph path) queries
  • Full-text search

This client wraps the HTTP API and provides a convenient Go interface.

Declared surface (v0.16.0 stability)

The client covers xolu's data-plane and semantic-map surface: entity CRUD, Commit, Search, OQL, Sulpher, graph basics (neighbours, query, shortest path), schemas (get + write + list, including schemaless entity types via ListEntities, added 2026-08-04, T-151), named sequences and generators, the full FSM machine surface, the full FSM definition surface (added 2026-08-04: Create/Replace/Delete/Validate, alongside the existing List/Get -- previously read-only), event- definition reads, cal (check/openings/propose/confirm), health/ availability, the native blob surface (added 2026-08-03, T-142: put/get/head/delete/list/usage), and async tenant-scoped export (added 2026-08-03, T-145: BlobExportStart/BlobExportStatus plus the Export convenience wrapper). This is the surface molu Parts 2–3 consume, and it is version-tied to the server.

Deliberately out of scope — documented exclusions, not omissions: timeseries, meta, admin, dynconfig, stats, async-query polling, and the deep graph analytics (pathExists, commonNeighbors, per-node inspection, edges, admin rebuild/verify). See docs/CLIENT_STAGE6_PLAN.md for the audit that drew this line; a consumer needing an excluded family reopens the scope decision rather than finding an accidental gap.

Export specifically, for anyone reading history in the register: a synchronous streaming client method (T-145, first draft) was built against the old, non-tenant-scoped GET /api/v1/export, then deliberately shelved (2026-08-03) in favour of the async, tenant- scoped, blob-backed design this package now implements — see pkg/tenantexport's own doc comment for the full history. The requirement T-145 named (the client has to actually deliver export data to the caller, streamed) didn't change; only the mechanism did. The old, now-unused GET /api/v1/export endpoint is untouched server-side.

Index

Constants

This section is empty.

Variables

AllGeneratorKinds enumerates the generator kinds a consumer can query. To build a complete generator listing, iterate this slice and call Client.ListGenerators for each kind.

View Source
var DefaultRetryPolicy = RetryPolicy{
	MaxAttempts:       3,
	InitialBackoff:    200 * time.Millisecond,
	MaxBackoff:        5 * time.Second,
	BackoffMultiplier: 2.0,
}

DefaultRetryPolicy is a sensible starting point: three attempts, 200 ms initial backoff, 5 s ceiling, doubling. Callers who want retries can pass this via WithRetryPolicy directly, or copy and modify it.

This is NOT the client's default when WithRetryPolicy is not supplied — that default is "no retries" (MaxAttempts=1) for backwards compatibility with pre-Stage-4 client versions.

Functions

func DefaultRetryOn

func DefaultRetryOn(resp *http.Response, err error) bool

DefaultRetryOn is the default retry-decision predicate: it returns true for transport-level errors (err != nil and not caused by context) and for HTTP 5xx responses.

It returns false on:

  • success responses (2xx)
  • client errors (4xx) including 401, 403, 404, 409, 422 — these are not transient and retrying will not fix them
  • context cancellation or deadline exceeded — the caller has decided the call should stop

Types

type AuthMode

type AuthMode int

AuthMode identifies which HTTP authentication mode the client uses when talking to xolu. See xolu's pkg/middleware/auth for the corresponding server-side handling.

const (
	// AuthNone sends no Authorization header. Used when the xolu server has
	// AuthType="" or when the client sits behind a trusted gateway.
	AuthNone AuthMode = iota
	// AuthAPIKey sends "Authorization: Bearer <key>" where the key is an
	// entry in the server's XOLU_API_KEYS list. See WithAPIKey.
	AuthAPIKey
	// AuthBearer sends "Authorization: Bearer <token>" where the token is a
	// server-issued opaque bearer token. See WithBearerToken.
	AuthBearer
	// AuthJWT sends "Authorization: Bearer <jwt>" where the JWT is signed
	// with the secret configured as XOLU_JWT_SECRET. See WithJWT.
	AuthJWT
)

type AvailableTransitions

type AvailableTransitions struct {
	State  string   `json:"state"`
	Inputs []string `json:"inputs"`
}

AvailableTransitions is the response of Client.GetMachineTransitions — the input symbols for which a transition from the current state exists.

Guards are not pre-evaluated at this endpoint; an input appears here if any transition names it from the current state, whether or not that transition's guard would currently permit the walk.

type BalAccount added in v0.26.0

type BalAccount struct {
	AccountID string `json:"account_id"`
	Unit      string `json:"unit"`
	Scale     uint8  `json:"scale"`
	Floor     string `json:"floor"`
	Postable  bool   `json:"postable"`
}

BalAccount is the response of BalDefine.

type BalAccountSummary added in v0.30.23

type BalAccountSummary struct {
	AccountID string `json:"account_id"`
	Unit      string `json:"unit"`
	Scale     uint8  `json:"scale"`
	Floor     string `json:"floor"`
	Ceiling   string `json:"ceiling,omitempty"`
	Postable  bool   `json:"postable"`
	Policy    string `json:"policy"`
	Value     string `json:"value"`
	Minor     int64  `json:"minor"`
	Version   int64  `json:"version"`
}

BalAccountSummary is one row of BalListAccounts -- an account's own definition joined with its current balance. Floor/Ceiling/Value are decimal strings at the account's own Scale (@B04); Minor carries the same balance as a raw int64 minor-unit value for exact arithmetic without re-parsing the decimal string, matching BalBalanceResult's own established shape. Ceiling is empty when the account was defined with no ceiling.

type BalAsOfResult added in v0.26.0

type BalAsOfResult struct {
	AccountID string    `json:"account_id"`
	At        time.Time `json:"at"`
	Value     string    `json:"value"`
	Minor     int64     `json:"minor"`
	Source    string    `json:"source"`
}

BalAsOfResult is the response of BalAsOf. Source is always "rollup" today — the derived, fast-path plane; the exact/audit path (the journal chain) has no HTTP surface and is verified equal to this one by the rollup rebuild oracle, not exposed as a caller-selectable option.

type BalBalanceResult added in v0.26.0

type BalBalanceResult struct {
	AccountID string `json:"account_id"`
	Value     string `json:"value"`
	Minor     int64  `json:"minor"`
	Version   int64  `json:"version"`
}

BalBalanceResult is the response of BalBalance. Value is the decimal-string rendering at the account's own declared scale; Minor is the same quantity as exact int64 minor units, useful when a caller wants to avoid decimal parsing entirely.

type BalCloseResult added in v0.26.0

type BalCloseResult struct {
	SealedThrough  time.Time `json:"sealed_through"`
	AccountsClosed int       `json:"accounts_closed"`
}

BalCloseResult is the response of BalClose. Sealing is tenant-wide (the whole account-set's seal frontier advances together, per T-64) — AccountsClosed is how many postable accounts received a closing checkpoint as part of this call, not a count the caller selects.

type BalDefineRequest added in v0.26.0

type BalDefineRequest struct {
	AccountID string  `json:"account_id"`
	Unit      string  `json:"unit"`
	Scale     uint8   `json:"scale"`
	Floor     *string `json:"floor,omitempty"`
	Ceiling   *string `json:"ceiling,omitempty"`
	Postable  *bool   `json:"postable,omitempty"`
}

BalDefineRequest defines an account. Floor and Ceiling are decimal strings at Scale (e.g. "-1000000" for scale 0, "10.50" for scale 2) — omit either for no bound. Postable defaults to true server-side when nil; set false only for summary/hierarchy accounts that never receive a direct transfer (XOLU-BAL005 refuses one that tries).

type BalEntriesResult added in v0.26.0

type BalEntriesResult struct {
	AccountID string     `json:"account_id"`
	Entries   []BalEntry `json:"entries"`
}

BalEntriesResult is the response of BalEntries. The server currently returns at most the account's 100 most recent entries — there is no pagination parameter on the wire today; a caller needing the full history should read it before any retention policy prunes it (bal.Store.PruneJournal, item 16).

type BalEntry added in v0.26.0

type BalEntry struct {
	EntryID         int64     `json:"entry_id"`
	TransferID      string    `json:"transfer_id"`
	Amount          string    `json:"amount"`
	PreviousBalance string    `json:"previous_balance"`
	CurrentBalance  string    `json:"current_balance"`
	Version         int64     `json:"version"`
	Memo            string    `json:"memo,omitempty"`
	At              time.Time `json:"at"`
}

BalEntry is one journal entry as BalEntries returns it.

type BalListAccountsResult added in v0.30.23

type BalListAccountsResult struct {
	Accounts []BalAccountSummary `json:"accounts"`
}

BalListAccountsResult is the response of BalListAccounts.

type BalTransferRequest added in v0.26.0

type BalTransferRequest struct {
	TransferID string `json:"transfer_id,omitempty"`
	From       string `json:"from"`
	To         string `json:"to"`
	Amount     string `json:"amount"`
	Scale      uint8  `json:"scale"`
	Memo       string `json:"memo,omitempty"`
	At         string `json:"at,omitempty"` // RFC3339; empty means "now" server-side
}

BalTransferRequest moves Amount (a decimal string at Scale) from From to To. TransferID is the client idempotency key — a UUID is generated server-side when omitted, but supplying one lets a caller safely retry a request whose response was lost. At defaults to now when omitted; a strictly-earlier At than an account's latest entry is refused (XOLU-BAL006) unless that account's policy is backdated (not settable over this API today — accounts are always created append_only).

type BalTransferResult added in v0.26.0

type BalTransferResult struct {
	TransferID string `json:"transfer_id"`
	From       string `json:"from"`
	To         string `json:"to"`
	Amount     string `json:"amount"`
}

BalTransferResult is the response of BalTransfer.

type BlobDeleteResult added in v0.26.0

type BlobDeleteResult struct {
	Key     string `json:"key"`
	Deleted bool   `json:"deleted"`
}

BlobDeleteResult is the response to a successful blob deletion.

Deletion removes the key alias only. The underlying content-addressed blob is not immediately removed -- xolu's own GC handles unreferenced blobs separately, per blob_handlers.go's own comment on this route.

type BlobExportJob added in v0.26.0

type BlobExportJob struct {
	Ticket string              `json:"ticket"`
	Status BlobExportJobStatus `json:"status"`
	// BlobKey is set once Status == BlobExportComplete -- the key this
	// tenant's export is stored under, retrievable via BlobGet.
	BlobKey string `json:"blob_key,omitempty"`
	// Error is set once Status == BlobExportFailed.
	Error string `json:"error,omitempty"`
}

BlobExportJob is the status of one export job.

type BlobExportJobStatus added in v0.26.0

type BlobExportJobStatus string

BlobExportJobStatus is an export job's lifecycle state, mirroring pkg/tenantexport.JobStatus on the wire.

const (
	BlobExportRunning  BlobExportJobStatus = "running"
	BlobExportComplete BlobExportJobStatus = "complete"
	BlobExportFailed   BlobExportJobStatus = "failed"
)

type BlobGetResult added in v0.26.0

type BlobGetResult struct {
	Body        io.ReadCloser
	ContentType string
	SHA256      string
	MD5         string
	Size        int64
	ETag        string
}

BlobGetResult carries a streamed blob's content alongside its metadata. Body MUST be closed by the caller (defer result.Body.Close()) -- closing it also releases the request's own context timeout, if one was configured; the connection is not fully released until then.

type BlobHeadResult added in v0.26.0

type BlobHeadResult struct {
	Key         string
	ContentType string
	Size        int64
	SHA256      string
	MD5         string
	// ETag is the raw ETag header value, quotes included (e.g.
	// `"deadbeef..."`), matching HTTP convention -- always equal to
	// `"` + SHA256 + `"` today, carried separately in case that
	// changes.
	ETag     string
	StoredAt time.Time
}

BlobHeadResult is the response to BlobHead -- metadata only, no content. Fields mirror BlobMeta; kept as a distinct type (not a type alias) because the server's own HEAD response carries ETag and a couple of header-only fields BlobMeta's GET/LIST shape doesn't.

type BlobListResult added in v0.26.0

type BlobListResult struct {
	Tenant string     `json:"tenant"`
	Prefix string     `json:"prefix,omitempty"`
	Count  int        `json:"count"`
	Blobs  []BlobMeta `json:"blobs"`
}

BlobListResult is the response to BlobList.

type BlobMeta added in v0.26.0

type BlobMeta struct {
	Key         string    `json:"key"`
	SHA256      string    `json:"sha256"`
	MD5         string    `json:"md5,omitempty"`
	Size        int64     `json:"size"`
	ContentType string    `json:"content_type,omitempty"`
	StoredAt    time.Time `json:"stored_at"`
}

BlobMeta describes one stored blob's metadata, without its content. Returned by BlobList (one per result) and mirrored by BlobHeadResult for a single-key lookup.

type BlobPutResult added in v0.26.0

type BlobPutResult struct {
	// Key is the stored key. Equal to the key BlobPut was called with,
	// or (when BlobPut was called with an empty key) the content's own
	// SHA256 — content-addressed storage with no separate alias.
	Key string `json:"key"`
	// SHA256 is the content hash, always populated.
	SHA256 string `json:"sha256"`
	// MD5 is the content hash in MD5, present for S3-compatible ETag
	// consumers. Empty is possible but not expected in practice.
	MD5 string `json:"md5,omitempty"`
	// Size is the stored content length in bytes.
	//
	// Known gap, not a client bug: the server's own PUT response does
	// not currently populate this field (confirmed directly against
	// blob_handlers.go's handleBlobPut, which never sets Size on the
	// blobPutResponse it writes) -- it will decode as 0 even for a
	// non-empty blob. Use BlobHead after a Put if the size is needed;
	// BlobHead's own response is populated correctly.
	Size int64 `json:"size"`
	// Created is true when this call created a new stored object
	// (false when the content was already present -- content-addressed
	// storage deduplicates identical bytes).
	Created bool `json:"created"`
}

BlobPutResult is the response to a successful blob upload.

type BlobUsageResult added in v0.26.0

type BlobUsageResult struct {
	Tenant    string     `json:"tenant"`
	BlobCount int64      `json:"blob_count"`
	KeyCount  int64      `json:"key_count"`
	Bytes     int64      `json:"bytes"`
	SampledAt *time.Time `json:"sampled_at,omitempty"`
}

BlobUsageResult is the response to BlobUsage -- the most recently sampled disk usage for the tenant's blob namespace, served from an in-memory cache the server's own background sampler maintains (the filesystem is never walked at request time). SampledAt is nil until the sampler completes its first walk; all counts read zero until then, not an error.

type CalBooking

type CalBooking struct {
	BookingID   string    `json:"booking_id"`
	CalendarID  string    `json:"calendar_id"`
	State       string    `json:"state"`
	Span        CalSpan   `json:"span"`
	Mode        string    `json:"mode"`
	Bearer      uint64    `json:"bearer"`
	BufferAfter time.Time `json:"buffer_after,omitempty"`
	CreatedAt   time.Time `json:"created_at,omitempty"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"`
	DetailRef   string    `json:"detail_ref,omitempty"`
}

CalBooking is a booking record as the server returns it from CalPropose and CalConfirm.

type CalCheckResult

type CalCheckResult struct {
	Feasible        bool      `json:"feasible"`
	NearestOpenings []CalSpan `json:"nearest_openings"`
}

CalCheckResult is the response of CalCheck: whether the span is bookable, and if not, the nearest alternative openings.

type CalCreateCalendarRequest added in v0.30.23

type CalCreateCalendarRequest struct {
	CalendarID   string `json:"calendar_id"`
	EntityRef    uint64 `json:"entity_ref,omitempty"`
	DefaultState string `json:"default_state,omitempty"`
	MatchPolicy  string `json:"match_policy,omitempty"`
}

CalCreateCalendarRequest is the request body of CalCreateCalendar. CalendarID is required; DefaultState/MatchPolicy default sensibly server-side (StateBinding/ConsiderBinding) when left empty.

type CalListBookingsResult added in v0.30.23

type CalListBookingsResult struct {
	Bookings []CalBooking `json:"bookings"`
}

CalListBookingsResult is the response of CalListBookings, reusing the existing CalBooking type (also returned by CalPropose/ CalConfirm) since the server's own handler shares the same bookingFromCal wire-conversion helper for all three.

type CalListCalendarsResult added in v0.30.23

type CalListCalendarsResult struct {
	Calendars []CalendarSummary `json:"calendars"`
}

CalListCalendarsResult is the response of CalListCalendars.

type CalOpening

type CalOpening struct {
	Start    time.Time `json:"start"`
	End      time.Time `json:"end"`
	MarginMs int64     `json:"margin_ms"`
}

CalOpening is one candidate window returned by CalOpenings, carrying the clear margin around it in milliseconds.

type CalOpeningsResult

type CalOpeningsResult struct {
	Objective Objective    `json:"objective"`
	Openings  []CalOpening `json:"openings"`
}

CalOpeningsResult is the response of CalOpenings; Objective echoes the objective actually applied (the server substitutes "earliest" when the request omitted one).

type CalProposeRequest

type CalProposeRequest struct {
	BookingID   string     `json:"booking_id"`
	CalendarID  string     `json:"calendar_id"`
	Span        CalSpan    `json:"span"`
	Mode        string     `json:"mode,omitempty"`
	Bearer      uint64     `json:"bearer,omitempty"`
	BufferAfter *time.Time `json:"buffer_after,omitempty"`
	DetailRef   string     `json:"detail_ref,omitempty"`
}

CalProposeRequest creates a booking in the proposed state. BookingID is client-generated identity (e.g. a ULID) and required; Mode defaults to "exclusive", the only mode the occupancy engine honours.

type CalSpan

type CalSpan struct {
	Start time.Time `json:"start"`
	End   time.Time `json:"end"`
}

CalSpan is a half-open time span; Start must be strictly before End.

type CalendarSummary added in v0.30.23

type CalendarSummary struct {
	CalendarID   string `json:"calendar_id"`
	EntityRef    uint64 `json:"entity_ref"`
	DefaultState string `json:"default_state"`
	MatchPolicy  string `json:"match_policy"`
}

CalendarSummary is one row of CalListCalendars, and the response of CalCreateCalendar.

type Client

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

Client provides access to the xolu REST API.

func New

func New(baseURL string, opts ...ClientOption) *Client

New creates a new xolu client.

func (*Client) BalAsOf added in v0.26.0

func (c *Client) BalAsOf(ctx context.Context, accountID string, at time.Time) (*BalAsOfResult, error)

BalAsOf returns accountID's balance as of instant at, read from the derived rollup plane (the fast path — nearest sealed checkpoint plus intervening buckets). Always agrees with the authoritative journal; the rollup rebuild oracle proves it server-side, not something a caller re-verifies per request.

Hits GET /api/v2/.../bal/asof?account={accountID}&at={RFC3339}. Returns *client.Error on non-2xx — notably XOLU-BAL002 for an unknown account.

func (*Client) BalBalance added in v0.26.0

func (c *Client) BalBalance(ctx context.Context, accountID string) (*BalBalanceResult, error)

BalBalance returns accountID's current authoritative balance — the guard-plane value, always exact and always current, unlike BalAsOf's derived-plane fast path.

Hits GET /api/v2/.../bal/balance?account={accountID}. Returns *client.Error on non-2xx — notably XOLU-BAL002 for an unknown account.

func (*Client) BalClose added in v0.26.0

func (c *Client) BalClose(ctx context.Context, at time.Time) (*BalCloseResult, error)

BalClose seals the tenant's whole account-set as of instant at (item 16 §7): advances the seal frontier and writes a closing checkpoint for every postable account together. Sealing is tenant-wide, not per-account — there is no way to close only one account's period over this API, by design (bal-conservation- primitive.md §7's "account-set" is the whole tenant here).

A closed period permanently refuses any future entry dated within it (XOLU-BAL003), regardless of an account's own backdated policy. This cannot be undone over the API or otherwise.

Hits POST /api/v2/.../bal/close. Returns *client.Error on non-2xx.

func (*Client) BalDefine added in v0.26.0

func (c *Client) BalDefine(ctx context.Context, req BalDefineRequest) (*BalAccount, error)

BalDefine creates or configures an account. Postable summary accounts (Postable: false) may parent postable leaves for hierarchical reporting but never receive a direct transfer.

Hits POST /api/v2/.../bal/def. Returns *client.Error on non-2xx.

func (*Client) BalEntries added in v0.26.0

func (c *Client) BalEntries(ctx context.Context, accountID string) (*BalEntriesResult, error)

BalEntries returns accountID's most recent journal entries (the server currently caps this at 100; see BalEntriesResult's doc).

Hits GET /api/v2/.../bal/entries?account={accountID}. Returns *client.Error on non-2xx — notably XOLU-BAL002 for an unknown account.

func (*Client) BalListAccounts added in v0.30.23

func (c *Client) BalListAccounts(ctx context.Context) (*BalListAccountsResult, error)

BalListAccounts returns every account defined on the tenant, each with its own definition and current balance -- no way existed to enumerate a tenant's own accounts at all before this (XM-2, XOT172); every other bal method requires already knowing an account's own id.

Hits GET /api/v2/.../bal/accounts. Returns *client.Error on non-2xx.

func (*Client) BalTransfer added in v0.26.0

func (c *Client) BalTransfer(ctx context.Context, req BalTransferRequest) (*BalTransferResult, error)

BalTransfer moves req.Amount (a decimal string at req.Scale) from req.From to req.To, both existing postable account ids. Supply req.TransferID for a caller-controlled idempotency key; a UUID is generated server-side when omitted.

Hits POST /api/v2/.../bal/transfer. Returns *client.Error on non-2xx — notably XOLU-BAL001 when the transfer would breach a floor or ceiling, and XOLU-BAL006 for a backdated entry.

func (*Client) BlobDelete added in v0.26.0

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

BlobDelete removes a key alias. The underlying content-addressed blob is not immediately removed -- xolu's own GC handles unreferenced blobs separately.

Hits DELETE /api/v1/blob/{key}. Returns *client.Error on non-2xx (XOLU-BLOB-not-found family maps to 404).

func (*Client) BlobExportStart added in v0.26.0

func (c *Client) BlobExportStart(ctx context.Context) (*BlobExportJob, error)

BlobExportStart starts an async export job for this client's own tenant. Returns immediately with a ticket; the export itself runs in the background server-side (deliberately low-priority and throttled to one job in flight per tenant -- a second call while one is already running returns *client.Error with HTTPStatus 409, carrying the existing ticket in its message).

Hits POST /api/v1/tenant/{tenant}/blob/export. Returns *client.Error on non-2xx.

func (*Client) BlobExportStatus added in v0.26.0

func (c *Client) BlobExportStatus(ctx context.Context, ticket string) (*BlobExportJob, error)

BlobExportStatus polls one export job's status by ticket.

Hits GET /api/v1/tenant/{tenant}/blob/export/{ticket}. Returns *client.Error (HTTPStatus 404) if the ticket is unknown to this tenant -- including a ticket that belongs to a different tenant, which is treated identically to "not found" rather than confirming it exists elsewhere.

func (*Client) BlobGet added in v0.26.0

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

BlobGet retrieves a blob's content as a stream -- the response body is never buffered into memory, so this is safe to use for blobs of any size. The caller is responsible for reading and closing result.Body.

Hits GET /api/v1/blob/{key}. Single attempt, not retried -- see this file's own header comment. Returns *client.Error on non-2xx (Body is nil in that case; the error response itself is small and safely buffered internally before being decoded).

func (*Client) BlobHead added in v0.26.0

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

BlobHead retrieves a blob's metadata without its content -- cheaper than BlobGet when only size/hash/existence is needed.

Hits HEAD /api/v1/blob/{key}. Single attempt, not retried -- see this file's own header comment. Returns *client.Error on non-2xx; the server's own HEAD handler returns bare status codes with no JSON body on error, so the resulting *client.Error carries an HTTP status but no Code/Message.

func (*Client) BlobList added in v0.26.0

func (c *Client) BlobList(ctx context.Context, prefix string) (*BlobListResult, error)

BlobList lists stored blobs, optionally filtered by key prefix, sorted by key ascending (the server's own sort order).

Hits GET /api/v1/blob. Returns *client.Error on non-2xx.

func (*Client) BlobPut added in v0.26.0

func (c *Client) BlobPut(ctx context.Context, key, contentType string, body io.Reader) (*BlobPutResult, error)

BlobPut uploads content under key. If key is empty, the server stores the content addressed by its own SHA256 and returns that hash as the effective key (BlobPutResult.Key) -- no separate alias is written. contentType is sent as-is; pass "" to let the server default to application/octet-stream.

Keys are FLAT, not hierarchical -- there is no folder/prefix structure at the storage layer. A non-empty key must not contain '/' or '\', must not be "." or "..", and must not start with "." (reserved for internal use) -- validated client-side against xolu's own rules (pkg/blob/store.go's validateKey) before any request is sent, matching this client's established convention (see bal.go) of catching an obviously-invalid call before spending a round trip on it. BlobList's prefix filter still works normally on flat keys (a plain string prefix match, e.g. prefix "log-" matches "log-2026-01" and "log-2026-02") -- "flat" means no '/' delimiter is meaningful, not that prefix filtering is unavailable.

Hits POST /api/v1/blob with X-Blob-Key set when key is non-empty. Single attempt, not retried -- see this file's own header comment. Returns *client.Error on non-2xx.

func (*Client) BlobUsage added in v0.26.0

func (c *Client) BlobUsage(ctx context.Context) (*BlobUsageResult, error)

BlobUsage returns the most recently sampled disk usage for the tenant's blob namespace. Served from an in-memory cache the server's own background sampler maintains -- cheap, but SampledAt may be nil (and all counts zero) if the sampler has not yet completed its first walk. That is a valid response, not an error.

Hits GET /api/v1/blob/usage. Returns *client.Error on non-2xx (503 if the blob subsystem is not enabled server-side at all).

func (*Client) CalCheck

func (c *Client) CalCheck(ctx context.Context, calendarID string, span CalSpan) (*CalCheckResult, error)

CalCheck asks whether span is bookable on the calendar right now, without creating anything. On infeasibility the result carries the nearest alternative openings.

Hits POST /api/v2/.../cal/check. Returns *client.Error on non-2xx.

func (*Client) CalConfirm

func (c *Client) CalConfirm(ctx context.Context, calendarID, bookingID string) (*CalBooking, error)

CalConfirm transitions a proposed booking to binding and returns the updated record.

Hits POST /api/v2/.../cal/confirm. Returns *client.Error on non-2xx — notably XOLU-CAL003 for an illegal state transition and XOLU-CAL005 for an unknown booking.

func (*Client) CalCreateCalendar added in v0.30.23

func (c *Client) CalCreateCalendar(ctx context.Context, req CalCreateCalendarRequest) (*CalendarSummary, error)

CalCreateCalendar creates a new calendar on the tenant -- XM-8, xoluman's own report: no route anywhere created a calendar at all before this, despite the underlying capability (Manager.CreateCalendar) already existing and working correctly. The actual root blocker behind their own XM-2 report: CalListCalendars/CalListBookings both worked correctly, but had nothing to list, since nothing could be created through the public API to list in the first place.

Hits POST /api/v2/.../cal/calendars. Returns *client.Error on non-2xx — notably XOLU-CAL008 (ErrCalCalendarExists) if req.CalendarID is already taken.

func (*Client) CalListBookings added in v0.30.23

func (c *Client) CalListBookings(ctx context.Context, calendarID string, from, to time.Time) (*CalListBookingsResult, error)

CalListBookings returns every live (proposed, binding, or honoured) booking on calendarID whose own span overlaps [from, to) -- the inverse of CalOpenings: what's already booked, not what's free. Requested by xoluman (XM-2) for an occupancy grid, where CalOpenings alone can't show what's actually on the calendar.

Hits GET /api/v2/.../cal/bookings. Returns *client.Error on non-2xx — notably XOLU-CAL002 (ErrCalCalendarNotFound) for an unknown calendar.

func (*Client) CalListBookingsForBearer added in v0.30.23

func (c *Client) CalListBookingsForBearer(ctx context.Context, bearer uint64) (*CalListBookingsResult, error)

CalListBookingsForBearer returns every live (proposed, binding, or honoured) booking held by bearer across every calendar on the tenant -- the cross-calendar complement to CalListBookings, which is scoped to one calendar at a time. Requested by xoluman (XM-2) as an example of a gap the per-calendar shape leaves open: "what bookings does bearer X hold across every calendar."

Hits GET /api/v2/.../cal/bookings/by-bearer. Returns *client.Error on non-2xx.

func (*Client) CalListCalendars added in v0.30.23

func (c *Client) CalListCalendars(ctx context.Context) (*CalListCalendarsResult, error)

CalListCalendars returns every calendar defined on the tenant. Confirmed missing during the XOT180 audit (2026-08-11) -- the underlying storage capability already existed but was never reachable via HTTP; any UI building an occupancy grid needs to know which calendars exist before it can ask what's booked on any one.

Hits GET /api/v2/.../cal/calendars. Returns *client.Error on non-2xx.

func (*Client) CalOpenings

func (c *Client) CalOpenings(ctx context.Context, calendarID string, from, to time.Time, duration time.Duration, objective Objective) (*CalOpeningsResult, error)

CalOpenings searches [from, to) for windows admitting duration, ranked by objective. The zero Objective lets the server default to ObjectiveEarliest; any other value is validated client-side against the four implemented objectives before the request is sent.

Hits POST /api/v2/.../cal/openings. Returns *client.Error on non-2xx.

func (*Client) CalPropose

func (c *Client) CalPropose(ctx context.Context, req CalProposeRequest) (*CalBooking, error)

CalPropose creates a booking in the proposed state. req.BookingID is client-generated identity (e.g. a ULID) and required; the returned booking carries the server-assigned fields (state, timestamps).

Hits POST /api/v2/.../cal/propose. Returns *client.Error on non-2xx — notably XOLU-CAL004 when the span conflicts with existing occupancy.

func (*Client) Commit

func (c *Client) Commit(ctx context.Context, req CommitRequest) (*CommitResult, error)

Commit performs an atomic upsert + one or more inserts in a single storage transaction. Use this when state-transition and audit-trail writes must land together or not at all. xolu endpoint: POST /commit (tenant-scoped: /api/v1/tenant/{t}/commit) Returns ErrConflict (wrapped) when the optimistic version check fails. Returns an error wrapping the xolu error message when an append entry uses an explicit ID that already exists. Maximum 25 entries in req.Append — enforced server-side (400 if exceeded).

func (*Client) Create

func (c *Client) Create(ctx context.Context, entity string, data map[string]any) (*Entity, error)

Create creates a new entity in the specified collection. xolu returns {"message":"…","id":N} on creation — the document is not echoed back. Data on the returned Entity is nil; call Get if the full document is needed.

func (*Client) CreateMachine

func (c *Client) CreateMachine(ctx context.Context, req CreateMachineRequest) (*Machine, error)

CreateMachine instantiates a new FSM machine from a definition. The definition must exist in the current tenant scope.

Hits POST /api/v2/fsm/machine. Returns *Machine on 201, *client.Error on non-2xx.

The response carries the machine's identity, initial state, and initial variable values (from the definition's declared defaults, further modified by any overrides supplied in the request).

func (*Client) CreateMachineDef added in v0.26.0

func (c *Client) CreateMachineDef(ctx context.Context, spec MachineSpec) (*MachineDefCreateResult, error)

CreateMachineDef registers a new FSM definition in the current tenant scope. spec is sent exactly as given -- server-side validation (determinism declared, states/transitions well-formed, exclusivity provable for a non-firstmatch machine) happens before anything is persisted; a spec that fails validation comes back as *client.Error, not a partially-created definition.

Hits POST /api/v2/fsm/def. Returns *client.Error on non-2xx (422 with an XOLU-FSM* code for a spec that fails validation, per the same rules ValidateMachineDef checks without storing).

func (*Client) DefineEntitySchema added in v0.26.0

func (c *Client) DefineEntitySchema(ctx context.Context, entityType string, schema map[string]interface{}) error

DefineEntitySchema registers or updates the schema for an entity type -- the write counterpart to GetEntitySchema. schema is the raw JSON Schema document (draft-07 shape: {"type":"object", "properties":{...},"required":[...]}), sent exactly as given; this client does not validate its contents beyond the entity type name itself, matching the server's own posture (schema shape validation happens server-side, at pkg/server/handlers.go's own validateSchemaFieldNames and the JSON Schema loader).

Calling this for an entity type that already has a schema updates it -- the server's own response message says "created/updated" regardless, and this client makes no distinction between the two cases in its own return value either.

Side effects, all server-side and outside this client's control: registering a schema creates or updates that entity type's adapted table (a column-per-field table optimised for direct SQL querying, replacing pure JSON-blob storage) and takes effect for validation immediately -- an existing entity of this type that doesn't conform to the new schema is not retroactively checked, but any subsequent write to it will be.

Hits POST /api/v1/schema/{entity}. Returns *client.Error on non-2xx (400 for an invalid entity name or non-identifier field names in the schema itself -- D-009's own DDL-injection guard -- 500 if schema loading or adapted-table registration fails server-side).

func (*Client) Delete

func (c *Client) Delete(ctx context.Context, entity string, id int64) error

Delete removes an entity by ID.

func (*Client) DeleteMachine

func (c *Client) DeleteMachine(ctx context.Context, id int64) error

DeleteMachine removes a machine and all its history from the current tenant scope.

Hits DELETE /api/v2/fsm/machine/{id}. Returns nil on 204, *client.Error on non-2xx (404 with XOLU-FSM003 when the machine does not exist).

func (*Client) DeleteMachineDef added in v0.26.0

func (c *Client) DeleteMachineDef(ctx context.Context, id int64) error

DeleteMachineDef removes an FSM definition.

Always permitted: confirmed directly against the server's own route comment ("delete a definition (always permitted)") and its handler (a plain DELETE with no check against existing machines) -- unlike ReplaceMachineDef's own future-machines-only framing might suggest by contrast, deleting a definition does NOT check whether any machine still references it. This client does not add a safety check of its own: no server-side query exists to count machines by definition ID to build one against, and adding that is a server-side feature request, not something to fake client-side.

Hits DELETE /api/v2/fsm/def/{id}. Returns nil on 204, *client.Error on non-2xx (404 with XOLU-FSM001/002/012 if id doesn't exist).

func (*Client) DxpDefCreate added in v0.26.0

func (c *Client) DxpDefCreate(ctx context.Context, req DxpDefCreateRequest) (*DxpDef, error)

DxpDefCreate registers a new dxp definition. The server computes and returns DxpAnalysis (CollapseEligible, EngineHomogeneous) at registration time; a caller does not supply it.

Hits POST /api/v2/.../dxp/def. Returns *client.Error on non-2xx -- notably XOLU-DXP006 when static analysis refuses the definition (unknown primitive, invalid pattern, malformed participant params).

func (*Client) DxpDefGet added in v0.26.0

func (c *Client) DxpDefGet(ctx context.Context, id int64) (*DxpDef, error)

DxpDefGet retrieves one definition by id, including its full spec, analysis, and bindings_schema -- everything a caller (or a molu-side tool adapter) needs to construct a valid DxpTxnCreateRequest against it without having to remember what was originally registered.

Hits GET /api/v2/.../dxp/def/{id}. Returns *client.Error on non-2xx -- notably XOLU-DXP006 (this def's own reserved code family) with HTTP 404 when id does not exist.

func (*Client) DxpDefList added in v0.26.0

func (c *Client) DxpDefList(ctx context.Context) (*DxpDefListResult, error)

DxpDefList returns every definition registered for the tenant, oldest first. Each entry is a DxpDefSummary, not a full DxpDef -- use DxpDefGet for one definition's spec and analysis.

Hits GET /api/v2/.../dxp/def. Returns *client.Error on non-2xx.

func (*Client) DxpTxnCreate added in v0.26.0

func (c *Client) DxpTxnCreate(ctx context.Context, req DxpTxnCreateRequest) (*DxpTxn, error)

DxpTxnCreate instantiates req.DefID and dispatches it -- one complete, synchronous call: by the time this returns, the instance has already reached a terminal status (committed, released, or expired). There is no separate "start" step and nothing left in-flight to poll for on a normal path; DxpTxnGet exists for after-the-fact observability (the sweep worker's own terminal states, or re-reading an instance created by another caller), not for waiting on this one to finish.

Hits POST /api/v2/.../dxp/txn. Returns *client.Error on non-2xx -- notably XOLU-DXP001 when Bindings fails DefID's own bindings_schema, and HTTP 404 when DefID does not exist. A non-committed outcome (released or expired) is NOT an error -- it is a normal response with Status set accordingly and Reason naming why; check resp.Status, do not assume a nil error means committed.

func (*Client) DxpTxnGet added in v0.26.0

func (c *Client) DxpTxnGet(ctx context.Context, id int64) (*DxpTxn, error)

DxpTxnGet retrieves one transaction instance by id, including its full resolved snapshot -- the after-the-fact observability surface item 20's own remaining scope named explicitly as missing until it was built: a caller (or the sweep worker's own operator-facing tooling) can now see a swept, expired, or torn instance's full participant list and outcome, not just that something happened.

Hits GET /api/v2/.../dxp/txn/{id}. Returns *client.Error on non-2xx -- HTTP 404 when id does not exist.

func (*Client) DxpTxnList added in v0.26.0

func (c *Client) DxpTxnList(ctx context.Context, status string) (*DxpTxnListResult, error)

DxpTxnList returns every transaction instance for the tenant, oldest first. status, if non-empty, filters to exactly one of "active", "committed", "released", or "expired" -- server-validated, not client-validated, since the set is small and stable enough that duplicating it here would only be one more place for it to drift. An empty status returns every instance regardless of outcome.

Hits GET /api/v2/.../dxp/txn[?status=]. Returns *client.Error on non-2xx.

func (*Client) Export added in v0.26.0

func (c *Client) Export(ctx context.Context, w io.Writer) (*ExportResult, error)

Export runs a complete tenant export and streams the result to w: starts the job, polls until it completes or fails, then downloads the resulting blob (via BlobGet, which streams rather than buffers) directly into w. This is the one-call convenience form; a caller wanting to observe progress, poll on its own schedule, or start an export without immediately waiting on it should use BlobExportStart/BlobExportStatus directly instead.

Polls every 2 seconds -- fixed, not configurable here; a caller needing a different cadence is exactly the caller who should be using the two primitives directly rather than this convenience wrapper. Respects ctx: cancelling or setting a deadline on ctx stops the poll loop and returns ctx.Err(), same as any other call on this client -- there is no separate timeout parameter, by design (Go's own idiom: the caller controls how long they're willing to wait via the context they pass in, e.g. context.WithTimeout(ctx, 10*time.Minute) for a large tenant).

Returns a plain Go error (not *client.Error) if the job itself fails server-side -- there's no HTTP status to carry for that case, just the job's own recorded failure reason.

func (*Client) Get

func (c *Client) Get(ctx context.Context, entity string, id int64) (*Entity, error)

Get retrieves a single entity by ID. xolu returns the flat document directly: {"id":1,"name":"Alice",…} The full document is stored in Entity.Data; ID is also extracted for convenience.

func (*Client) GetEntitySchema

func (c *Client) GetEntitySchema(ctx context.Context, entityType string) (*EntitySchema, error)

GetEntitySchema fetches the schema declaration for a single entity type.

Hits GET /api/v1/schema/{entity}. Returns *client.Error on non-2xx.

The returned EntitySchema carries the raw JSON Schema in `Schema` plus a field breakdown (`Fields`, `Refs`) extracted client-side by walking the schema. Consumers that need finer control over field extraction can decode `Schema` themselves — it is preserved verbatim.

func (*Client) GetEventDef

func (c *Client) GetEventDef(ctx context.Context, id int64) (*EventDef, error)

GetEventDef fetches a single event subscription by ID.

Hits GET /api/v2/event/def/{id}. Returns *client.Error on non-2xx.

func (*Client) GetMachine

func (c *Client) GetMachine(ctx context.Context, id int64) (*Machine, error)

GetMachine fetches a machine's full record — identity, current state, live variables.

Hits GET /api/v2/fsm/machine/{id}. Returns *client.Error with code XOLU-FSM* on non-2xx (including 404 when the machine does not exist).

func (*Client) GetMachineDef

func (c *Client) GetMachineDef(ctx context.Context, id int64) (*MachineDef, error)

GetMachineDef fetches the full definition body for a single FSM definition by ID.

Hits GET /api/v2/fsm/def/{id}. Returns *client.Error on non-2xx (including XOLU-FSM* codes when the definition is not found or is malformed).

func (*Client) GetMachineHistory

func (c *Client) GetMachineHistory(ctx context.Context, id int64) ([]HistoryEntry, error)

GetMachineHistory returns the ordered walk history for a machine, oldest first. The first entry records the machine's creation; each subsequent entry records one walk.

Hits GET /api/v2/fsm/machine/{id}/history. The wire envelope is {"machine": id, "entries": [...]} — this method returns the inner slice.

xolu v0.14.4 does not support pagination on this endpoint; the full history is returned in one response. Consumers of large history sets should design their access patterns around this.

func (*Client) GetMachineResult

func (c *Client) GetMachineResult(ctx context.Context, id int64) (*MachineResult, error)

GetMachineResult returns a convenience summary: current state, terminal flag, live vars, and (when terminal) the final transition's output.

Hits GET /api/v2/fsm/machine/{id}/result.

The FinalOutput field is nil until Terminal becomes true. A caller can poll this endpoint and act once Terminal flips.

func (*Client) GetMachineState

func (c *Client) GetMachineState(ctx context.Context, id int64) (*MachineState, error)

GetMachineState returns just the current state and terminal flag for a machine — a lightweight probe compared to GetMachine.

Hits GET /api/v2/fsm/machine/{id}/state.

func (*Client) GetMachineTransitions

func (c *Client) GetMachineTransitions(ctx context.Context, id int64) (*AvailableTransitions, error)

GetMachineTransitions returns the input symbols for which a transition from the machine's current state exists.

Hits GET /api/v2/fsm/machine/{id}/transitions.

Guards are not pre-evaluated: an input appears here if any transition names it from the current state, whether or not that transition's guard would currently permit the walk. Callers wanting a proven-permissible input must attempt the walk and handle the XOLU-FSM005 rejection.

func (*Client) GetMachineVars

func (c *Client) GetMachineVars(ctx context.Context, id int64) (map[string]VariableSnapshot, error)

GetMachineVars returns the machine's live variable snapshot: each variable's current value alongside its declared type and default.

Hits GET /api/v2/fsm/machine/{id}/vars. The response is a flat map (no envelope key) — the returned map is keyed by variable name.

func (*Client) GetSchemaSuggestion added in v0.26.0

func (c *Client) GetSchemaSuggestion(ctx context.Context, entityType string) (*SchemaSuggestion, error)

GetSchemaSuggestion previews what schema-promotion's heuristic engine would infer for entityType, without applying anything -- safe to call at any time, purely read-only.

Hits GET /api/v1/entity/{type}/schema-suggestion. Returns *client.Error on non-2xx (404 if the entity type has no data to infer from).

func (*Client) GetSequence

func (c *Client) GetSequence(ctx context.Context, name string) (*Sequence, error)

GetSequence fetches a single named sequence's current metadata (start, step, current value, creation timestamp).

Hits GET /api/v2/gen/seq/{name} (equivalent to /api/v2/seq/{name}, xolu's permanent alias). Returns *client.Error on non-2xx.

Use ListSequences to enumerate all sequences; this method retrieves a specific sequence when the name is known out of band.

func (*Client) GraphNeighbors

func (c *Client) GraphNeighbors(ctx context.Context, nodeID string, direction string) (*NeighborResult, error)

GraphNeighbors retrieves neighbors of a node in the graph. direction must be "out", "in", or "both" (default: "out"). xolu endpoint: POST /graph/neighbors with JSON body. Response: {"neighbors":{"outgoing":{node:label},"incoming":{node:label}}}

func (*Client) GraphQuery

func (c *Client) GraphQuery(ctx context.Context, query string, maxDepth int) (*GraphQueryResult, error)

GraphQuery executes a Sulpher graph path query. Previously named Sulpher; renamed to match the xolu endpoint. xolu endpoint: POST /graph/query maxDepth of 0 uses xolu's server default.

func (*Client) GraphShortestPath

func (c *Client) GraphShortestPath(ctx context.Context, from, to string, maxDepth int) (*PathResult, error)

GraphShortestPath finds the shortest path between two nodes. maxDepth of 0 uses xolu's server default. xolu endpoint: POST /graph/shortestPath with JSON body. Returns PathResult with Exists=false and empty Path when no path exists.

func (*Client) Health

func (c *Client) Health(ctx context.Context) error

Health checks if the xolu server is healthy.

Hits GET /health. Returns nil on 200 (server process is alive; storage layer's Ping succeeded within the server's 2-second timeout). Returns a non-nil error on any non-2xx response, transport failure, or timeout.

Health is appropriate for liveness probes (is the process alive?). For readiness probes (is the process ready to serve traffic?) use Ready instead.

Health does NOT apply the client's configured auth header, and never will: confirmed directly against the server's own auth middleware (2026-08-04, T-161, reported by the xoluman team) -- /health is deliberately exempt from auth server-side, alongside /ready, /version, and /metrics, the standard convention for liveness/ readiness probes (an orchestrator checking whether to restart a process shouldn't need a credential to ask). Sending an auth header here would be a pure no-op: the server ignores it for this route regardless of what the client sends, valid or not. A connection with a wrong or expired credential looks identical to a correctly configured one through Health alone -- that is inherent to what /health checks, not a client-side gap. Use TestConnection instead to verify a credential is actually accepted.

func (*Client) List

func (c *Client) List(ctx context.Context, entity string, params *ListParams) (*ListResult, error)

List retrieves entities from a collection with optional pagination. xolu returns a PagedResponse envelope:

{"data":[…],"pagination":{"page":N,"per_page":N,"total_items":N,"total_pages":N}}

Pagination parameters: xolu uses page/per_page; Limit maps to per_page, Offset is converted to a page number (Offset/Limit + 1, floored at 1).

func (*Client) ListEntities added in v0.26.0

func (c *Client) ListEntities(ctx context.Context, includeGraph bool) ([]EntityListEntry, error)

ListEntities enumerates every entity type that currently has data for this tenant, schemaless or not -- the fuller counterpart to ListEntityTypes, which only sees entity types with a registered schema. Pass includeGraph=true to also compute each entity type's graph edge counts and the relationship names touching it; leave it false for the common case, since that computation costs one indexed pass over the tenant's graph table per entity type and most callers don't need it.

Hits GET /api/v1/entities (?include_graph=true when requested). Returns *client.Error on non-2xx (501 if the store isn't SQLite- backed).

func (*Client) ListEntityTypes

func (c *Client) ListEntityTypes(ctx context.Context) ([]EntityTypeSummary, error)

ListMachineDefs returns summaries of every FSM definition registered in the current tenant scope. Each summary carries id, name, and creation timestamp only; use GetMachineDef to fetch the full spec.

Hits GET /api/v2/fsm/def. Requires xolu's v2 API to be enabled (XOLU_API_V2_ENABLED=true). Returns *client.Error on non-2xx. ListEntityTypes enumerates the entity types that currently have a registered schema, sorted by name.

Hits GET /api/v1/schemas (T-24). Returns *client.Error on non-2xx.

func (*Client) ListEventDefs

func (c *Client) ListEventDefs(ctx context.Context) ([]EventDef, error)

ListEventDefs returns every registered event subscription in the current tenant scope.

Hits GET /api/v2/event/def. Returns *client.Error on non-2xx.

The wire envelope key is "subscriptions" (not "events" or "definitions"); see xolu's pkg/server/v2_event_handlers.go handleEventList.

func (*Client) ListGenerators

func (c *Client) ListGenerators(ctx context.Context, kind GeneratorKind) ([]GeneratorDef, error)

ListGenerators returns the named generators registered under a single generator kind in the current tenant scope. Since xolu keeps a separate list per kind, a consumer building a full generator inventory must call this method for each of AllGeneratorKinds.

Hits GET /api/v2/gen/{kind}. Returns *client.Error on non-2xx.

Note: named sequences do NOT appear in this listing. Sequences live at a separate route (/api/v2/gen/seq) which xolu v0.14.3 exposes only per-name, not as a list. See the xolu technical-debt tracker.

func (*Client) ListMachineDefs

func (c *Client) ListMachineDefs(ctx context.Context) ([]MachineDefSummary, error)

ListMachineDefs enumerates every registered FSM definition in the current tenant scope.

Hits GET /api/v2/.../fsm/def. Returns *client.Error on non-2xx.

func (*Client) ListMachines

func (c *Client) ListMachines(ctx context.Context, filter *MachineFilter) ([]MachineSummary, error)

ListMachines returns every machine matching an optional filter. A nil filter (or a filter with all fields zero) returns every machine in the current tenant scope.

Hits GET /api/v2/fsm/machine?[filter query params].

The wire envelope key is "machines" per xolu's handleFSMMachineList.

func (*Client) ListSequences

func (c *Client) ListSequences(ctx context.Context) ([]SequenceSummary, error)

ListSequences enumerates the tenant's named sequences, sorted by name.

Hits GET /api/v2/.../gen/seq (T-25). Returns *client.Error on non-2xx. Returns SequenceSummary values (which match the list wire format), not the Sequence type used by GetSequence — see T-32 for the divergence.

func (*Client) OQL

func (c *Client) OQL(ctx context.Context, query string) (*OQLResult, error)

OQL executes an OQL (SQL-like) query.

func (*Client) Patch

func (c *Client) Patch(ctx context.Context, entity string, id int64, data map[string]any) (*Entity, error)

Patch partially updates an existing entity. xolu returns {"message":"…"} on success — no document echo. Data on the returned Entity is nil; call Get if the updated document is needed.

func (*Client) PatchMachine

func (c *Client) PatchMachine(ctx context.Context, id int64, req PatchMachineRequest) (*Machine, error)

PatchMachine applies overrides to a machine's spec snapshot. Live state, live variable values, and history are preserved unchanged.

Hits PATCH /api/v2/fsm/machine/{id}. Returns *client.Error carrying an XOLU-FSM* validation code on non-2xx.

The returned *Machine reflects the patched machine (identity, current state, live vars) — the underlying snapshot spec is not echoed back; callers who need the post-patch spec should re-fetch the machine's definition or read the snapshot from xolu's storage tier directly.

func (*Client) PromoteFlex added in v0.26.0

func (c *Client) PromoteFlex(ctx context.Context, entityType string, schema map[string]interface{}) (*PromoteFlexResult, error)

PromoteFlex promotes entityType to schemaful immediately: registers schema (or, if schema is nil, an auto-inferred one) and creates the adapted table. Does not migrate pre-existing rows -- check result.Warning; a non-empty value means some exist and are now split across storage (reachable by ID, invisible to LIST/count). Use PromoteStrict instead if that split is not acceptable for this entity type.

Hits POST /api/v1/entities/promote/flex/{type}. Returns *client.Error on non-2xx (404 if schema is nil and the entity type has no data to infer from).

func (*Client) PromoteStrict added in v0.26.0

func (c *Client) PromoteStrict(ctx context.Context, entityType string, schema map[string]interface{}) (*PromoteJob, error)

PromoteStrict runs a complete strict promotion and waits for the result: starts the job, polls until it completes, is rejected, or fails, and returns the final PromoteJob. This is the one-call convenience form; a caller wanting to observe progress or start a promotion without immediately waiting on it should use PromoteStrictStart/PromoteStrictStatus directly instead.

Respects ctx: cancelling or setting a deadline on ctx stops the poll loop and returns ctx.Err(). Does NOT return an error for a rejected promotion -- rejection is a normal, successful outcome of strict promotion's own design (it means the check worked); inspect job.Status and job.Failures rather than relying on the error return to distinguish rejection from success.

func (*Client) PromoteStrictStart added in v0.26.0

func (c *Client) PromoteStrictStart(ctx context.Context, entityType string, schema map[string]interface{}) (*PromoteJob, error)

PromoteStrictStart starts an async strict promotion for entityType: validates every existing row against schema (or, if schema is nil, an auto-inferred one) and, only if every row passes, migrates all of them into a newly-registered adapted table as one atomic operation. Returns immediately with a ticket to poll via PromoteStrictStatus.

Throttled per (tenant, entity type), not per tenant -- promoting two different entity types for the same tenant concurrently is fine. A second call for an entity type already being promoted returns *client.Error with HTTPStatus 409, carrying the existing ticket in its message.

Hits POST /api/v1/entities/promote/strict/{type}. Returns *client.Error on non-2xx.

func (*Client) PromoteStrictStatus added in v0.26.0

func (c *Client) PromoteStrictStatus(ctx context.Context, ticket string) (*PromoteJob, error)

PromoteStrictStatus polls one strict-promotion job's status by ticket.

Hits GET /api/v1/entities/promote/status/{ticket}. Returns *client.Error (HTTPStatus 404) if the ticket is unknown.

func (*Client) Raw added in v0.26.0

func (c *Client) Raw(ctx context.Context, method, path string, contentType string, body io.Reader) (*RawResult, error)

Raw issues an arbitrary HTTP request against this client's connected instance, applying the client's configured auth and nothing else -- no tenant-path rewriting, no error-shape decoding, no retry.

path is appended directly to the client's base URL and must start with "/" (e.g. "/api/v1/bal/def", "/api/v1/tenant/t0000/bal/def", "/health"); it is not rewritten or tenant-prefixed. body may be nil for methods that don't send one. contentType is sent as the Content-Type header when body is non-nil; pass "" to default to "application/json", matching every other method in this package (Raw is most often used for the same JSON API surface, just for a path this client has no typed wrapper for).

A non-nil error means the request never completed -- a transport failure, not an HTTP error status. Any response the server actually sent, including 4xx/5xx, comes back as a non-nil *RawResult with a nil error; check result.StatusCode.

func (*Client) Ready

func (c *Client) Ready(ctx context.Context) error

Ready checks if the xolu server is ready to serve traffic.

Hits GET /ready. Returns nil on 200 (server is fully initialised and the storage layer's Ping succeeded). Returns a non-nil error on 503 (server is still initialising or storage is unreachable), any other non-2xx response, transport failure, or timeout.

Ready is the correct endpoint for readiness probes and for consumers that want to gate their own traffic on xolu's ability to serve — for example, molu's health probe in its gated-dispatch design.

Auth is not required to reach /ready; the endpoint is deliberately unauthenticated so probes work without credentials.

func (*Client) ReplaceMachineDef added in v0.26.0

func (c *Client) ReplaceMachineDef(ctx context.Context, id int64, spec MachineSpec) (*MachineDefReplaceResult, error)

ReplaceMachineDef overwrites an existing FSM definition's spec in place, re-validating it the same way CreateMachineDef does.

Affects future machines only: a machine already created against the old spec keeps running against the version it was created with. This is not retroactive, and there is no way to migrate an in-flight machine to a replaced definition -- confirmed directly against the server's own route comment ("replace a definition (future machines only)"), not assumed.

Hits PUT /api/v2/fsm/def/{id}. Returns *client.Error on non-2xx (404 with XOLU-FSM001/002/012 if id doesn't exist, 422 for a spec that fails validation).

func (*Client) Save

func (c *Client) Save(ctx context.Context, entity string, id int64, data map[string]any) (created bool, err error)

Save upserts an entity with a caller-specified ID. xolu endpoint: POST /{entity}/save/{id} Returns created=true when a new record was inserted, false when an existing record was replaced. Use this for idempotent writes where the caller owns the ID (e.g. device registration keyed on hardware ID).

func (*Client) Search

func (c *Client) Search(ctx context.Context, entity string, params SearchParams) ([]Entity, error)

Search performs a full-text search on an entity collection. Search performs a full-text search across entities. xolu endpoint: GET /api/v1/search?q=…&entity={optional} Response: {"query":"…","entity":"…","count":N,"results":[flat docs…]} The entity argument is deprecated — populate SearchParams.Entity instead. If both are non-empty, SearchParams.Entity takes precedence.

func (*Client) Sulpher

func (c *Client) Sulpher(ctx context.Context, query string) (*GraphQueryResult, error)

Sulpher is a backward-compatible alias for GraphQuery with maxDepth=0. Deprecated: use GraphQuery.

func (*Client) TSGetTimeline added in v0.30.23

func (c *Client) TSGetTimeline(ctx context.Context, timelineID int64) (*TSTimeline, error)

TSGetTimeline returns a single timeline's own definition.

Hits GET /api/v1/.../ts/tl/{timelineID}. Returns *client.Error on non-2xx — notably XOLU-TS004 for an undefined timeline.

func (*Client) TSListTimelines added in v0.30.23

func (c *Client) TSListTimelines(ctx context.Context) ([]TSTimeline, error)

TSListTimelines returns every timeline defined on the tenant.

Hits GET /api/v1/.../ts/tl/list. Returns *client.Error on non-2xx.

func (*Client) TSQueryRange added in v0.30.23

func (c *Client) TSQueryRange(ctx context.Context, req TSQueryRangeRequest) (*TSQueryRangeResult, error)

TSQueryRange returns every event on req.Timeline within [req.From, req.To) across req.Dims. req.Dims is required and must be non-empty — the server rejects an empty Dims with XOLU-TS007 before ever querying the store. req.Limit defaults server-side to 1000 (capped at the server's own configured maximum) when left zero; req.Order defaults to "asc".

Hits POST /api/v1/.../ts/query/range (the POST form of range query — a structured JSON body rather than a query string, avoiding URL-length limits for wide Dims sets). Returns *client.Error on non-2xx — notably XOLU-TS011 if [From, To) exceeds the server's own configured maximum range.

func (*Client) TSRollupGet added in v0.30.23

func (c *Client) TSRollupGet(ctx context.Context, timelineID int64, rollupID string) (*TSRollup, error)

TSRollupGet returns a single rollup's own definition.

Hits GET /api/v1/.../ts/tl/{timelineID}/rollup/{rollupID}. Returns *client.Error on non-2xx — notably XOLU-TS025 (ErrTSRollupNotFound) for an unknown rollup id.

func (*Client) TSRollupList added in v0.30.23

func (c *Client) TSRollupList(ctx context.Context, timelineID int64) ([]TSRollup, error)

TSRollupList returns every rollup defined with timelineID as its own source.

Hits GET /api/v1/.../ts/tl/{timelineID}/rollup/list. Returns *client.Error on non-2xx — notably XOLU-TS004 for an undefined timeline.

func (*Client) TestConnection added in v0.27.2

func (c *Client) TestConnection(ctx context.Context) error

TestConnection verifies both that the server is reachable and that the client's configured credential is actually accepted -- the check Health cannot do (see Health's own doc comment for why).

Hits GET /api/v1/schemas: authenticated like any other v1 request (goes through the normal request pipeline, unlike /health), cheap (a schema listing, no heavy work), and tenant-independent (works regardless of whether a tenant is configured on the client, so a connection can be tested before a tenant is even chosen).

Returns nil only on a genuine 200. Returns *client.Error on non-2xx -- in particular HTTPStatus 401/403 for a rejected or missing credential, the exact distinction Health cannot make. Suited to a "Test connection" UI action: unlike Health, a wrong or expired credential here is reported, not silently accepted.

func (*Client) Update

func (c *Client) Update(ctx context.Context, entity string, id int64, data map[string]any) (*Entity, error)

Update replaces an existing entity. xolu returns {"message":"…"} on success — no document echo. Data on the returned Entity is nil; call Get if the updated document is needed.

func (*Client) V2Availability

func (c *Client) V2Availability(ctx context.Context) (*V2Availability, error)

V2Availability fetches the v2 subsystem availability map — a consumer can use this to check whether xolu's v2 API is enabled on the target server and which subsystems are currently live.

Hits GET /api/v2/. This endpoint always exists when v2 is enabled and returns 404 when v2 is disabled. Does not require auth.

func (*Client) ValidateMachineDef added in v0.26.0

func (c *Client) ValidateMachineDef(ctx context.Context, spec MachineSpec) (*MachineDefValidation, error)

ValidateMachineDef checks spec the same way CreateMachineDef would, without storing anything.

Always responds 200, valid or not -- validity is data in the response body (result.Valid), never encoded as an HTTP status. A non-nil error from this method means the request itself failed (transport, decode) — it is NOT how an invalid spec is reported. Check result.Valid and result.Errors for that; do not use errors.As/*client.Error to detect an invalid spec, since a correctly-rejected spec never produces one.

Hits POST /api/v2/fsm/def/validate. Returns *client.Error only for a genuine transport-level non-2xx, which this endpoint is not expected to produce under normal use.

func (*Client) WalkMachine

func (c *Client) WalkMachine(ctx context.Context, id int64, req WalkRequest) (*WalkResult, error)

WalkMachine drives a machine through one transition. The input symbol is required; the payload is available to guards and set-clauses under the "payload." prefix during evaluation.

Hits POST /api/v2/fsm/machine/{id}/walk.

On success returns *WalkResult with the previous and current states, the terminal flag, any Mealy outputs emitted, the post-walk variable map, and the history row id.

On rejection returns *client.Error with an XOLU-FSM* code. Common rejection codes:

XOLU-FSM003  machine not found
XOLU-FSM004  no transition for (state, input)
XOLU-FSM005  guard rejected the transition
XOLU-FSM006  machine is in a terminal state (no further walks)
XOLU-FSM007  input query failed
XOLU-FSM008  storage error inside the walk transaction

Callers can dispatch on Error.Code to distinguish these.

func (*Client) WithTenantContext

func (c *Client) WithTenantContext(tenantID string) *Client

WithTenantContext returns a new client with the specified tenant ID. This is useful for per-request tenant context.

func (*Client) WithTimeout

func (c *Client) WithTimeout(timeout time.Duration) *Client

WithTimeout returns a shallow-copied client whose per-call timeout is set to the given value. Useful for one-off overrides:

err := client.WithTimeout(2*time.Second).Ready(ctx)

The parent client is not modified.

type ClientOption

type ClientOption func(*Client)

ClientOption configures the Client.

func WithAPIKey

func WithAPIKey(key string) ClientOption

WithAPIKey sets the API key sent as "Authorization: Bearer <key>" on every request. Corresponds to XOLU_AUTH_TYPE=apikey on the server and to entries in the server's XOLU_API_KEYS list.

Only one of WithAPIKey, WithBearerToken, WithJWT should be set. If more than one is set, the last one wins.

func WithBearerToken

func WithBearerToken(token string) ClientOption

WithBearerToken sets a server-issued bearer token sent as "Authorization: Bearer <token>" on every request. Corresponds to XOLU_AUTH_TYPE=bearertoken on the server.

Only one of WithAPIKey, WithBearerToken, WithJWT should be set. If more than one is set, the last one wins.

func WithCallTimeout

func WithCallTimeout(timeout time.Duration) ClientOption

WithCallTimeout sets the default per-call timeout. Every request's context is wrapped with context.WithTimeout(timeout) before dispatch, unless the caller's context already carries a tighter deadline (in which case the caller's deadline wins).

A zero timeout means "no per-call timeout" — the client relies on the caller's context deadline and on the httpClient's own Timeout field.

This complements rather than replaces WithHTTPClient's Timeout field. The httpClient's Timeout is a hard ceiling on total request duration including body read; WithCallTimeout is a per-call deadline on the whole operation (retries included).

func WithHTTPClient

func WithHTTPClient(c *http.Client) ClientOption

WithHTTPClient sets a custom HTTP client.

func WithJWT

func WithJWT(token string) ClientOption

WithJWT sets a JWT sent as "Authorization: Bearer <jwt>" on every request. The JWT must be signed with the secret configured as XOLU_JWT_SECRET on the server. Corresponds to XOLU_AUTH_TYPE=jwt on the server; JWT claims like tenants:[...] and tenant_admin:true are honoured by xolu's TenantAuthMode.

Only one of WithAPIKey, WithBearerToken, WithJWT should be set. If more than one is set, the last one wins.

func WithLogger

func WithLogger(logger *slog.Logger) ClientOption

WithLogger enables structured request telemetry via log/slog. Every completed HTTP attempt is logged at debug level (method, path, status, duration, attempt number); auth failures at info level; retries at warn level. Never any payload content.

The default (no option supplied) is a discarding logger — the client emits no telemetry unless the caller explicitly opts in. This avoids polluting the caller's log stream through slog.Default().

Passing nil is equivalent to omitting the option.

func WithRetryPolicy

func WithRetryPolicy(p RetryPolicy) ClientOption

WithRetryPolicy enables automatic retries for idempotent requests. See the RetryPolicy documentation for the semantics.

The default (no option supplied) is "no retries" — MaxAttempts=1 — matching pre-Stage-4 client behaviour. Callers must opt in explicitly.

Only GET, HEAD, PUT, DELETE, and OPTIONS retry. POST and PATCH never retry regardless of policy, per RFC 9110 §9.2.2 idempotency guarantees. If a caller needs to retry a POST or PATCH they consider replay-safe, they wrap the call themselves.

func WithTenant

func WithTenant(tenantID string) ClientOption

WithTenant sets the default tenant ID for all requests.

func WithTenantID

func WithTenantID(id uint16) ClientOption

WithTenantID sets the tenant for all requests, formatting the uint16 ID as the 4-digit uppercase hex prefix xolu requires (e.g. 1 -> "0001"). Prefer this over WithTenant when working with numeric tenant IDs.

type CommitAppend

type CommitAppend struct {
	Entity string         `json:"entity"`
	ID     *int64         `json:"id,omitempty"` // nil = auto-assign
	Data   map[string]any `json:"data"`
}

CommitAppend describes one record to insert in a Commit operation. If ID is nil xolu auto-assigns an ID. An explicit ID that already exists causes ErrAlreadyExists and rolls back the entire commit.

type CommitRequest

type CommitRequest struct {
	Update CommitUpdate   `json:"update"`
	Append []CommitAppend `json:"append"`
}

CommitRequest is the payload for Commit. Maximum 25 entries in Append.

type CommitResult

type CommitResult struct {
	Update struct {
		Entity  string `json:"entity"`
		ID      int64  `json:"id"`
		Created bool   `json:"created"`
		Version int    `json:"version"`
	} `json:"update"`
	Appended []struct {
		Entity string `json:"entity"`
		ID     int64  `json:"id"`
	} `json:"appended"`
}

CommitResult is returned on a successful Commit.

type CommitUpdate

type CommitUpdate struct {
	Entity  string         `json:"entity"`
	ID      int64          `json:"id"`
	Version *int           `json:"version,omitempty"` // nil = unconditional
	Data    map[string]any `json:"data"`
}

CommitUpdate describes the entity to upsert in a Commit operation. If Version is non-nil the write is conditional: it succeeds only when the stored _version matches *Version. A mismatch returns ErrConflict (409).

type CreateMachineRequest

type CreateMachineRequest struct {
	// Definition is the fsm_def_id to instantiate.
	Definition int64 `json:"definition"`
	// Ref is an optional external identifier bound to the machine.
	Ref string `json:"ref,omitempty"`
	// Overrides narrow variable defaults or guard expressions on a
	// per-machine basis. Nil means no overrides.
	Overrides *MachineOverrides `json:"overrides,omitempty"`
}

CreateMachineRequest is the body of Client.CreateMachine. The definition ID is required; Ref is optional and binds an external identifier to the machine (an entity URI, a business key, a slug — xolu does not interpret it beyond using it for lookup and filtering).

Overrides let the caller narrow variable defaults or guard expressions at instantiation time without editing the definition. The override map is applied to a snapshot copy of the definition and then re-validated as a whole; failure returns XOLU-FSM* validation errors.

Note that inline entity creation via the `entity` field is deferred in xolu v0.14.4 preview and is not exposed by the client. Bind with `ref` instead.

type DxpAnalysis added in v0.26.0

type DxpAnalysis struct {
	CollapseEligible  bool     `json:"collapse_eligible"`
	EngineHomogeneous bool     `json:"engine_homogeneous"`
	Warnings          []string `json:"warnings,omitempty"`
}

DxpAnalysis is the static-analysis result computed once at registration and returned with every def response thereafter. CollapseEligible and EngineHomogeneous are separate facts: a participant set can be tenant-scoped (collapse-eligible per @D06) while still including a non-SQL primitive, which forces the phased dispatch path regardless.

type DxpDef added in v0.26.0

type DxpDef struct {
	ID             int64                  `json:"id"`
	Name           string                 `json:"name"`
	CreatedAt      string                 `json:"created_at"`
	Analysis       DxpAnalysis            `json:"analysis"`
	Spec           *DxpDefCreateRequest   `json:"spec,omitempty"`
	BindingsSchema map[string]interface{} `json:"bindings_schema,omitempty"`
}

DxpDef is a registered definition, as returned by DxpDefCreate and DxpDefGet. Spec and BindingsSchema are populated by DxpDefGet only (DxpDefCreate's own response echoes just what a caller needs to proceed to DxpTxnCreate: the id and the computed analysis) -- both are the zero value on a DxpDefCreate response, not an error.

type DxpDefCreateRequest added in v0.26.0

type DxpDefCreateRequest struct {
	Name           string                 `json:"name"`
	Pattern        string                 `json:"pattern"`
	Participants   []DxpParticipant       `json:"participants"`
	PhaseTTL       DxpPhaseTTL            `json:"phase_ttl"`
	BindingsSchema map[string]interface{} `json:"bindings_schema,omitempty"`
}

DxpDefCreateRequest is the body POST /dxp/def accepts. BindingsSchema is an optional JSON Schema object validated against a dxp/txn's own bindings at instantiation time -- omit it to skip bindings validation entirely (matches the server's own "no schema means validation passes" convention).

type DxpDefListResult added in v0.26.0

type DxpDefListResult struct {
	Definitions []DxpDefSummary `json:"definitions"`
}

DxpDefListResult is the response of DxpDefList.

type DxpDefSummary added in v0.26.0

type DxpDefSummary struct {
	ID        int64  `json:"id"`
	Name      string `json:"name"`
	CreatedAt string `json:"created_at"`
}

DxpDefSummary is one entry in DxpDefList's response -- deliberately narrower than DxpDef (no spec, no analysis): matches what GET /dxp/def actually returns per definition, not what GET /dxp/def/{id} returns for one.

type DxpParticipant added in v0.26.0

type DxpParticipant struct {
	ID        string                 `json:"id"`
	Primitive string                 `json:"primitive"`
	Op        string                 `json:"op"`
	Params    map[string]interface{} `json:"params,omitempty"`
}

DxpParticipant is one participant in a dxp/def, matching the doctrine's own worked-example JSON shape exactly: an id local to this def, the primitive it targets ("bal", "cal", "fsm", "entity", "ts"), the op that primitive exposes, and its params -- which may contain {"$ref": "<binding name>"} templates resolved against a dxp/txn's own bindings at instantiation time (jsonplate).

type DxpPhaseTTL added in v0.26.0

type DxpPhaseTTL struct {
	Reserve string `json:"reserve"`
}

DxpPhaseTTL is a dxp/def's own phase_ttl block. Reserve is the only def-configurable phase timeout today -- Validate/Execute timing is coordinator-owned, never def-configurable.

type DxpTxn added in v0.26.0

type DxpTxn struct {
	ID               int64          `json:"id"`
	DefID            int64          `json:"def_id"`
	DefName          string         `json:"def_name,omitempty"`
	Status           string         `json:"status"`
	CommittedThrough int            `json:"committed_through"`
	Reason           string         `json:"reason,omitempty"`
	DeadlineNs       int64          `json:"deadline_ns,omitempty"`
	CreatedAt        string         `json:"created_at"`
	Snapshot         DxpTxnSnapshot `json:"snapshot"`
}

DxpTxn is a transaction instance, as returned by DxpTxnCreate and DxpTxnGet. Status is one of "active" (should not appear here -- POST /dxp/txn dispatches synchronously in the same request, so a freshly-created instance is already terminal by the time a caller sees it), "committed", "released", or "expired". Reason is set only on a non-committed outcome; DefName and DeadlineNs are populated by DxpTxnGet only, matching what GET /dxp/txn/{id} returns that POST /dxp/txn's own response does not.

type DxpTxnCreateRequest added in v0.26.0

type DxpTxnCreateRequest struct {
	DefID    int64                  `json:"def_id"`
	Bindings map[string]interface{} `json:"bindings,omitempty"`
}

DxpTxnCreateRequest is the body POST /dxp/txn accepts -- one complete, self-contained invocation (dxp-coordinator-design.md's own recorded correction: closer to calling a stored procedure than opening a transaction). Bindings must satisfy DefID's own bindings_schema, if it has one.

type DxpTxnListResult added in v0.26.0

type DxpTxnListResult struct {
	Instances []DxpTxnSummary `json:"instances"`
}

DxpTxnListResult is the response of DxpTxnList.

type DxpTxnSnapshot added in v0.26.0

type DxpTxnSnapshot struct {
	Pattern      string           `json:"pattern"`
	Participants []DxpParticipant `json:"participants"`
	PhaseTTL     DxpPhaseTTL      `json:"phase_ttl"`
}

DxpTxnSnapshot is the fully-resolved def cloned into a dxp/txn at creation -- every participant's {"$ref": ...} already replaced with its bound value, never a template by the time a caller sees this.

type DxpTxnSummary added in v0.26.0

type DxpTxnSummary struct {
	ID               int64  `json:"id"`
	DefID            int64  `json:"def_id"`
	DefName          string `json:"def_name"`
	Status           string `json:"status"`
	CommittedThrough int    `json:"committed_through"`
	CreatedAt        string `json:"created_at"`
}

DxpTxnSummary is one entry in DxpTxnList's response -- deliberately narrower than DxpTxn (no snapshot, no deadline): matches what GET /dxp/txn actually returns per instance.

type Entity

type Entity struct {
	ID        int64
	Data      map[string]any
	CreatedAt time.Time
	UpdatedAt time.Time
}

Entity represents a document stored in xolu. Data holds the complete flat document as returned by the server, including the "id" field. ID is extracted for convenience.

After Create, Data is nil — xolu does not echo the document on creation. Call Get if the full document is needed after a write. After Update or Patch, Data is also nil for the same reason.

type EntityGraphFootprint added in v0.26.0

type EntityGraphFootprint struct {
	OutEdges          int64    `json:"out_edges"`
	InEdges           int64    `json:"in_edges"`
	RelationshipTypes []string `json:"relationship_types"`
}

EntityGraphFootprint is one entity type's graph edge counts, present only when ListEntities was called with IncludeGraph.

type EntityIndex added in v0.26.0

type EntityIndex struct {
	Name    string   `json:"name"`
	Columns []string `json:"columns"`
	Unique  bool     `json:"unique"`
}

EntityIndex describes one index on an adapted entity type's table.

type EntityListEntry added in v0.26.0

type EntityListEntry struct {
	EntityType string `json:"entity_type"`
	Count      int64  `json:"count"`
	HasSchema  bool   `json:"has_schema"`
	Adapted    bool   `json:"adapted"`
	// Columns and Indexes are populated only when Adapted is true.
	Columns []string      `json:"columns,omitempty"`
	Indexes []EntityIndex `json:"indexes,omitempty"`
	// Graph is populated only when ListEntities was called with
	// includeGraph -- computing it costs one indexed pass over the
	// graph table per entity type, so it's opt-in server-side, not
	// computed by default.
	Graph *EntityGraphFootprint `json:"graph,omitempty"`
	// FirstSeen/LastUpdate are empty for an adapted entity type --
	// its own table carries no timestamp columns (its columns are
	// derived purely from the registered schema's fields), so there
	// is genuinely nothing to report, not a gap in this client.
	FirstSeen  string `json:"first_seen,omitempty"`
	LastUpdate string `json:"last_update,omitempty"`
}

EntityListEntry describes one entity type that has actual data for the current tenant -- whether or not it has a registered schema. This is the key difference from ListEntityTypes, which only sees entity types with a schema: a type written to without ever calling DefineEntitySchema for it appears here with HasSchema=false and nothing else missing except Columns/Indexes (which only exist for an adapted table).

type EntitySchema

type EntitySchema struct {
	// Name is the entity type name (e.g. "users", "orders").
	Name string `json:"name"`
	// Schema is the raw JSON Schema document for the entity, exactly as
	// returned by xolu.
	Schema json.RawMessage `json:"schema"`
	// Fields lists the entity's declared fields with their JSON Schema types.
	Fields []FieldDef `json:"fields,omitempty"`
	// Refs lists the subset of Fields that carry `"format":"ref"` — the
	// reference edges that populate xolu's graph layer.
	Refs []RefFieldDef `json:"refs,omitempty"`
}

EntitySchema describes a registered entity type — its declared fields, its JSON Schema, and the subset of fields that carry REF references to other entities.

Returned by Client.GetEntitySchema.

The `Schema` field is the raw JSON Schema xolu holds for the entity type. Field-level extraction (`Fields`, `Refs`) is done client-side by walking the schema; consumers that need more sophisticated inspection can decode `Schema` themselves.

type EntityTypeSummary

type EntityTypeSummary struct {
	Name string `json:"name"`
}

EntityTypeSummary is one entry of GET /api/v1/schemas (T-24): an entity type with a registered schema. Name-only by design — the server tracks no registration timestamps.

type Error

type Error struct {
	// Code is the XOLU-<AREA><NUM> error code (e.g. "XOLU-ST001"). Empty when
	// the server did not return a structured error body.
	Code string
	// HTTPStatus is the HTTP status code (e.g. 400, 404, 500).
	HTTPStatus int
	// Message is the human-readable error message.
	Message string
	// Detail is the raw JSON body of the error response, preserved verbatim
	// so callers can extract server-specific fields the client does not
	// model. Nil when the response body was empty or not valid JSON.
	Detail json.RawMessage

	// StatusCode is preserved as an alias for HTTPStatus for backwards
	// compatibility with earlier client releases. New code should use
	// HTTPStatus.
	//
	// Deprecated: use HTTPStatus.
	StatusCode int
	// Details is preserved as a decoded map for backwards compatibility.
	// New code should use Detail (raw JSON) and decode as needed.
	//
	// Deprecated: use Detail.
	Details map[string]any
}

Error represents an error response from xolu.

xolu's server writes structured errors in the shape:

{"error":{"code":"XOLU-ST001","message":"...","status":400}}

The client parses that shape into Code, Message, and Status. When the server returns an error in the older flat shape ({"error":"message"}) or a non-JSON body, Code is left empty and Message carries the raw content.

Callers can dispatch on the code using errors.As:

var xerr *client.Error
if errors.As(err, &xerr) && xerr.Code == "XOLU-ST001" {
    // entity not found
}

func (*Error) Error

func (e *Error) Error() string

type EventDef

type EventDef struct {
	// ID is the subscription's numeric identifier, tenant-scoped.
	ID int64 `json:"id"`
	// EventType is the event type this subscription reacts to
	// (e.g. "entity.updated", "fsm.step", "commit.applied").
	EventType string `json:"event_type"`
	// ActionType names the delivery mechanism ("webhook", "oql").
	ActionType string `json:"action_type"`
	// Config is the raw action configuration.
	Config json.RawMessage `json:"config,omitempty"`
	// Execution declares the delivery mode ("async" today; "sync" is
	// accepted but silently downgraded — see the xolu changelog).
	Execution string `json:"execution"`
	// CreatedAt is the timestamp of subscription creation.
	CreatedAt string `json:"created_at,omitempty"`
}

EventDef is one registered event subscription, as returned by Client.ListEventDefs and Client.GetEventDef.

Wire shape verified against pkg/server/v2_event_handlers.go eventDef.

`Config` is the raw action configuration (webhook URL and headers, OQL query, etc.). Its shape depends on ActionType.

type ExportResult added in v0.26.0

type ExportResult struct {
	// Ticket is the job that produced this export, in case the caller
	// wants to correlate it with server-side logs.
	Ticket string
	// BlobKey is the key the export is stored under -- the same key
	// BlobExportStatus reported, kept here so a caller using Export's
	// one-call form still has it without a separate status check.
	BlobKey string
	SHA256  string
	Size    int64
}

ExportResult describes a completed, delivered export.

type FieldAnalysis added in v0.26.0

type FieldAnalysis struct {
	Field         string   `json:"field"`
	InferredType  string   `json:"inferred_type"`
	Coverage      float64  `json:"coverage"`
	Confidence    string   `json:"confidence"`
	SuggestedEnum []string `json:"suggested_enum,omitempty"`
	Note          string   `json:"note,omitempty"`
}

FieldAnalysis is one field's inferred shape and the evidence behind it -- mirrors the server's own type field-for-field.

type FieldDef

type FieldDef struct {
	// Name is the field name as it appears in JSON documents.
	Name string `json:"name"`
	// Type is the JSON Schema type ("string", "integer", "number",
	// "boolean", "object", "array"). Always set directly from the
	// schema's own "type" key -- never "ref" or any other xolu-specific
	// tag; those live in Format instead (extractFieldsFromSchema sets
	// them from entirely separate JSON Schema keys, "type" and "format").
	Type string `json:"type"`
	// Required is true when the field is listed under the schema's
	// "required" array.
	Required bool `json:"required,omitempty"`
	// Format is the JSON Schema "format" declaration when present
	// (e.g. "email", "uuid", "date-time"). Empty when absent.
	Format string `json:"format,omitempty"`
}

FieldDef is a single declared field on an entity.

type GCPolicy

type GCPolicy struct {
	StalledAfter string `json:"stalled_after,omitempty"`
	DeadAfter    string `json:"dead_after,omitempty"`
	OnGCCollect  string `json:"on_gc_collect,omitempty"`
}

GCPolicy is the optional GC policy block on a definition.

type GeneratorDef

type GeneratorDef struct {
	Name   string          `json:"name"`
	Config json.RawMessage `json:"config,omitempty"`
}

GeneratorDef is one named generator instance under a given kind, as returned by Client.ListGenerators.

The `Config` field is the raw generator configuration; its shape depends on the kind and is documented in the xolu generator subsystem.

type GeneratorKind

type GeneratorKind string

GeneratorKind identifies one of xolu's stateless generator kinds. Named generators are per-kind lists queryable with Client.ListGenerators.

The four values below match the routes registered in pkg/server/v2_handlers.go under /api/v2/gen/{type}.

const (
	GeneratorUUIDv4 GeneratorKind = "uuid_v4"
	GeneratorUUIDv7 GeneratorKind = "uuid_v7"
	GeneratorCUID   GeneratorKind = "cuid"
	GeneratorULID   GeneratorKind = "ulid"
)

type GraphQueryResult

type GraphQueryResult struct {
	Status string           `json:"status"`
	Result []map[string]any `json:"result"` // xolu uses "result", not "data"
	Stats  GraphQueryStats  `json:"stats"`
}

GraphQueryResult represents the result of a Sulpher graph query. Previously named SulpherResult; renamed to match the xolu endpoint name.

type GraphQueryStats

type GraphQueryStats struct {
	NodesTraversed int   `json:"nodes_traversed"`
	PathsFound     int   `json:"paths_found"`
	ExecutionTime  int64 `json:"execution_time_ms"`
}

GraphQueryStats contains Sulpher execution statistics.

type HistoryEntry

type HistoryEntry struct {
	// ID is the numeric identifier of this history row.
	ID int64 `json:"id"`
	// From is the state the machine was in before this step. Nil for the
	// initial "machine created" entry.
	From *string `json:"from"`
	// To is the state the machine was in after this step. Always set,
	// including on the initial entry (equal to the initial state).
	To string `json:"to"`
	// Input is the input symbol that drove the transition. Nil for the
	// initial entry.
	Input *string `json:"input"`
	// Payload is the raw payload supplied by the walk caller. Preserved
	// as raw JSON because xolu emits arbitrary caller-supplied shapes.
	Payload json.RawMessage `json:"payload,omitempty"`
	// Vars is the live variable map after this step, preserved as raw
	// JSON for the same reason.
	Vars json.RawMessage `json:"vars"`
	// Outputs is the transition's Mealy output, preserved as raw JSON.
	// Omitted when the transition emitted nothing.
	Outputs json.RawMessage `json:"outputs,omitempty"`
	// Note is a human-readable annotation. Present on the initial
	// "machine created" entry; typically nil on walk entries.
	Note string `json:"note,omitempty"`
	// At is the timestamp of this step.
	At string `json:"at"`
}

HistoryEntry is one row of a machine's history, as returned by Client.GetMachineHistory. The list is ordered by history id (ascending).

The very first entry has From=nil, Input=nil, and Note="machine created"; subsequent entries record each walk with the emitting transition's input and payload.

type ListParams

type ListParams struct {
	Limit  int
	Offset int
	Sort   string // field name, prefix with - for descending
}

ListParams configures list queries.

type ListResult

type ListResult struct {
	Entities   []Entity
	Page       int
	PerPage    int
	TotalItems int
	TotalPages int
}

ListResult holds a page of entities and the pagination metadata returned by xolu's PagedResponse envelope.

type Machine

type Machine struct {
	// ID is the machine's numeric identifier, tenant-scoped.
	ID int64 `json:"id"`
	// Definition is the fsm_def_id the machine was instantiated from.
	Definition int64 `json:"definition"`
	// DefinitionName is the cached copy of the definition's name.
	DefinitionName string `json:"definition_name"`
	// DefinitionDeleted is true when the source definition has been
	// deleted since machine creation. The machine continues to operate
	// on its self-contained snapshot; this flag is informational.
	DefinitionDeleted bool `json:"definition_deleted"`
	// State is the machine's current state name.
	State string `json:"state"`
	// Vars is the current live variable map. Keys are variable names,
	// values are the raw JSON values as the FSM evaluator stores them.
	Vars map[string]interface{} `json:"vars"`
	// Ref is the optional external identifier bound at creation time,
	// echoed only when present.
	Ref string `json:"ref,omitempty"`
	// CreatedAt is the timestamp of machine creation.
	CreatedAt string `json:"created_at"`
}

Machine is the full record returned by Client.CreateMachine, Client.GetMachine, and Client.PatchMachine. It carries identity, current state, and live variable values.

Response shape identical for create/get/patch (verified from source).

type MachineDef

type MachineDef struct {
	// ID is the definition's numeric identifier, tenant-scoped.
	ID int64 `json:"id"`
	// CreatedAt is the timestamp of definition creation.
	CreatedAt string `json:"created_at"`
	// Spec is the definition body — states, transitions, variables.
	Spec MachineSpec `json:"spec"`
	// Analysis is xolu's structural-analysis output for the definition.
	// Kept as json.RawMessage here for backwards compatibility with
	// existing callers of this already-shipped field; call
	// ParsedAnalysis() for the structured form. See ParsedAnalysis's
	// own doc comment for why this field itself wasn't just changed to
	// *MachineDefAnalysis directly.
	Analysis json.RawMessage `json:"analysis,omitempty"`
}

MachineDef is the full body of an FSM definition, as returned by Client.GetMachineDef.

Wire shape verified against pkg/server/v2_fsm_def_handlers.go handleFSMDefGet and the internal fsmDefinitionSpec / fsmStateSpec / fsmVariableSpec / fsmTransitionSpec types in pkg/server/v2_fsm_common.go.

The `Analysis` field is xolu's internal analysis output (reachability, determinism, and other structural properties). It is preserved as json.RawMessage because its shape is xolu-server-internal and may evolve.

func (*MachineDef) ParsedAnalysis added in v0.26.0

func (m *MachineDef) ParsedAnalysis() (*MachineDefAnalysis, error)

ParsedAnalysis decodes Analysis into its structured form.

Analysis itself stayed json.RawMessage rather than becoming *MachineDefAnalysis directly to avoid a breaking change to an already-shipped field for any existing caller relying on the raw bytes; this method is the additive, opt-in path to the same structured data CreateMachineDef/ReplaceMachineDef/ValidateMachineDef return directly. The original doc comment on Analysis claimed the shape "is xolu-server-internal and may evolve" -- checked directly against pkg/server/v2_fsm_common.go's own fsmAnalysis struct before writing this: it's a stable, well-defined set of fields (reachability, determinism, cycles, warnings), not internal debug scratch data, and carries no instability markers anywhere in the server code. Worth exposing structured, not worth forcing every caller to re-parse raw JSON for.

Returns nil, nil if Analysis is empty (e.g. a MachineDef fetched before analysis was populated, or a definition predating this field).

type MachineDefAnalysis added in v0.26.0

type MachineDefAnalysis struct {
	// Reachable is false if any declared state cannot be reached from
	// Initial by any sequence of transitions.
	Reachable bool `json:"reachable"`
	// Deterministic reports whether the machine is a plain DFA (no
	// transition carries an Output) versus a Mealy machine.
	Deterministic bool `json:"deterministic"`
	// Determinism is the spec's own declared determinism level, echoed
	// back (not independently re-derived) so a caller can compare what
	// it asked for against what Reachable/ExclusivityVerified actually
	// found.
	Determinism string `json:"determinism"`
	// ExclusivityVerified is true when the analyzer proved that no two
	// candidate transitions for the same (state, input) pair can both
	// match -- required for a non-firstmatch machine; absent/false
	// does not by itself mean the machine is broken for a firstmatch
	// machine, where ambiguity is resolved by declaration order instead.
	ExclusivityVerified bool `json:"exclusivity_verified,omitempty"`
	// TerminalStates lists every state with no outgoing transitions.
	TerminalStates []string `json:"terminal_states"`
	// Cycles lists detected cycles in the transition graph, if any.
	Cycles []string `json:"cycles,omitempty"`
	// Warnings carries non-fatal structural observations that didn't
	// block acceptance of the spec (e.g. an unreachable state alongside
	// an otherwise valid machine).
	Warnings []string `json:"warnings,omitempty"`
}

MachineDefAnalysis is xolu's structural-analysis output for an FSM definition -- reachability, determinism, and cycle detection, the same checks CreateMachineDef/ReplaceMachineDef/ValidateMachineDef all run before accepting a spec. Wire shape verified directly against pkg/server/v2_fsm_common.go's own fsmAnalysis struct.

type MachineDefCreateResult added in v0.26.0

type MachineDefCreateResult struct {
	ID        int64               `json:"id"`
	Name      string              `json:"name"`
	CreatedAt string              `json:"created_at"`
	Analysis  *MachineDefAnalysis `json:"analysis"`
}

MachineDefCreateResult is the response from CreateMachineDef.

type MachineDefReplaceResult added in v0.26.0

type MachineDefReplaceResult struct {
	ID       int64               `json:"id"`
	Name     string              `json:"name"`
	Analysis *MachineDefAnalysis `json:"analysis"`
}

MachineDefReplaceResult is the response from ReplaceMachineDef. Deliberately narrower than MachineDefCreateResult -- no CreatedAt, since a replace doesn't create anything new -- matching the server's own response shape exactly rather than padding it out to look like MachineDefCreateResult.

type MachineDefSummary

type MachineDefSummary struct {
	ID        int64  `json:"id"`
	Name      string `json:"name"`
	CreatedAt string `json:"created_at"`
}

MachineDefSummary is one entry in the list returned by Client.ListMachineDefs. It carries only identity fields; the full definition body must be fetched with Client.GetMachineDef.

Wire shape verified against pkg/server/v2_fsm_def_handlers.go handleFSMDefList.

type MachineDefValidation added in v0.26.0

type MachineDefValidation struct {
	Valid    bool                        `json:"valid"`
	Analysis *MachineDefAnalysis         `json:"analysis,omitempty"`
	Errors   []MachineDefValidationError `json:"errors,omitempty"`
}

MachineDefValidation is the response from ValidateMachineDef. Exactly one of Analysis (Valid true) or Errors (Valid false) is populated.

type MachineDefValidationError added in v0.26.0

type MachineDefValidationError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

MachineDefValidationError is one validation failure. Deliberately not *client.Error: that type represents an actual non-2xx transport response (its own doc comment: "HTTPStatus is the HTTP status code"), and ValidateMachineDef never produces one -- an invalid spec is data in a 200 response, not a transport failure, so reusing client.Error here would misrepresent what actually happened.

type MachineFilter

type MachineFilter struct {
	// Definition filters by fsm_def_id. Zero means no filter.
	Definition int64
	// State filters by current state name. Empty string means no filter.
	State string
	// Ref filters by the external identifier bound at creation. Empty
	// string means no filter.
	Ref string
}

MachineFilter is an optional set of query parameters for Client.ListMachines. A nil filter or a filter with all fields empty returns every machine in the current tenant scope.

The three filters map directly to the "definition", "state", and "ref" query parameters accepted by GET /api/v2/fsm/machine.

type MachineOverrides

type MachineOverrides struct {
	// Variables overrides variable declarations. Keyed by variable name.
	Variables map[string]VariableDef `json:"variables,omitempty"`
	// Transitions overrides transition guards. Keyed by transition input.
	Transitions map[string]TransitionOverride `json:"transitions,omitempty"`
}

MachineOverrides is the shape of the `overrides` block on CreateMachineRequest and PatchMachineRequest. Mirrors xolu's internal fsmOverrides in pkg/server/v2_fsm_common.go.

type MachineResult

type MachineResult struct {
	// Machine is the machine's numeric identifier.
	Machine int64 `json:"machine"`
	// State is the current state name.
	State string `json:"state"`
	// Terminal is true when State is a terminal state.
	Terminal bool `json:"terminal"`
	// Vars is the live variable map.
	Vars map[string]interface{} `json:"vars"`
	// FinalOutput is the output emitted by the transition that reached
	// the current state, but only meaningful once Terminal is true.
	// Preserved as raw JSON because xolu emits either a JSON array of
	// output names or an empty array; consumers can decode as needed.
	FinalOutput json.RawMessage `json:"final_output,omitempty"`
}

MachineResult is the response of Client.GetMachineResult — a convenience over state + vars + final transition output.

For a machine that has not yet reached a terminal state, Terminal is false and FinalOutput is nil; State and Vars still reflect the current non-final values, so a caller can poll this endpoint and act once Terminal becomes true.

type MachineSpec

type MachineSpec struct {
	Name           string                 `json:"name"`
	Description    string                 `json:"description,omitempty"`
	Initial        string                 `json:"initial"`
	Determinism    string                 `json:"determinism"`
	States         map[string]StateDef    `json:"states"`
	Variables      map[string]VariableDef `json:"variables,omitempty"`
	Transitions    []TransitionDef        `json:"transitions"`
	OutputAlphabet []string               `json:"output_alphabet,omitempty"`
	LinkedStates   map[string]int64       `json:"linked_states,omitempty"`
	GC             *GCPolicy              `json:"gc,omitempty"`
	// InputQueries associates an OQL SELECT with an input symbol. See the
	// xolu documentation for the exact semantics of the query-before-walk
	// evaluation pattern.
	InputQueries map[string]string `json:"input_queries,omitempty"`
}

MachineSpec is the wire-format definition body. It matches xolu's internal fsmDefinitionSpec byte-for-byte.

type MachineState

type MachineState struct {
	State    string `json:"state"`
	Terminal bool   `json:"terminal"`
}

MachineState is the response of Client.GetMachineState — a lightweight current-state snapshot without the full variable map. Use GetMachine for the richer view.

type MachineSummary

type MachineSummary struct {
	// ID is the machine's numeric identifier, tenant-scoped.
	ID int64 `json:"id"`
	// Definition is the fsm_def_id the machine was instantiated from.
	Definition int64 `json:"definition"`
	// DefinitionName is a cached copy of the definition's name at
	// creation time. Persists even if the definition is later renamed or
	// deleted.
	DefinitionName string `json:"definition_name"`
	// State is the machine's current state name.
	State string `json:"state"`
	// Ref is the optional external identifier bound at creation time,
	// e.g. an entity URI. Nil when the machine was created without a ref.
	Ref *string `json:"ref"`
	// CreatedAt is the timestamp of machine creation.
	CreatedAt string `json:"created_at"`
}

MachineSummary is one entry in the list returned by Client.ListMachines. The list envelope key is "machines" per xolu's handleFSMMachineList.

type NeighborResult

type NeighborResult struct {
	Outgoing map[string]string `json:"outgoing,omitempty"`
	Incoming map[string]string `json:"incoming,omitempty"`
}

NeighborResult is returned by GraphNeighbors. Outgoing and Incoming map neighbour node ID to relationship label.

type OQLResult

type OQLResult struct {
	Status string           `json:"status"`
	Data   []map[string]any `json:"data"`
	Stats  OQLStats         `json:"stats"`
}

OQLResult represents the result of an OQL query.

type OQLStats

type OQLStats struct {
	RowsScanned   int   `json:"rows_scanned"`
	RowsReturned  int   `json:"rows_returned"`
	RowsAffected  int   `json:"rows_affected,omitempty"`
	ExecutionTime int64 `json:"execution_time_ms"`
}

OQLStats contains OQL execution statistics.

type Objective

type Objective string

Objective selects how CalOpenings ranks candidate windows. The four values are the complete set the server implements; the zero value "" lets the server default to ObjectiveEarliest.

const (
	ObjectiveEarliest   Objective = "earliest"
	ObjectiveFirstFit   Objective = "first-fit"
	ObjectiveEmptiest   Objective = "emptiest"
	ObjectiveLongestClr Objective = "longest-clear-margin"
)

type PatchMachineRequest

type PatchMachineRequest struct {
	Overrides *MachineOverrides `json:"overrides,omitempty"`
}

PatchMachineRequest is the body of Client.PatchMachine.

A patch applies overrides to the machine's spec snapshot; live state, live variable values, and history are preserved unchanged. Re-validation of the resulting snapshot occurs as a whole; failure returns XOLU-FSM* errors and no persistent change is made.

type PathResult

type PathResult struct {
	From   string   `json:"from"`
	To     string   `json:"to"`
	Exists bool     `json:"exists"`
	Path   []string `json:"path"`
	Length int      `json:"length"`
}

PathResult is returned by GraphShortestPath.

type PromoteFlexResult added in v0.26.0

type PromoteFlexResult struct {
	Message      string                 `json:"message"`
	AutoInferred bool                   `json:"auto_inferred"`
	Schema       map[string]interface{} `json:"schema"`
	// Warning is set when the server detected pre-existing rows that
	// were NOT migrated into the new adapted table -- see this file's
	// own header comment. Empty when there was nothing pre-existing.
	Warning string `json:"warning,omitempty"`
}

PromoteFlexResult is the response from PromoteFlex.

type PromoteJob added in v0.26.0

type PromoteJob struct {
	Ticket     string                 `json:"ticket"`
	EntityType string                 `json:"entity_type"`
	Status     PromoteJobStatus       `json:"status"`
	Result     *PromoteResult         `json:"result,omitempty"`
	Failures   []RowValidationFailure `json:"failures,omitempty"`
	Error      string                 `json:"error,omitempty"`
}

PromoteJob is a strict-promotion job's current status.

type PromoteJobStatus added in v0.26.0

type PromoteJobStatus string

PromoteJobStatus is a strict-promotion job's lifecycle state.

const (
	PromoteJobRunning  PromoteJobStatus = "running"
	PromoteJobComplete PromoteJobStatus = "complete"
	PromoteJobFailed   PromoteJobStatus = "failed"
	// PromoteJobRejected means strict promotion worked exactly as
	// designed and correctly declined to promote because not every
	// row validated against the schema -- distinct from Failed, which
	// means something actually went wrong (a storage error). Check
	// Failures for exactly which rows and why.
	PromoteJobRejected PromoteJobStatus = "rejected"
)

type PromoteResult added in v0.26.0

type PromoteResult struct {
	MigratedRows int  `json:"migrated_rows"`
	AutoInferred bool `json:"auto_inferred"`
}

PromoteResult is the outcome of a successfully completed strict promotion.

type RawResult added in v0.26.0

type RawResult struct {
	// StatusCode is the HTTP status exactly as received -- 2xx, 4xx,
	// 5xx, whatever the server sent. Not treated as an error condition
	// by Raw itself; inspect it directly.
	StatusCode int
	// Body is the full response body, read to completion. Not
	// interpreted or decoded in any way.
	Body []byte
	// Header is the response's own HTTP headers.
	Header http.Header
}

RawResult is the unfiltered response to a Raw request.

type RefFieldDef

type RefFieldDef struct {
	// Name is the field name (e.g. "author_id").
	Name string `json:"name"`
	// Target is the entity type the reference points to
	// (e.g. "users"). Extracted from the schema's `"target"` extension
	// when present; empty when the target is polymorphic.
	Target string `json:"target,omitempty"`
}

RefFieldDef is a field whose value is a reference to another entity.

type RetryPolicy

type RetryPolicy struct {
	// MaxAttempts is the total number of attempts including the first.
	// MaxAttempts=1 means "no retry", MaxAttempts=3 means "up to two
	// retries after the first attempt". Values less than 1 are treated
	// as 1.
	MaxAttempts int

	// InitialBackoff is the wait before the second attempt. Subsequent
	// attempts wait InitialBackoff * BackoffMultiplier^(attempt-1),
	// capped at MaxBackoff.
	InitialBackoff time.Duration

	// MaxBackoff is the ceiling on backoff between attempts. Zero means
	// "no ceiling", which is rarely what a caller wants; the default
	// policy from DefaultRetryPolicy sets a sensible ceiling.
	MaxBackoff time.Duration

	// BackoffMultiplier is the factor by which backoff grows between
	// attempts. Values less than 1 (including zero) are treated as 1,
	// producing constant backoff.
	BackoffMultiplier float64

	// RetryOn decides whether a given attempt outcome is retryable.
	// If nil, DefaultRetryOn is used, which retries transport errors
	// and 5xx responses.
	//
	// The predicate MUST NOT return true for context cancellation or
	// deadline exceeded — the retry loop honours those errors as final
	// regardless of RetryOn's answer, but the predicate is called first
	// and should return false on them for clarity.
	RetryOn func(resp *http.Response, err error) bool
	// contains filtered or unexported fields
}

RetryPolicy configures automatic retries for idempotent requests. The zero value corresponds to "no retries" — the same behaviour as pre-Stage-4 clients.

A caller who wants retries builds the policy explicitly:

c := client.New(baseURL,
    client.WithRetryPolicy(client.RetryPolicy{
        MaxAttempts:       3,
        InitialBackoff:    200 * time.Millisecond,
        MaxBackoff:        5 * time.Second,
        BackoffMultiplier: 2.0,
    }))

A retry policy applies to a call only when:

  • the HTTP method is idempotent (GET, HEAD, PUT, DELETE, OPTIONS), and
  • the failure classifies as retryable via RetryOn (default: transport errors and 5xx responses; not 4xx; not context cancellation).

Retries are silent to the caller: telemetry emitted via WithLogger reports each retry at warn level, but the returned error and result reflect only the final attempt.

type RowValidationFailure added in v0.26.0

type RowValidationFailure struct {
	ID     int      `json:"id"`
	Errors []string `json:"errors"`
}

RowValidationFailure is one row that failed validation during strict promotion.

type SchemaSuggestion added in v0.26.0

type SchemaSuggestion struct {
	EntityType      string                 `json:"entity_type"`
	SampledRows     int                    `json:"sampled_rows"`
	TotalRows       int                    `json:"total_rows"`
	SuggestedSchema map[string]interface{} `json:"suggested_schema"`
	FieldAnalysis   []FieldAnalysis        `json:"field_analysis"`
}

SchemaSuggestion is the full response from GetSchemaSuggestion.

type SearchParams

type SearchParams struct {
	Query  string
	Entity string // optional entity type filter
	Limit  int
	Offset int
}

SearchParams configures search queries. Entity is optional — when set, xolu scopes the search to that entity type.

type Sequence

type Sequence struct {
	Name        string `json:"name"`
	Start       int64  `json:"start"`
	Current     int64  `json:"current"`
	IncrementBy int64  `json:"increment_by"`
	Cycle       bool   `json:"cycle"`
	MinVal      *int64 `json:"min_val,omitempty"`
	MaxVal      *int64 `json:"max_val,omitempty"`
}

Sequence is a single named monotonic sequence, as returned by Client.GetSequence.

Note that xolu v0.14.3 does not expose a "list all sequences" endpoint; consumers that need to enumerate sequences must know their names out of band. See the xolu debt tracker for the planned list endpoint. Sequence matches handleSeqGet's wire format. T-32: the earlier shape declared `step` and `created_at`, which the server never sends — Step was silently zero from Stage 2 through v0.15.3. Breaking change in v0.16.0: Step → IncrementBy, CreatedAt dropped, Cycle and the optional min/max bounds added.

type SequenceSummary

type SequenceSummary struct {
	Name        string `json:"name"`
	Current     int64  `json:"current"`
	IncrementBy int64  `json:"increment_by"`
	Cycle       bool   `json:"cycle"`
}

SequenceSummary is one entry of GET /api/v2/.../gen/seq (T-25). Field names match the wire exactly; note this differs from the Sequence type used by GetSequence, whose "step"/"created_at" tags do not match what the server actually sends (filed as register item T-32).

type StateDef

type StateDef struct {
	Terminal bool `json:"terminal"`
}

StateDef is a single state declaration.

type SulpherResult

type SulpherResult = GraphQueryResult

SulpherResult is an alias for GraphQueryResult for backward compatibility. Deprecated: use GraphQueryResult.

type TSEvent added in v0.30.23

type TSEvent struct {
	Timeline int64       `json:"timeline"`
	Dims     []uint64    `json:"dims"`
	Time     time.Time   `json:"time"`
	Nums     []float64   `json:"nums,omitempty"`
	Payload  interface{} `json:"payload,omitempty"`
}

TSEvent is one event as returned by TSQueryRange. Payload is whatever JSON value the event was appended with (or nil) -- the server carries it through opaquely, this client does the same.

type TSQueryRangeRequest added in v0.30.23

type TSQueryRangeRequest struct {
	Timeline uint64    `json:"timeline"`
	Dims     []uint64  `json:"dims"`
	From     time.Time `json:"from"`
	To       time.Time `json:"to"`
	Limit    int       `json:"limit,omitempty"`
	Order    string    `json:"order,omitempty"` // "asc" (default) or "desc"
}

TSQueryRangeRequest is TSQueryRange's own request. Dims is required and must be non-empty -- confirmed directly against the server's own handler (HandleTSQueryRangePost), which rejects an empty Dims with XOLU-TS007 before ever reaching the store. Limit and Order are optional; the server defaults Limit to 1000 (capped server-side at its own configured maximum) and Order to "asc" when left zero-value.

type TSQueryRangeResult added in v0.30.23

type TSQueryRangeResult struct {
	Count  uint64    `json:"count"`
	Events []TSEvent `json:"events"`
}

TSQueryRangeResult is TSQueryRange's own response.

type TSRollup added in v0.30.23

type TSRollup struct {
	ID             string    `json:"id"`
	SourceTID      int64     `json:"source_tid"`
	DestTID        int64     `json:"dest_tid"`
	BucketDuration string    `json:"bucket_duration"`
	LateWindow     string    `json:"late_window,omitempty"`
	Running        bool      `json:"running"`
	CreatedAt      time.Time `json:"created_at"`
}

TSRollup is the response shape for TSRollupList/TSRollupGet. LateWindow is empty when the rollup was defined with no late-data grace window. BucketDuration/LateWindow travel as Go duration strings (e.g. "1h0m0s"), matching the server's own time.Duration.String() encoding exactly -- not re-parsed or reformatted by this client. SourceTID/DestTID are int64 on the wire specifically -- the server casts its own internal uint32 TimelineID to int64 before serializing (tsRollupDefResponse), so this matches the actual JSON type, not the internal one.

type TSTimeline added in v0.30.23

type TSTimeline struct {
	ID            int64      `json:"id"`
	Name          string     `json:"name,omitempty"`
	Dims          int        `json:"dims"`
	RetentionDays int        `json:"retention_days"`
	CreatedAt     time.Time  `json:"created_at"`
	FirstWriteAt  *time.Time `json:"first_write_at,omitempty"`
}

TSTimeline is the response shape for TSListTimelines/TSGetTimeline. FirstWriteAt is nil for a timeline that has never received an event.

type TransitionDef

type TransitionDef struct {
	From   json.RawMessage   `json:"from"`
	Input  string            `json:"input"`
	To     string            `json:"to"`
	Guard  string            `json:"guard,omitempty"`
	Output string            `json:"output,omitempty"`
	Set    map[string]string `json:"set,omitempty"`
}

TransitionDef is a single transition. `From` is a json.RawMessage because xolu accepts either a single state name (JSON string) or a list of state names (JSON array) on the wire. Use FromStates() to normalise.

`Guard` and `Set` values are T-SQL expression fragments, evaluated at walk time by the FSM evaluator. They are returned verbatim so callers can display them, log them, or reason about them without re-fetching.

func (*TransitionDef) FromStates

func (t *TransitionDef) FromStates() ([]string, error)

FromStates normalises the From field into a slice of state names, accepting either a JSON string or a JSON array of strings.

type TransitionOverride

type TransitionOverride struct {
	// Guard is the new T-SQL guard expression. Nil means "leave the
	// existing guard in place"; the empty string means "clear the guard".
	Guard *string `json:"guard,omitempty"`
}

TransitionOverride carries the overridable fields of a transition. In xolu v0.14.4 only Guard is overridable.

type V2Availability

type V2Availability struct {
	Version    string          `json:"version"`
	Enabled    bool            `json:"enabled"`
	AsOf       time.Time       `json:"as_of"`
	Warning    string          `json:"warning,omitempty"`
	Subsystems json.RawMessage `json:"subsystems,omitempty"`
}

V2Availability is the response of GET /api/v2/ — the map of v2 subsystems and their current status. Useful for a consumer to check whether v2 is enabled on this server before attempting v2 calls.

The `Subsystems` map is left as json.RawMessage because the per-subsystem entries have evolved as new subsystems land; keeping it raw avoids version coupling.

type VariableDef

type VariableDef struct {
	Type    string      `json:"type"`
	Default interface{} `json:"default"`
}

VariableDef is a single machine-variable declaration.

type VariableSnapshot

type VariableSnapshot struct {
	Value   interface{} `json:"value"`
	Type    string      `json:"type,omitempty"`
	Default interface{} `json:"default,omitempty"`
}

VariableSnapshot is one entry in the map returned by Client.GetMachineVars. Each variable's live value is carried alongside its declared type and the default value from the machine's snapshot spec — a caller can distinguish "value equal to default" from "value has diverged" without re-fetching the definition.

type WalkRequest

type WalkRequest struct {
	// Input is the input symbol driving the transition. Required.
	Input string `json:"input"`
	// Payload provides arbitrary key/value data available to guards and
	// set-clauses under the "payload." prefix during evaluation. Nil is
	// permitted; the FSM will use only variables and (optionally) the
	// pre-walk query result.
	Payload map[string]interface{} `json:"payload,omitempty"`
}

WalkRequest is the body of Client.WalkMachine.

type WalkResult

type WalkResult struct {
	// Previous is the state the machine was in before the walk.
	Previous string `json:"previous"`
	// Current is the state the machine is in after the walk.
	Current string `json:"current"`
	// Terminal is true when Current is a terminal state.
	Terminal bool `json:"terminal"`
	// Outputs is the Mealy output emitted by the transition. Multi-valued
	// because a machine's output alphabet may name several outputs;
	// individual transitions typically emit at most one.
	Outputs []string `json:"outputs"`
	// Vars is the live variable map after set-clauses have applied.
	Vars map[string]interface{} `json:"vars"`
	// HistoryID is the id of the history row recording this walk.
	HistoryID int64 `json:"history_id"`
}

WalkResult is the response of Client.WalkMachine, returned on a successful transition.

A rejected walk (no matching transition, guard failed, terminal state, etc.) returns *client.Error carrying an XOLU-FSM* code — not a WalkResult with a diagnostic. Callers dispatch on the error code.

Jump to

Keyboard shortcuts

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