api

package
v0.2.3 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Index

Constants

View Source
const (
	LinkKindMention  = "mention"
	LinkKindLink     = "link"
	LinkKindCard     = "card"
	LinkKindEmbed    = "embed"
	LinkKindRelation = "relation"
)

Link kinds — the established vocabulary.

View Source
const (
	ErrBlockNotFound    = "blocks.not_found"
	ErrBlockTypeMissing = "blocks.type_required"
	ErrBlockRejected    = "blocks.rejected"
)

Error code namespace for block endpoints.

View Source
const (
	// ErrBundleNotFound — no live record for the bundle id.
	ErrBundleNotFound = "bundle.not_found"
	// ErrBundleNotReady — the winning root's tree has not reached this
	// device yet, so its id is not writable. Retryable.
	ErrBundleNotReady = "bundle.not_ready"
	// ErrBundleNotLoser — the resolve target is the current winner, or
	// was never claimed for this bundle.
	ErrBundleNotLoser = "bundle.not_loser"
	// ErrBundleLoserNotReady — the losing root is still syncing or
	// still inside the quiescence window, so what is stored locally is
	// not yet the whole of it. Retryable.
	ErrBundleLoserNotReady = "bundle.loser_not_ready"
	// ErrBundleReserved — the id is under the server's `system:` prefix;
	// only the server's own catalog installs there.
	ErrBundleReserved = "bundle.reserved"
	// ErrDatasetModuleReserved — a part or dataset draft names a module
	// reserved to the server's own installs.
	ErrDatasetModuleReserved = "dataset.module_reserved"
)

Bundles-registry error codes.

View Source
const (
	ErrChatTextRequired       = "chat.text_required"
	ErrChatTextTooLong        = "chat.text_too_long"
	ErrChatReplyIdInvalid     = "chat.reply_id_invalid"
	ErrChatAgentInvalid       = "chat.agent_invalid"
	ErrChatEmojiInvalid       = "chat.emoji_invalid"
	ErrChatUnknownField       = "chat.unknown_field"
	ErrChatNotAuthor          = "chat.not_author"
	ErrChatNotFound           = "chat.not_found"
	ErrChatRejected           = "chat.rejected"
	ErrChatAttachmentsInvalid = "chat.attachments_invalid"
	ErrChatContextInvalid     = "chat.context_invalid"
	ErrChatControlInvalid     = "chat.control_invalid"
)

Error code namespace for chat endpoints.

View Source
const (
	// EventScopeDevice — this process only: delivered to local
	// subscribers, never leaves the machine.
	EventScopeDevice = "device"
	// EventScopeAccount — every device of this account.
	EventScopeAccount = "account"
	// EventScopeSpace — every member of the space named by SpaceId.
	EventScopeSpace = "space"
)

Event Scope values — a closed set.

View Source
const (
	EventUIOpenSpace  = "ui.open_space"
	EventUIOpenObject = "ui.open_object"
)

UI event types — the device-scope vocabulary UI windows subscribe to for navigation. Data carries {spaceId, objectId?, source?}: spaceId is the *target* space to open (independent of the envelope's scope routing), objectId is required for EventUIOpenObject, source is a free-form publisher hint (UI display only). An open set — new UI operations add a new type with no server change; unknown types are ignored client-side.

View Source
const (
	// FileStateDurable — verified network receipt recorded (or inline).
	FileStateDurable = "durable"
	// FileStateInFlight — registered, backup not confirmed yet.
	FileStateInFlight = "inflight"
	// FileStateLimited — the network refused backup (storage limit);
	// retried on a slow cadence and on POST .../retry.
	FileStateLimited = "limited"
)

File durability states — FileStatus.State.

View Source
const (
	// ErrFileNotFound — unknown fileId, unknown objectId on attach, or
	// a files query against an object with no files attached yet.
	ErrFileNotFound = "file.not_found"
	// ErrFileNotDurable — offload refused: the local bytes are the only
	// copy (file not backed up yet). 409.
	ErrFileNotDurable = "file.not_durable"
	// ErrFileNotAvailable — content download refused: the bytes are not
	// local and cannot be fetched yet (file not durable, or the network
	// advertises no public read base). Retryable resource state — for a
	// freshly synced row, retry once the row shows networkSign (the
	// files/query/subscribe update event). 409.
	ErrFileNotAvailable = "file.not_available"
	// ErrFileVariantInvalid — variant/variantOf pairing broken, or the
	// variant original lives on a different object. 400.
	ErrFileVariantInvalid = "file.variant_invalid"
)

Error code namespace for file endpoints.

View Source
const (
	ErrMarkdownNoMatch   = "markdown.no_match"          // 400 — oldText not found in the current rendering
	ErrMarkdownAmbiguous = "markdown.ambiguous_match"   // 400 — >1 occurrences without replaceAll
	ErrMarkdownOverlap   = "markdown.overlapping_edits" // 400 — two edits matched intersecting text
)

Error code namespace for the markdown edit endpoint.

View Source
const (
	MemberStatusUnknown  = "unknown"
	MemberStatusJoining  = "joining"
	MemberStatusActive   = "active"
	MemberStatusRemoved  = "removed"
	MemberStatusDeclined = "declined"
	MemberStatusRemoving = "removing"
	MemberStatusCanceled = "canceled"
)

Member status string values. Mirror space.MemberStatus 1:1.

View Source
const (
	MemberEventKindAdded   = "added"
	MemberEventKindChanged = "changed"
	MemberEventKindRemoved = "removed"
)

Member event kinds — wire values for MemberEvent.Kind.

View Source
const (
	ProcessStateRunning   = "running"
	ProcessStateDone      = "done"
	ProcessStateFailed    = "failed"
	ProcessStateCancelled = "cancelled"
)

Process State values — a closed set. Only running processes are heartbeat-kept; terminal states linger briefly in the view and then expire.

View Source
const (
	EventProcessStarted   = "process.started"
	EventProcessProgress  = "process.progress"
	EventProcessDone      = "process.done"
	EventProcessFailed    = "process.failed"
	EventProcessCancelled = "process.cancelled"
	EventProcessCancel    = "process.cancel"
)

Process event types — the `process.*` corner of the event bus vocabulary the helper endpoints emit (envelope target = process id). EventProcessCancel is a directive addressed at the owner, not a state change: the owner reacts and emits the terminal event.

View Source
const (
	PushPlatformIOS     = "ios"
	PushPlatformAndroid = "android"
)

Push platform wire values (mirror space.PushPlatform).

View Source
const (
	SearchModeHybrid = "hybrid"
	SearchModeFTS    = "fts"
	SearchModeVector = "vector"
)

Search modes. Hybrid runs both legs and fuses by reciprocal rank; fts / vector run one leg only.

View Source
const (
	// VectorStatusUsed: the vector leg ran and contributed to ranking.
	VectorStatusUsed = "used"
	// VectorStatusUnavailable: an embedder is configured but did not
	// answer for this query — unreachable, or not within the query
	// budget — retry later may differ. Hybrid degraded to FTS;
	// mode=vector would have returned 503.
	VectorStatusUnavailable = "unavailable"
	// VectorStatusDisabled: no embedder is configured on this server —
	// vector search can never run until config changes.
	VectorStatusDisabled = "disabled"
	// VectorStatusSkipped: vector was not attempted although available
	// on this server — the caller asked for mode=fts, or the Filter
	// matched no object so no leg ran.
	VectorStatusSkipped = "skipped"
)

VectorStatus values — the search response tells the consumer (often an agent deciding how much to trust recall) what happened to the vector leg, not just that it silently fell back to lexical search.

View Source
const (
	SpaceStatusUnknown    = "unknown"
	SpaceStatusActive     = "active"
	SpaceStatusJoining    = "joining"
	SpaceStatusLeaving    = "leaving"
	SpaceStatusDeleted    = "deleted"
	SpaceStatusRemoteDead = "remote_dead"
	// SpaceStatusOneToOnePending is an incoming 1-1 (direct) space
	// awaiting local approval — not yet materialized or synced. Discover
	// these via GET /v1/spaces?status=one_to_one_pending (hidden from the
	// active-only default list), then accept/decline. Device-local.
	SpaceStatusOneToOnePending = "one_to_one_pending"
	// SpaceStatusOneToOneDeclined is a 1-1 the user declined — a synced,
	// account-wide sticky marker. Hidden from the default list like
	// deleted; an explicit POST /v1/spaces/one-to-one overrides it.
	SpaceStatusOneToOneDeclined = "one_to_one_declined"
	// SpaceStatusInvitePending is a regular space another account added
	// this account to directly (ACL add by identity). Already a full
	// member; approval is a local gate — nothing is downloaded until
	// accepted. Synced account-wide. Discover via
	// GET /v1/spaces?status=invite_pending, then
	// POST /v1/spaces/:spaceId/invite/accept or .../invite/decline.
	SpaceStatusInvitePending = "invite_pending"
	// SpaceStatusInviteDeclined is a direct-add invite the user declined
	// — synced, sticky, non-terminal (accept overrides). Hidden from the
	// default list like deleted.
	SpaceStatusInviteDeclined = "invite_declined"
	// SpaceStatusGuestRevoked is a guest-key (public-access) space whose
	// shared guest identity was removed from the ACL — the owner revoked
	// public access. The local copy stays readable; new content no longer
	// arrives. Remove with DELETE /v1/spaces/:spaceId.
	SpaceStatusGuestRevoked = "guest_revoked"
)

Space status string values exposed on the wire. Mirror the space.Status enum 1:1.

View Source
const (
	SpacePermissionNone   = "none"
	SpacePermissionReader = "reader"
	SpacePermissionGuest  = "guest"
	SpacePermissionWriter = "writer"
	SpacePermissionAdmin  = "admin"
	SpacePermissionOwner  = "owner"
)

Space permission string values for SpaceInfo.OwnRole. Mirror the space.Permission enum 1:1. Pre-staged for the ACL/Members endpoints that still return 501.

View Source
const (
	// SubscribeClosedServerShutdown — the server is exiting (signal or
	// POST /v1/shutdown). Reconnect when the server is back up.
	SubscribeClosedServerShutdown = "server_shutdown"

	// SubscribeClosedDeauthorized — the account behind the stream was
	// torn down in place (DELETE /v1/auth, or a POST /v1/auth switch to
	// another account) while the server stays up. Re-read GET /v1/auth
	// before resubscribing: the server is unauthorized or serving a
	// different account.
	SubscribeClosedDeauthorized = "deauthorized"

	// SubscribeClosedSDKClosed — the SDK released the underlying
	// subscription channel (typically because the space or SDK closed).
	// Reconnect after re-resolving the space.
	SubscribeClosedSDKClosed = "sdk_closed"

	// SubscribeClosedOverflow — only on query/subscribe streams. The
	// per-sub mailbox filled before the consumer could drain it; the
	// SDK closes the subscription rather than dropping events. Recovery
	// is resubscribe (which re-Snapshots).
	SubscribeClosedOverflow = "overflow"

	// SubscribeClosedDrifted — only on query/subscribe streams. More
	// than DriftBudgetPercent of the held window left without
	// replacements; the SDK closes the subscription rather than
	// re-Query the database on the hot path. Recovery is resubscribe.
	SubscribeClosedDrifted = "drifted"
)

Reason values for SubscribeClosed. Stable strings; clients should switch on these rather than message text. Shared across every SSE family — query/subscribe, sync-status/subscribe, members/subscribe.

View Source
const (
	MutableNever    = "never"
	MutableByAuthor = "author"
	MutableByAnyone = "any"

	StampCreator    = "creator"
	StampCreateTime = "createTime"
	StampModifyTime = "modifyTime"

	IdRuleAuto = "auto"
	IdRuleUser = "user"

	DeleteByAnyone = "anyone"
	DeleteByAuthor = "author"
)

Wire labels for the dataset-schema behavioral vocabulary. Mirror the SDK enums 1:1 (space.Mutability / Stamp / IdRule / DeletePolicy).

View Source
const (
	ModuleRecords = "records"
	ModuleEditor  = "editor"
	ModuleChat    = "chat"
)

Module slugs a dataset declaration may name. `records` is the SDK's built-in generic module (a schema-enforced dataset the declaration fully describes); `editor` and `chat` are this server's compiled-in modules — the module owns their schema, so a declaration carries no fields.

View Source
const (
	CollectionEditorBlocks = "editor_blocks"
	CollectionChatMessages = "chat_messages"
)

Canonical collections of the compiled-in modules — what a shared dataset of the module is, and the default the editor CLI writes.

View Source
const (
	PropertyKindString  = "string"
	PropertyKindNumber  = "number"
	PropertyKindBoolean = "boolean"
	PropertyKindNull    = "null"
	PropertyKindArray   = "array"
	PropertyKindObject  = "object"
	// PropertyKindDatetime is an instant: `{"$date": "<RFC 3339>"}` on
	// the wire in both directions (writes also accept
	// `{"$date": <unix millis>}`). The kind the `date` / `datetime`
	// formats imply — see docs/03-api.md § Types.
	PropertyKindDatetime = "datetime"
)

PropertyKind* are the wire-string forms of space.PropertyKind. Mirror the SDK enum 1:1; expand when the SDK adds new kinds.

View Source
const ControlTokenHeader = "X-Any-Control-Token"

ControlTokenHeader carries the managed-mode control token. A managed server accepts POST/DELETE /v1/auth and POST /v1/shutdown only with the token its spawning host holds; a standalone server refuses those operations regardless (docs/03-api.md § Auth).

View Source
const DefaultSearchMaxData = 512

DefaultSearchMaxData is the Data window applied when a request leaves MaxData unset: enough for a one-line preview or an agent to judge the match, and a bounded reply whatever the record size — the full record stays one dataset query away.

View Source
const (
	// ErrCatalogNotFound — no usecase with that id in the catalog.
	ErrCatalogNotFound = "catalog.not_found"
)

Catalog error codes.

View Source
const EventLinksUpdated = "links.updated"

EventLinksUpdated is the device-scope event the link index publishes after a page changed edges: data is EventLinksUpdatedData.

View Source
const MaxEventLinksTargets = 200

MaxEventLinksTargets caps EventLinksUpdatedData.Targets.

View Source
const MaxSearchPassages = 10

MaxSearchPassages caps SearchRequest.Passages.

View Source
const MetaKeyMaxBytes = 64

MetaKeyMaxBytes bounds a meta key on a type or a collection.

Variables

This section is empty.

Functions

func CheckMetaEntry added in v0.2.2

func CheckMetaEntry(key string, v any, nilOK bool) string

CheckMetaEntry validates one entry of a definition's meta bag: a single-level key (no '.', no '$', at most MetaKeyMaxBytes) and a scalar value — string, bool or number. nilOK admits a nil value, the clear on PATCH. Returns "" when the entry is fine, otherwise the reason, worded for the caller's error message.

Types

type ACLAcceptRequest

type ACLAcceptRequest struct {
	RequestRecordId string `json:"requestRecordId"`
	Permission      string `json:"permission"`
}

ACLAcceptRequest is the body of POST /v1/spaces/:spaceId/acl/accept. `permission` is granted on accept; valid values are the SpacePermission* constants minus SpacePermissionOwner.

type ACLAddAccount

type ACLAddAccount struct {
	Identity   string          `json:"identity"`
	Permission string          `json:"permission"`
	Metadata   AccountMetadata `json:"metadata,omitempty"`
}

ACLAddAccount is one entry in an AddAccounts batch.

type ACLAddRequest

type ACLAddRequest struct {
	Accounts []ACLAddAccount `json:"accounts"`
}

ACLAddRequest is the body of POST /v1/spaces/:spaceId/acl/add.

type ACLChangePermissionsRequest

type ACLChangePermissionsRequest struct {
	Changes []ACLPermissionChange `json:"changes"`
}

ACLChangePermissionsRequest is the body of POST /v1/spaces/:spaceId/acl/permissions.

type ACLDeclineRequest

type ACLDeclineRequest struct {
	Identity string `json:"identity"`
}

ACLDeclineRequest is the body of POST /v1/spaces/:spaceId/acl/decline.

type ACLOwnershipRequest

type ACLOwnershipRequest struct {
	NewOwner     string `json:"newOwner"`
	OldOwnerPerm string `json:"oldOwnerPerm"`
}

ACLOwnershipRequest is the body of POST /v1/spaces/:spaceId/acl/ownership.

type ACLPermissionChange

type ACLPermissionChange struct {
	Identity   string `json:"identity"`
	Permission string `json:"permission"`
}

ACLPermissionChange is one entry in a ChangePermissions batch.

type ACLRemoveRequest

type ACLRemoveRequest struct {
	Identities []string `json:"identities"`
}

ACLRemoveRequest is the body of POST /v1/spaces/:spaceId/acl/remove.

type APIError

type APIError struct {
	Code    string         `json:"code"`
	Message string         `json:"message"`
	Details map[string]any `json:"details,omitempty"`
}

type AccessCodeRequest

type AccessCodeRequest struct {
	// Code is the invite code as typed; compared upper-cased with
	// whitespace removed.
	Code string `json:"code"`
}

AccessCodeRequest is the body of POST /v1/account/access-code.

type AccessCodeResponse

type AccessCodeResponse struct {
	// Status is "accepted" (limits are being granted) or
	// "already_redeemed" (this account redeemed a code before).
	Status       string `json:"status" enums:"accepted,already_redeemed"`
	RedemptionId string `json:"redemptionId,omitempty"`
}

AccessCodeResponse relays the invite service's answer.

type AccountDiscoveryStatus added in v0.2.3

type AccountDiscoveryStatus struct {
	Enabled bool `json:"enabled"`
	// Relays are the configured pkarr relays, as hosts.
	Relays []string `json:"relays"`
	// Devices is how many sibling devices the record names.
	Devices int `json:"devices"`
	// OwnEntry — the record names this device with its current relay.
	OwnEntry      bool       `json:"ownEntry"`
	LastResolved  *time.Time `json:"lastResolved,omitempty"`
	LastPublished *time.Time `json:"lastPublished,omitempty"`
	// LastError is the last failed cycle; empty after a good one.
	LastError string `json:"lastError,omitempty"`
	// ClockAheadMs is how far the relays' record was dated past this
	// device's clock — a sibling whose clock runs ahead. Zero when it
	// was not.
	ClockAheadMs int64 `json:"clockAheadMs,omitempty"`
}

AccountDiscoveryStatus is the pkarr record through which this account's own devices find each other — including a device that holds nothing but the mnemonic. Disabled when no pkarr relay is configured; devices then know each other only through the records of the spaces they share.

type AccountMetadata

type AccountMetadata struct {
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	IconCID     string `json:"iconCid,omitempty"`
}

AccountMetadata mirrors space.AccountMetadata.

type AccountResponse

type AccountResponse struct {
	Id       string           `json:"id"`
	Metadata *AccountMetadata `json:"metadata,omitempty"`
	// TechSpaceId is the account's tech space — the :spaceId for
	// account-level bundles (see docs/03-api.md § Bundles).
	TechSpaceId string `json:"techSpaceId"`
}

AccountResponse is the body of GET /v1/account. Metadata is the locally-stored profile (read from tech-space); omitted when no profile has ever been written on this device. Symmetric with the PUT /v1/account/metadata write path — readback is deterministic, no coordinator round-trip, no 60-second watcher tick.

type AddDatasetFieldResponse

type AddDatasetFieldResponse struct {
	FieldDefId string `json:"fieldDefId"`
}

AddDatasetFieldResponse is the body returned by POST …/datasets/:defId/fields.

type AddDatasetResponse

type AddDatasetResponse struct {
	DatasetDefId string `json:"datasetDefId"`
	// Collection is the computed collection name the new dataset's
	// records live in.
	Collection string `json:"collection"`
}

AddDatasetResponse is the body returned by POST …/parts/:partId/datasets.

type AddPartResponse

type AddPartResponse struct {
	PartId string `json:"partId"`
}

AddPartResponse is the body returned by POST …/types/:typeId/parts.

type AddPropertyRequest

type AddPropertyRequest struct {
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	// XKey is the property's handle — an alias, not a storage key
	// (values live under the content-addressed propId). Unique within
	// the type (409 property.xkey_conflict); mutable via PATCH.
	XKey string `json:"xKey,omitempty"`
	Kind string `json:"kind"`
	// Meta holds the consumer flags the server interprets — today only
	// meta["index"] = "<scope>" | "none" for the search indexer
	// (docs/13-index.md). Any other key is rejected; descriptive
	// metadata lives under xFormat.
	Meta map[string]string `json:"meta,omitempty"`
	// XFormat is the property's descriptor: everything descriptive
	// beyond the kind — the semantic slug, icon, ordering key, option
	// set, relation targets, per-format config (docs/27-descriptors.md).
	// An object; the server validates the keys it interprets (type,
	// icon, pos, options, relation, config, links) against the vocabulary and
	// the slug against kind, stores vendor-namespaced keys verbatim,
	// and reserves validate / compute. Every path under it is mutable
	// via PATCH.
	XFormat json.RawMessage `json:"xFormat,omitempty"`
	// Scope is the property's write/sync class: "synced" (default,
	// everyone in the space), "account" (this account's devices only),
	// or "local" (this device only, never synced). "derived" is
	// reserved for built-ins and rejected. Pinned by the first write,
	// like kind — changing a property's scope means defining a new
	// property. Property VALUE writes auto-route by the declared scope
	// (POST /v1/spaces/:spaceId/properties/:objectId/set/:typeId).
	Scope string `json:"scope,omitempty"`
}

AddPropertyRequest is the body of POST /v1/spaces/:spaceId/types/:typeId/properties. Kind is the wire string from PropertyKind* below and is required — nothing is defaulted from the descriptor. Items / Properties / Required from space.PropertyDraft are not exposed in v1.

type AddPropertyResponse

type AddPropertyResponse struct {
	PropId string `json:"propId"`
}

AddPropertyResponse is the body returned by AddProperty.

type AggregateResponse

type AggregateResponse struct {
	Records []json.RawMessage `json:"records,omitzero"`
	Plan    *string           `json:"plan,omitempty"`
}

AggregateResponse is the body of POST /v1/spaces/:spaceId/aggregate and POST /v1/spaces/:spaceId/objects/aggregate — both use Agg.All (or Agg.Explain with explain=true) under the hood.

Records are pipeline RESULT documents, not dataset rows: a $group doc carries the group key as `id` (never `_id`), a $count doc is `{<name>: N}` with no id at all. Rendered the same way as QueryResponse records (anyenc → FastJson → RawMessage).

Plan replaces Records when the request set explain=true. It is the pushed prefix's access plan plus the in-pipeline stage list — diagnostic only, NOT a stable format; don't parse it. Records uses omitzero, not omitempty: the result path always sends a non-nil slice (so an empty result is `"records": []`, matching QueryResponse), while the explain path leaves it nil and the field disappears entirely.

type AuthAccount

type AuthAccount struct {
	// Id is the StrKey account address ("A…"). Empty for a default
	// root wallet whose id can't be derived without a passkey.
	Id string `json:"id,omitempty"`
	// Default marks the legacy flat-layout wallet at the data-dir root.
	Default bool `json:"default,omitempty"`
}

AuthAccount is one locally-available account in AuthStatusResponse.

type AuthCapabilities

type AuthCapabilities struct {
	// Deauthorize: DELETE /v1/auth tears the account down in place.
	Deauthorize bool `json:"deauthorize"`
	// SwitchAccount: POST /v1/auth with replace:true switches accounts
	// in place.
	SwitchAccount bool `json:"switchAccount"`
	// Shutdown: POST /v1/shutdown stops the server.
	Shutdown bool `json:"shutdown"`
}

AuthCapabilities are the lifecycle operations this server accepts. Clients branch on these bits, never on the mode string, so a future mode does not break them.

type AuthRequest

type AuthRequest struct {
	// Mnemonic restores (or first-creates) the account derived from
	// this BIP-39 phrase.
	Mnemonic string `json:"mnemonic,omitempty"`
	// AccountId selects an account that already has a local wallet
	// (standalone only).
	AccountId string `json:"accountId,omitempty"`
	// Index is the account derivation index for Mnemonic. Omitted
	// means 1, the `any` default; pass 0 explicitly to restore an
	// anytype-derived (or pre-index-1 any) account.
	Index *uint32 `json:"index,omitempty"`
	// Replace switches a managed server from its current account to
	// the one this request names, tearing the current engine down
	// first. Without it a different account is refused. Never implied.
	Replace bool `json:"replace,omitempty"`
}

AuthRequest is the POST /v1/auth body. Mnemonic and AccountId are mutually exclusive; with neither set a fresh account is generated.

type AuthResponse

type AuthResponse struct {
	AccountId string `json:"accountId"`
	// Created is true when this account had no local state before this
	// call (fresh generation or first restore on this device).
	Created bool `json:"created"`
	// Mnemonic is returned exactly once: when the server generated a
	// fresh account (no mnemonic/accountId in the request). The caller
	// must surface it to the user for backup.
	Mnemonic string `json:"mnemonic,omitempty"`
	// AlreadyAuthorized reports that the request named the account the
	// server already runs: nothing was booted. With a mnemonic this
	// confirms the phrase derives to the running account; with an
	// accountId it confirms only that the id matches.
	AlreadyAuthorized bool `json:"alreadyAuthorized,omitempty"`
}

AuthResponse is the POST /v1/auth reply.

type AuthStatusResponse

type AuthStatusResponse struct {
	Authorized bool   `json:"authorized"`
	AccountId  string `json:"accountId,omitempty"`
	// Mode is the server's ownership mode, fixed at launch.
	Mode string `json:"mode" enums:"standalone,managed"`
	// Capabilities lists which lifecycle operations this server
	// accepts; every bit is false on a standalone server.
	Capabilities AuthCapabilities `json:"capabilities"`
	// Accounts are the wallets on disk (standalone only — a managed
	// server holds no keys and reports an empty list; the client owns
	// the account list there).
	Accounts []AuthAccount `json:"accounts"`
}

AuthStatusResponse is the GET /v1/auth reply.

type BacklinksAllResponse

type BacklinksAllResponse struct {
	Spaces []SpaceBacklinks `json:"spaces"`
}

BacklinksAllResponse is the body of GET /v1/backlinks?target=… — the edges pointing at one target from every space this device indexes. Spaces without an edge are omitted; never null.

type BacklinksResponse

type BacklinksResponse struct {
	Object []Link `json:"object"`
	Parts  []Link `json:"parts"`
	// Truncated reports that the read hit its cap (`limit`, max 500)
	// before the split into Object / Parts; there is no continuation.
	Truncated bool `json:"truncated,omitempty"`
}

BacklinksResponse is the body of GET /v1/spaces/:spaceId/objects/:objectId/backlinks. Object holds the edges pointing at the object itself; Parts the edges pointing at one of its records or property values (a block link stays a block link — the parent is not counted twice). When the read is narrowed to one part (`?record=` / `?prop=`), Object holds the edges to that part and Parts is empty. Neither is ever null.

type BlockCreateRequest

type BlockCreateRequest struct {
	Type  string         `json:"type"`
	Style map[string]any `json:"style,omitempty"`
	Text  string         `json:"text,omitempty"`
	Nav   *BlockNav      `json:"nav,omitempty"`
}

BlockCreateRequest is the body of POST .../blocks. `type` is required; everything else is optional with safe defaults.

If `nav.pos` is empty the server allocates the next lexid after the current max for `nav.parentId`. If `nav.parentId` is omitted the new block is top-level.

type BlockNav

type BlockNav struct {
	ParentId string `json:"parentId"`
	Pos      string `json:"pos"`
}

BlockNav is the per-record sibling-ordering namespace. parentId references another block's id; pos is a lexid that sorts siblings.

type BlockPatchRequest

type BlockPatchRequest struct {
	Set   map[string]json.RawMessage `json:"set,omitempty" swaggertype:"object"`
	Unset []string                   `json:"unset,omitempty"`
}

BlockPatchRequest is the body of PATCH .../blocks/:blockId.

  • `set` maps a dotted field path to its new JSON value. Each entry becomes one $set op against that path. Empty/omitted == no $set ops.
  • `unset` is a list of dotted field paths to $unset. Empty/omitted == no $unset ops.

Both lists may be supplied together; the handler emits them as one atomic record-modify (single DAG change). Empty patch is a no-op that still returns the record's current _ver.

type Bundle

type Bundle struct {
	// Id is the stable bundle identifier — the record id. Permanent:
	// a successor install takes a new id (record deletes are refused,
	// so a reused id could never be reclaimed).
	Id string `json:"id"`
	// Name is the display name, stamped as `any.name` on the root by
	// whichever device installed it.
	Name string `json:"name,omitempty"`
	// RootId is the winning root object id. Setup objects are derived
	// from it, so this one id names the whole install. Provisional
	// until the space syncs.
	RootId string `json:"rootId"`
	// Roots is every root ever claimed for this bundle — the add-only
	// audit trail. A resolved loser stays listed; its death is
	// recorded by the deletion of its tree.
	Roots []string `json:"roots,omitempty"`
	// Losers is the live conflict set: claimed roots that are neither
	// the winner nor already deleted. Non-empty means two devices
	// installed concurrently — merge what matters out of each, then
	// resolve it.
	Losers []string `json:"losers,omitempty"`
	// Derived reports that the winner is the root derived from the
	// bundle id: the same id on every device, so this install cannot
	// fork — and cannot be uninstalled, a derived object being
	// undeletable. Absent means an ordinary created root.
	Derived bool `json:"derived,omitempty"`
}

Bundle is one row of a space's bundles registry.

type BundleChildRequest

type BundleChildRequest struct {
	// Seed derives the child deterministically under the bundle's
	// current winner. Permanent — a successor object takes a new seed.
	Seed string `json:"seed"`
	// Type is the child's one type, set on first materialization —
	// required (400 request.missing_field), `page` for a plain
	// document; Collections the child lacks are added on every call.
	Type        string   `json:"type"`
	Collections []string `json:"collections,omitempty"`
}

BundleChildRequest is the body of POST /v1/spaces/:spaceId/bundles/:bundleId/children.

type BundleChildResponse

type BundleChildResponse struct {
	ObjectId string `json:"objectId"`
}

BundleChildResponse carries the derived child's object id.

type BundleEnsureRequest

type BundleEnsureRequest struct {
	// Id is the bundle identifier. Required.
	Id string `json:"id"`
	// Name is the display name, written on install.
	Name string `json:"name,omitempty"`
	// RootType is the type of the root Ensure mints (its one type,
	// `any.type`): required when the body declares nothing (every
	// object has a type; `page` for a plain document), refused next to
	// a declaration — a declaring root carries its marker there.
	// RootCollections are the collections the root is filed under at
	// birth (a `miniapp` root is an app root). Both ride the root's
	// first change.
	RootType        string   `json:"rootType,omitempty"`
	RootCollections []string `json:"rootCollections,omitempty"`
	// RootProperties seeds the root's property values, keyed
	// owner → propId → value (same shape as POST /objects), written
	// with the membership; an owner that is neither rootType nor the
	// root's own declaration is added to rootCollections.
	RootProperties map[string]map[string]any `json:"rootProperties,omitempty"`
	// Derived installs the bundle on the root derived from its id
	// rather than a created one. Every device computes that id
	// offline, so the install never forks and never waits for the
	// registry to converge — which is the only way both sides of a
	// 1-1 (where nobody is the owner) can install while apart.
	//
	// Permanent in both directions: a derived root cannot be deleted,
	// so the bundle can never be uninstalled, and an existing install
	// on a created root is adopted rather than migrated. Ask for it
	// for a space's chat; not for anything a user may remove.
	Derived bool `json:"derived,omitempty"`
	// Parts declares the root's parts with their datasets (same shape
	// as POST …/types/:typeId/parts); the root becomes a type
	// definition, typeId = rootId, and — a definition implements
	// itself — the records are written through POST …/upsert /
	// …/modify on the root (dataset = the computed collection,
	// `<rootId>_<key>` for a namespaced one). Declared once on install;
	// later evolution goes through the …/types/:rootId/parts routes.
	// Parts or properties are required on the tech space. Refused with
	// `collection`.
	Parts []PartDraftRequest `json:"parts,omitempty"`
	// Properties declares property definitions on the root (same shape
	// as POST …/types/:typeId/properties, xKey REQUIRED and unique):
	// the root becomes a type (or, with `collection`, a collection)
	// objects use, and each property's id is derived from (rootId,
	// xKey) so two devices installing while apart mint one column per
	// handle. Resolve xKey → propId through GET …/types/:rootId/
	// properties (or …/collections/:rootId/properties). Declared once
	// on install (an adopt fills in only definitions the root lacks);
	// later evolution goes through the …/properties routes.
	Properties []AddPropertyRequest `json:"properties,omitempty"`
	// XKey is the root definition's handle (same meaning as on POST
	// …/types): what a client resolves it by, and what
	// relation.targetTypes in other declarations name. Unique within
	// the space among listed types and collections (409
	// type.xkey_conflict). An xKey alone declares a MARKER — a type, or
	// with `collection` a collection, with no properties and no parts.
	// Written on install. A writer's adopt fills in a handle the root
	// lacks (an install that predates it); an existing handle is never
	// changed.
	XKey string `json:"xKey,omitempty"`
	// Layout seeds the root type's rendering slice (same shape as POST
	// …/types; refused with `collection`); Hidden keeps the definition
	// out of the default listings. Both are written on install only —
	// an adopt never patches them. Hidden is explicit: a root that only
	// hosts its bundle's records should ask for it (a listed type is
	// one a client may set on other objects, granting them the bundle's
	// collections); a root that is a definition other objects use stays
	// listed.
	Layout json.RawMessage `json:"layout,omitempty"`
	Hidden bool            `json:"hidden,omitempty"`
	// Collection makes the declaration a COLLECTION instead of a type:
	// the root carries `__collection__` in any.type, properties are its
	// columns, and objects are filed under it through any.collections.
	// Parts and layout are refused with it.
	Collection bool `json:"collection,omitempty"`
}

BundleEnsureRequest is the body of POST /v1/spaces/:spaceId/bundles.

type BundleEnsureResponse

type BundleEnsureResponse struct {
	// Bundle is the converged registry row.
	Bundle Bundle `json:"bundle"`
	// Installed reports whether THIS call registered the install.
	// False means an existing one was adopted — which for a derived
	// bundle may still materialize the root's tree on this device,
	// since that id is one every device can mint.
	//
	// For a derived install it reports what THIS DEVICE did: both
	// sides of a partition can report true for the one root they
	// share.
	Installed bool `json:"installed"`
}

BundleEnsureResponse is the reply to an Ensure call.

type BundleGetResponse

type BundleGetResponse struct {
	Bundle Bundle `json:"bundle"`
	// Synced: see BundleListResponse.Synced.
	Synced bool `json:"synced"`
}

BundleGetResponse is the reply to GET /v1/spaces/:spaceId/bundles/:bundleId.

type BundleListResponse

type BundleListResponse struct {
	Bundles []Bundle `json:"bundles"`
	// Synced reports whether the registry converged before this read
	// (the read-side lock): true means an absent bundle is definitively
	// not installed; false (the wait expired — cold offline device)
	// means absence is provisional.
	Synced bool `json:"synced"`
}

BundleListResponse is the reply to GET /v1/spaces/:spaceId/bundles.

type BundleResolveRequest

type BundleResolveRequest struct {
	// LoserRootId is the losing root to delete, cascading to its
	// derived children. Call it only once whatever mattered has been
	// merged out — the server never merges for you.
	LoserRootId string `json:"loserRootId"`
}

BundleResolveRequest is the body of POST /v1/spaces/:spaceId/bundles/:bundleId/resolve.

type CRDTVersionState

type CRDTVersionState struct {
	Supported int  `json:"supported"`
	Stored    int  `json:"stored"`
	Newer     bool `json:"newer"`
}

CRDTVersionState mirrors the SDK's account CRDT-version state.

type CatalogBundle

type CatalogBundle struct {
	Id          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	// Derived installs the bundle on the root derived from its id —
	// never forks, never deletable. The general chat only.
	Derived bool `json:"derived,omitempty"`
	// Hidden keeps the root's definition out of pickers; needs `type`,
	// `collection` or `parts`.
	Hidden bool `json:"hidden,omitempty"`
	// RootType is the root's type when the bundle declares nothing (a
	// bare app root): a registered type id, `page` for a plain
	// document. Required then, refused next to a declaration.
	RootType string `json:"rootType,omitempty"`
	// Type declares the type the root defines; Collection the
	// collection. Exclusive. A root hosting its own records (parts)
	// needs no flag: a definition implements itself.
	Type       *CatalogType       `json:"type,omitempty"`
	Collection *CatalogCollection `json:"collection,omitempty"`
	// Miniapp is a value map on the built-in `miniapp` collection the
	// root is filed under: `bundle` is this bundle's id (filled when
	// omitted), any other key must be a property the built-in declares.
	Miniapp map[string]any `json:"miniapp,omitempty"`
	// Parts declare records datasets on the root (the
	// POST …/types/:typeId/parts draft shape).
	Parts []PartDraftRequest `json:"parts,omitempty"`
	// Supersedes names bundles of the same usecase this one stands in
	// for. A space that has any of them installed keeps them and never
	// receives this bundle; every other space receives this bundle and
	// never the ones it names. A superseded bundle may share its xKey
	// with the bundle that supersedes it — the two never meet in a space.
	Supersedes []string `json:"supersedes,omitempty"`
	// Superseded marks a bundle another one of the usecase supersedes:
	// kept where a space already has it, never what a new space
	// receives. Derived from the other bundles' `supersedes` — the
	// listing reports it, a catalog source does not declare it.
	Superseded bool `json:"superseded,omitempty"`
}

CatalogBundle is one bundle of a usecase: one created root under a `system:<name>/v<n>` id. What the root IS follows from what it declares — a type objects have (`type`), a collection objects are filed under (`collection`), the object a client opens (`miniapp`), records on the root (`parts`) — in any combination but type with collection, or collection with parts.

type CatalogCollection

type CatalogCollection struct {
	XKey       string               `json:"xKey"`
	Properties []AddPropertyRequest `json:"properties,omitempty"`
	// Meta is the definition's open bag of consumer flags (see
	// CollectionsCreateRequest): one string, bool or number per
	// single-level key, opaque to the server. Setup writes each key the
	// installed definition lacks and never overwrites one it carries.
	Meta map[string]any `json:"meta,omitempty"`
}

CatalogCollection is the collection a catalog bundle declares on its root: a handle and columns, no parts, no layout.

type CatalogListResponse

type CatalogListResponse struct {
	Usecases []CatalogUsecase `json:"usecases"`
}

CatalogListResponse is the body of GET /v1/catalog.

type CatalogSetupBundle

type CatalogSetupBundle struct {
	// Usecase is the entry the bundle belongs to (the requested one or
	// a dependency).
	Usecase string `json:"usecase"`
	// Id is the bundle id.
	Id string `json:"id"`
	// Bundle is the converged registry row.
	Bundle Bundle `json:"bundle"`
	// Installed reports whether THIS call registered the root.
	Installed bool `json:"installed"`
	// TypeId is the root's id when the bundle declares a type — the
	// namespace of its property values (`<typeId>.<propId>`).
	TypeId string `json:"typeId,omitempty"`
	// CollectionId is the root's id when the bundle declares a
	// collection.
	CollectionId string `json:"collectionId,omitempty"`
	// Properties maps each declared property's xKey to its id.
	Properties map[string]string `json:"properties,omitempty"`
	// Miniapp is the value map the catalog declares on the built-in
	// `miniapp` collection, `bundle` included — what an install writes and an
	// adopt by a writer fills in where absent. Read the root for what it
	// carries.
	Miniapp map[string]any `json:"miniapp,omitempty"`
}

CatalogSetupBundle is one install a setup ensured.

type CatalogSetupRequest

type CatalogSetupRequest struct {
	SpaceId string `json:"spaceId"`
}

CatalogSetupRequest is the body of POST /v1/catalog/:usecaseId/setup.

type CatalogSetupResponse

type CatalogSetupResponse struct {
	// Usecase is the id that was asked for.
	Usecase string `json:"usecase"`
	// Bundles are the installs in setup order.
	Bundles []CatalogSetupBundle `json:"bundles"`
}

CatalogSetupResponse is the reply to a setup: every bundle the call touched, dependencies first, the requested usecase's bundles last.

type CatalogType

type CatalogType struct {
	// XKey is the type's handle — what clients resolve it by and what
	// relation.targetTypes name. Unique across the catalog, types and
	// collections together.
	XKey string `json:"xKey"`
	// Layout is the rendering slug, `{type, config?}`.
	Layout json.RawMessage `json:"layout,omitempty"`
	// Properties are the columns (the POST …/types/:typeId/properties
	// draft shape); each carries an xKey, the property id derives from
	// it.
	Properties []AddPropertyRequest `json:"properties,omitempty"`
}

CatalogType is the type a catalog bundle declares on its root.

type CatalogUsecase

type CatalogUsecase struct {
	// Id is the usecase slug — the `:usecaseId` path segment. Never
	// enters a space.
	Id          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	// Requires lists the usecases set up before this one, transitively.
	Requires []string `json:"requires,omitempty"`
	// Bundles are the usecase's own installs, in setup order.
	Bundles []CatalogBundle `json:"bundles"`
}

CatalogUsecase is one catalog entry as the catalog declares it.

type ChatAgentMeta

type ChatAgentMeta struct {
	Name      string `json:"name"`
	DebugLink string `json:"debugLink,omitempty"`
	Done      bool   `json:"done"`
	// Outcome says how the run behind a done:true message ended when
	// it did not end normally — `interrupted` (the user stopped it),
	// `error` (it died). Absent on a normal reply. Opaque to the
	// server; clients key their rendering (a stop mark, a warning) on
	// it instead of parsing the text.
	Outcome string `json:"outcome,omitempty"`
}

ChatAgentMeta marks a message as agent-authored. `Name` is the display label; like the old fromAgent tag it is NOT verified against any identity / signature — `creator` stays the change signer. `DebugLink` is an opaque drill-down link into the run's debug page, by convention `any://<spaceId>/<debugLogObjectId>[#turn_<n>]`. `Done` is liveness: false means the run that produced this message is still going (clients show a typing indicator until a done:true message lands). The whole group is create-only and immutable.

type ChatAttachment

type ChatAttachment struct {
	Type string `json:"type"`
	Link string `json:"link"`
}

ChatAttachment is one entry in a message's attachments map. `Type` is an open enum — known values are "link" and "image"; clients fall back to rendering `Link` as a plain anchor for unknown types. `Link` is the URL (any:// for in-space references, https:// or similar for out-of-space resources). Attachments are immutable post-create.

type ChatEditRequest

type ChatEditRequest struct {
	Text string `json:"text"`
}

ChatEditRequest is the body of PATCH .../messages/:msgId. Only `text` is editable post-creation — replyToMessageId is intentionally stable so thread structure doesn't shift. Edit by non-author returns 403 chat.not_author.

type ChatMessageContext

type ChatMessageContext struct {
	SpaceId  string `json:"spaceId"`
	ObjectId string `json:"objectId,omitempty"`
	View     string `json:"view,omitempty"`
}

ChatMessageContext is where the sender was when they sent the message — the page on screen, stamped by the client. `SpaceId` is the space in view (required), `ObjectId` the open object / collection / record when there is one, `View` the client's view kind (an open string: "object", "collection", "mail", …). Optional on send, create-only and immutable; an agent reading the chat takes "here"/"this page" from it. No timestamp: the message's createdAt is when the user was there.

type ChatMessageControl

type ChatMessageControl struct {
	Kind string `json:"kind"`
	Hard bool   `json:"hard,omitempty"`
}

ChatMessageControl is a client's signal to the agent serving the chat, carried on a message of its own (text may be empty). `Kind` is an open string the agent interprets — `break` asks the run in flight to stop; `Hard` = now (vs. wrap up at the next turn). Create-only, immutable; a client renders it as a marker, not a bubble.

type ChatSendRequest

type ChatSendRequest struct {
	Text             string                    `json:"text"`
	ReplyToMessageId string                    `json:"replyToMessageId,omitempty"`
	Agent            *ChatAgentMeta            `json:"agent,omitempty"`
	Attachments      map[string]ChatAttachment `json:"attachments,omitempty"`
	Context          *ChatMessageContext       `json:"context,omitempty"`
	Control          *ChatMessageControl       `json:"control,omitempty"`
}

ChatSendRequest is the body of POST /v1/spaces/:spaceId/objects/:objectId/messages. `text` is a markdown-formatted string; rendering is the client's problem. Server stamps creator, createdAt, modifiedAt.

`agent` is optional and marks the message as written by an agent acting on behalf of the signer (vs typed by the signer directly).

`attachments` is a map keyed by short opaque ids (≤ 64 chars, [A-Za-z0-9_-]+) carrying {type, link, order?}. Create-only.

`context` is the sender's view at send time (ChatMessageContext). Optional, create-only.

`control` is a signal to the agent (ChatMessageControl) — the one case where `text` may be empty. Optional, create-only.

type CollectionInfo

type CollectionInfo struct {
	Id          string         `json:"id"`
	Name        string         `json:"name,omitempty"`
	Description string         `json:"description,omitempty"`
	IconCID     string         `json:"iconCid,omitempty"`
	XKey        string         `json:"xKey,omitempty"`
	BuiltIn     bool           `json:"builtIn,omitempty"`
	Hidden      bool           `json:"hidden,omitempty"`
	Meta        map[string]any `json:"meta,omitempty"`
}

CollectionInfo mirrors space.CollectionInfo on the wire. Registered collections report xKey = id, like registered types.

type CollectionPatchRequest

type CollectionPatchRequest struct {
	Name        *string        `json:"name,omitempty"`
	Description *string        `json:"description,omitempty"`
	IconCID     *string        `json:"iconCid,omitempty"`
	Hidden      *bool          `json:"hidden,omitempty"`
	Meta        map[string]any `json:"meta,omitempty"`
}

CollectionPatchRequest is the body of PATCH /v1/spaces/:spaceId/collections/:collectionId — the display and listing metadata, same rules as TypePatchRequest. At least one field is required.

type CollectionsCreateRequest

type CollectionsCreateRequest struct {
	Name        string         `json:"name,omitempty"`
	Description string         `json:"description,omitempty"`
	IconCID     string         `json:"iconCid,omitempty"`
	XKey        string         `json:"xKey,omitempty"`
	Hidden      bool           `json:"hidden,omitempty"`
	Meta        map[string]any `json:"meta,omitempty"`
}

CollectionsCreateRequest is the body of POST /v1/spaces/:spaceId/collections. A collection is a type without parts or layout: a column group objects are filed under (`any.collections`) next to their one type. Mirrors space.CollectionCreateParams; xKey, hidden and meta follow the type rules (TypesCreateRequest).

type CollectionsCreateResponse

type CollectionsCreateResponse struct {
	CollectionId string `json:"collectionId"`
}

CollectionsCreateResponse is the body returned by POST /v1/spaces/:spaceId/collections.

type CollectionsListResponse

type CollectionsListResponse struct {
	Collections []CollectionInfo `json:"collections"`
}

CollectionsListResponse is the body of GET /v1/spaces/:spaceId/collections.

type DatasetDefResponse

type DatasetDefResponse struct {
	Id string `json:"id"`
	// Key is the slug inside the type; collection is the name reads and
	// writes address (`dataset` on /query, /modify, /upsert …) — the
	// module's canonical collection when shared, `<typeId>_<key>`
	// otherwise. Server-computed, never client-set.
	Key        string `json:"key"`
	Collection string `json:"collection"`
	Module     string `json:"module"`
	Shared     bool   `json:"shared,omitempty"`
	// PartId is the owning part's id.
	PartId      string               `json:"partId"`
	DisplayName string               `json:"displayName,omitempty"`
	Description string               `json:"description,omitempty"`
	Dynamic     bool                 `json:"dynamic,omitempty"`
	IdRule      string               `json:"idRule"`
	IdPattern   string               `json:"idPattern,omitempty"`
	IdMaxLen    int                  `json:"idMaxLen,omitempty"`
	DeleteBy    string               `json:"deleteBy"`
	SkipHistory bool                 `json:"skipHistory,omitempty"`
	Search      *DatasetSearchFields `json:"search,omitempty"`
	Fields      []DatasetFieldDef    `json:"fields"`
	// Invalid marks a definition whose folded declaration fails
	// validation (invalidReason says why) — a records fold missing a
	// creator stamp behind an author rule, an unknown module, a shared
	// rule violation. Invalid definitions never register or accept data
	// but stay listed so they can be repaired or removed.
	Invalid       bool   `json:"invalid,omitempty"`
	InvalidReason string `json:"invalidReason,omitempty"`
}

DatasetDefResponse mirrors space.DatasetDef — the compiled view of one dataset definition.

type DatasetDraftRequest

type DatasetDraftRequest struct {
	// Key is the dataset's slug inside its type ([a-z][a-z0-9_]*, ≤ 64)
	// — pinned. A namespaced dataset lives in the collection
	// `<typeId>_<key>`; a shared dataset's key is its module's canonical
	// collection name and may be omitted.
	Key string `json:"key,omitempty"`
	// Module is the serving module: "records" (the default) or
	// "editor". "chat" is reserved to the server (400
	// dataset.module_reserved) — the catalog's general-chat usecase is
	// its one declaration.
	Module string `json:"module,omitempty"`
	// Shared makes the type participate in the module's canonical
	// collection (editor_blocks) instead of a namespaced one, so two
	// types sharing the editor give an object carrying both a single
	// body. Editor: either; records: never.
	Shared      bool   `json:"shared,omitempty"`
	DisplayName string `json:"displayName,omitempty"`
	Description string `json:"description,omitempty"`
	// Dynamic keeps a free-form keyspace next to the declared fields.
	Dynamic bool `json:"dynamic,omitempty"`
	// IdRule: "auto" (default — ids derived from the change) or "user"
	// (caller-supplied ids, constrained by idPattern/idMaxLen; the id
	// doubles as the upsert idempotency key).
	IdRule    string `json:"idRule,omitempty"`
	IdPattern string `json:"idPattern,omitempty"`
	IdMaxLen  int    `json:"idMaxLen,omitempty"`
	// DeleteBy: "anyone" (default) or "author" (requires a
	// stamp:creator field among fields).
	DeleteBy string `json:"deleteBy,omitempty"`
	// SkipHistory keeps the dataset out of the version-history index.
	SkipHistory bool `json:"skipHistory,omitempty"`
	// Search is the optional search-extraction annotation (x-search):
	// which record fields feed the search index's title/text, and
	// optionally which index scope the entries land under.
	Search *DatasetSearchFields `json:"search,omitempty"`
	// Fields are the initial field definitions (records datasets only —
	// a module owns its schema). Declare required fields here — fields
	// added later cannot be required.
	Fields []DatasetFieldDraft `json:"fields,omitempty"`
}

DatasetDraftRequest is one dataset declaration — an element of PartDraftRequest.Datasets or the body of POST /v1/spaces/:spaceId/types/:typeId/parts/:partId/datasets. Mirrors space.DatasetDraft. The behavioral parts (key, module, shared, idRule/idPattern/idMaxLen, deleteBy, skipHistory, field kinds/flags) are pinned for the definition's life — remove and re-add to change them; display parts (displayName, description, search leaves) patch via PATCH …/datasets/:defId.

type DatasetFieldDef

type DatasetFieldDef struct {
	// Id is the field definition record's id — the identity
	// PATCH / DELETE …/fields/:fieldId target.
	Id          string `json:"id"`
	Key         string `json:"key"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	Kind        string `json:"kind"`
	// Shape is the full declared value shape (kind plus items /
	// properties) when one was declared beyond the bare kind.
	Shape     *DatasetFieldShape `json:"shape,omitempty"`
	Scope     string             `json:"scope"`
	Required  bool               `json:"required,omitempty"`
	MutableBy string             `json:"mutableBy"`
	Stamp     string             `json:"stamp,omitempty"`
	// XFormat is the field's descriptor as stored; absent when none was
	// declared.
	XFormat json.RawMessage `json:"xFormat,omitempty"`
}

DatasetFieldDef mirrors space.DatasetFieldDef.

type DatasetFieldDraft

type DatasetFieldDraft struct {
	// Key is the on-record field name — pinned.
	Key         string `json:"key"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	// Kind is a PropertyKind* wire string. Required unless stamp
	// implies one (creator ⇒ string, createTime/modifyTime ⇒ datetime).
	Kind string `json:"kind,omitempty"`
	// Shape optionally refines array/object values.
	Shape *DatasetFieldShape `json:"shape,omitempty"`
	// Scope: "synced" (default) or "local"; "derived" is implied by
	// stamp and rejected otherwise.
	Scope string `json:"scope,omitempty"`
	// Required: field must be present on create. Incompatible with stamp.
	Required bool `json:"required,omitempty"`
	// MutableBy: "never" (default — write-once), "author", "any".
	// "author" requires a stamp:creator field in the dataset.
	MutableBy string `json:"mutableBy,omitempty"`
	// Stamp: "creator" | "createTime" | "modifyTime" — value derived at
	// apply time, client writes rejected.
	Stamp string `json:"stamp,omitempty"`
	// XFormat is the field's descriptor — the same object a property
	// definition carries (AddPropertyRequest.XFormat), validated the
	// same way against the field's kind. Mutable via
	// PATCH …/fields/:fieldId.
	XFormat json.RawMessage `json:"xFormat,omitempty"`
}

DatasetFieldDraft is one field declaration — input to a records dataset draft and POST …/datasets/:defId/fields. Mirrors space.DatasetFieldDraft.

type DatasetFieldPatchRequest

type DatasetFieldPatchRequest struct {
	Set   map[string]json.RawMessage `json:"set,omitempty" swaggertype:"object"`
	Unset []string                   `json:"unset,omitempty"`
}

DatasetFieldPatchRequest is the body of PATCH /v1/spaces/:spaceId/types/:typeId/datasets/:defId/fields/:fieldId — a per-path patch over one field definition's mutable leaves (space.TypesAPI.PatchDatasetField): name, description (strings) and every path under xFormat (the property PATCH rules — a set targets a leaf, a container can only be unset). The behavioral declaration (key, kind, shape, scope, required, mutableBy, stamp) is pinned and rejected with 400 dataset.immutable. At least one entry across Set/Unset required.

type DatasetFieldShape

type DatasetFieldShape struct {
	Kind       string                        `json:"kind"`
	Items      *DatasetFieldShape            `json:"items,omitempty"`
	Properties map[string]*DatasetFieldShape `json:"properties,omitempty"`
}

DatasetFieldShape is a recursive JSON-Schema-subset value shape (handler.FieldShape on the wire): a kind plus optional items / properties refinement.

type DatasetPatchRequest

type DatasetPatchRequest struct {
	Set   map[string]json.RawMessage `json:"set,omitempty" swaggertype:"object"`
	Unset []string                   `json:"unset,omitempty"`
}

DatasetPatchRequest is the body of PATCH /v1/spaces/:spaceId/types/:typeId/datasets/:defId — a per-path patch over a dataset definition's mutable leaves (space.DatasetDefPatch).

Mutable paths: description, displayName, search.title, search.text, search.scope (string leaves; a whole `search` replace is pinned). Everything else — the key, module, shared flag, id rule, delete gate, field kinds/flags — is pinned and rejected with 400 dataset.immutable. At least one entry across Set/Unset required.

type DatasetSchema

type DatasetSchema struct {
	Name   string          `json:"name"`
	Schema json.RawMessage `json:"schema"`
	// Owners are the types that declare the dataset: one for a
	// registered-type or namespaced dataset, every type sharing the
	// module for a canonical collection (empty while nothing declares
	// it), none for space-level built-ins. Records exist only on objects
	// carrying one of them; consumers gate indexing/eviction on it.
	Owners []string `json:"owners,omitempty"`
	// Module is the serving module ("records", "editor", "chat"; empty
	// for built-ins and registered-type datasets); Shared marks a
	// module's canonical collection.
	Module string `json:"module,omitempty"`
	Shared bool   `json:"shared,omitempty"`
}

DatasetSchema is the wire shape for space.DatasetSchema — one dataset's field declaration rendered as a standard JSON Schema document. Schema is carried as RawMessage so the JSON Schema (which the SDK already marshals) isn't double-encoded into a string.

The JSON Schema object looks like:

{"type":"object",
 "properties":{"<field>":{"type":"string","title":"…","x-scope":"synced"}},
 "additionalProperties":<dynamic>}

The `x-scope` extension keyword on each property carries the field's class: "synced" (user/DAG-written, synced across devices), "derived" (handler-computed, read-only to writers), or "local" (device-local, never synced). `additionalProperties:true` marks a dynamic dataset whose undeclared keys are permitted and treated as synced.

Datasets with behavioral schema declarations (runtime-defined ones, and built-ins that declare them) carry further extension keywords: per-field `x-mutable-by` ("author"/"any"; absent = write-once) and `x-stamp` ("creator"/"createTime"/"modifyTime" — derived at apply, client writes rejected); doc-level standard `required`, `x-delete-by` ("author"; absent = anyone), `x-id` ("user" with `x-id-pattern` / `x-id-max-length`; absent = auto-derived ids), and `x-search` ({title, text, scope} — the record fields feeding the search index and the index scope its entries land under; scope absent = "basic").

type DatasetSearchFields

type DatasetSearchFields struct {
	Title string `json:"title,omitempty"`
	// Text accepts a bare field-key string OR a non-empty array of
	// unique field keys; a single key always reads back as the bare
	// string. The generated schema can only show the array form — the
	// string form is equally valid on the wire.
	Text  SearchText `json:"text,omitempty"`
	Scope string     `json:"scope,omitempty"`
}

DatasetSearchFields mirrors space.SearchFields — the x-search mapping. Title/text may be empty (either alone suffices). Scope is the index scope slug the dataset's entries land under (index. ValidScope); empty = the indexer's default scope ("basic").

type DatasetsResponse

type DatasetsResponse struct {
	Datasets []DatasetSchema `json:"datasets"`
}

DatasetsResponse is the body of GET /v1/spaces/:spaceId/datasets and GET /v1/datasets — the JSON-Schema description of every dataset the space (or the account's tech-space system objects) hosts, for consumer discovery.

type DeleteRecordsRequest

type DeleteRecordsRequest struct {
	ObjectId  string   `json:"objectId"`
	Dataset   string   `json:"dataset,omitempty"`
	RecordIds []string `json:"recordIds"`
	TraceIds  []string `json:"traceIds,omitempty"`
}

DeleteRecordsRequest documents the body of POST /v1/spaces/:spaceId/delete-records.

type DerivedSpaceInfo

type DerivedSpaceInfo struct {
	Name    string `json:"name"`
	SpaceId string `json:"spaceId"`
	Created bool   `json:"created"`
	Status  string `json:"status,omitempty"`
}

DerivedSpaceInfo is one row of GET /v1/spaces/derived — a registry entry resolved against the account: the deterministic spaceId the entry derives to, and whether a usable space row exists (materialized here or on any of the account's devices). Resolving ids never creates anything; materialize with POST /v1/spaces/derived/:name. Status is the raw row status when a row exists (omitted otherwise); a "deleted" row — wedged before the permanence guard existed — reports created=false and refuses materialization.

type DerivedSpaceListResponse

type DerivedSpaceListResponse struct {
	Spaces []DerivedSpaceInfo `json:"spaces"`
}

DerivedSpaceListResponse is the body of GET /v1/spaces/derived.

type DeviceActivateRequest

type DeviceActivateRequest struct {
	App string `json:"app"`
}

DeviceActivateRequest is the body of POST /v1/devices/activate — claim the active role for one app slug on THIS device.

type DeviceActiveClaim

type DeviceActiveClaim struct {
	Seq int64 `json:"seq"`
	At  int64 `json:"at"`
}

DeviceActiveClaim is one device's claim to be the active instance of one app slug. Seq is a writer-supplied monotonic counter (claim = max of all visible seqs + 1); At is the claim's unix-seconds timestamp. Deliberately NOT a CRDT version id: versionIds are peer-locally allocated, so they cannot arbitrate across devices — the claim data itself is what every reader resolves on.

type DeviceInfo

type DeviceInfo struct {
	PeerId  string `json:"peerId"`
	Name    string `json:"name,omitempty"`
	OS      string `json:"os,omitempty"`
	Version string `json:"version,omitempty"`

	Apps         map[string]map[string]any    `json:"apps,omitempty"`
	ActiveClaims map[string]DeviceActiveClaim `json:"activeClaims,omitempty"`
}

DeviceInfo is the wire shape of one row in the account's tech-space `devices` dataset: one row per device (peer), row id = peerId. The registry is member-replicated across the account's devices; each device upserts its own row (name/os/version stamped server-side on boot and via PUT /v1/devices/me).

Apps is an open slug set (same convention as index scopes and UI command actions): presence of a slug means "installed on this device"; the per-slug object carries free-form app metadata (conventionally a `version` string). Nothing app-specific is baked into the server.

ActiveClaims carries this device's per-app claim to be the app's active instance. Winners are resolved reader-side — see DevicesListResponse.Active and docs/23-devices.md § Election.

type DeviceUpdateRequest

type DeviceUpdateRequest struct {
	Name string                    `json:"name,omitempty"`
	Apps map[string]map[string]any `json:"apps,omitempty"`
}

DeviceUpdateRequest is the body of PUT /v1/devices/me — the restricted self-row upsert. peerId / os / version are stamped server-side and cannot be supplied; the body carries only the caller-owned fields, and only present fields are written (empty name = leave as-is). Apps entries merge per slug; an explicit null value uninstalls that slug (`{"apps": {"bao": null}}`).

type DevicesListResponse

type DevicesListResponse struct {
	Devices []DeviceInfo      `json:"devices"`
	Active  map[string]string `json:"active,omitempty"`
	Self    string            `json:"self"`
}

DevicesListResponse is the body of GET /v1/devices.

Active maps app slug → the peerId of that app's active device, resolved server-side by the canonical election rule (highest claim Seq, tiebreak highest At, final tiebreak lexicographically-largest peerId, candidates limited to devices whose row still carries the app slug). Both the UI and agent runtimes MUST consume this field rather than reimplementing the rule — one implementation, no divergent winners. A slug is absent when no installed device has claimed it.

Self is THIS server's own peerId — how a consumer (UI, agent runtime) tells whether it is the active device without a separate identity call.

type ErrorEnvelope

type ErrorEnvelope struct {
	Error APIError `json:"error"`
}

type Event

type Event struct {
	Type    string          `json:"type"`
	Scope   string          `json:"scope"`
	SpaceId string          `json:"spaceId,omitempty"`
	Target  string          `json:"target,omitempty"`
	Data    json.RawMessage `json:"data,omitempty"`
	Sender  *EventSender    `json:"sender,omitempty"`
}

Event is one envelope on the account-wide ephemeral event bus (POST /v1/events → GET /v1/events/subscribe). At-most-once: nothing is stored, there is no replay, a subscriber only sees events published after it connects. See docs/21-events.md.

Type is an open dotted slug set (e.g. "process.progress", "ui.open_space") — new kinds need no server change. Scope routes delivery: EventScopeDevice fans out in-process only; account and space ride the SDK's pub/sub to the account's devices / the space's members. SpaceId is required iff Scope == EventScopeSpace. Target optionally narrows the subject (objectId, runId, processId, …) and is filterable on subscribe. Data is the free-form payload.

Sender is server-stamped, never client-supplied: Identity is the publishing account (signature-verified for network scopes), Self is true when the event came from this account (any of its devices).

A sessionId field is reserved for a future per-connection identity; not implemented.

type EventLinksUpdatedData

type EventLinksUpdatedData struct {
	SpaceId   string   `json:"spaceId"`
	Targets   []string `json:"targets"`
	Truncated bool     `json:"truncated,omitempty"`
}

EventLinksUpdatedData is the payload of EventLinksUpdated: the canonical targets (object references, or the identity / file URI) whose backlinks changed in spaceId. Targets is capped at MaxEventLinksTargets; Truncated says more changed than listed — a panel showing an unlisted target re-reads too.

type EventPublishRequest

type EventPublishRequest struct {
	Type    string `json:"type"`
	Scope   string `json:"scope"`
	SpaceId string `json:"spaceId,omitempty"`
	Target  string `json:"target,omitempty"`
	// Data is free-form: any JSON value, capped at 64 KiB marshaled.
	// The generated schema can only show the object form — a scalar or
	// an array is equally valid on the wire.
	Data json.RawMessage `json:"data,omitempty"`
}

EventPublishRequest is the body of POST /v1/events — Event minus the server-stamped sender. Strict-bound: unknown top-level keys (including "sender") answer 400 request.unknown_field.

type EventPublishResponse

type EventPublishResponse struct {
	Subscribers int `json:"subscribers"`
}

EventPublishResponse is the body of POST /v1/events. Subscribers is how many local subscribers matched the event (0 = nobody listening). A valid publish always succeeds — the bus is fire-and-forget.

type EventSender

type EventSender struct {
	Identity string `json:"identity"`
	Self     bool   `json:"self"`
}

EventSender identifies the publisher of an Event. Stamped by the server; a sender field inside a publish body is rejected.

type FileCacheFreeRequest

type FileCacheFreeRequest struct {
	Bytes int64 `json:"bytes"`
}

FileCacheFreeRequest is the body of POST /v1/files/cache/free.

type FileCacheFreeResult

type FileCacheFreeResult struct {
	Freed int64 `json:"freed"`
}

FileCacheFreeResult reports the bytes actually reclaimed — less than requested when nothing else is safely evictable.

type FileCacheInfo

type FileCacheInfo struct {
	Size int64 `json:"size"`
}

FileCacheInfo is the body of GET /v1/files/cache — local bytes held by file content across all spaces (complete + partial copies).

type FileInfo

type FileInfo struct {
	FileId   string `json:"fileId"`
	ObjectId string `json:"objectId"`
	// RootCid is the content address of the encrypted file. Empty for
	// inline-tier files (bytes ride the CRDT row itself).
	RootCid string `json:"rootCid,omitempty"`
	// Size is the plaintext byte size.
	Size int64 `json:"size"`
	// Inline reports the inline tier (no rootCid, no backup needed).
	Inline bool `json:"inline"`
	// Durable reports a verified network-custody receipt (inline files
	// are durable by construction). False right after attach is normal:
	// backup runs in the background — watch /files/subscribe or re-GET.
	Durable bool `json:"durable"`
	// Cached reports a complete local copy (always true for inline).
	Cached    bool   `json:"cached"`
	Name      string `json:"name,omitempty"`
	Mime      string `json:"mime,omitempty"`
	Variant   string `json:"variant,omitempty"`
	VariantOf string `json:"variantOf,omitempty"`
}

FileInfo describes one attached file — the unsealed member view. Name / Mime / Variant / VariantOf come from the sealed (member-only) part of the payloads row and are empty for a keyless reader.

type FileListResponse

type FileListResponse struct {
	Files []FileInfo `json:"files"`
}

FileListResponse is the body of GET /v1/spaces/:spaceId/files.

type FileStats

type FileStats struct {
	Total    int `json:"total"`
	Durable  int `json:"durable"`
	InFlight int `json:"inflight"`
	Limited  int `json:"limited"`
}

FileStats are the space's aggregate durability counts (GET /v1/spaces/:spaceId/files/stats).

type FileStatus

type FileStatus struct {
	FileId   string `json:"fileId"`
	ObjectId string `json:"objectId"`
	State    string `json:"state"`
	Cached   bool   `json:"cached"`
	// Attempts counts failed background attempts since the last
	// success/enqueue; 0 when no work is pending.
	Attempts int    `json:"attempts,omitempty"`
	LastErr  string `json:"lastErr,omitempty"`
}

FileStatus is the point-in-time durability + availability view of one file. Also the payload of the per-space `status` SSE frames on GET /v1/spaces/:spaceId/files/subscribe.

type GlobalP2PStatus added in v0.2.3

type GlobalP2PStatus struct {
	Enabled bool `json:"enabled"`
	// EndpointId is this device's iroh endpoint id (its device key).
	EndpointId string `json:"endpointId"`
	// Ticket is what this device publishes for others to dial; empty
	// until the relay session is up. Relay-only by construction — it
	// never carries this device's IP addresses.
	Ticket string `json:"ticket,omitempty"`
	// HomeRelay is the relay URL inside Ticket.
	HomeRelay string `json:"homeRelay,omitempty"`
	// RelayConnected — the session to the home relay is up. Until it
	// is, this device can dial out but cannot be reached.
	RelayConnected bool `json:"relayConnected"`
	// Peers are the peers known through records, connected or not —
	// except any in the disabled tier, which the SDK drops from this
	// list. A device silent for 30 days is therefore absent here, not
	// listed as disabled.
	Peers []P2PPeerStatus `json:"peers"`
	// Account is the account-level discovery record (pkarr).
	Account AccountDiscoveryStatus `json:"account"`
}

GlobalP2PStatus is the internet-wide layer: this device's iroh endpoint, its relay session, and every peer known through records.

type HealthResponse

type HealthResponse struct {
	Status    string    `json:"status"`
	Version   string    `json:"version"`
	StartedAt time.Time `json:"startedAt"`
	// NetworkId is the any-sync network this server joins: the networkId
	// of the nodeconf it started with. Set whether or not an account is
	// authorized. The server names no networks; clients map well-known
	// ids to names themselves.
	NetworkId string `json:"networkId"`
	Account   string `json:"account"`
	// Bootstrapping is true while the booted SDK's background boot pass
	// (eager space loading + offline catch-up) is still running. The
	// server serves throughout; per-space convergence is /sync-status.
	// False when unauthorized and after the pass completes.
	Bootstrapping bool `json:"bootstrapping"`
	// CRDTVersion is the account's CRDT data-model version state
	// (absent when unauthorized): the version this server's SDK
	// supports, the one recorded on the account's tech space, and
	// `newer` — true when the recorded one is above the supported one,
	// which makes the account read-only until the server is upgraded
	// (every synced write answers 409 sdk.crdt_version_newer).
	CRDTVersion *CRDTVersionState `json:"crdtVersion,omitempty"`
}

type HistoryChange

type HistoryChange struct {
	Version   string                 `json:"version"`
	Author    string                 `json:"author"`
	Timestamp int64                  `json:"timestamp"` // author clock, Unix seconds — display-only
	Dataset   string                 `json:"dataset"`
	TraceIds  []string               `json:"traceIds,omitempty"`
	Touched   []HistoryTouchedRecord `json:"touched,omitempty"`
	// Truncated is RESERVED (always false today): the SDK keeps full
	// history locally. It becomes meaningful with the future
	// snapshot-horizon contract.
	Truncated bool `json:"truncated,omitempty"`
	GroupSize int  `json:"groupSize"`
}

HistoryChange is one listed change, or one coalesced group of consecutive same-author changes (groupSize > 1) whose handle is the group's newest ChangeId.

type HistoryDatasetDiff

type HistoryDatasetDiff struct {
	Dataset string              `json:"dataset"`
	Records []HistoryRecordDiff `json:"records"`
}

HistoryDatasetDiff groups record diffs of one dataset.

type HistoryDiffResponse

type HistoryDiffResponse struct {
	Base     string               `json:"base,omitempty"`
	Version  string               `json:"version"`
	Datasets []HistoryDatasetDiff `json:"datasets"`
}

HistoryDiffResponse is GET .../history/diff. Base is empty for a per-change effect diff (version diffed against its DAG parents).

type HistoryFieldDiff

type HistoryFieldDiff struct {
	Path []string `json:"path"`
	// Before / After are leaf values — usually a string, number or
	// boolean. The generated schema can only show the object form.
	Before json.RawMessage `json:"before,omitempty"`
	After  json.RawMessage `json:"after,omitempty"`
}

HistoryFieldDiff is one leaf-level field difference; absent side is omitted. Peer-local bookkeeping (_ver etc.) never appears.

type HistoryListResponse

type HistoryListResponse struct {
	Changes []HistoryChange `json:"changes"`
	// Cursor resumes the next page; empty = history exhausted.
	Cursor string `json:"cursor,omitempty"`
}

HistoryListResponse is one page of GET /spaces/{spaceId}/objects/{objectId}/history.

type HistoryRecordDiff

type HistoryRecordDiff struct {
	Id     string             `json:"id"`
	Kind   string             `json:"kind"`
	Fields []HistoryFieldDiff `json:"fields,omitempty"`
}

HistoryRecordDiff is one record's difference. Kind is one of "added", "removed", "changed", "deleted".

type HistoryRecordResponse

type HistoryRecordResponse struct {
	Version  string          `json:"version"`
	Dataset  string          `json:"dataset"`
	RecordId string          `json:"recordId"`
	Exists   bool            `json:"exists"`
	Deleted  bool            `json:"deleted,omitempty"`
	Record   json.RawMessage `json:"record,omitempty"`
}

HistoryRecordResponse is GET .../history/{version}/datasets/ {dataset}/records/{recordId}: one record at a version. Exists=false when the record was not present at that cut; Deleted=true when it was tombstoned (Record then carries the tombstone row).

type HistoryTouchedRecord

type HistoryTouchedRecord struct {
	Dataset  string   `json:"dataset"`
	RecordId string   `json:"recordId"`
	Ops      []string `json:"ops,omitempty"`
}

HistoryTouchedRecord names one record a change touched with its op kinds (e.g. "$set", "delete").

type HistoryViewDataset

type HistoryViewDataset struct {
	Dataset string            `json:"dataset"`
	Records []json.RawMessage `json:"records"`
}

HistoryViewDataset is one dataset's records at a version. Records are raw dataset rows (same shape as /query results).

type HistoryViewResponse

type HistoryViewResponse struct {
	Version  string               `json:"version"`
	Datasets []HistoryViewDataset `json:"datasets"`
}

HistoryViewResponse is GET /spaces/{spaceId}/objects/{objectId}/history/{version}: the object's live records as of that version, grouped by dataset. Synced scope only — local/account values have no history and are excluded.

type IdentitiesListResponse

type IdentitiesListResponse struct {
	Identities []IdentityInfo `json:"identities"`
}

IdentitiesListResponse is the body of GET /v1/identities.

type IdentityEventPayload

type IdentityEventPayload struct {
	Added   []IdentityInfo `json:"added,omitempty"`
	Updated []IdentityInfo `json:"updated,omitempty"`
	Removed []string       `json:"removed,omitempty"`
}

IdentityEventPayload is the data payload of an `event: identities` frame on the identities subscribe SSE stream — one frame per directory change batch, mirroring space.IdentityListEvent. Added/Updated carry the post-event row; Removed carries the identity strings that left the directory.

type IdentityInfo

type IdentityInfo struct {
	Identity    string   `json:"identity"`
	Name        string   `json:"name,omitempty"`
	Description string   `json:"description,omitempty"`
	IconCID     string   `json:"iconCid,omitempty"`
	SpaceIds    []string `json:"spaceIds"`
}

IdentityInfo is the wire shape of space.IdentityInfo — one row in the account-global identities directory: every account identity this account has encountered (across spaces, 1-1s, inbox invites). It is a device-local, persistent cache.

Name / Description / IconCID are the last identityRepo profile resolved for this identity and are OMITTED until resolved: profiles are encrypted, so a known identity surfaces id-only until its decryption key arrives (via a shared space's ACL or a 1-1 invite) and the background fetch completes. Clients must tolerate an empty name.

SpaceIds is the set of spaces where this identity is currently seen (pruned when we leave/offload a space). The directory carries NO per-space rights — roles (owner/admin/writer/reader) live on the members list (GET /v1/spaces/:id/members), which is the authoritative per-space roster.

type InviteCreateResponse

type InviteCreateResponse struct {
	SpaceId     string `json:"spaceId"`
	InviteToken string `json:"inviteToken"`
}

InviteCreateResponse is the body returned by POST /v1/spaces/:spaceId/invites. `inviteToken` is the share-friendly base58 token (space.EncodeInvite) — the only piece a joiner needs to call POST /v1/spaces/join.

type InviteInfo

type InviteInfo struct {
	RecordId string `json:"recordId"`
	// Permission is "none" for the request-to-join invites v1 mints —
	// the role is chosen at accept time, not carried by the invite.
	Permission string `json:"permission"`
	// InviteToken is the same share token POST /invites returned at
	// mint time, recovered from the minting account's synced custody.
	// Present only on that account's devices — other members (any
	// role) never held the private key and get no token. Also omitted
	// for invites minted before custody shipped (regenerate once to
	// make the token durable) and for custody gone stale (invite
	// replaced or revoked on another device).
	InviteToken string `json:"inviteToken,omitempty"`
}

InviteInfo mirrors space.InviteInfo. RecordId is what the DELETE /v1/spaces/:spaceId/invites/:recordId path expects.

type InvitesListResponse

type InvitesListResponse struct {
	Invites []InviteInfo `json:"invites"`
}

InvitesListResponse is the body of GET /v1/spaces/:spaceId/invites.

type JoinRequest

type JoinRequest struct {
	RecordId    string `json:"recordId"`
	Identity    string `json:"identity"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	IconCID     string `json:"iconCid,omitempty"`
}

JoinRequest mirrors space.JoinRequestInfo.

type JoinRequestsResponse

type JoinRequestsResponse struct {
	Requests []JoinRequest `json:"requests"`
}

JoinRequestsResponse is the body of GET /v1/spaces/:spaceId/members/requests.

type Link struct {
	Source LinkSource `json:"source"`
	Kind   string     `json:"kind"`
	Target LinkTarget `json:"target"`
}

Link is one edge. Kind is the edge kind: mention, link, card, embed, relation (an open set — see docs/13-index.md § Links).

type LinkSource

type LinkSource struct {
	SpaceId  string `json:"spaceId"`
	ObjectId string `json:"objectId"`
	Dataset  string `json:"dataset"`
	RecordId string `json:"recordId"`
	// TypeId is the type declaring a property value's source (`prop`
	// edges only): the value lives at record[typeId][recordId].
	TypeId string `json:"typeId,omitempty"`
	// Field is the record field the reference was read from, for a
	// runtime record with link-bearing fields; absent for a block or
	// message text and for a property value.
	Field string `json:"field,omitempty"`
}

LinkSource is where an edge was found: the object, the collection (a module or runtime collection, or the virtual `prop` for a property value) and the record (the property id under `prop`).

type LinkTarget

type LinkTarget struct {
	Uri      string `json:"uri"`
	Kind     string `json:"kind"`
	SpaceId  string `json:"spaceId"`
	ObjectId string `json:"objectId,omitempty"`
	Dataset  string `json:"dataset,omitempty"`
	RecordId string `json:"recordId,omitempty"`
	PropId   string `json:"propId,omitempty"`
	Identity string `json:"identity,omitempty"`
	FileId   string `json:"fileId,omitempty"`
}

LinkTarget is the canonical any:// target, parsed. Uri is the canonical string (docs/19-links.md); Kind is the URI kind (o, p, m, f); the id fields are populated per kind.

type LinksResponse

type LinksResponse struct {
	Links []Link `json:"links"`
	// Truncated reports that the read hit its cap.
	Truncated bool `json:"truncated,omitempty"`
}

LinksResponse is the body of GET /v1/spaces/:spaceId/objects/:objectId/links — the edges whose source is the object (or the one record / property it was narrowed to). Never null.

type LocalAggregateRequest

type LocalAggregateRequest struct {
	Coll             LocalCollection  `json:"coll"`
	Pipeline         []map[string]any `json:"pipeline"`
	GroupLimit       *int             `json:"groupLimit,omitempty"`
	AccumArrayLimit  *int             `json:"accumArrayLimit,omitempty"`
	MemoryLimitBytes *int             `json:"memoryLimitBytes,omitempty"`
	Explain          bool             `json:"explain,omitempty"`
}

LocalAggregateRequest is the body of POST /v1/local/aggregate. The stage vocabulary is GET /v1/local/meta's `stages`. $out / $merge / $lookup name collections by StorageName and must name LOCAL ones (400 local.bad_sink_target otherwise); a sink pipeline answers `written` instead of `records`.

type LocalAggregateResponse

type LocalAggregateResponse struct {
	Records []json.RawMessage `json:"records,omitzero"`
	Plan    *string           `json:"plan,omitempty"`
	Written *int              `json:"written,omitempty"`
}

LocalAggregateResponse is the body of POST /v1/local/aggregate: exactly one of Records (result docs), Plan (explain=true) or Written (a $out / $merge pipeline — documents written to the target).

type LocalCollection

type LocalCollection struct {
	// Scope is "account" or "space".
	Scope string `json:"scope"`
	// SpaceId binds a space-scoped collection; required iff scope is
	// "space". Nothing drops the collection when the space goes away.
	SpaceId string `json:"spaceId,omitempty"`
	// Name: ^[a-z0-9][a-z0-9_-]{0,63}$.
	Name string `json:"name"`
}

LocalCollection addresses one local collection on the wire.

type LocalCollectionInfo

type LocalCollectionInfo struct {
	LocalCollection
	// StorageName is the collection's any-store name (the "l_"-tagged
	// form). It is what a pipeline's $out / $merge `into` / $lookup
	// `from` must name — those stages take raw collection names.
	StorageName string       `json:"storageName"`
	Count       int          `json:"count"`
	Indexes     []LocalIndex `json:"indexes"`
}

LocalCollectionInfo describes an existing local collection.

type LocalDeleteRequest

type LocalDeleteRequest struct {
	Coll LocalCollection `json:"coll"`
	Ids  []string        `json:"ids,omitempty"`
	// Filter is omitzero, not omitempty: `{}` (delete everything) must
	// survive marshalling; only a nil map is absent.
	Filter map[string]any `json:"filter,omitzero"`
}

LocalDeleteRequest is the body of POST /v1/local/delete: exactly one of Ids / Filter. Filter deletes are collected under one read and removed in chunks of 256 — NOT atomic per call; a concurrent writer can interleave.

type LocalDeleteResponse

type LocalDeleteResponse struct {
	// Deleted counts documents actually removed (an id that was already
	// gone is not counted, not an error).
	Deleted int `json:"deleted"`
}

LocalDeleteResponse is the body of POST /v1/local/delete.

type LocalDiscoveryRequest added in v0.2.3

type LocalDiscoveryRequest struct {
	// Enabled false stops announce and browse within seconds and keeps
	// them stopped; true starts them at once. Required: an absent value
	// is 400 request.missing_field rather than a silent off. Held for
	// the process lifetime, across logout and account switches; a host
	// restates it after a restart, and may state it before the first
	// POST /v1/auth.
	Enabled *bool `json:"enabled"`
}

LocalDiscoveryRequest is the body of PUT /v1/local-discovery: whether this device announces and browses on the local network (mDNS). The QUIC listener and the global p2p layer are unaffected.

type LocalDiscoveryResponse added in v0.2.3

type LocalDiscoveryResponse struct {
	Enabled bool `json:"enabled"`
}

LocalDiscoveryResponse is the switch state: what the live engine reports, or, with no engine up, what the next boot will start with.

type LocalDocsRequest

type LocalDocsRequest struct {
	Coll LocalCollection `json:"coll"`
	// Docs are JSON objects. A missing `id` is minted server-side
	// (insert and upsert alike); it must be a string when present.
	Docs []map[string]any `json:"docs"`
}

LocalDocsRequest is the body of POST /v1/local/insert and POST /v1/local/upsert. At most 1000 docs per request; written in chunks of 256 per transaction, so a failure mid-way leaves earlier chunks committed.

type LocalEnsureRequest

type LocalEnsureRequest struct {
	LocalCollection
	// Indexes to ensure on the collection (idempotent).
	Indexes []LocalIndex `json:"indexes,omitempty"`
}

LocalEnsureRequest is the body of PUT /v1/local/collections.

type LocalEnsureResponse

type LocalEnsureResponse struct {
	Collection LocalCollectionInfo `json:"collection"`
	Created    bool                `json:"created"`
}

LocalEnsureResponse is the body of PUT /v1/local/collections: 201 when this call created the collection, 200 when it already existed.

type LocalGetRequest

type LocalGetRequest struct {
	Coll LocalCollection `json:"coll"`
	Id   string          `json:"id"`
}

LocalGetRequest is the body of POST /v1/local/get.

type LocalIdsResponse

type LocalIdsResponse struct {
	Ids []string `json:"ids"`
}

LocalIdsResponse is the body of insert / upsert: the ids of every written document, in request order.

type LocalImportResponse

type LocalImportResponse struct {
	Collections []LocalCollectionInfo `json:"collections"`
}

LocalImportResponse is the body of POST /v1/local/import: every collection the file carried, as it stands after the import (in file order). The export itself, GET /v1/local/export, has no JSON body — it streams the file.

type LocalIndex

type LocalIndex struct {
	// Name is derived from Fields when empty (e.g. "kind,-at").
	Name string `json:"name,omitempty"`
	// Fields are field paths, "-" prefix for descending.
	Fields []string `json:"fields"`
	Unique bool     `json:"unique,omitempty"`
	Sparse bool     `json:"sparse,omitempty"`
}

LocalIndex is one range index on a local collection.

type LocalIndexesRequest

type LocalIndexesRequest struct {
	Coll   LocalCollection `json:"coll"`
	Ensure []LocalIndex    `json:"ensure,omitempty"`
	// Drop names indexes to remove (a missing name is not an error).
	Drop []string `json:"drop,omitempty"`
}

LocalIndexesRequest is the body of POST /v1/local/indexes.

type LocalIndexesResponse

type LocalIndexesResponse struct {
	Indexes []LocalIndex `json:"indexes"`
}

LocalIndexesResponse is the body of POST /v1/local/indexes: the collection's indexes after the change.

type LocalListResponse

type LocalListResponse struct {
	Collections []LocalCollectionInfo `json:"collections"`
}

LocalListResponse is the body of GET /v1/local/collections.

type LocalMetaResponse

type LocalMetaResponse struct {
	Stages       []string `json:"stages"`
	Accumulators []string `json:"accumulators"`
}

LocalMetaResponse is the body of GET /v1/local/meta: the aggregation grammar as any-store advertises it.

type LocalQueryRequest

type LocalQueryRequest struct {
	Coll   LocalCollection `json:"coll"`
	Filter map[string]any  `json:"filter,omitempty"`
	Sort   []string        `json:"sort,omitempty"`
	// Limit defaults to 100, capped at 1000.
	Limit        int  `json:"limit,omitempty"`
	Offset       int  `json:"offset,omitempty"`
	IncludeTotal bool `json:"includeTotal,omitempty"`
	// Projection shapes the records that come back — the same
	// mongo-style grammar the dataset query endpoints take (docs/09-
	// query.md § Projection): field paths to 1 (include) or -1
	// (exclude), `id` always present. A local record carries no `_ver`
	// and no delivery counters, so the protocol-field rules there are
	// simply inert here. `$project` inside /v1/local/aggregate is the
	// equivalent for a pipeline.
	Projection map[string]int `json:"projection,omitempty"`
}

LocalQueryRequest is the body of POST /v1/local/query. The reply is QueryResponse; `total`/`hasNext` ride includeTotal as on /query.

type LocalRecordResponse

type LocalRecordResponse struct {
	Record json.RawMessage `json:"record"`
}

LocalRecordResponse is the body of POST /v1/local/get.

type LocalUpdateRequest

type LocalUpdateRequest struct {
	Coll LocalCollection `json:"coll"`
	Id   string          `json:"id"`
	// Modifier is a mongo-style modifier ($set / $unset / $inc / …).
	Modifier map[string]any `json:"modifier"`
	// Upsert creates the document from the modifier when the id is
	// absent instead of answering 404 local.doc_not_found.
	Upsert bool `json:"upsert,omitempty"`
}

LocalUpdateRequest is the body of POST /v1/local/update.

type LocalUpdateResponse

type LocalUpdateResponse struct {
	// Modified reports whether the modifier changed the document.
	Modified bool `json:"modified"`
	// Record is the document after the update.
	Record json.RawMessage `json:"record"`
}

LocalUpdateResponse is the body of POST /v1/local/update.

type MarkdownContent

type MarkdownContent struct {
	Content string `json:"content"`
}

MarkdownContent documents the body of GET/PUT .../editor/markdown.

type MarkdownEdit

type MarkdownEdit struct {
	OldText    string `json:"oldText"`
	NewText    string `json:"newText"`
	ReplaceAll bool   `json:"replaceAll,omitempty"`
}

MarkdownEdit is one targeted replacement against an object's rendered markdown: oldText is matched against the bytes GET .../editor/markdown returns and must be unique unless replaceAll. See docs/03-api.md § Objects for the matching rules.

type MarkdownEditRequest

type MarkdownEditRequest struct {
	Edits []MarkdownEdit `json:"edits"`
}

MarkdownEditRequest is the body of PATCH .../editor/markdown. All edits match against the original document independently and must not overlap; any failing edit rejects the whole request.

type MarkdownSetResponse

type MarkdownSetResponse struct {
	Inserted  []string `json:"inserted"`
	Updated   []string `json:"updated"`
	Deleted   []string `json:"deleted"`
	Unchanged int      `json:"unchanged"`
}

MarkdownSetResponse documents the response of PUT .../editor/markdown.

type Member

type Member struct {
	Identity        string `json:"identity"`
	Permission      string `json:"permission"`
	Status          string `json:"status"`
	Name            string `json:"name,omitempty"`
	Description     string `json:"description,omitempty"`
	IconCID         string `json:"iconCid,omitempty"`
	RequestRecordId string `json:"requestRecordId,omitempty"`
}

Member is the wire shape of space.Member. Permission and Status are rendered as strings; identityRepo-decoded profile fields surface when populated.

type MemberEventPayload

type MemberEventPayload struct {
	Kind     string  `json:"kind"`
	Member   Member  `json:"member"`
	Previous *Member `json:"previous"`
}

MemberEventPayload is the data payload of an `event: member` frame on the members subscribe SSE stream. Kind discriminates the change; Member carries the post-event state; Previous carries pre-event state (nil for Added).

type MembersListResponse

type MembersListResponse struct {
	Members []Member `json:"members"`
}

MembersListResponse is the body of GET /v1/spaces/:spaceId/members.

type ModifyResult

type ModifyResult struct {
	VersionId  string        `json:"versionId"`
	ChangeId   string        `json:"changeId"`
	RecordIds  []string      `json:"recordIds"`
	Rejections []OpRejection `json:"rejections,omitempty"`
}

ModifyResult is the response shape for Space.Modify, Space.Delete, and PropertiesAPI.Set. Always includes versionId/changeId/recordIds — clients use RecordIds[0] to read auto-derived ids when they submitted a record with empty Id.

Rejections is the partial-success list: ops the handler refused at apply time (kind mismatch, unknown property, immutable field…). The change still committed with this versionId/changeId, but those ops did not land. Empty / omitted means everything took.

type ObjectCreateRequest

type ObjectCreateRequest struct {
	// Type is the object's one type — what it IS: its parts, its layout
	// and one column group. Required (400 request.missing_field);
	// `page` is the plain document. Nothing is stamped server-side.
	Type string `json:"type"`
	// Collections lists the collections the object is filed under at
	// create — column groups without parts (docs/28-well-known-bundles.md:
	// an object is in a space's wiki tree only when it is in the wiki
	// collection).
	Collections []string `json:"collections,omitempty"`
	// InitialProperties carries the object's starting property values,
	// keyed by owner (the type or a collection) then property id — the
	// ONLY home for them: {"initialProperties": {"any": {"name":
	// "Dune"}}}. A top-level name/description/group key is rejected.
	InitialProperties map[string]map[string]any `json:"initialProperties,omitempty"`
}

ObjectCreateRequest documents the body of POST /v1/spaces/:spaceId/objects. AUTHORITATIVE like QueryBodyParams: the server derives its strict unknown-field rejection from these json tags — this is the whole create vocabulary.

type ObjectDebugResponse

type ObjectDebugResponse struct {
	ObjectId string `json:"objectId"`

	// SyncState is one of: unknown, offline, syncing, synced, error.
	// Pending is the set of heads the per-space syncstatus tracker is
	// waiting for a responsible-node HeadsApply on; empty means
	// converged with the last sender we trust.
	SyncState  string    `json:"syncState"`
	Pending    []string  `json:"pending"`
	LastSyncAt time.Time `json:"lastSyncAt"`

	// Heads / HeadsCount: current tree heads. HeadsCount > 1 means the
	// object is diverged across concurrent writers right now.
	// BranchCount counts every DAG branch that ever existed —
	// merged-in lineages (one per extra parent on a merge) plus
	// still-open ones (HeadsCount - 1). TreeLen is total change count.
	// Snapshots is the number of changes carrying IsSnapshot; costs a
	// full IterateRoot walk.
	Heads       []string `json:"heads"`
	HeadsCount  int      `json:"headsCount"`
	BranchCount int      `json:"branchCount"`
	TreeLen     int      `json:"treeLen"`
	Snapshots   int      `json:"snapshots"`

	// LatestVersionId is the lexid-max OrderId across Heads. Empty
	// when the tree has no heads (root-only / transient cold-restore).
	// Local to this peer — VersionIds don't match across peers.
	LatestVersionId string `json:"latestVersionId"`

	// MaxAddSeq is the controller's delivery-order watermark — the
	// highest AddSeq the apply path has seen. Exposed here as a
	// sanity check that the controller is keeping up with the tree;
	// not a cross-peer primitive.
	MaxAddSeq uint64 `json:"maxAddSeq"`
}

ObjectDebugResponse is the wire shape of Space.Debug().Object(objectId). The tree-structure fields are gathered under the object tree mutex so they form a jointly-consistent snapshot; the read blocks local writes for the duration of the IterateRoot walk.

Diagnostic-only: this surface mirrors the SDK's DebugAPI, which is explicitly not stable. Production UI should subscribe to the per-space /sync-status endpoints once the SDK lands them.

type ObjectGetResponse

type ObjectGetResponse struct {
	ObjectId string          `json:"objectId"`
	Record   json.RawMessage `json:"record"`
}

ObjectGetResponse is the body of GET /v1/spaces/:spaceId/objects/:objectId: the object's row from the space's objects collection (any.type, any.collections and property values, meta included), rendered as JSON.

type ObjectSyncStatusResponse

type ObjectSyncStatusResponse struct {
	ObjectId   string    `json:"objectId"`
	State      string    `json:"state"`
	LastSyncAt time.Time `json:"lastSyncAt"`
}

ObjectSyncStatusResponse is the wire shape of Space.SyncStatus().Object(objectId). Unknown ids return State = "unknown" with a zero LastSyncAt — same contract as the SDK.

type ObjectsCreateResponse

type ObjectsCreateResponse struct {
	ObjectId string `json:"objectId"`
}

ObjectsCreateResponse is the body returned by POST /v1/spaces/:spaceId/objects. The SDK currently surfaces only the new object id; a richer info object will follow when the SDK exposes one.

type Op

type Op struct {
	Type  string `json:"type" enums:"$set,$unset,$inc,$addToSet,$pull"`
	Path  string `json:"path,omitempty"`
	Value any    `json:"value,omitempty"`
}

Op documents one operation in a modify batch.

type OpRejection

type OpRejection struct {
	RecordIndex int    `json:"recordIndex"`
	RecordId    string `json:"recordId,omitempty"`
	OpIndex     int    `json:"opIndex"`
	Reason      string `json:"reason"`
}

OpRejection mirrors space.OpRejection 1:1 on the wire. RecordIndex and OpIndex are positional; RecordId resolves the auto-derived id for empty-id records; Reason is human-readable text from the handler. OpIndex == -1 means the whole record was rejected (BeforeCreate / BeforeDelete).

type P2PPeerStatus

type P2PPeerStatus struct {
	PeerId    string   `json:"peerId"`
	SpaceIds  []string `json:"spaceIds"`
	Connected bool     `json:"connected"`
	// Sources that know the peer: "lan", "global" (a space's records),
	// "account" (this account's own device record), in any
	// combination. A peer in the top-level list always carries at
	// least "lan", and one in global.peers may also carry it — a
	// device on the same LAN that a space's records also name appears
	// in both lists, so presence under global is not proof that
	// traffic is relayed.
	Sources []string `json:"sources,omitempty"`
	// LastSeen is the newest liveness evidence — a record heartbeat or
	// a local connection. Zero for LAN-only peers.
	LastSeen *time.Time `json:"lastSeen,omitempty"`
	// Tier derived from LastSeen: active, stale, dormant, disabled. It
	// sets how often the peer is dialed. Empty for LAN-only peers.
	Tier string `json:"tier,omitempty"`
	// Failures counts consecutive failed global dials.
	Failures int `json:"failures,omitempty"`
}

P2PPeerStatus is one discovered peer. SpaceIds is the union over every source that knows the peer: for a LAN-only peer, the spaces it PROVED it shares in the space exchange (the handshake reveals only the intersection of the two space sets, not everything the peer holds); for a peer also known through records, the spaces those records name as well. Read Sources before treating the set as the LAN handshake's proof.

type P2PStatusResponse

type P2PStatusResponse struct {
	// PeerId is THIS device's peer id. Devices of one account must
	// each have a distinct peerId — devices sharing one cannot pair.
	PeerId          string          `json:"peerId"`
	Enabled         bool            `json:"enabled"`
	ListenerStarted bool            `json:"listenerStarted"`
	Port            int             `json:"port"`
	Possibility     string          `json:"possibility"`
	State           string          `json:"state"`
	Peers           []P2PPeerStatus `json:"peers"`
	// LocalDiscovery is the mDNS switch (PUT /v1/local-discovery): false
	// means announce and browse are off and Possibility reads `disabled`.
	// Distinct from Enabled, the p2p.enabled config opt-out fixed at
	// boot, which also takes the QUIC listener down.
	LocalDiscovery bool `json:"localDiscovery"`
	// Global is the internet-wide layer (iroh over the relays).
	Global GlobalP2PStatus `json:"global"`
}

P2PStatusResponse is the wire shape of SDK.P2PStatus() — the account-wide snapshot of both direct layers: the local network (the top-level fields) and the internet-wide one (global). Diagnostic; the per-space p2p state lives in SpaceSyncStatusResponse (p2p / localPeers).

Possibility is one of: unknown, possible, nointerfaces, restricted, disabled. State is one of: unknown, notpossible, notconnected, connected, restricted; it is connected when ANY direct peer is, LAN or global.

type PartDefResponse

type PartDefResponse struct {
	Id       string               `json:"id"`
	Key      string               `json:"key"`
	Name     string               `json:"name,omitempty"`
	Icon     string               `json:"icon,omitempty"`
	Pos      string               `json:"pos,omitempty"`
	Hidden   bool                 `json:"hidden,omitempty"`
	UI       json.RawMessage      `json:"ui,omitempty"`
	Uses     []string             `json:"uses,omitempty"`
	Datasets []DatasetDefResponse `json:"datasets"`
}

PartDefResponse mirrors space.PartDef — the compiled view of one part.

type PartDraftRequest

type PartDraftRequest struct {
	// Key is the part's slug ([a-z][a-z0-9_]*, ≤ 64), unique within the
	// type — pinned.
	Key string `json:"key"`
	// Name / Icon / Pos are the display slice; clients sort parts by
	// pos. Hidden parts are not shown by default but stay revealable.
	Name   string `json:"name,omitempty"`
	Icon   string `json:"icon,omitempty"`
	Pos    string `json:"pos,omitempty"`
	Hidden bool   `json:"hidden,omitempty"`
	// UI is the widget descriptor — {type, config} in the xFormat shape
	// (v1 slugs: document, chat, table, list, board, gallery, chart,
	// properties; open set, an unknown slug renders the module default).
	// Written whole.
	UI json.RawMessage `json:"ui,omitempty"`
	// Uses names other datasets OF THIS TYPE the part renders without
	// owning them (dataset keys).
	Uses []string `json:"uses,omitempty"`
	// Datasets are the part's initial dataset declarations.
	Datasets []DatasetDraftRequest `json:"datasets,omitempty"`
}

PartDraftRequest is the body of POST /v1/spaces/:spaceId/types/:typeId/parts and one element of a bundle ensure's `parts`. Mirrors space.PartDraft: a display unit of the type owning one or more datasets. The key is pinned; the display slice patches via PATCH …/parts/:partId; datasets evolve via POST …/parts/:partId/datasets.

type PartPatchRequest

type PartPatchRequest struct {
	Set   map[string]json.RawMessage `json:"set,omitempty" swaggertype:"object"`
	Unset []string                   `json:"unset,omitempty"`
}

PartPatchRequest is the body of PATCH /v1/spaces/:spaceId/types/:typeId/parts/:partId — a per-path patch over the part's mutable leaves: name, icon, pos (strings), hidden (boolean), ui (an object, replaced whole), uses (an array of dataset keys). The key is pinned → 400 dataset.immutable. At least one entry across Set/Unset required.

type PeerSyncStats

type PeerSyncStats struct {
	PeerId     string    `json:"peerId"`
	LastSyncAt time.Time `json:"lastSyncAt"`
	New        int       `json:"new"`
	Changed    int       `json:"changed"`
	LastErr    string    `json:"lastErr,omitempty"`
}

PeerSyncStats mirrors space.PeerSyncStats. New + Changed are post-deletionState counts handed to the SDK's TreeSyncer (trees we'll actually pull / push). LastErr is omitted when the last round succeeded.

type Process

type Process struct {
	Identity  string        `json:"identity"`
	Self      bool          `json:"self"`
	Id        string        `json:"id"`
	Kind      string        `json:"kind"`
	Title     string        `json:"title"`
	Scope     string        `json:"scope"`
	SpaceId   string        `json:"spaceId,omitempty"`
	Target    string        `json:"target,omitempty"`
	State     string        `json:"state"`
	Done      int64         `json:"done"`
	Total     int64         `json:"total,omitempty"`
	Message   string        `json:"message,omitempty"`
	Error     *ProcessError `json:"error,omitempty"`
	StartedAt int64         `json:"startedAt"`
	UpdatedAt int64         `json:"updatedAt"`
}

Process is one row of the live process view (GET /v1/processes) — the server's last-event-wins picture of a long-running operation built from `process.*` events on the event bus. Nothing is persisted: a server restart forgets every process, remote processes materialize from their periodic broadcasts, and entries expire when their owner stops heartbeating. See docs/22-processes.md.

Processes are keyed (identity, id): id uniqueness is publisher-local, and identity comes from the server-stamped (for network scopes signature-verified) event sender — a remote peer can neither collide with nor spoof another publisher's process. Self is true when the process belongs to this account (any of its devices).

Scope/SpaceId/Target mirror the registering envelope: scope is where the process broadcasts (device/account/space), Target is the process's subject (objectId, runId, …) — distinct from the envelope target, which carries the process id. State is one of the ProcessState* values; Error is set when State is failed. Done/Total are the owner's progress counters (Total 0 = unknown).

StartedAt/UpdatedAt are unix seconds of local observation — this device's clock, not the owner's. Display/expiry quality only.

type ProcessCancelRequest

type ProcessCancelRequest struct {
	Identity string `json:"identity,omitempty"`
}

ProcessCancelRequest is the body of POST /v1/processes/:id/cancel. Identity disambiguates when more than one publisher runs a process with the same id (the composite key); with a single match it may be omitted. Strict-bound.

type ProcessError

type ProcessError struct {
	Code    string `json:"code,omitempty"`
	Message string `json:"message"`
}

ProcessError is the terminal failure payload of a process — carried by the process.failed event and surfaced on the failed Process row.

type ProcessFinishRequest

type ProcessFinishRequest struct {
	Status string        `json:"status"`
	Error  *ProcessError `json:"error,omitempty"`
}

ProcessFinishRequest is the body of POST /v1/processes/:id/finish. Status is done, failed or cancelled; Error is required iff failed. Strict-bound.

type ProcessListResponse

type ProcessListResponse struct {
	Processes []Process `json:"processes"`
}

ProcessListResponse is the body of GET /v1/processes — the live view, expired entries swept.

type ProcessProgressRequest

type ProcessProgressRequest struct {
	Done    *int64  `json:"done,omitempty"`
	Total   *int64  `json:"total,omitempty"`
	Message *string `json:"message,omitempty"`
}

ProcessProgressRequest is the body of POST /v1/processes/:id/progress. Every field is optional: an absent field keeps its current value (the server folds the stored state into the emitted frame), an explicit value sets it — total 0 back to unknown, message "" blank. A bare {} is therefore a pure heartbeat. Done/Total are free-unit counters; Message is a short human-readable status line. Owners re-POST progress at least every 15s even when idle — a running process not heard from for 45s expires from the view. Strict-bound.

type ProcessRegisterRequest

type ProcessRegisterRequest struct {
	Id      string `json:"id"`
	Kind    string `json:"kind"`
	Title   string `json:"title"`
	Scope   string `json:"scope"`
	SpaceId string `json:"spaceId,omitempty"`
	Target  string `json:"target,omitempty"`
}

ProcessRegisterRequest is the body of POST /v1/processes. Id names the process (publisher-local uniqueness; the event-target grammar [A-Za-z0-9._-]{1,128} applies — it becomes a topic segment). Re-registering an id restarts the process view. Scope routes the broadcasts (device/account/space; SpaceId required iff space); Target optionally names the process's subject. Strict-bound.

type PropertiesGetResponse

type PropertiesGetResponse struct {
	Record json.RawMessage `json:"record"`
}

PropertiesGetResponse is the body of GET /v1/spaces/:spaceId/properties/:objectId. Record is the property record rendered as JSON — *anyenc.Value converted via FastJson(arena).MarshalTo. Carried as RawMessage so it is not double-encoded.

type PropertiesListResponse

type PropertiesListResponse struct {
	Properties []PropertyDef `json:"properties"`
}

PropertiesListResponse is the body of GET /v1/spaces/:spaceId/types/:typeId/properties.

type PropertiesSetRequest

type PropertiesSetRequest struct {
	Patch map[string]any `json:"patch"`
}

PropertiesSetRequest documents the body of POST /v1/spaces/:spaceId/properties/:objectId/set/:typeId.

type PropertyDef

type PropertyDef struct {
	Id          string `json:"id"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	XKey        string `json:"xKey,omitempty"`
	Kind        string `json:"kind"`
	// Meta is the consumer flag map (meta["index"] for the search
	// indexer).
	Meta map[string]string `json:"meta,omitempty"`
	// Scope is the property's write/sync class (synced / derived /
	// account / local). Definitions written before scopes existed
	// read back as "synced".
	Scope      string        `json:"scope,omitempty"`
	Items      *PropertyDef  `json:"items,omitempty"`
	Properties []PropertyDef `json:"properties,omitempty"`
	Required   []string      `json:"required,omitempty"`
	// XFormat is the descriptor as stored — absent for a property that
	// never declared one, which renders structurally from Kind.
	XFormat json.RawMessage `json:"xFormat,omitempty"`
}

PropertyDef mirrors space.PropertyDef on the wire. Recursive Items / Properties fields and Required are emitted only when populated.

type PropertyPatchRequest

type PropertyPatchRequest struct {
	Set   map[string]json.RawMessage `json:"set,omitempty" swaggertype:"object"`
	Unset []string                   `json:"unset,omitempty"`
}

PropertyPatchRequest is the body of PATCH /v1/spaces/:spaceId/types/:typeId/properties/:propId — a generic per-path patch to a property definition (space.PropertyPatch). Set assigns values at dotted field paths; Unset removes them (a whole option subtree, e.g. "xFormat.options.high", is unset by naming it).

Mutable paths: name, description, xKey, meta.index, and every path under xFormat. A set targets a leaf — never an object, so a container (options, options.<key>, relation, config, the whole bag) can only be unset, not replaced. Pinned paths (kind, scope, items, properties) are rejected with 400 property.immutable. At least one entry across Set/Unset required.

type PushSubscription

type PushSubscription struct {
	SpaceKey string `json:"spaceKey"`
	Topic    string `json:"topic"`
}

PushSubscription is one row of GET /v1/push/subscriptions: the base58-encoded space push PUBLIC key (the push server's space identifier — not a spaceId) and the subscribed topic string. Signatures are never returned by the server.

type PushSubscriptionsResponse

type PushSubscriptionsResponse struct {
	Subscriptions []PushSubscription `json:"subscriptions"`
}

PushSubscriptionsResponse is the body of GET /v1/push/subscriptions — the account's topic set as the push server holds it.

type PushTokenSetRequest

type PushTokenSetRequest struct {
	Platform string `json:"platform"`
	Token    string `json:"token"`
}

PushTokenSetRequest is the body of POST /v1/push/token: this device's mobile push transport ("ios" | "android" — the push server's platform enum has no desktop entry, so desktop/headless servers are send-only) and the opaque APNs/FCM token the shell obtained. Re-POST on token rotation; DELETE on logout.

type PushTokenStatus

type PushTokenStatus struct {
	Registered bool   `json:"registered"`
	Platform   string `json:"platform,omitempty"`
}

PushTokenStatus is the body of GET /v1/push/token — the LOCAL registration state (does a persisted token exist on this device, and for which platform). No push-node round trip.

type QueryBodyParams

type QueryBodyParams struct {
	// Filter is a mongo-style condition over record fields; omitted or
	// empty matches every record. Operator grammar: docs/09-query.md
	// (a bad operator answers 400 filter.unknown_operator listing the
	// full set).
	Filter map[string]any `json:"filter,omitempty"`
	// Sort lists field paths, "-" prefix for descending (e.g.
	// "-createdAt"). Required when limit > 0 on subscribe, so the
	// window is well-defined.
	Sort []string `json:"sort,omitempty"`
	// Limit bounds the window; 0 or absent = unbounded.
	Limit int `json:"limit,omitempty"`
	// Offset skips past the first N matches of the sorted result.
	Offset int `json:"offset,omitempty"`
	// IncludeTotal populates `total` (every match, regardless of
	// limit/offset) + `hasNext` in the snapshot reply.
	IncludeTotal bool `json:"includeTotal,omitempty"`
	// MailboxCapacity (subscribe only) sizes the event mailbox before
	// the stream closes with reason "overflow". Default 256, min 16.
	MailboxCapacity int `json:"mailboxCapacity,omitempty"`
	// DriftBudgetPercent (subscribe only) bounds window drift before
	// the stream closes with reason "drifted". Default 30.
	DriftBudgetPercent int `json:"driftBudgetPercent,omitempty"`
	// Projection shapes the records that come back, mongo-style: a flat
	// object of dotted field paths to 1 (include) or -1 (exclude).
	// `{"any":1,"nav":1}` is include mode — nothing but those subtrees;
	// `{"_ver":-1}` is exclude mode — every user field but that one.
	// Omitted, records ship their full form. Three rules worth knowing:
	// `id` always rides along and cannot be excluded, `_ver` is narrowed
	// to the projection automatically (never name a `_ver` path), and
	// `_addSeq`/`_applySeq` drop unless named. Full grammar and the
	// divergences from mongo: docs/09-query.md § Projection.
	Projection map[string]int `json:"projection,omitempty"`
}

QueryBodyParams is the shared windowed query/subscribe vocabulary — the exact top-level field set every query surface accepts beyond its own addressing extras (objectId / dataset). It is AUTHORITATIVE, not doc-only: the server derives its strict unknown-field rejection from these json tags (jsonFieldNames in internal/server), so a field absent here is a field the server 400s. Keep it in lockstep with applyQueryParams.

type QueryResponse

type QueryResponse struct {
	Records []json.RawMessage `json:"records"`
	Total   *int              `json:"total,omitempty"`
	HasNext *bool             `json:"hasNext,omitempty"`
}

QueryResponse is the body of POST /v1/spaces/:spaceId/query and POST /v1/spaces/:spaceId/objects/query — both use Query.Snapshot under the hood. Each record is a *anyenc.Value rendered as JSON via FastJson(arena).MarshalTo. Carried as RawMessage so the outer envelope is not double-encoded.

Total is the unbounded filter-matching count (independent of limit/offset), populated only when the request body sets includeTotal=true. Pointer so the field is omitted when the caller didn't ask (`null` would be misleading; absent is unambiguous), and an explicit zero still survives the round trip.

HasNext reports whether more filter-matching records exist past this page (offset+len(records) < total). The SDK derives it from the same count, so it is meaningful only when includeTotal=true — gated on the same flag and omitted otherwise (when unknown the SDK forces it false, which would falsely read as "no more pages").

type QuerySubscribeEvent

type QuerySubscribeEvent struct {
	VersionId string                 `json:"versionId"`
	Added     []QuerySubscribeRecord `json:"added,omitempty"`
	Updated   []QuerySubscribeRecord `json:"updated,omitempty"`
	Removed   []RemovedRecord        `json:"removed,omitempty"`
}

QuerySubscribeEvent is one batch of windowed transitions delivered in an `event: changes` SSE frame. It groups every record-level change observed during one CRDT apply:

  • Added — records that entered the visible window.
  • Updated — records already in the window whose state changed.
  • Removed — records that left the visible window, each tagged with a Reason. Branch on reason=="deleted" to drop the object for good (it's tombstoned); "filtered-out" and "displaced" mean the record left your result set but still exists, so a fresh Snapshot would return it.

VersionId is the per-change DAG order of the underlying CRDT apply. Useful for fence-and-replay semantics ("I've processed up to X — discard ≤ X"). VersionIds are locally-scoped (each peer assigns its own); don't compare across peers.

Total is intentionally absent — the windowed engine does not maintain a live counter. Callers who need a refreshed count call Snapshot again.

type QuerySubscribeRecord

type QuerySubscribeRecord struct {
	Id  string             `json:"id"`
	Doc json.RawMessage    `json:"doc"`
	Ops []SubscribeEventOp `json:"ops,omitempty"`
}

QuerySubscribeRecord is one record's worth of state inside a QuerySubscribeEvent's Added / Updated slices. Doc is the full post-apply JSON value (safe to retain past the event). Ops carries the per-field $set / $unset ops from the triggering change — same shape as SubscribeEventOp on the raw stream, so callers can apply atomic updates against a local mirror without re-materialising the whole record.

Under a request `projection`, both halves are shaped and Ops can come back EMPTY — every op of the triggering change fell outside the projection, so nothing the caller holds changed. Treat an empty Ops as "no visible change", never as "re-materialise from Doc": Doc is authoritative either way.

type QuerySubscribeSnapshot

type QuerySubscribeSnapshot struct {
	Records []json.RawMessage `json:"records"`
	Total   *int              `json:"total,omitempty"`
	HasNext *bool             `json:"hasNext,omitempty"`
}

QuerySubscribeSnapshot is the data payload of the `event: snapshot` frame on a query/subscribe stream. It mirrors QueryResponse — the same point-in-time materialised window the bare Snapshot endpoint returns. Carried as its own type so future extensions (e.g. cursor) can land here without entangling Snapshot's HTTP shape.

type RecordModify

type RecordModify struct {
	Id     string `json:"id,omitempty"`
	Upsert bool   `json:"upsert,omitempty"`
	Ops    []Op   `json:"ops"`
}

RecordModify documents one record in a modify batch.

type RemovedRecord

type RemovedRecord struct {
	Id     string `json:"id"`
	Reason string `json:"reason"`
}

RemovedRecord is one id that left the visible window, tagged with the cause. Reason is one of:

  • "deleted" — the record was tombstoned; it no longer exists. Drop it from local state for good.
  • "filtered-out" — an update changed a field so the query's filter no longer matches. The record still exists.
  • "displaced" — a higher-priority arrival (or the record's own sort-key change) pushed it past the Limit boundary. Still matches the filter; just outside the window.

Only "deleted" means the object is gone; for the other two a fresh Snapshot would still return it.

type SearchHit

type SearchHit struct {
	Scope    string `json:"scope"`
	ObjectId string `json:"objectId"`
	Dataset  string `json:"dataset"`
	RecordId string `json:"recordId"`
	// Chunk is the 0-based chunk of the record this hit shows: long
	// records are indexed as several docs, and the hit is the record's
	// best-ranked one. One hit per record — no client-side dedupe.
	Chunk int `json:"chunk,omitempty"`
	// Data is the hit's indexed text, windowed to MaxData runes around
	// the first matching term. DataOffset is the window's rune offset
	// into the chunk's full indexed text and DataTotal that text's rune
	// length — Data is the whole text iff DataOffset == 0 and
	// len([]rune(Data)) == DataTotal.
	Data       string  `json:"data"`
	DataOffset int     `json:"dataOffset,omitempty"`
	DataTotal  int     `json:"dataTotal"`
	Score      float64 `json:"score"`
	// Passages are the record's next best matching chunks. Absent when
	// the request did not ask (SearchRequest.Passages) and when the
	// record has no other matching chunk in the search window.
	Passages []SearchPassage `json:"passages,omitempty"`
}

SearchHit is one ranked result — the indexed record's identity plus its indexed text. Score semantics depend on the effective mode: BM25 for fts, cosine similarity for vector, RRF for hybrid; within one response higher is always better.

type SearchPassage

type SearchPassage struct {
	Chunk      int     `json:"chunk,omitempty"`
	Data       string  `json:"data"`
	DataOffset int     `json:"dataOffset,omitempty"`
	DataTotal  int     `json:"dataTotal"`
	Score      float64 `json:"score"`
}

SearchPassage is one further matching chunk of a hit's record, with the same Data window fields as the hit.

type SearchRequest

type SearchRequest struct {
	// Query is the search text. Required.
	Query string `json:"query"`
	// Scopes restricts results to the given index scopes (basic, chat,
	// props, …). Empty = all scopes.
	Scopes []string `json:"scopes,omitempty"`
	// Limit caps returned records — every hit is a distinct
	// (objectId, dataset, recordId). Default 10, max 100.
	Limit int `json:"limit,omitempty"`
	// Mode is hybrid (default), fts, or vector. Vector requires an
	// embedder configured on the server.
	Mode string `json:"mode,omitempty"`
	// Require / Exclude are extra must / must-not terms ($require /
	// $exclude) — a hit must contain every Require term and no Exclude
	// term, in every mode: the FTS leg matches on them, and vector hits
	// are post-filtered against the FTS index before fusion. Each term
	// may be a "phrase" or prefix*.
	Require []string `json:"require,omitempty"`
	Exclude []string `json:"exclude,omitempty"`
	// MaxData bounds each hit's Data to a window of at most this many
	// runes around the first query/require term match (the head when
	// nothing matches). 0 = DefaultSearchMaxData; -1 = the whole indexed
	// chunk text. DataOffset / DataTotal on the hit locate the window.
	MaxData int `json:"maxData,omitempty"`
	// Passages asks for up to this many further matching chunks per
	// record, best first, on hit.passages (0 = none, max 10). They are
	// the record's other chunks that ranked within the search window,
	// not every chunk of the record.
	Passages int `json:"passages,omitempty"`
	// Filter keeps only hits whose host object matches this condition,
	// in the /objects/query filter grammar verbatim (any.type,
	// any.collections, <ownerId>.<propId>, modifiedAt, …), in every mode — like Require /
	// Exclude. The object's live row is checked, so a property write is
	// honored at once. Limit still counts matching records. An object
	// with no row never matches.
	Filter json.RawMessage `json:"filter,omitempty"`
}

SearchRequest is the body of POST /v1/spaces/:spaceId/search. The search runs over the server's local index (see docs/13-index.md).

type SearchResponse

type SearchResponse struct {
	Hits []SearchHit `json:"hits"`
	Mode string      `json:"mode"`
	// VectorStatus: used | unavailable | disabled | skipped — whether
	// semantic recall participated in this response and, if not, why.
	VectorStatus string `json:"vectorStatus"`
	// Truncated is set when a leg's read budget under Filter ended and
	// the page holds fewer than Limit records: the index may hold
	// matches the reply cannot show. Absent without a filter. A Filter
	// no object satisfies answers empty without running a leg
	// (VectorStatus then reads skipped, or disabled without an embedder).
	Truncated bool `json:"truncated,omitempty"`
}

SearchResponse is the reply. Mode reports the mode that actually ran: a hybrid request degrades to "fts" when no embedder is configured or the query embedding failed — VectorStatus says which of those it was.

type SearchText

type SearchText []string

SearchText is the search `text` mapping's wire form: a bare field key or a non-empty array of field keys (the indexer joins the mapped values into one body). A single key marshals as the bare string, so single-field declarations and discovery output keep the canonical scalar shape. An empty string unmarshals to nil ("no text mapping"); an empty array stays a non-nil empty slice so declaration validation can reject it explicitly.

func (SearchText) MarshalJSON

func (t SearchText) MarshalJSON() ([]byte, error)

func (*SearchText) UnmarshalJSON

func (t *SearchText) UnmarshalJSON(data []byte) error

type SpaceAggregateObjectsRequest

type SpaceAggregateObjectsRequest struct {
	Pipeline         []map[string]any `json:"pipeline"`
	GroupLimit       *int             `json:"groupLimit,omitempty"`
	AccumArrayLimit  *int             `json:"accumArrayLimit,omitempty"`
	MemoryLimitBytes *int             `json:"memoryLimitBytes,omitempty"`
	Explain          bool             `json:"explain,omitempty"`
}

SpaceAggregateObjectsRequest documents the body of POST /v1/spaces/:spaceId/objects/aggregate.

type SpaceAggregateRequest

type SpaceAggregateRequest struct {
	ObjectId         string           `json:"objectId"`
	Dataset          string           `json:"dataset"`
	Pipeline         []map[string]any `json:"pipeline"`
	GroupLimit       *int             `json:"groupLimit,omitempty"`
	AccumArrayLimit  *int             `json:"accumArrayLimit,omitempty"`
	MemoryLimitBytes *int             `json:"memoryLimitBytes,omitempty"`
	Explain          bool             `json:"explain,omitempty"`
}

SpaceAggregateRequest documents the body of POST /v1/spaces/:spaceId/aggregate.

type SpaceBacklinks struct {
	SpaceId   string `json:"spaceId"`
	Object    []Link `json:"object"`
	Parts     []Link `json:"parts"`
	Truncated bool   `json:"truncated,omitempty"`
}

SpaceBacklinks is one space's share of an account-wide read.

type SpaceCreateRequest

type SpaceCreateRequest struct {
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	IconCID     string `json:"iconCid,omitempty"`
	SpaceType   string `json:"spaceType,omitempty"`
}

SpaceCreateRequest is the body of POST /v1/spaces. Mirrors space.CreateRequest.

type SpaceDebugResponse

type SpaceDebugResponse struct {
	SpaceId string          `json:"spaceId"`
	Peers   []PeerSyncStats `json:"peers"`
}

SpaceDebugResponse is the wire shape of Space.Debug().Space(). In-memory only — peers reset on server restart, so Peers is empty until at least one diff round has completed against a responsible peer.

type SpaceInfo

type SpaceInfo struct {
	Id                 string         `json:"id"`
	Type               string         `json:"type,omitempty"`
	SpaceType          string         `json:"spaceType,omitempty"`
	Author             string         `json:"author,omitempty"`
	Name               string         `json:"name,omitempty"`
	Description        string         `json:"description,omitempty"`
	IconCID            string         `json:"iconCid,omitempty"`
	Status             string         `json:"status"`
	OwnRole            string         `json:"ownRole" enums:"owner,admin,writer,reader,guest,none"`
	CreatedAt          time.Time      `json:"createdAt"`
	Settings           map[string]any `json:"settings,omitempty"`
	SpaceIndexObjectId string         `json:"spaceIndexObjectId,omitempty"`
	Push               *SpacePushKeys `json:"push,omitempty"`
	// Derived marks a space created by the account's own derivation
	// (POST /v1/spaces/derived/:name or another consumer of the SDK's
	// Derive). Derived spaces are permanent — DELETE refuses them with
	// 409 space.derived_undeletable. Absent on created / joined / 1-1
	// spaces.
	Derived bool `json:"derived,omitempty"`
}

SpaceInfo is the wire shape for space.SpaceInfo. Status and OwnRole are rendered as strings rather than the SDK's uint8 enums; see SpaceStatus / SpacePermission for the mapping.

OwnRole is the caller's own role in the space, mirrored from ACL state by the SDK (one pass at space load + one per applied ACL record, so permission changes land as row updates). Present on list rows and single-space responses alike. "none" doubles as "not mirrored yet" — treat it as unknown/no-access, with GET …/members/me as the authoritative per-space read. On a 1-1 space participants report "writer", never "owner" (the ACL owner is a synthetic shared key).

SpaceIndexObjectId is the deterministic id of the in-space `spaceIndex` derived object — stable across peers, useful for clients that want to attach a subscribe stream for live metadata updates. Omitted when the server can't resolve a Space handle for this row (e.g. tombstoned entries in `GET /v1/spaces`).

SpaceType is the app-level classification tag (read from the in-space spaceIndex), distinct from the on-wire header Type: 1-1 spaces carry "any.onetoone", created spaces "any.space". Use it to filter direct chats vs regular spaces client-side. Author is the space owner's account identity, resolved best-effort from the ACL (empty when the ACL isn't loadable). Settings is the account-private, client-owned per-space settings object (free-form keys, scalar values — numbers surface as JSON numbers/float64). Written per key via PATCH /v1/spaces/:spaceId/settings; synced across the account's own devices through the tech space, never visible to other members. Omitted when never written.

Push is the space's push-notification key material (see docs/20-push.md § Receiver-side keys), mirrored from ACL state so a mobile client can cache it and decrypt push payloads while `any` is not running. Populated on list rows AND single-space responses (it's a plain row field — no space load needed); omitted until the SDK's per-space mirror has run, e.g. on a joiner whose access is still pending. Rotation (encKey/encKeyId change) is observed live on the `POST /v1/spaces/query/subscribe` stream.

type SpaceJoinRequest

type SpaceJoinRequest struct {
	InviteToken string          `json:"inviteToken"`
	Metadata    AccountMetadata `json:"metadata,omitempty"`
}

SpaceJoinRequest is the body of POST /v1/spaces/join. Mirrors space.JoinRequest.

type SpaceListQueryRequest

type SpaceListQueryRequest struct {
	// Dataset defaults to "spaces"; "profile" is the only other
	// reachable value (closed allowlist — identities is deliberately
	// excluded, read it via GET /v1/identities).
	Dataset string `json:"dataset,omitempty" enums:"spaces,profile"`
	QueryBodyParams
}

SpaceListQueryRequest documents the body of POST /v1/spaces/query[/subscribe] — the account's tech-space rows. Unlike SpaceQueryRequest there is NO objectId: the target object is fixed server-side to the tech-space index.

type SpaceListResponse

type SpaceListResponse struct {
	Spaces []SpaceInfo `json:"spaces"`
}

SpaceListResponse is the body of GET /v1/spaces.

type SpaceModifyRequest

type SpaceModifyRequest struct {
	ObjectId string         `json:"objectId"`
	Dataset  string         `json:"dataset"`
	Records  []RecordModify `json:"records"`
	TraceIds []string       `json:"traceIds,omitempty"`
	// Scope selects the write route: "synced" (default — the object's
	// own DAG change) or "local" (device-only materialization for
	// fields the dataset schema declares local-scope; explicit record
	// ids, no upsert, no traceIds). See docs/03-api.md § Modify records.
	Scope string `json:"scope,omitempty" enums:"synced,local"`
}

SpaceModifyRequest documents the body of POST /v1/spaces/:spaceId/modify.

type SpaceOneToOneRequest

type SpaceOneToOneRequest struct {
	OtherIdentity string `json:"otherIdentity"`
}

SpaceOneToOneRequest is the body of POST /v1/spaces/one-to-one. The single field mirrors the arg of Service.OneToOne — the other party's account identity (the `id` from their GET /v1/account), exchanged out-of-band. Derivation is symmetric: both peers calling with each other's identity land on the same spaceId.

type SpacePushKeys

type SpacePushKeys struct {
	SpaceKey string `json:"spaceKey"`
	EncKey   string `json:"encKey"`
	EncKeyId string `json:"encKeyId"`
}

SpacePushKeys is the per-space key material a push RECEIVER caches — the wire twin of the SDK's space.PushKeys, byte-compatible with anytype-heart's spacePushNotificationKey / spacePushNotificationEncryptionKey space-view details.

SpaceKey is base64(std) of the protobuf-marshalled ed25519 private key identifying the space on the push server. EncKey is base64(std) of the raw AES payload key derived from the CURRENT ACL read key; EncKeyId is hex(sha256(raw EncKey bytes)) — the value an incoming push carries as its KeyId. Clients keep an append-only per-space {encKeyId → encKey} cache: EncKey rotates with the ACL read key, and payloads encrypted before a rotation still arrive under the old id. Holding EncKey decrypts push payloads only (one-way derivation from the read key), never space data.

type SpaceQueryObjectsRequest

type SpaceQueryObjectsRequest struct {
	QueryBodyParams
}

SpaceQueryObjectsRequest documents the body of POST /v1/spaces/:spaceId/objects/query[/subscribe] and the per-object files query — surfaces addressed entirely by the path.

type SpaceQueryRequest

type SpaceQueryRequest struct {
	// ObjectId names the object whose dataset is queried. Required.
	ObjectId string `json:"objectId"`
	// Dataset names the per-object dataset (chat_messages,
	// editor_blocks, …). Required.
	Dataset string `json:"dataset"`
	// IncludeDeleted (snapshot only) returns the dataset's record-level
	// tombstones next to the live rows: `{id, _deletedAt, _ver, …}`
	// with the content wiped. Lets a writer of an `id: user` dataset
	// find the highest id ever used — a deleted id is burned, so the
	// live maximum is not the next free one. Refused on `/subscribe`
	// (400 request.invalid_field); the other query surfaces reject it
	// as an unknown field (a deleted OBJECT is purged, not tombstoned).
	IncludeDeleted bool `json:"includeDeleted,omitempty"`
	QueryBodyParams
}

SpaceQueryRequest documents the body of POST /v1/spaces/:spaceId/query[/subscribe] — one object's dataset, addressed in the body.

type SpaceRegisterIncomingRequest

type SpaceRegisterIncomingRequest struct {
	PeerIdentity string          `json:"peerIdentity"`
	DisplayHint  AccountMetadata `json:"displayHint,omitempty"`
}

SpaceRegisterIncomingRequest is the body of POST /v1/spaces/one-to-one/register-incoming. Mirrors Service.RegisterIncoming: drop an out-of-band incoming 1-1 request (the app learned of the peer's intent through its own channel) into a device-local `one_to_one_pending` row for the user to approve, without materializing storage. DisplayHint is an optional name/icon snapshot for the UI. No-op if a row for the derived space already exists.

type SpaceSettingsPatchRequest

type SpaceSettingsPatchRequest struct {
	Set   map[string]any `json:"set,omitempty"`
	Unset []string       `json:"unset,omitempty"`
}

SpaceSettingsPatchRequest is the body of PATCH /v1/spaces/:spaceId/settings — a per-key patch of the account-private `settings` object on the space's tech-space row (deliberately separate from PATCH /v1/spaces/:spaceId, which writes the member-replicated name/description/icon). Keys are the caller's vocabulary: non-empty, dot-free (single level under `settings`). Values are scalars — string, number, or bool. At least one set or unset entry is required; a key may not appear in both. Works on any row the account knows, deleted/tombstoned included.

type SpaceSyncStatusResponse

type SpaceSyncStatusResponse struct {
	SpaceId      string    `json:"spaceId"`
	State        string    `json:"state"`
	Synced       int       `json:"synced"`
	Total        int       `json:"total"`
	NetworkPeers int       `json:"networkPeers"`
	LocalPeers   int       `json:"localPeers"`
	GlobalPeers  int       `json:"globalPeers"`
	P2P          string    `json:"p2p"`
	LastSyncedAt time.Time `json:"lastSyncedAt"`
}

SpaceSyncStatusResponse is the wire shape of Space.SyncStatus().Space() — the rolled-up sync state for one space. Cheap to read; safe to poll on a render tick.

State is one of: unknown, offline, syncing, synced, error. Synced / Total count regular objects (excluding ACL / settings / spaceIndex / members system trees). The three peer counts are the paths this space is syncing over right now: NetworkPeers the responsible sync nodes, LocalPeers the LAN peers, GlobalPeers the internet-wide direct peers (relayed or hole-punched), each with a live connection. P2P summarizes the two direct counts as one of: unknown, notpossible, notconnected, connected, restricted.

type SpaceUpdateRequest

type SpaceUpdateRequest struct {
	Name        *string `json:"name,omitempty"`
	Description *string `json:"description,omitempty"`
	IconCID     *string `json:"iconCid,omitempty"`
}

SpaceUpdateRequest is the body of PATCH /v1/spaces/:spaceId. Pointer semantics mirror space.SetMetadataRequest: a nil field is leave-unchanged; a non-nil pointer to an empty string sets the field to empty. spaceType is intentionally not patchable — it's pinned by the initial Create. At least one of Name, Description, or IconCID must be present; an all-empty body returns 400 request.missing_field.

type SubscribeClosed

type SubscribeClosed struct {
	Reason string `json:"reason"`
}

SubscribeClosed is the data payload of the terminal `event: closed` frame. Reason is one of the SubscribeClosed* constants.

type SubscribeEventOp

type SubscribeEventOp struct {
	Type    string          `json:"type"`
	Path    []string        `json:"path"`
	Payload json.RawMessage `json:"payload,omitempty"`
}

SubscribeEventOp is one $set or $unset op the SDK emits to subscribers (windowed Query.Subscribe or — historically — the raw apply stream). $inc / $addToSet / $pull / $incGated are projected to the post-apply value as $set / $unset before delivery, so a thin client without a CRDT engine can apply Ops naively.

Path is the dotted-segment field path, always a JSON array on the wire (never `null` — an empty array `[]` means the record root). On $set, an empty Path activates the multi-field form: Payload is an object whose top-level keys are themselves dot-separated paths to assign at. Payload is the JSON-shaped post-apply value for $set, omitted for $unset.

type SubscribeReady

type SubscribeReady struct{}

SubscribeReady is the data payload of the initial `event: ready` SSE frame on every subscribe-shaped endpoint (query/subscribe, members/subscribe, sync-status/subscribe). Empty in v1; reserved so the wire shape doesn't change when we add fields.

type SyncStatusLagged

type SyncStatusLagged struct {
	Total uint64 `json:"total"`
}

SyncStatusLagged is the data payload of an `event: lagged` frame on a sync-status subscribe stream. Emitted when the server's per-subscriber forwarder dropped a state event because the consumer fell behind. State-flip events are sparse, so this should be rare; when it happens the client should re-GET the current status to resync.

type SyncStatusReady

type SyncStatusReady struct{}

SyncStatusReady is the data payload of the initial `event: ready` frame on /sync-status subscribe streams. Empty in v1; reserved so future additive fields don't break the wire shape.

type TypeDatasetsListResponse

type TypeDatasetsListResponse struct {
	Datasets []DatasetDefResponse `json:"datasets"`
}

TypeDatasetsListResponse is the body of GET /v1/spaces/:spaceId/types/:typeId/datasets — every dataset of every part, flat.

type TypeInfo

type TypeInfo struct {
	Id          string `json:"id"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	IconCID     string `json:"iconCid,omitempty"`
	// XKey is the stable, caller-side programmatic key. For builtin/registered
	// types it equals Id (a clean literal like "chat"); for user types it's
	// the value set at create (or derived from Name by the client). Clients use
	// it as the stable type handle in dotted property paths.
	XKey    string `json:"xKey,omitempty"`
	BuiltIn bool   `json:"builtIn,omitempty"`
	// Layout — see TypesCreateRequest. Absent on built-ins.
	Layout json.RawMessage `json:"layout,omitempty"`
	// Hidden / Meta — see TypesCreateRequest. GET …/types omits hidden
	// types unless includeHidden=true.
	Hidden bool           `json:"hidden,omitempty"`
	Meta   map[string]any `json:"meta,omitempty"`
}

TypeInfo mirrors space.TypeInfo on the wire.

type TypePartsListResponse

type TypePartsListResponse struct {
	Parts []PartDefResponse `json:"parts"`
}

TypePartsListResponse is the body of GET /v1/spaces/:spaceId/types/:typeId/parts.

type TypePatchRequest

type TypePatchRequest struct {
	Name        *string         `json:"name,omitempty"`
	Description *string         `json:"description,omitempty"`
	IconCID     *string         `json:"iconCid,omitempty"`
	Layout      json.RawMessage `json:"layout,omitempty"`
	Hidden      *bool           `json:"hidden,omitempty"`
	Meta        map[string]any  `json:"meta,omitempty"`
}

TypePatchRequest is the body of PATCH /v1/spaces/:spaceId/types/:typeId — a user type's display and rendering metadata. Absent fields keep their value; an empty string clears a text field; `"layout": null` clears the layout (the generated schema shows the object form only — swag cannot express a nullable object). `meta` patches the flag bag per key: a scalar sets the key, `null` unsets it, keys not named are untouched. At least one field is required.

type TypesCreateRequest

type TypesCreateRequest struct {
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	IconCID     string `json:"iconCid,omitempty"`
	// XKey is the stable, caller-side programmatic key for the type
	// (e.g. "agent_memory"). REQUIRED on create and unique per space: the
	// server rejects an empty xKey (type.xkey_required) and one that
	// collides with an existing type's xKey or id (type.xkey_conflict).
	// Clients derive it as a slug of Name. It's the only human handle a
	// type resolves by — the display Name is not a resolution key.
	XKey string `json:"xKey,omitempty"`
	// Layout is how the type's header and parts compose — {type,
	// config} in the xFormat shape (v1 slugs: page, tabs, chat, profile;
	// open set, unknown renders as page). Mutable via PATCH
	// …/types/:typeId.
	Layout json.RawMessage `json:"layout,omitempty"`
	// Hidden keeps the type out of GET …/types by default (pass
	// includeHidden=true to list it) and out of a client's pickers;
	// GET …/types/:typeId always resolves it. Meta is the open bag of
	// consumer flags — one string, bool or number per single-level key
	// (no '.', no '$', ≤64 bytes), written per key so concurrent
	// writers merge; opaque to the server. Both mutable via PATCH.
	Hidden bool           `json:"hidden,omitempty"`
	Meta   map[string]any `json:"meta,omitempty"`
}

TypesCreateRequest is the body of POST /v1/spaces/:spaceId/types. Mirrors space.TypeCreateParams.

type TypesCreateResponse

type TypesCreateResponse struct {
	TypeId string `json:"typeId"`
}

TypesCreateResponse is the body returned by POST /v1/spaces/:spaceId/types.

type TypesListResponse

type TypesListResponse struct {
	Types []TypeInfo `json:"types"`
}

TypesListResponse is the body of GET /v1/spaces/:spaceId/types.

type UpsertRecord

type UpsertRecord struct {
	Id     string         `json:"id"`
	Fields map[string]any `json:"fields"`
}

UpsertRecord is one row: the caller-supplied record id plus the desired field values (top-level field → value).

type UpsertRejection

type UpsertRejection struct {
	Index  int    `json:"index"`
	Id     string `json:"id,omitempty"`
	Code   string `json:"code"`
	Reason string `json:"reason"`
}

UpsertRejection reports one rejected record. Code is a stable machine code: upsert.immutable_field, upsert.not_author, upsert.record_deleted, or upsert.rejected (creation screening — missing required field, id pattern/length violation, undeclared field, stamped-field write — with the specific cause in reason).

type UpsertRequest

type UpsertRequest struct {
	ObjectId string         `json:"objectId"`
	Dataset  string         `json:"dataset"`
	Records  []UpsertRecord `json:"records"`
	// PageSize caps records per emitted change. 0 = 500.
	PageSize int      `json:"pageSize,omitempty"`
	TraceIds []string `json:"traceIds,omitempty"`
}

UpsertRequest is the body of POST /v1/spaces/:spaceId/upsert — schema-driven batch ingest into an id:user dataset (space.UpsertBatch). Per record: absent id ⇒ created; present ⇒ only declared-mutable fields are diffed, changed ones written per-path, identical records skipped; a differing write-once field ⇒ whole-record rejection. The record id is the idempotency key — re-running an identical batch is a no-op. Not transactional against concurrent writers: intended deployment is a single ingest writer per dataset.

type UpsertResult

type UpsertResult struct {
	Pages      []ModifyResult    `json:"pages"`
	Created    int               `json:"created"`
	Updated    int               `json:"updated"`
	Skipped    int               `json:"skipped"`
	Rejections []UpsertRejection `json:"rejections,omitempty"`
}

UpsertResult mirrors space.UpsertResult. Pages holds one ModifyResult per emitted change, in page order (pages with nothing to write are absent). Rejections is the partial-success list — the call still returns 200; counters cover the records that landed.

Jump to

Keyboard shortcuts

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