types

package
v0.4.3 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package types owns the types-and-properties machinery: the per-space Registry, the built-in `any` and `type` type objects, property definition schemas, schema compilation from property records, and the typePropertyHandler (implements crdt.Handler).

The Registry is the single place that:

  • caches compiled schemas per typeId
  • tracks the known-shortIds set per type (the DataVersion gate)
  • persists the per-space detached-changes collection
  • resolves x-key → propId lookups
  • emits OnShortIdAdded so higher layers can drain detached changes

Not public — space.TypesAPI wraps the registry for caller use. See docs/data-structure.md §"Types, Properties & Data Schemas" and docs/types-properties-proposal.md.

Index

Constants

View Source
const RecordsModule = "records"

RecordsModule is the built-in generic module: a schema-enforced dataset with no canonical collection, always namespaced. Every other module is caller-registered (config.Config.Modules).

Variables

View Source
var ErrInvalidDataVersion = errors.New("types: invalid DataVersion")

ErrInvalidDataVersion is returned by ParseDataVersion when the input doesn't match `typeId:shortId[;...]`.

View Source
var ErrUnknownModule = errors.New("types: unknown module")

ErrUnknownModule marks a dataset declaring a module this SDK does not carry. The definition compiles Invalid: visible, never registered.

Functions

func CloneXFormat

func CloneXFormat(m map[string]any) map[string]any

CloneXFormat deep-copies a descriptor so a public view never aliases the caller's (or a registration's) nested maps and slices.

func CollectionName

func CollectionName(typeId, key string) string

CollectionName is the namespaced collection of one dataset: the declaring type's id and the dataset key joined by `_`. Type ids are content-addressed CIDs without `_`, so the first `_` always splits.

func DatasetHeadIds

func DatasetHeadIds(ctx context.Context, db anystore.DB, typeId, key string) ([]string, error)

DatasetHeadIds lists the live head record ids declaring key on the type object — the winner and every concurrent duplicate the compile layer hides. Nil when the type has no datasets collection.

func DatasetHeadKey

func DatasetHeadKey(ctx context.Context, db anystore.DB, typeId, defId string) (string, error)

DatasetHeadKey resolves a live head record's dataset key by its record id — the winner OR a hidden concurrent duplicate. Empty when the id names no live head. Removal by a stale DefId (read before convergence) resolves its key here so the whole dataset goes, not just the hidden duplicate.

func DecodeXFormat

func DecodeXFormat(v *anyenc.Value) map[string]any

DecodeXFormat reads a stored `x-format` object into plain Go values — nested objects as map[string]any, arrays as []any, numbers as float64, instants as time.Time, binaries as []byte, object ids as their hex string, float vectors as []float64 — for the public definition views. Nil for an absent, non-object or empty value. The bag is opaque: no key is interpreted here.

func EncodeDataVersion

func EncodeDataVersion(pairs []DataVersionPair) string

EncodeDataVersion joins the pairs into wire form. Pairs whose ShortId is empty are skipped — a missing shortId means the type has had no important changes yet, so there's nothing to gate on. Returns "" when every pair was empty.

func HasDatasetDefs

func HasDatasetDefs(ctx context.Context, db anystore.DB, typeId string) (bool, error)

HasDatasetDefs reports whether anything was ever declared on the type object — live or tombstoned records alike (a tombstone keeps no fields, so a removed part is known only by its presence). False when the type has no datasets collection.

func PartIds

func PartIds(ctx context.Context, db anystore.DB, typeId, key string) ([]string, error)

PartIds lists the live part record ids declaring key on the type object — the winner and every concurrent duplicate.

Types

type CompiledDataset

type CompiledDataset struct {
	// Name is the dataset's collection name — the module's canonical
	// collection for a shared dataset, `<typeId>_<key>` otherwise.
	Name string
	// Key is the dataset's slug inside its type; for a shared dataset
	// it equals the canonical collection name.
	Key string
	// Module is the module serving the dataset (`records` for the
	// generic schema-enforced kind).
	Module string
	// Shared marks a dataset that participates in the module's
	// canonical collection instead of a namespaced one.
	Shared bool
	// PartId is the owning part record's id.
	PartId string
	// DefId is the head record's id — the definition's stable identity.
	DefId string
	// TypeId is the declaring type object.
	TypeId string
	// Schema is the compiled declaration the generic schema handler
	// enforces. Empty for a module-served dataset — the module owns the
	// schema.
	Schema schema.Dataset
	// SkipHistory mirrors the head's skipHistory flag.
	SkipHistory bool
	// Search mirrors the head's search annotation (also inside Schema).
	Search *schema.SearchFields
	// DisplayName / Description are the head's mutable display fields.
	DisplayName string
	Description string
	// SchemaRev fingerprints the compiled declaration. A controller
	// registered with an older rev (a field added/removed since it was
	// built) is stale and gets lazily evicted; identical declarations
	// on every peer produce the identical rev.
	SchemaRev string
	// Invalid marks a definition whose folded declaration fails
	// validation (e.g. author rules without a creator stamp — a
	// cross-record fact no record-local handler check can see — or an
	// unknown module). Invalid definitions never register or accept
	// data, but they stay VISIBLE so the management API can repair or
	// remove them — otherwise their key would wedge unreachably.
	Invalid       bool
	InvalidReason string
	// FieldDefIds are the field records' ids, aligned with
	// Schema.Fields — the identities RemoveDatasetField targets.
	FieldDefIds []string
}

CompiledDataset is one dataset declaration folded out of a type object's `datasets` records.

func CompileDatasetDefs

func CompileDatasetDefs(ctx context.Context, db anystore.DB, typeId string, modules Modules) ([]CompiledDataset, error)

CompileDatasetDefs is the flat dataset view of CompileTypeParts — every dataset of every part, in collection order.

type CompiledPart

type CompiledPart struct {
	Id     string // the part record's id
	Key    string
	TypeId string
	Name   string
	Icon   string
	Pos    string
	Hidden bool
	UI     map[string]any
	Uses   []string
	// Datasets are the part's datasets in key order, invalid ones
	// included (flagged).
	Datasets []CompiledDataset
}

CompiledPart is one part folded out of a type object's records: the display slice plus the datasets declared under it.

type CompiledType

type CompiledType struct {
	Parts    []CompiledPart
	Datasets []CompiledDataset
}

CompiledType is a type's parts and the flat view over their datasets.

func CompileTypeParts

func CompileTypeParts(ctx context.Context, db anystore.DB, typeId string, modules Modules) (*CompiledType, error)

CompileTypeParts folds a type object's `datasets` records into parts and dataset declarations — one storage pass, deterministic on converged records:

  • tombstoned records are skipped;
  • duplicate part keys fold into one: display from the smallest creation `_ver.id`, datasets and `uses` unioned;
  • a head whose part is absent, or a field whose head is absent, is an orphan and is skipped;
  • duplicate dataset keys within the type name the same collection by construction: the smallest creation `_ver.id` is the definition's identity and display, fields union by key across every head (smallest `_ver.id` per key), and a disagreement on a pinned leaf marks the definition invalid;
  • `_ver.id` comparison is sound within one tree: orderId VALUES are peer-local but their relative order converges, so every replica picks the same winner;
  • the collection rule (Modules.Collection) decides the collection; an unknown module or a shared violation marks the definition invalid; a type declaring two shared datasets of one module keeps the smallest `_ver.id` and marks the rest invalid;
  • a module-served dataset carries no fields (the module owns the schema): field records under it are orphans;
  • a `records` dataset whose folded declaration fails ValidateDatasetDecl is emitted with Invalid set: visible for repair/removal, never registered.

Returns (nil, nil) when the type has no datasets collection.

type DataVersionPair

type DataVersionPair struct {
	TypeId  string
	ShortId string
}

DataVersionPair is one (typeId, shortId) entry inside a DataVersion.

func ParseDataVersion

func ParseDataVersion(s string) ([]DataVersionPair, error)

ParseDataVersion splits a wire-format DataVersion into its pairs. Empty input yields nil, no error — the gate treats that as "no schema constraints attached to this change". Returns ErrInvalidDataVersion on malformed input.

type LiveRegistry

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

LiveRegistry is the real Registry: it answers kind / shortId lookups by reading the per-type-object collections on the SDK DB.

No in-memory caching in v1 — every lookup hits any-store. Cheap for the gate (single FindId by id) and avoids invalidation bookkeeping. Add caching with an event-driven invalidation when the gate's hot path benchmarks demand it.

Naming convention: collections are `<typeId>/properties` (defs) and `<typeId>/shortIds` (sibling). Both are written by typetype.PropertyHandler at apply time.

func NewLiveRegistry

func NewLiveRegistry(db anystore.DB, static map[string]map[string]PropInfo) *LiveRegistry

NewLiveRegistry returns a Registry bound to the given SDK DB and a static schema overlay (built-ins + registered external types). Pass a nil db to disable collection lookups (overlay-only, e.g. equivalent to StubRegistry{} for user types); pass a nil overlay for none.

func (*LiveRegistry) KnownShortId

func (r *LiveRegistry) KnownShortId(ctx context.Context, typeId, shortId string) (bool, error)

KnownShortId reports whether the type's shortIds dataset has a row with id = shortId. The shortId row itself is added or removed by typetype.PropertyHandler on every "important" change to the type's properties dataset.

func (*LiveRegistry) LatestShortId

func (r *LiveRegistry) LatestShortId(ctx context.Context, typeId string) (string, error)

LatestShortId returns the lexicographically-greatest `_ver.id` from the type's shortIds dataset. The lex-monotonic VersionId allocator guarantees this is the most-recently-applied important change.

Returns ("", nil) when the type has had no important changes yet (e.g. a type with no properties). Callers stamp DataVersion as empty in that case.

func (*LiveRegistry) LookupKind

func (r *LiveRegistry) LookupKind(typeId, propId string) (schema.Kind, bool)

LookupKind resolves the declared kind of (typeId, propId): from the static overlay when typeId is a built-in / registered type, otherwise from the type's `properties` defs collection. Returns (KindUnknown, false) when the type, the property, or the kind is absent.

func (*LiveRegistry) PropsOf

func (r *LiveRegistry) PropsOf(typeId string) ([]PropInfo, bool)

PropsOf returns the declared properties of typeId — from the static overlay, or by scanning the defs collection for a user type. ok is false only when neither source resolves (unknown type). An empty, existing type resolves as (nil, true).

func (*LiveRegistry) TypeKnown

func (r *LiveRegistry) TypeKnown(typeId string) bool

TypeKnown reports whether a schema source exists for typeId: the static overlay (built-in / registered) or a materialised `<typeId>_properties` defs collection (a user type with at least one important change). Used by the writer-side validator to tell "type not here yet" apart from "type known, property unknown".

type ModuleInfo

type ModuleInfo struct {
	Name       string
	Canonical  string
	SharedOnly bool
	Reserved   bool
}

ModuleInfo is what the compiler needs to know about a module: its name, the shared collection it owns (empty = none), whether it admits namespaced instances, and whether runtime declarations may name it at all (Reserved — a draft-time refusal; the compile keeps an applied declaration valid).

type Modules

type Modules map[string]ModuleInfo

Modules is the module catalog keyed by name. Always carries the built-in records module.

func NewModules

func NewModules(infos ...ModuleInfo) Modules

NewModules builds a catalog from the caller's modules plus records.

func (Modules) Collection

func (m Modules) Collection(typeId, key, module string, shared bool) (string, error)

Collection applies the collection rule to one declaration: a shared dataset is the module's canonical collection, anything else is namespaced under the declaring type. The error names the rule the declaration violates.

func (Modules) Reserved

func (m Modules) Reserved(module string) bool

Reserved reports whether module is registered as reserved. Unknown modules are not — Collection reports them.

type PropInfo

type PropInfo struct {
	Id    string
	Name  string
	Kind  schema.Kind
	Scope schema.Scope
}

PropInfo is one declared property: its id, display name, kind, and write/sync scope. Returned by PropsOf for validation and error formatting. A zero Scope reads as ScopeSynced (definitions written before scopes existed carry no scope field).

func (PropInfo) EffectiveScope

func (p PropInfo) EffectiveScope() schema.Scope

EffectiveScope normalizes the zero value to ScopeSynced — the scope every pre-scope definition implicitly had.

type Registry

type Registry interface {
	// LookupKind returns the declared kind of the property with the
	// given (typeId, propId). Returns (KindUnknown, false) if either
	// the type or the property is unknown to this registry.
	LookupKind(typeId, propId string) (schema.Kind, bool)

	// TypeKnown reports whether a schema for typeId is resolvable —
	// a built-in (any / spaceIndex), a registered external type, or a
	// user type whose property defs have synced. Distinguishes
	// "type not implemented / not here yet" from "type known, property
	// unknown" so the writer-side validator can produce a precise
	// rejection.
	TypeKnown(typeId string) bool

	// PropsOf returns the declared properties of typeId for validation
	// and for building agent-readable error messages (valid-property
	// lists). ok is false when the type is unresolvable.
	PropsOf(typeId string) (props []PropInfo, ok bool)
}

Registry resolves (typeId, propId) to the property's declared schema kind. The full Registry will also expose x-key lookups, the known- shortIds set, and detached-changes drainage; for v1 only the kind-lookup surface is needed by the property handler.

Implementations:

  • real: built from per-space type-object trees on space open; compiled schemas are cached, invalidated by type-object changes.
  • StubRegistry (registry_stub.go): hand-stuffed map for tests.

A handler depending on the Registry takes a Registry value at construction; nil means "no validation" (the handler skips kind checks). This lets callers wire the handler before the type system is available, and adopts validation later.

type StubRegistry

type StubRegistry struct {
	// Kinds[typeId][propId] = declared kind.
	Kinds map[string]map[string]schema.Kind
	// Scopes[typeId][propId] = declared scope. Optional — absent
	// entries read as the zero value (ScopeSynced via
	// PropInfo.EffectiveScope), matching pre-scope definitions.
	Scopes map[string]map[string]schema.Scope
}

StubRegistry is a hand-stuffed Registry for tests and bring-up of downstream packages that need a concrete value before the real Registry exists. Not safe for concurrent writes after first use.

func (StubRegistry) LookupKind

func (s StubRegistry) LookupKind(typeId, propId string) (schema.Kind, bool)

func (StubRegistry) PropsOf

func (s StubRegistry) PropsOf(typeId string) ([]PropInfo, bool)

PropsOf returns the stub's declared properties for typeId. Names are empty (the stub stores kinds and scopes only). ok mirrors TypeKnown.

func (*StubRegistry) Set

func (s *StubRegistry) Set(typeId, propId string, kind schema.Kind)

Set adds or overwrites a property entry. Useful for incremental test setup: r.Set("any", "name", schema.KindString).

func (*StubRegistry) SetScoped

func (s *StubRegistry) SetScoped(typeId, propId string, kind schema.Kind, scope schema.Scope)

SetScoped adds or overwrites a property entry with an explicit scope.

func (StubRegistry) TypeKnown

func (s StubRegistry) TypeKnown(typeId string) bool

TypeKnown reports whether the stub has any entry for typeId.

Directories

Path Synopsis
Package anytype is the built-in `any` type — the universal shape every object in a space implements: name, description, icon (synced, CRDT-mutable), plus id, author, spaceId, createdAt, modifiedAt, modifiedBy (derived, read-only, stamped from any-sync context).
Package anytype is the built-in `any` type — the universal shape every object in a space implements: name, description, icon (synced, CRDT-mutable), plus id, author, spaceId, createdAt, modifiedAt, modifiedBy (derived, read-only, stamped from any-sync context).
Package collectiontype is the built-in `collection` meta-type — the shape of collection objects.
Package collectiontype is the built-in `collection` meta-type — the shape of collection objects.
Package spaceindex is the built-in `spaceIndex` type — one derived object per space carrying the space's display metadata (name, description, icon, spaceType) as CRDT-mutable base-scope properties.
Package spaceindex is the built-in `spaceIndex` type — one derived object per space carrying the space's display metadata (name, description, icon, spaceType) as CRDT-mutable base-scope properties.
Package typetype is the built-in `type` meta-type — the shape of type objects themselves.
Package typetype is the built-in `type` meta-type — the shape of type objects themselves.

Jump to

Keyboard shortcuts

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