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
- Variables
- func CloneXFormat(m map[string]any) map[string]any
- func CollectionName(typeId, key string) string
- func DatasetHeadIds(ctx context.Context, db anystore.DB, typeId, key string) ([]string, error)
- func DatasetHeadKey(ctx context.Context, db anystore.DB, typeId, defId string) (string, error)
- func DecodeXFormat(v *anyenc.Value) map[string]any
- func EncodeDataVersion(pairs []DataVersionPair) string
- func HasDatasetDefs(ctx context.Context, db anystore.DB, typeId string) (bool, error)
- func PartIds(ctx context.Context, db anystore.DB, typeId, key string) ([]string, error)
- type CompiledDataset
- type CompiledPart
- type CompiledType
- type DataVersionPair
- type LiveRegistry
- func (r *LiveRegistry) KnownShortId(ctx context.Context, typeId, shortId string) (bool, error)
- func (r *LiveRegistry) LatestShortId(ctx context.Context, typeId string) (string, error)
- func (r *LiveRegistry) LookupKind(typeId, propId string) (schema.Kind, bool)
- func (r *LiveRegistry) PropsOf(typeId string) ([]PropInfo, bool)
- func (r *LiveRegistry) TypeKnown(typeId string) bool
- type ModuleInfo
- type Modules
- type PropInfo
- type Registry
- type StubRegistry
- func (s StubRegistry) LookupKind(typeId, propId string) (schema.Kind, bool)
- func (s StubRegistry) PropsOf(typeId string) ([]PropInfo, bool)
- func (s *StubRegistry) Set(typeId, propId string, kind schema.Kind)
- func (s *StubRegistry) SetScoped(typeId, propId string, kind schema.Kind, scope schema.Scope)
- func (s StubRegistry) TypeKnown(typeId string) bool
Constants ¶
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 ¶
var ErrInvalidDataVersion = errors.New("types: invalid DataVersion")
ErrInvalidDataVersion is returned by ParseDataVersion when the input doesn't match `typeId:shortId[;...]`.
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 ¶
CloneXFormat deep-copies a descriptor so a public view never aliases the caller's (or a registration's) nested maps and slices.
func CollectionName ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.
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
// 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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.
type PropInfo ¶
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 ¶
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 ¶
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.
Source Files
¶
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. |