client

package
v0.30.38 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 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) LocContains added in v0.30.38

func (c *Client) LocContains(ctx context.Context, lat, lon float64) (*LocContainsResult, error)

LocContains returns every fence the given point currently falls inside.

Hits GET /api/v2/.../loc/contains?lat=...&lon=.... Returns *client.Error on non-2xx.

func (*Client) LocDefine added in v0.30.38

func (c *Client) LocDefine(ctx context.Context, req LocDefineRequest) (*LocLocation, error)

LocDefine creates or reconfigures a location. Set req.ParentID to nil for a root location, or to an existing location's own id to place this one under it.

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

func (*Client) LocDelete added in v0.30.38

func (c *Client) LocDelete(ctx context.Context, locationID string, force bool) error

LocDelete removes locationID. force, when true, matches the server's own ?force=true query flag (behaviour for a non-empty location is a server-side policy this client does not second-guess or duplicate -- whatever LocDelete without force refuses, force is the caller's own explicit override).

Hits DELETE /api/v2/.../loc/{location_id}[?force=true]. Returns *client.Error on non-2xx.

func (*Client) LocFenceAttach added in v0.30.38

func (c *Client) LocFenceAttach(ctx context.Context, req LocFenceAttachRequest) (*LocFence, error)

LocFenceAttach defines a fence -- either obj-anchored (req.Subject, "kind:key" shorthand) or tree-aligned (req.AlignedTo, a plain location id) -- exactly one of the two set.

Hits POST /api/v2/.../loc/fences/attach. Returns *client.Error on non-2xx -- notably XOLU-LOC022 if both Capacity and Pattern are set.

func (*Client) LocFenceDelete added in v0.30.38

func (c *Client) LocFenceDelete(ctx context.Context, ref LocFenceRef) error

LocFenceDelete removes ref.

Hits DELETE /api/v2/.../loc/fences/{kind}/{key}. Returns *client.Error on non-2xx.

func (*Client) LocFenceGet added in v0.30.38

func (c *Client) LocFenceGet(ctx context.Context, ref LocFenceRef) (*LocFence, error)

LocFenceGet returns ref's own current record. Construct ref via LocFenceRefByLocation or LocFenceRefBySubject.

Hits GET /api/v2/.../loc/fences/{kind}/{key}. Returns *client.Error on non-2xx -- notably 404 if ref was never defined.

func (*Client) LocFenceList added in v0.30.38

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

LocFenceList returns every fence defined on the tenant.

Hits GET /api/v2/.../loc/fences/list. Returns *client.Error on non-2xx.

func (*Client) LocFencePatch added in v0.30.38

func (c *Client) LocFencePatch(ctx context.Context, ref LocFenceRef, geometry LocFenceGeometry) (*LocFence, error)

LocFencePatch replaces ref's own geometry. Never touches capacity, pattern, or current membership -- only the stored shape changes; membership stays correct until the next report/move naturally revisits it, or until LocFenceReconcile is asked to look.

Hits PATCH /api/v2/.../loc/fences/{kind}/{key}. Returns *client.Error on non-2xx.

func (*Client) LocFenceReconcile added in v0.30.38

func (c *Client) LocFenceReconcile(ctx context.Context, ref LocFenceRef) (*LocFenceReconcileResult, error)

LocFenceReconcile reports ref's own recorded-vs-observed membership drift -- advisory only, never writes anything.

Hits GET /api/v2/.../loc/fences/{kind}/{key}/reconcile. Returns *client.Error on non-2xx.

func (*Client) LocGet added in v0.30.38

func (c *Client) LocGet(ctx context.Context, locationID string) (*LocLocation, error)

LocGet returns locationID's own current record.

Hits GET /api/v2/.../loc/{location_id}. Returns *client.Error on non-2xx -- notably 404 if locationID was never defined.

func (*Client) LocList added in v0.30.38

func (c *Client) LocList(ctx context.Context, optParentID string) (*LocListResult, error)

LocList returns every location defined on the tenant. optParentID, when non-empty, filters to direct children of that location only (matching the server's own ?parent_id= query filter); pass "" for every location regardless of parent.

Hits GET /api/v2/.../loc/list[?parent_id=...]. Returns *client.Error on non-2xx.

func (*Client) LocMove added in v0.30.38

func (c *Client) LocMove(ctx context.Context, entityType string, entityID int64, toLocationID string) (*LocMoveResult, error)

LocMove moves the entity identified by entityType/entityID to toLocationID, computing and reporting any fence boundaries crossed by the move.

Hits POST /api/v2/.../loc/move. Returns *client.Error on non-2xx.

func (*Client) LocNearby added in v0.30.38

func (c *Client) LocNearby(ctx context.Context, lat, lon, radiusM float64) (*LocNearbyResult, error)

LocNearby returns locations and fences near the given point, within radiusM meters.

Hits GET /api/v2/.../loc/nearby?lat=...&lon=...&radius_m=.... Returns *client.Error on non-2xx.

func (*Client) LocPatch added in v0.30.38

func (c *Client) LocPatch(ctx context.Context, locationID string, req LocPatchRequest) (*LocLocation, error)

LocPatch partially updates locationID. See LocPatchRequest's own doc comment for the tri-state Capacity semantics (nil outer pointer = leave unchanged; non-nil outer pointing at nil inner = clear to unlimited; non-nil outer pointing at a value = set that ceiling). Capacity is excluded from this struct's own JSON tags precisely because standard marshaling cannot distinguish those three states through one field the way a hand-built body can -- built manually here rather than relying on encoding/json for exactly that field.

Hits PATCH /api/v2/.../loc/{location_id}. Returns *client.Error on non-2xx.

func (*Client) LocPatternDefine added in v0.30.38

func (c *Client) LocPatternDefine(ctx context.Context, name string, capacity int64) (*LocPattern, error)

LocPatternDefine defines a fence-type pattern -- not a fence or a location itself, addressed by a plain (tenant, name).

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

func (*Client) LocPatternDelete added in v0.30.38

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

LocPatternDelete removes id.

Hits DELETE /api/v2/.../loc/patterns/{id}. Returns *client.Error on non-2xx.

func (*Client) LocPatternGet added in v0.30.38

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

LocPatternGet returns id's own current record.

Hits GET /api/v2/.../loc/patterns/{id}. Returns *client.Error on non-2xx -- notably 404 if id was never defined.

func (*Client) LocPatternList added in v0.30.38

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

LocPatternList returns every pattern defined on the tenant.

Hits GET /api/v2/.../loc/patterns/list. Returns *client.Error on non-2xx.

func (*Client) LocReport added in v0.30.38

func (c *Client) LocReport(ctx context.Context, entityType string, entityID int64, point LocPoint) (*LocReportResult, error)

LocReport records a raw lat/lon/alt point for the entity identified by entityType/entityID, independent of any /loc leaf placement, and reports whether the report itself crossed a fence boundary.

Hits POST /api/v2/.../loc/report. Returns *client.Error on non-2xx.

func (*Client) LocSubjectHistory added in v0.30.38

func (c *Client) LocSubjectHistory(ctx context.Context, entityType string, entityID int64) (*LocSubjectHistoryResult, error)

LocSubjectHistory returns the entity/id subject's own movement journal, newest first.

Hits GET /api/v2/.../loc/subjects/{entity}/{id}/history. Returns *client.Error on non-2xx.

func (*Client) LocSubjectPosition added in v0.30.38

func (c *Client) LocSubjectPosition(ctx context.Context, entityType string, entityID int64) (*LocSubjectPosition, error)

LocSubjectPosition resolves the entity/id subject's own current canonical state -- leaf placement, fence membership, and last raw report, whichever of those this subject has actually been tracked by.

Hits GET /api/v2/.../loc/subjects/{entity}/{id}/position. Returns *client.Error on non-2xx.

func (*Client) OQL

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

OQL executes an OQL (SQL-like) query.

func (*Client) ObjAttach added in v0.30.38

func (c *Client) ObjAttach(ctx context.Context, req ObjAttachRequest) (*ObjSubject, error)

ObjAttach attaches obj capability to req.Subject ("kind:key" shorthand). A freshly-attached subject always starts unassigned (PositionKind == "").

Hits POST /api/v2/.../obj/attach. Returns *client.Error on non-2xx -- notably XOLU-OBJ006 if the subject is already attached.

func (*Client) ObjCapacityPatch added in v0.30.38

func (c *Client) ObjCapacityPatch(ctx context.Context, subject string, capacity ObjCapacity) (*ObjSubject, error)

ObjCapacityPatch updates subject's own capacity ceilings (any of the three dimensions may be omitted to leave it unchanged; the server's own current-usage totals are read-only and never set from here). Returns subject's own updated record.

Hits PATCH /api/v2/.../obj/{kind}/{key}/capacity. Returns *client.Error on non-2xx.

func (*Client) ObjContents added in v0.30.38

func (c *Client) ObjContents(ctx context.Context, subject string, transitive bool) (*ObjContentsResult, error)

ObjContents returns subject's own directly-contained subjects, or every subject in its transitive containment tree when transitive is true.

Hits GET /api/v2/.../obj/{kind}/{key}/contents[?depth=all]. Returns *client.Error on non-2xx.

func (*Client) ObjDemote added in v0.30.38

func (c *Client) ObjDemote(ctx context.Context, req ObjDemoteRequest) (*ObjPromoteResult, error)

ObjDemote reverses a promotion -- removes obj capability from req.Subject together with a bal transfer back out, the same atomic pairing ObjPromote makes going in.

Hits POST /api/v2/.../obj/demote. Returns *client.Error on non-2xx.

func (*Client) ObjDetach added in v0.30.38

func (c *Client) ObjDetach(ctx context.Context, subject string) error

ObjDetach removes obj capability from subject entirely -- distinct from Retire (the lifecycle terminal state, §6); this is plain bookkeeping cleanup. Refused (409) if subject is currently positioned anywhere other than unassigned.

Hits DELETE /api/v2/.../obj/{kind}/{key}. Returns *client.Error on non-2xx.

func (*Client) ObjGet added in v0.30.38

func (c *Client) ObjGet(ctx context.Context, subject string) (*ObjSubject, error)

ObjGet returns subject's own current record.

Hits GET /api/v2/.../obj/{kind}/{key}. Returns *client.Error on non-2xx -- notably 404 if subject was never attached.

func (*Client) ObjList added in v0.30.38

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

ObjList returns every subject currently attached in the tenant -- no way existed to enumerate obj data at all before this (XOT209, found by reading the full obj route table directly: every other route requires an already-known subject). An empty tenant returns an empty slice, not an error -- exactly the shape a caller doing a tenant-emptiness check needs.

Hits GET /api/v2/.../obj/list. Returns *client.Error on non-2xx.

func (*Client) ObjMove added in v0.30.38

func (c *Client) ObjMove(ctx context.Context, subject string, target ObjMoveTarget) (*ObjSubject, error)

ObjMove moves subject to target -- either a real /loc leaf (Kind: "loc_leaf", LocationID set) or containment inside another already-attached subject (Kind: "obj", Subject set to the container's own "kind:key"). Returns subject's own updated record.

Hits PUT /api/v2/.../obj/{kind}/{key}/move. Returns *client.Error on non-2xx -- a move to a loc_leaf can surface /loc's own errors unwrapped (e.g. XOLU-LOC002 for a capacity refusal).

func (*Client) ObjPosition added in v0.30.38

func (c *Client) ObjPosition(ctx context.Context, subject string) (*ObjPositionResult, error)

ObjPosition resolves subject's own current position, following a containment chain to its own root if subject is contained by another subject rather than placed directly on a /loc leaf. AsOf is always "live" today -- there is no historical-position query yet.

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

func (*Client) ObjPromote added in v0.30.38

func (c *Client) ObjPromote(ctx context.Context, req ObjPromoteRequest) (*ObjPromoteResult, error)

ObjPromote promotes an entity (either an existing one, by key, or a new one created inline) to obj capability together with a bal transfer, as one atomic dxp-orchestrated operation -- not two separate calls a caller sequences and hopes stay consistent. req.Position.Kind must be "obj" in this server release (containment into an already-attached subject); req.Entity must set exactly one of ExistingKey or Create.

Hits POST /api/v2/.../obj/promote. Returns *client.Error on non-2xx -- notably XOLU-OBJ (entity-selection) errors when Entity sets both or neither of its own two fields.

func (*Client) ObjReport added in v0.30.38

func (c *Client) ObjReport(ctx context.Context, subject string, lat, lon, alt float64) error

ObjReport records subject's own current point (lat/lon, alt optional) -- a raw position report, independent of /loc containment.

Hits POST /api/v2/.../obj/{kind}/{key}/report. Returns *client.Error on non-2xx.

func (*Client) ObjRetire added in v0.30.38

func (c *Client) ObjRetire(ctx context.Context, subject string) error

ObjRetire moves subject to its own terminal lifecycle state (obj-00-design.md §12) -- once set, never cleared. Distinct from Detach (bookkeeping removal); this is a permanent record.

Hits POST /api/v2/.../obj/{kind}/{key}/retire. Returns *client.Error on non-2xx.

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) TSAggregate added in v0.30.38

func (c *Client) TSAggregate(ctx context.Context, req TSAggregateRequest) (*TSAggregateResult, error)

TSAggregate computes req.Function over req.NumField, optionally bucketed by req.Interval. See TSAggregateRequest's own doc comment for the exact 9-value Interval enum, and TSAggregateResult's own doc comment for the bucketed-vs-scalar union shape the response takes.

Hits POST /api/v1/.../ts/aggregate. Returns *client.Error on non-2xx -- notably XOLU-TS (invalid-agg-field) if NumField is out of the 0-6 range.

func (*Client) TSAppend added in v0.30.38

func (c *Client) TSAppend(ctx context.Context, e TSEvent) error

TSAppend appends a single event to a timeline. e.Time is marshaled as RFC3339Nano (Go's own time.Time JSON encoding), matching what the server's own parseTSTime accepts.

Hits POST /api/v1/.../ts/events. Returns *client.Error on non-2xx -- notably XOLU-TS004 for an undefined timeline, XOLU-TS007 for a dims-count mismatch against the timeline's own definition.

func (*Client) TSBatchAppend added in v0.30.38

func (c *Client) TSBatchAppend(ctx context.Context, events []TSEvent) (*TSBatchAppendResult, error)

TSBatchAppend appends events atomically -- checked directly against pkg/timeseries's own AppendBatch before writing this: the current implementation validates every event first and returns an outright error if any one is invalid, before any event is written, so a response is only ever returned when every event in this call succeeded together. See TSBatchAppendResult's own doc comment for why Accepted/Failed are still surfaced as returned rather than this client asserting Accepted == Total itself.

Hits POST /api/v1/.../ts/events/batch. Returns *client.Error on non-2xx -- notably XOLU-TS006 if len(events) exceeds the server's own configured maximum batch size.

func (*Client) TSDefineTimeline added in v0.30.38

func (c *Client) TSDefineTimeline(ctx context.Context, req TSDefineTimelineRequest) (*TSTimeline, error)

TSDefineTimeline defines a new timeline. req.Dims is fixed for the timeline's own lifetime once set here.

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

func (*Client) TSDeleteTimeline added in v0.30.38

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

TSDeleteTimeline removes timelineID's own definition together with its event data and rollups -- the inverse of TSDefineTimeline. Distinct from a future data-only purge (Wave 16 Stage 7), which keeps the definition.

Hits DELETE /api/v1/.../ts/tl/{timeline_id}. Returns *client.Error on non-2xx -- notably 409 if the timeline still has rollups and cascade deletion is disabled server-side (remove the rollups first), 404 for an undefined timeline.

func (*Client) TSDeleteTimelineData added in v0.30.38

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

TSDeleteTimelineData removes every event from timelineID, keeping the timeline's own definition -- distinct from TSDeleteTimeline (Wave 16 Stage 3), which removes both together.

Hits DELETE /api/v1/.../ts/tl/{timeline_id}/data. Returns *client.Error on non-2xx.

func (*Client) TSFullAggregate added in v0.30.38

func (c *Client) TSFullAggregate(ctx context.Context, req TSFullAggregateRequest) (*TSFullAggregateResult, error)

TSFullAggregate combines TSRangeAggregate's own exact statistics with approximate quantile estimates in one pass. An empty/nil req.Quantiles is equivalent to plain TSRangeAggregate at no extra cost server-side (no quantile sketch allocated).

Hits POST /api/v1/.../ts/full_aggregate. Returns *client.Error on non-2xx.

func (*Client) TSGetRetention added in v0.30.38

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

TSGetRetention returns the tenant's own store-level default retention plus every timeline's own current setting.

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

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) TSLatest added in v0.30.38

func (c *Client) TSLatest(ctx context.Context, req TSLatestRequest) (*TSQueryRangeResult, error)

TSLatest returns the req.N most recent events for a timeline (defaulting to 10 if req.N is 0), optionally bounded by From/To.

Hits GET /api/v1/.../ts/events/latest?timeline=...&dims=...&n=.... Returns *client.Error on non-2xx.

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) TSPatchRetention added in v0.30.38

func (c *Client) TSPatchRetention(ctx context.Context, defaultRetentionDays int) (*TSPatchRetentionResult, error)

TSPatchRetention updates the tenant's own store-level default retention. Per-timeline retention is set via TSUpdateTimeline, not here.

Hits PATCH /api/v1/.../ts/retention. Returns *client.Error on non-2xx.

func (*Client) TSProvision added in v0.30.38

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

TSProvision is a one-time per-tenant setup call, required before any other ts operation succeeds against a fresh tenant.

Hits POST /api/v1/.../ts/provision. Returns *client.Error on non-2xx.

func (*Client) TSPurgeTimelineRange added in v0.30.38

func (c *Client) TSPurgeTimelineRange(ctx context.Context, timelineID int64, from, to time.Time) error

TSPurgeTimelineRange removes events in [from, to) from timelineID, keeping everything outside that range. from/to are formatted explicitly as time.RFC3339 (not relying on time.Time's default JSON marshaling, which produces RFC3339Nano) -- confirmed directly against the server's own strict time.Parse(time.RFC3339, ...) call before choosing this, the same discipline TSRollupRun already follows for the identical reason.

Hits POST /api/v1/.../ts/tl/{timeline_id}/data/purge. Returns *client.Error on non-2xx -- notably a refusal if to is not after from.

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) TSQueryRangeGet added in v0.30.38

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

TSQueryRangeGet is the query-string-based alternative to TSQueryRange -- same semantics, same result shape (reused directly, no separate type), different transport: query parameters instead of a JSON body. The server's own doc comment on the POST variant notes it exists specifically to avoid URL-length limits for complex queries -- this GET form is the simpler, curl-friendly counterpart for everything else.

Hits GET /api/v1/.../ts/events?timeline=...&dims=...&from=...&to=.... Returns *client.Error on non-2xx.

func (*Client) TSRangeAggregate added in v0.30.38

func (c *Client) TSRangeAggregate(ctx context.Context, req TSRangeAggregateRequest) (*TSRangeAggregateResult, error)

TSRangeAggregate computes count/sum/avg/min/max for all seven numeric fields in one pass -- more efficient than several TSAggregate calls when multiple fields are needed. Does not support time bucketing; use TSAggregate for that.

Hits POST /api/v1/.../ts/range_aggregate. Returns *client.Error on non-2xx.

func (*Client) TSRollupDefine added in v0.30.38

func (c *Client) TSRollupDefine(ctx context.Context, timelineID int64, req TSRollupDefineRequest) (*TSRollup, error)

TSRollupDefine defines a rollup on timelineID, aggregating into req.DestTID at req.BucketDuration intervals.

Hits POST /api/v1/.../ts/tl/{timeline_id}/rollup/def. Returns *client.Error on non-2xx -- notably XOLU-TS (rollup-cycle or rollup-depth) errors if this definition would create a cycle or exceed the server's own max rollup chain depth.

func (*Client) TSRollupDelete added in v0.30.38

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

TSRollupDelete removes rollupID and stops its worker.

Hits DELETE /api/v1/.../ts/tl/{timeline_id}/rollup/{rollup_id}. Returns *client.Error on non-2xx.

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) TSRollupParent added in v0.30.38

func (c *Client) TSRollupParent(ctx context.Context, timelineID int64) (*TSRollup, error)

TSRollupParent returns the rollup definition for which timelineID is the destination -- its own parent in the rollup tree.

Hits GET /api/v1/.../ts/tl/{timeline_id}/rollup/parent. Returns *client.Error on non-2xx -- notably 404 if timelineID has no rollup parent.

func (*Client) TSRollupRun added in v0.30.38

func (c *Client) TSRollupRun(ctx context.Context, timelineID int64, rollupID string, req TSRollupRunRequest) error

TSRollupRun manually triggers rollupID for req's own bounded range. The request body's own From/To are formatted explicitly as time.RFC3339 (not relying on time.Time's default JSON marshaling, which produces RFC3339Nano) -- confirmed directly against the server's own strict time.Parse(time.RFC3339, ...) call before choosing this, not assumed lenient.

Hits POST /api/v1/.../ts/tl/{timeline_id}/rollup/{rollup_id}/run. Returns *client.Error on non-2xx -- notably 404 for an unknown rollup.

func (*Client) TSRollupStatus added in v0.30.38

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

TSRollupStatus returns rollupID's own operational status.

Hits GET /api/v1/.../ts/tl/{timeline_id}/rollup/{rollup_id}/status. Returns *client.Error on non-2xx -- notably 404 for an unknown rollup.

func (*Client) TSRollupTree added in v0.30.38

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

TSRollupTree returns the full rollup tree for the tenant. Returns nil (not an error) for a tenant with no timelines at all -- the server's own response body is a bare JSON null in that case, confirmed directly against treeNodeToResponse's own nil handling.

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

func (*Client) TSStats added in v0.30.38

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

TSStats returns store-level diagnostics for the whole tenant.

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

func (*Client) TSSyncGet added in v0.30.38

func (c *Client) TSSyncGet(ctx context.Context, timelineID int64) (*TSSyncStatus, error)

TSSyncGet returns timelineID's own current WAL-fsync durability mode. See TSSyncStatus's own doc comment for what NoSync actually governs.

Hits GET /api/v1/.../ts/tl/{timeline_id}/sync. Returns *client.Error on non-2xx.

func (*Client) TSSyncOff added in v0.30.38

func (c *Client) TSSyncOff(ctx context.Context, timelineID int64) (*TSSyncStatus, error)

TSSyncOff enables nosync mode for timelineID -- an append returns immediately without waiting for WAL fsync. Faster, but a crash before the kernel's own dirty-page writeback (typically under a second) can lose the most recent writes to this timeline.

Hits POST /api/v1/.../ts/tl/{timeline_id}/sync/off. Returns *client.Error on non-2xx.

func (*Client) TSSyncOn added in v0.30.38

func (c *Client) TSSyncOn(ctx context.Context, timelineID int64) (*TSSyncStatus, error)

TSSyncOn restores synchronous (crash-durable) write mode for timelineID -- the default mode; an append waits for WAL fsync before returning.

Hits POST /api/v1/.../ts/tl/{timeline_id}/sync/on. Returns *client.Error on non-2xx.

func (*Client) TSTimelineStats added in v0.30.38

func (c *Client) TSTimelineStats(ctx context.Context, timelineID int64) (*TSTimelineStatsResult, error)

TSTimelineStats returns per-timeline diagnostics for timelineID.

Hits GET /api/v1/.../ts/stats/{timeline_id}. Returns *client.Error on non-2xx -- notably 404 for an undefined timeline.

func (*Client) TSUpdateTimeline added in v0.30.38

func (c *Client) TSUpdateTimeline(ctx context.Context, timelineID int64, req TSUpdateTimelineRequest) (*TSTimeline, error)

TSUpdateTimeline updates timelineID's own mutable fields (name, retention). See TSUpdateTimelineRequest's own doc comment for why dims cannot be changed here.

Hits PATCH /api/v1/.../ts/tl/{timeline_id}. Returns *client.Error on non-2xx -- notably 404 for an undefined timeline.

func (*Client) TenantSummary added in v0.30.38

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

TenantSummary returns a single-round-trip data-presence summary for the connected tenant -- every store a tenant's own data can live in, derived server-side from the same table inventory pkg/tenantexport's own backup path uses. res.Empty is the boolean answer; the full per-store breakdown is included in the same response for a caller that wants more than yes/no.

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

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 LocAnchor added in v0.30.38

type LocAnchor struct {
	Lat       float64 `json:"lat"`
	Lon       float64 `json:"lon"`
	Alt       float64 `json:"alt"`
	TrueNorth float64 `json:"true_north"`
}

LocAnchor is a location's own geo-referenced point -- present only on a location whose own placement chain includes an anchor (directly or inherited).

type LocContainsResult added in v0.30.38

type LocContainsResult struct {
	Fences []string `json:"fences"`
}

LocContainsResult is GET /loc/contains's own response -- every fence a given lat/lon point currently falls inside.

type LocDefineRequest added in v0.30.38

type LocDefineRequest struct {
	LocationID string       `json:"location_id"`
	ParentID   *string      `json:"parent_id"`
	Name       string       `json:"name"`
	Postable   *bool        `json:"postable,omitempty"`
	Capacity   *int64       `json:"capacity,omitempty"`
	Pattern    *string      `json:"pattern,omitempty"`
	Placement  LocPlacement `json:"placement"`
}

LocDefineRequest defines or reconfigures a location. Postable governs whether obj/entities may be placed directly on this node (false for a summary/grouping node, matching bal's own postable- account distinction); nil leaves the server's own default. Capacity is a plain item-count ceiling, nil for unlimited.

type LocFence added in v0.30.38

type LocFence struct {
	FenceID        string           `json:"fence_id"`
	AlignedTo      string           `json:"aligned_to,omitempty"`
	Geometry       LocFenceGeometry `json:"geometry"`
	Capacity       *int64           `json:"capacity,omitempty"`
	PatternID      *string          `json:"pattern_id,omitempty"`
	PatternDeleted *bool            `json:"pattern_deleted,omitempty"`
	Warnings       []string         `json:"warnings,omitempty"`
}

LocFence is the shape every fence read/write that returns a single fence uses -- attach, get, and patch.

type LocFenceAttachRequest added in v0.30.38

type LocFenceAttachRequest struct {
	Subject   string           `json:"subject,omitempty"`
	AlignedTo string           `json:"aligned_to,omitempty"`
	Geometry  LocFenceGeometry `json:"geometry"`
	Capacity  *int64           `json:"capacity,omitempty"`
	Pattern   *string          `json:"pattern,omitempty"`
}

LocFenceAttachRequest defines a fence. Exactly one of Subject or AlignedTo identifies it -- Subject for an obj-anchored fence ("kind:key" shorthand, proven equivalent to the server's own structured REF form; this client only ever sends the shorthand), AlignedTo for a tree-aligned fence (identity is the location itself -- a plain location id, not a subject). Capacity and Pattern are mutually exclusive (XOLU-LOC022) -- set at most one, never both.

type LocFenceCenter added in v0.30.38

type LocFenceCenter struct {
	Lat  float64 `json:"lat"`
	Lon  float64 `json:"lon"`
	Self bool    `json:"self,omitempty"`
}

LocFenceCenter is a circle fence's own center point. Self, when true, means "anchored to the subject itself" -- confirmed NOT supported in this server release (obj-dependent, wave 10 not built), refused with a real error before this client ever sends the request.

type LocFenceDelta added in v0.30.38

type LocFenceDelta struct {
	Entered []string `json:"entered"`
	Exited  []string `json:"exited"`
}

LocFenceDelta is the entered/exited fence id sets a move or report produces, when fence membership actually changed.

type LocFenceDrift added in v0.30.38

type LocFenceDrift struct {
	SubjectRef string `json:"subject_ref"`
	Recorded   string `json:"recorded"`
	Observed   string `json:"observed"`
}

LocFenceDrift is one subject's own recorded-vs-observed disagreement in a reconcile response. Recorded and Observed are short status strings the server defines (e.g. "member", "outside_new_boundary"), not booleans -- verified directly against pkg/loc's own FenceDrift before being typed here.

type LocFenceGeometry added in v0.30.38

type LocFenceGeometry struct {
	Type        string          `json:"type"`
	Coordinates [][][2]float64  `json:"coordinates,omitempty"`
	Center      *LocFenceCenter `json:"center,omitempty"`
	RadiusM     float64         `json:"radius_m,omitempty"`
}

LocFenceGeometry is exactly one of two shapes, selected by Type -- the two literal strings the server accepts, preserved verbatim rather than normalized: "Polygon" (Coordinates set -- a single closed exterior ring, [longitude, latitude] pairs per position, standard GeoJSON order and NOT [lat, lon] -- verified directly against loc.DecodeGeoJSONPolygon before writing this, not assumed; at least 3 distinct vertices plus a closing repeat of the first position, interior rings/holes not supported in this server release) or "circle" (Center + RadiusM set).

type LocFenceListResult added in v0.30.38

type LocFenceListResult struct {
	Fences []string `json:"fences"`
}

LocFenceListResult is GET /loc/fences/list's own response.

type LocFenceReconcileResult added in v0.30.38

type LocFenceReconcileResult struct {
	FenceID       string          `json:"fence_id"`
	RecordedCount int             `json:"recorded_count"`
	ObservedCount int             `json:"observed_count"`
	Drift         []LocFenceDrift `json:"drift"`
}

LocFenceReconcileResult is GET /loc/fences/{id}/reconcile's own response -- advisory only, this call never writes anything.

type LocFenceRef added in v0.30.38

type LocFenceRef struct {
	Kind string
	Key  string
}

LocFenceRef identifies which fence a lookup (Get/Delete/Patch/ Reconcile) targets -- Kind and Key exactly mirror the server's own GET /loc/fences/{kind}/{key} path, two explicit segments, never a single string to parse apart. Construct via LocFenceRefByLocation or LocFenceRefBySubject rather than by hand.

This replaces an earlier design (a single fenceID string, split on ":") that collapsed the server's own already-unambiguous two- segment URL into one ambiguous client parameter and then tried to guess the split back out -- a real bug, confirmed directly by TestAdversarial_FenceLookupPathColonCollision: a tree-aligned location legitimately named "root:special" defeated the guess. Mirrors dxp.Claim's own Primitive+Resource shape (an explicit tag field alongside a primitive-scoped string, not one overloaded string) -- the same pattern already established elsewhere in this codebase for exactly this problem.

func LocFenceRefByLocation added in v0.30.38

func LocFenceRefByLocation(locationID string) LocFenceRef

LocFenceRefByLocation identifies a tree-aligned fence by its own location's plain id -- safe for any id, including one containing a colon, since Kind ("id") and Key (the id verbatim) are always two separate fields here, never inferred from the id's own shape.

func LocFenceRefBySubject added in v0.30.38

func LocFenceRefBySubject(kind, key string) LocFenceRef

LocFenceRefBySubject identifies an obj-anchored fence by the same kind/key split LocFenceAttachRequest's own Subject shorthand uses (e.g. kind="vehicles", key="47" for "vehicles:47"), passed here as two already-split fields rather than a string to re-split.

type LocHistoryEntry added in v0.30.38

type LocHistoryEntry struct {
	At      string   `json:"at"`
	Kind    string   `json:"kind"`
	From    *string  `json:"from,omitempty"`
	To      *string  `json:"to,omitempty"`
	Entered []string `json:"entered,omitempty"`
	Exited  []string `json:"exited,omitempty"`
}

LocHistoryEntry is one row in a subject's own movement journal. From/To are set only for a move entry; Entered/Exited are set only for a report entry (or a tree-aligned move, which also carries fence deltas).

type LocListResult added in v0.30.38

type LocListResult struct {
	Locations []LocLocation `json:"locations"`
}

LocListResult is GET /loc/list's own response shape.

type LocLocation added in v0.30.38

type LocLocation struct {
	LocationID     string       `json:"location_id"`
	ParentID       *string      `json:"parent_id"`
	Name           string       `json:"name"`
	Postable       bool         `json:"postable"`
	Capacity       *int64       `json:"capacity,omitempty"`
	Pattern        *string      `json:"pattern,omitempty"`
	PatternID      *string      `json:"pattern_id,omitempty"`
	PatternDeleted *bool        `json:"pattern_deleted,omitempty"`
	Placement      LocPlacement `json:"placement"`
	Warnings       []string     `json:"warnings,omitempty"`
}

LocLocation is the shape every loc read/write that returns a single location uses (define, get, patch, and each entry in LocListResult).

type LocMoveResult added in v0.30.38

type LocMoveResult struct {
	Moved  bool          `json:"moved"`
	Leaf   string        `json:"leaf"`
	Fences LocFenceDelta `json:"fences"`
}

LocMoveResult is POST /loc/move's own response shape.

type LocNearbyFence added in v0.30.38

type LocNearbyFence struct {
	FenceID   string  `json:"fence_id"`
	DistanceM float64 `json:"distance_m"`
}

type LocNearbyLocation added in v0.30.38

type LocNearbyLocation struct {
	LocationID string  `json:"location_id"`
	DistanceM  float64 `json:"distance_m"`
}

LocNearbyLocation and LocNearbyFence are GET /loc/nearby's own per-result entries.

type LocNearbyResult added in v0.30.38

type LocNearbyResult struct {
	Locations []LocNearbyLocation `json:"locations"`
	Fences    []LocNearbyFence    `json:"fences"`
}

LocNearbyResult is GET /loc/nearby's own response.

type LocPatchRequest added in v0.30.38

type LocPatchRequest struct {
	Name      *string       `json:"name,omitempty"`
	Placement *LocPlacement `json:"placement,omitempty"`
	Capacity  **int64       `json:"-"` // marshaled specially, see loc.go's own LocPatch
}

LocPatchRequest partially updates a location. Every field is tri-state, matching the server's own raw-map-keyed patch semantics exactly: a nil field is genuinely absent from the request and leaves that property unchanged; Capacity is a double pointer for exactly this reason -- a non-nil *Capacity pointing at a nil *int64 explicitly clears the ceiling to unlimited, while a nil outer pointer (the zero value) omits the field entirely and leaves the existing ceiling untouched. Name and Placement don't need the same double-pointer treatment: the server has no "clear the name" or "clear the placement" operation, only "set" or "leave alone."

type LocPattern added in v0.30.38

type LocPattern struct {
	Name     string `json:"name"`
	Capacity int64  `json:"capacity"`
}

LocPattern is a fence-type pattern (T-131) -- not a fence or a location itself, addressed by a plain (tenant, id), the shape every pattern read/write uses.

type LocPatternListResult added in v0.30.38

type LocPatternListResult struct {
	Patterns []LocPattern `json:"patterns"`
}

LocPatternListResult is GET /loc/patterns/list's own response.

type LocPlacement added in v0.30.38

type LocPlacement struct {
	OffsetX  float64    `json:"offset_x"`
	OffsetY  float64    `json:"offset_y"`
	OffsetZ  float64    `json:"offset_z"`
	Rotation float64    `json:"rotation"`
	Anchor   *LocAnchor `json:"anchor,omitempty"`
}

LocPlacement is a location's own placement relative to its parent (offsets + rotation), plus an optional Anchor establishing (or re-establishing) a real-world geo reference at this node -- most locations inherit their anchor from an ancestor and never set their own.

type LocPoint added in v0.30.38

type LocPoint struct {
	Lat float64 `json:"lat"`
	Lon float64 `json:"lon"`
	Alt float64 `json:"alt,omitempty"`
}

LocPoint is a raw lat/lon/alt report, independent of any /loc leaf placement -- the same shape obj's own Report uses, duplicated rather than shared across packages for the same reason bal/cal/dxp each keep their own wire types instead of a shared package: each primitive's own request shape is free to diverge from the others' without a shared type forcing them to move together.

type LocReportResult added in v0.30.38

type LocReportResult struct {
	Changed bool     `json:"changed"`
	Fences  []string `json:"fences"`
}

LocReportResult is POST /loc/report's own response shape. Changed is true iff this report crossed at least one fence boundary; Fences is always the subject's own full current fence membership, not just what changed.

type LocSubject added in v0.30.38

type LocSubject struct {
	Type   string `json:"type,omitempty"`
	Entity string `json:"entity"`
	ID     int64  `json:"id"`
}

LocSubject identifies the entity a move or report acts on. Type is carried through to the server but not currently used server-side to compute the canonical subject reference (Entity + ID alone produce "entity:id"); included here because the wire shape requires it, not because this client asserts a meaning for it beyond what the server itself currently does.

type LocSubjectHistoryResult added in v0.30.38

type LocSubjectHistoryResult struct {
	Entries    []LocHistoryEntry `json:"entries"`
	NextCursor *string           `json:"next_cursor,omitempty"`
}

LocSubjectHistoryResult is GET /loc/subjects/{entity}/{id}/history's own response -- newest first.

type LocSubjectPosition added in v0.30.38

type LocSubjectPosition struct {
	Leaf            *string   `json:"leaf,omitempty"`
	Fences          []string  `json:"fences"`
	LastReportPoint *LocPoint `json:"last_report_point,omitempty"`
	AsOf            *string   `json:"as_of,omitempty"`
}

LocSubjectPosition is GET /loc/subjects/{entity}/{id}/position's own response. Leaf is nil for a subject only ever report-tracked; LastReportPoint is nil for one only ever moved -- both nil means this subject has never been referenced by either verb at all.

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 ObjAttachRequest added in v0.30.38

type ObjAttachRequest struct {
	Subject  string      `json:"subject"`
	Capacity ObjCapacity `json:"capacity,omitempty"`
}

ObjAttachRequest attaches obj capability to an entity. Subject is the "kind:key" shorthand (e.g. "vehicles:47") -- the server also accepts a structured form, but the shorthand is this client's own deliberate choice, matching how every other obj method here takes a plain subject string rather than a split kind/key pair.

type ObjCapacity added in v0.30.38

type ObjCapacity struct {
	MaxWeightKg *float64 `json:"max_weight_kg,omitempty"`
	MaxVolumeM3 *float64 `json:"max_volume_m3,omitempty"`
	MaxCount    *int64   `json:"max_count,omitempty"`
	CurWeightKg float64  `json:"cur_weight_kg,omitempty"`
	CurVolumeM3 float64  `json:"cur_volume_m3,omitempty"`
	CurCount    int64    `json:"cur_count,omitempty"`
}

ObjCapacity mirrors objCapacityJSON server-side. All three fields are optional (nil = unlimited on that dimension); CurWeightKg/ CurVolumeM3/CurCount are read-only, server-computed running totals, never sent on a request.

type ObjContentsResult added in v0.30.38

type ObjContentsResult struct {
	Contents []string `json:"contents"`
}

ObjContentsResult is GET /obj/{kind}/{key}/contents's response.

type ObjDemoteRequest added in v0.30.38

type ObjDemoteRequest struct {
	Subject     string `json:"subject"`
	BalAccount  string `json:"bal_account"`
	FromAccount string `json:"from_account"`
	Amount      string `json:"amount"`
	Scale       *uint8 `json:"scale,omitempty"`
	Memo        string `json:"memo,omitempty"`
}

ObjDemoteRequest reverses a promotion -- removes obj capability from Subject ("kind:key" shorthand) together with a bal transfer back out, the same atomic pairing ObjPromoteRequest makes going in.

type ObjListResult added in v0.30.38

type ObjListResult struct {
	Subjects []ObjSubject `json:"subjects"`
}

ObjListResult is GET /obj/list's own response shape (XOT209, the enumeration endpoint this client method wraps).

type ObjMoveTarget added in v0.30.38

type ObjMoveTarget struct {
	Kind       string `json:"kind"`
	LocationID string `json:"location_id,omitempty"`
	Subject    string `json:"subject,omitempty"`
}

ObjMoveTarget is a move's own destination -- exactly one of the two shapes below, matching objMoveTargetJSON server-side precisely:

  • loc_leaf: Kind: "loc_leaf", LocationID: the leaf's own id.
  • obj (containment): Kind: "obj", Subject: the container's own "kind:key" shorthand (T-120).

type ObjPositionResolved added in v0.30.38

type ObjPositionResolved struct {
	Kind       string  `json:"kind"`
	LocationID *string `json:"location_id,omitempty"`
}

ObjPositionResolved is ObjPositionResult's own "resolved" field -- LocationID is set only when Kind is "loc_leaf".

type ObjPositionResult added in v0.30.38

type ObjPositionResult struct {
	Resolved ObjPositionResolved `json:"resolved"`
	Chain    []string            `json:"chain"`
	AsOf     string              `json:"as_of"`
}

ObjPositionResult is GET /obj/{kind}/{key}/position's response. Chain is the resolution path (e.g. subject -> container -> ... -> loc_leaf, for a containment chain); AsOf is always the literal string "live" today -- the server has no historical-position query yet, named here rather than typed as a real timestamp that would silently misrepresent that.

type ObjPromoteEntity added in v0.30.38

type ObjPromoteEntity struct {
	Kind        string                 `json:"kind"`
	ExistingKey *int                   `json:"existing_key,omitempty"`
	Create      map[string]interface{} `json:"create,omitempty"`
}

ObjPromoteEntity selects or creates the entity a promotion attaches obj capability to -- exactly one of ExistingKey or Create must be set, matching the server's own XOR validation (XOLU rejects both- or-neither with ErrObjEntitySelectionInvalid).

type ObjPromotePosition added in v0.30.38

type ObjPromotePosition struct {
	Kind    string `json:"kind"`
	Subject string `json:"subject"`
}

ObjPromotePosition is where the newly-promoted subject lands. Kind must be "obj" (containment into an already-attached subject) in this server release -- Subject is that container's own "kind:key" shorthand.

type ObjPromoteRequest added in v0.30.38

type ObjPromoteRequest struct {
	BalAccount string             `json:"bal_account"`
	ToAccount  string             `json:"to_account"`
	Amount     string             `json:"amount"`
	Scale      *uint8             `json:"scale,omitempty"`
	Memo       string             `json:"memo,omitempty"`
	Entity     ObjPromoteEntity   `json:"entity"`
	Position   ObjPromotePosition `json:"position"`
}

ObjPromoteRequest promotes an entity to obj capability as one atomic operation together with a bal transfer -- a real, dxp-orchestrated transaction, not two separate calls a caller sequences themselves. Amount is a decimal string (@B04, matching every other bal-touching request in this client), not a float.

type ObjPromoteResult added in v0.30.38

type ObjPromoteResult struct {
	Subject          string `json:"subject"`
	TxnID            int64  `json:"txn_id"`
	Status           string `json:"status"`
	CommittedThrough int    `json:"committed_through"`
	Reason           string `json:"reason"`
}

ObjPromoteResult is the shared response shape for both ObjPromote and ObjDemote -- verified identical server-side (both handlers write the same five fields). Status/CommittedThrough/Reason mirror the dxp dispatch outcome directly, not a client-invented summary.

type ObjSubject added in v0.30.38

type ObjSubject struct {
	Subject      string      `json:"subject"`
	Capacity     ObjCapacity `json:"capacity,omitempty"`
	PositionKind string      `json:"position_kind"`
	LocLeafID    *string     `json:"loc_leaf_id,omitempty"`
}

ObjSubject is the shape every obj read/write that returns a single subject uses -- attach, get, move, and capacity-patch all return this same shape server-side (subjectResponse).

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 TSAggregateRequest added in v0.30.38

type TSAggregateRequest struct {
	Timeline int64     `json:"timeline"`
	Dims     []uint64  `json:"dims"`
	From     time.Time `json:"from"`
	To       time.Time `json:"to"`
	NumField int       `json:"num_field"`
	Function string    `json:"function"`
	Interval string    `json:"interval,omitempty"`
}

TSAggregateRequest computes Function over NumField (0-6), optionally bucketed by Interval. Interval, when set, must be exactly one of "1m", "5m", "15m", "30m", "1h", "6h", "12h", "1d", "7d" -- checked directly against the server's own parseInterval, which recognizes only these nine literal strings, not an arbitrary Go duration. Leave Interval empty for a single scalar result over the whole range instead of buckets.

type TSAggregateResult added in v0.30.38

type TSAggregateResult struct {
	Timeline int64      `json:"timeline"`
	NumField int        `json:"num_field"`
	Function string     `json:"function"`
	Interval string     `json:"interval,omitempty"`
	Buckets  []TSBucket `json:"buckets,omitempty"`
	Value    *float64   `json:"value,omitempty"`
	Count    *uint64    `json:"count,omitempty"`
	From     *time.Time `json:"from,omitempty"`
	To       *time.Time `json:"to,omitempty"`
}

TSAggregateResult is exactly one of two shapes, determined by whether the request set Interval: Buckets is populated for a bucketed request (Value/Count/From/To all nil); Value/Count/From/To are populated for a scalar request (Buckets nil/empty). Never both.

type TSBatchAppendResult added in v0.30.38

type TSBatchAppendResult struct {
	Total    int `json:"total"`
	Accepted int `json:"accepted"`
	Failed   int `json:"failed"`
}

TSBatchAppendResult is TSBatchAppend's own response. Checked directly against pkg/timeseries's own AppendBatch, not assumed from the response shape's own apparent implication of partial success: every failure path there returns (0, err) before any event is written, and the only success path returns (len(events), nil) -- there is currently no code path producing Accepted < Total. This client does not assume that invariant holds forever (a future AppendBatch could genuinely support partial acceptance without this wire shape needing to change), so Failed/Accepted are still surfaced as returned rather than this client asserting Accepted == Total itself.

type TSBucket added in v0.30.38

type TSBucket struct {
	Time  time.Time `json:"time"`
	Value float64   `json:"value"`
	Count uint64    `json:"count"`
}

TSBucket is one time bucket in a TSAggregateResult's own Buckets.

type TSDefineTimelineRequest added in v0.30.38

type TSDefineTimelineRequest struct {
	ID            int64  `json:"id"`
	Name          string `json:"name,omitempty"`
	Dims          int    `json:"dims"`
	RetentionDays int    `json:"retention_days,omitempty"`
}

TSDefineTimelineRequest defines a new timeline. Dims is fixed for the timeline's own lifetime -- confirmed directly against HandleTSUpdateTimeline, which silently ignores this field if sent on an update (the store's own UpdateTimeline call never reads it), which is exactly why TSUpdateTimelineRequest below doesn't expose it at all rather than accept a value that would be quietly dropped.

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 TSFullAggregateRequest added in v0.30.38

type TSFullAggregateRequest struct {
	Timeline       int64     `json:"timeline"`
	Dims           []uint64  `json:"dims"`
	From           time.Time `json:"from"`
	To             time.Time `json:"to"`
	Quantiles      []float64 `json:"quantiles,omitempty"`       // e.g. [0.5, 0.9, 0.99]
	QuantileFields []uint8   `json:"quantile_fields,omitempty"` // nil = all fields
}

TSFullAggregateRequest combines TSRangeAggregate's own exact statistics with approximate quantile estimates in one pass. QuantileFields selects which numeric fields (0-6) get quantile estimates -- nil means all seven. An empty/nil Quantiles is equivalent to plain TSRangeAggregate at no extra cost (no quantile sketch allocated server-side).

type TSFullAggregateResult added in v0.30.38

type TSFullAggregateResult struct {
	Timeline  int64        `json:"timeline"`
	Count     uint64       `json:"count"`
	Fields    [7]bool      `json:"fields"`
	Sums      [7]float64   `json:"sums"`
	Avgs      [7]float64   `json:"avgs"`
	Mins      [7]float64   `json:"mins"`
	Maxs      [7]float64   `json:"maxs"`
	Quantiles [7][]float64 `json:"quantiles"`
}

TSFullAggregateResult is TSFullAggregate's own response. Fields/ Sums/Avgs/Mins/Maxs follow TSRangeAggregateResult's own seven- element convention exactly. Quantiles[i] is nil when field i had no events or wasn't in the request's own QuantileFields; otherwise the slice holds one estimate per entry in the request's own Quantiles, in the same order.

type TSLatestRequest added in v0.30.38

type TSLatestRequest struct {
	Timeline int64
	Dims     []uint64
	N        int
	From     time.Time
	To       time.Time
}

TSLatestRequest is TSLatest's own request -- N defaults to 10 server-side if 0. From/To are optional bounds, checked directly against the server's own "parse if present, ignore gracefully if absent" handling -- zero-value time.Time fields here are correctly treated as "no bound," not an error.

type TSPatchRetentionResult added in v0.30.38

type TSPatchRetentionResult struct {
	DefaultRetentionDays int    `json:"default_retention_days"`
	Status               string `json:"status"`
}

TSPatchRetentionResult is PATCH /retention's own response.

type TSProvisionResult added in v0.30.38

type TSProvisionResult struct {
	TenantID   string `json:"tenant_id"`
	Timeseries string `json:"timeseries"`
}

TSProvisionResult is POST /provision's own response -- a one-time per-tenant setup call. Timeseries is always the literal string "enabled" on success.

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 TSRangeAggregateRequest added in v0.30.38

type TSRangeAggregateRequest struct {
	Timeline int64     `json:"timeline"`
	Dims     []uint64  `json:"dims"`
	From     time.Time `json:"from"`
	To       time.Time `json:"to"`
}

TSRangeAggregateRequest computes count/sum/avg/min/max for all seven numeric fields in one pass -- more efficient than several TSAggregate calls when multiple fields are needed. Does not support time bucketing; use TSAggregate for that.

type TSRangeAggregateResult added in v0.30.38

type TSRangeAggregateResult struct {
	Timeline int64      `json:"timeline"`
	Count    uint64     `json:"count"`
	Fields   [7]bool    `json:"fields"`
	Sums     [7]float64 `json:"sums"`
	Avgs     [7]float64 `json:"avgs"`
	Mins     [7]float64 `json:"mins"`
	Maxs     [7]float64 `json:"maxs"`
}

TSRangeAggregateResult is TSRangeAggregate's own response. Fields[i] is true iff numeric field i had at least one event in range; Sums/ Avgs/Mins/Maxs[i] are meaningless (typically 0) when Fields[i] is false, matching the server's own convention exactly rather than this client inventing a different sentinel.

type TSRetentionResult added in v0.30.38

type TSRetentionResult struct {
	DefaultRetentionDays int                   `json:"default_retention_days"`
	Timelines            []TSTimelineRetention `json:"timelines"`
}

TSRetentionResult is GET /retention's own response -- the tenant's own store-level default plus every timeline's own current setting. Per-timeline retention is set via TSUpdateTimeline, not here.

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 TSRollupDefineRequest added in v0.30.38

type TSRollupDefineRequest struct {
	DestTID        int64  `json:"dest_tid"`
	BucketDuration string `json:"bucket_duration"`
	LateWindow     string `json:"late_window,omitempty"`
}

TSRollupDefineRequest defines a rollup on a source timeline. BucketDuration and LateWindow are Go duration strings (e.g. "5m"), not time.Duration -- matching the server's own wire shape exactly, which parses them with time.ParseDuration.

type TSRollupRunRequest added in v0.30.38

type TSRollupRunRequest struct {
	From    time.Time
	To      time.Time
	Cascade bool
}

TSRollupRunRequest manually triggers a rollup for a bounded range. From/To are optional -- zero-value time.Time means "no bound," the server's own default. Cascade, when true, also runs every descendant rollup definition for the corresponding time windows.

type TSRollupStatusReport added in v0.30.38

type TSRollupStatusReport struct {
	ID            string    `json:"id"`
	SourceTID     int64     `json:"source_tid"`
	DestTID       int64     `json:"dest_tid"`
	LastRunAt     time.Time `json:"last_run_at,omitempty"`
	LastBucketEnd time.Time `json:"last_bucket_end,omitempty"`
	EventsWritten int64     `json:"events_written"`
	LastError     string    `json:"last_error,omitempty"`
	Running       bool      `json:"running"`
}

TSRollupStatusReport is a rollup worker's own operational status.

type TSRollupTreeNode added in v0.30.38

type TSRollupTreeNode struct {
	TID      int64               `json:"tid"`
	Def      *TSRollup           `json:"def,omitempty"`
	Children []*TSRollupTreeNode `json:"children,omitempty"`
}

TSRollupTreeNode is one node in the tenant-wide rollup tree (GET /rollup/tree) -- Def is nil for a timeline with no rollup definition of its own; Children is nil/empty for a leaf.

type TSStatsResult added in v0.30.38

type TSStatsResult struct {
	TenantID  string `json:"tenant_id"`
	Timelines int    `json:"timelines"`
	DiskBytes int64  `json:"disk_bytes"`
}

TSStatsResult is GET /stats's own response -- store-level diagnostics for the whole tenant.

type TSSyncStatus added in v0.30.38

type TSSyncStatus struct {
	TimelineID int64 `json:"timeline_id"`
	NoSync     bool  `json:"nosync"`
}

TSSyncStatus is the shape every sync read/write returns. NoSync governs WAL fsync durability, not data replication or mirroring despite the name's own first impression: NoSync=false (the default, "sync on") waits for fsync before an append returns -- crash-durable, slower. NoSync=true ("sync off") returns immediately without waiting -- faster, but a crash before the kernel's own dirty-page writeback (typically under a second) can lose the most recent writes.

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 TSTimelineRetention added in v0.30.38

type TSTimelineRetention struct {
	ID            int64  `json:"id"`
	Name          string `json:"name,omitempty"`
	RetentionDays int    `json:"retention_days"`
}

TSTimelineRetention is one entry in TSRetentionResult's own Timelines.

type TSTimelineStatsResult added in v0.30.38

type TSTimelineStatsResult struct {
	TimelineID             int64      `json:"timeline_id"`
	Name                   string     `json:"name,omitempty"`
	TotalEvents            int64      `json:"total_events"`
	TotalEventsApproximate bool       `json:"total_events_approximate"`
	OldestEvent            *time.Time `json:"oldest_event,omitempty"`
	NewestEvent            *time.Time `json:"newest_event,omitempty"`
}

TSTimelineStatsResult is GET /stats/{timeline_id}'s own response. TotalEventsApproximate, when true, means TotalEvents is an estimate, not an exact count -- matching the server's own documented trade-off for a store that doesn't track exact counts cheaply. OldestEvent/NewestEvent are nil for a timeline with no events at all.

type TSUpdateTimelineRequest added in v0.30.38

type TSUpdateTimelineRequest struct {
	Name          string `json:"name,omitempty"`
	RetentionDays int    `json:"retention_days,omitempty"`
}

TSUpdateTimelineRequest updates a timeline's own mutable fields -- Name and RetentionDays only. Dims is deliberately not a field here at all (see TSDefineTimelineRequest's own doc comment for why).

type TenantSummary added in v0.30.38

type TenantSummary struct {
	Primary   map[string]int `json:"primary"`
	Loc       map[string]int `json:"loc"`
	Obj       map[string]int `json:"obj"`
	TS        int            `json:"ts"`
	CalIndex  int            `json:"cal_index"`
	BalRollup int            `json:"bal_rollup"`
	// Blob is the tenant's own uploaded blob key count (XOT216) --
	// always 0 when blob is disabled server-wide, matching every
	// other per-store field's own "never used this primitive"
	// treatment, not a sentinel meaning "unknown."
	Blob  int  `json:"blob"`
	Empty bool `json:"empty"`
}

TenantSummary is GET /tenant-summary's own response -- a single-round-trip data-presence check across every store a tenant's own data can live in, derived server-side from the same authoritative table lists pkg/tenantexport's own backup path uses (not a second, independently-maintained notion of what counts). Primary/Loc/Obj are keyed by the underlying table's own name; TS/ CalIndex/BalRollup are key counts in the three per-tenant Pebble stores. Empty is computed server-side once and included directly, rather than left for every caller to re-derive the same "are all of these maps and ints zero" check independently.

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