Documentation
¶
Index ¶
- Constants
- Variables
- func AutoSnapshotMessage(idleAfter time.Duration) string
- func EvaluateQueryExpression(expr QueryExpr, universe map[string]struct{}, ...) map[string]struct{}
- func EvaluateQueryExpressionWithCompare(expr QueryExpr, universe map[string]struct{}, ...) map[string]struct{}
- func IsBackendError(err error) bool
- func IsConflict(err error) bool
- func IsCoreIndex(name string) bool
- func IsDestinationExists(err error) bool
- func IsInvalidConfig(err error) bool
- func IsPermissionDenied(err error) bool
- func IsRetryable(err error) bool
- func IsSchemaInvalid(err error) bool
- func IsSystemIndex(name string) bool
- func IsTemporary(err error) bool
- func NewAliasNotFoundError(alias string) error
- func NewBackendError(backend, op string, status int, cause error, transient bool) error
- func NewInvalidConfigError(msg string) error
- func NewRateLimitError(retryAfter time.Duration, msg string, cause error) error
- func NewTransientError(cause error) error
- func NormalizeTag(s string) string
- func NormalizeTags(tags []string) []string
- func ParseStatsTime(raw string) time.Time
- func ParseTags(raw string) []string
- func RandomCode(context.Context) string
- func RemoteErrorCode(err error) (code string, status int)
- func RemoteErrorFromCode(code string, status int, msg string) error
- func RenderMarkdown(src []byte, opts RenderOptions) ([]byte, error)
- func RepoContainsKeg(ctx context.Context, repo Repository) (bool, error)
- func ResolveNodeLink(dest string, opts RenderOptions) (string, bool)
- func SchemaFilename(typeName string) (string, error)
- func UpdateConfig(ctx context.Context, k Keg, f func(*Config)) error
- func UpdateMeta(ctx context.Context, k Keg, id NodeId, f func(*NodeMeta)) error
- func ValidSchemaTypeName(typeName string) error
- func ValidateAssetName(name string) error
- func ValidateImage(data []byte) (string, error)
- func ValidationContextFromHeaders(ctx context.Context, header func(string) string) context.Context
- func ValidationHeaderValues(ctx context.Context) map[string]string
- func WithValidationActor(ctx context.Context, actor ValidationActor) context.Context
- func WithValidationMode(ctx context.Context, mode ValidationMode) context.Context
- type AliasNotFoundError
- type AssetKind
- type AssetSummary
- type BackendError
- type BacklinkIndex
- type ChangesIndex
- func (idx *ChangesIndex) Add(ctx context.Context, data *NodeData) error
- func (idx *ChangesIndex) Clear(ctx context.Context) error
- func (idx *ChangesIndex) Data(ctx context.Context) ([]byte, error)
- func (idx ChangesIndex) Entries(ctx context.Context) []NodeIndexEntry
- func (idx *ChangesIndex) Rm(ctx context.Context, node NodeId) error
- type CompareResolver
- type Config
- func (kc *Config) Location() *time.Location
- func (kc *Config) ResolveAlias(alias string) (*Target, error)
- func (kc *Config) SnapshotPolicy() (mode string, idleAfter time.Duration, err error)
- func (kc *Config) String() string
- func (kc *Config) ToJSON() ([]byte, error)
- func (kc *Config) ToYAML() ([]byte, error)
- func (kc *Config) Touch(t time.Time)
- func (kc *Config) UserIndexEntries() []IndexEntry
- type ConfigOption
- type ConfigV1
- type ConfigV2
- type CreateOptions
- type Dex
- func (dex *Dex) Add(ctx context.Context, data *NodeData) error
- func (dex *Dex) Backlinks(ctx context.Context, node NodeId) ([]NodeId, bool)
- func (dex *Dex) Changes(ctx context.Context) []NodeIndexEntry
- func (dex *Dex) Clear(ctx context.Context)
- func (dex *Dex) GetRef(ctx context.Context, id NodeId) *NodeIndexEntry
- func (dex *Dex) Links(ctx context.Context, node NodeId) ([]NodeId, bool)
- func (dex *Dex) NextNode(ctx context.Context) NodeId
- func (dex *Dex) NodeListIndex(ctx context.Context, name string) ([]NodeIndexEntry, bool)
- func (dex *Dex) Nodes(ctx context.Context) []NodeIndexEntry
- func (dex *Dex) Remove(ctx context.Context, node NodeId) error
- func (dex *Dex) TagLinks(ctx context.Context, node NodeId) ([]NodeId, bool)
- func (dex *Dex) TagList(ctx context.Context) []string
- func (dex *Dex) TagNodes(ctx context.Context, tag string) ([]NodeId, bool)
- func (dex *Dex) Write(ctx context.Context, repo Repository) error
- type DexOption
- type ExportNodesOptions
- type FsRepo
- func (f *FsRepo) AcquireLock(ctx context.Context, id NodeId) (LockToken, error)
- func (f *FsRepo) AppendSnapshot(ctx context.Context, id NodeId, in SnapshotWrite) (Snapshot, error)
- func (f *FsRepo) ClearIndexes(ctx context.Context) error
- func (f *FsRepo) ContentFilePath(id NodeId) string
- func (f *FsRepo) DeleteAsset(ctx context.Context, id NodeId, kind AssetKind, name string) error
- func (f *FsRepo) DeleteFile(ctx context.Context, id NodeId, name string) error
- func (f *FsRepo) DeleteImage(ctx context.Context, id NodeId, name string) error
- func (f *FsRepo) DeleteNode(ctx context.Context, id NodeId) error
- func (f *FsRepo) DeleteSchema(ctx context.Context, typeName string) error
- func (f *FsRepo) Emit(ev NodeEvent)
- func (f *FsRepo) ForceReleaseLock(ctx context.Context, id NodeId) error
- func (f *FsRepo) GetIndex(ctx context.Context, name string) ([]byte, error)
- func (f *FsRepo) GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (Snapshot, []byte, []byte, *NodeStats, error)
- func (f *FsRepo) HasNode(ctx context.Context, id NodeId) (bool, error)
- func (f *FsRepo) ListAssets(ctx context.Context, id NodeId, kind AssetKind) ([]string, error)
- func (f *FsRepo) ListFiles(ctx context.Context, id NodeId) ([]string, error)
- func (f *FsRepo) ListImages(ctx context.Context, id NodeId) ([]string, error)
- func (f *FsRepo) ListIndexes(ctx context.Context) ([]string, error)
- func (f *FsRepo) ListNodes(ctx context.Context) ([]NodeId, error)
- func (f *FsRepo) ListSchemas(ctx context.Context) ([]string, error)
- func (f *FsRepo) ListSnapshots(ctx context.Context, id NodeId) ([]Snapshot, error)
- func (f *FsRepo) LockStatus(ctx context.Context, id NodeId) (LockInfo, error)
- func (f *FsRepo) MetaFilePath(id NodeId) string
- func (f *FsRepo) MoveNode(ctx context.Context, id NodeId, dst NodeId) error
- func (f *FsRepo) Name() string
- func (f *FsRepo) Next(ctx context.Context) (NodeId, error)
- func (f *FsRepo) NodeDirPath(id NodeId) string
- func (f *FsRepo) NodeFilesExist(ctx context.Context, id NodeId) (bool, bool, error)
- func (f *FsRepo) ReadConfig(ctx context.Context) (*Config, error)
- func (f *FsRepo) ReadContent(ctx context.Context, id NodeId) ([]byte, error)
- func (f *FsRepo) ReadContentAt(ctx context.Context, id NodeId, rev RevisionID) ([]byte, error)
- func (f *FsRepo) ReadFile(ctx context.Context, id NodeId, name string) ([]byte, error)
- func (f *FsRepo) ReadImage(ctx context.Context, id NodeId, name string) ([]byte, error)
- func (f *FsRepo) ReadMeta(ctx context.Context, id NodeId) ([]byte, error)
- func (f *FsRepo) ReadSchema(ctx context.Context, typeName string) ([]byte, error)
- func (f *FsRepo) ReadStats(ctx context.Context, id NodeId) (*NodeStats, error)
- func (f *FsRepo) ReleaseLock(ctx context.Context, id NodeId, token LockToken) error
- func (f *FsRepo) RestoreSnapshot(ctx context.Context, id NodeId, rev RevisionID, createRestoreSnapshot bool) error
- func (f *FsRepo) Runtime() *toolkit.Runtime
- func (f *FsRepo) Watch(ctx context.Context, ids ...NodeId) (<-chan NodeEvent, error)
- func (f *FsRepo) WithNodeLock(ctx context.Context, id NodeId, fn func(context.Context) error) error
- func (f *FsRepo) WriteAsset(ctx context.Context, id NodeId, kind AssetKind, name string, data []byte) error
- func (f *FsRepo) WriteConfig(ctx context.Context, config *Config) error
- func (f *FsRepo) WriteContent(ctx context.Context, id NodeId, data []byte) error
- func (f *FsRepo) WriteFile(ctx context.Context, id NodeId, name string, data []byte) error
- func (f *FsRepo) WriteImage(ctx context.Context, id NodeId, name string, data []byte) error
- func (f *FsRepo) WriteIndex(ctx context.Context, name string, data []byte) error
- func (f *FsRepo) WriteMeta(ctx context.Context, id NodeId, data []byte) error
- func (f *FsRepo) WriteSchema(ctx context.Context, typeName string, data []byte) error
- func (f *FsRepo) WriteStats(ctx context.Context, id NodeId, stats *NodeStats) error
- type GrepMatch
- type GrepOptions
- type HTTPOption
- type ImportNodesOptions
- type ImportedNode
- type IndexBuilder
- type IndexEntry
- type IndexOptions
- type InvalidConfigError
- type Keg
- type KegOption
- type KegSummary
- type LinkEntry
- type LinkIndex
- type LocalKeg
- func (k *LocalKeg) AppendSnapshot(ctx context.Context, id NodeId, msg string) (Snapshot, error)
- func (k *LocalKeg) Commit(ctx context.Context, id NodeId) error
- func (k *LocalKeg) Config(ctx context.Context) (*Config, error)
- func (k *LocalKeg) Create(ctx context.Context, opts *CreateOptions) (NodeId, error)
- func (k *LocalKeg) DeleteFile(ctx context.Context, id NodeId, name string) error
- func (k *LocalKeg) DeleteImage(ctx context.Context, id NodeId, name string) error
- func (k *LocalKeg) DeleteSchema(ctx context.Context, typeName string) error
- func (k *LocalKeg) Dex(ctx context.Context) (*Dex, error)
- func (k *LocalKeg) ExportNodes(ctx context.Context, opts ExportNodesOptions) (io.ReadCloser, error)
- func (k *LocalKeg) ForceUnlock(ctx context.Context, id NodeId) error
- func (k *LocalKeg) GetContent(ctx context.Context, id NodeId) ([]byte, error)
- func (k *LocalKeg) GetMeta(ctx context.Context, id NodeId) (*NodeMeta, error)
- func (k *LocalKeg) GetMetaRaw(ctx context.Context, id NodeId) ([]byte, error)
- func (k *LocalKeg) GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (Snapshot, []byte, []byte, *NodeStats, error)
- func (k *LocalKeg) GetStats(ctx context.Context, id NodeId) (*NodeStats, error)
- func (k *LocalKeg) Grep(ctx context.Context, opts GrepOptions) ([]GrepMatch, error)
- func (k *LocalKeg) ImportNodes(ctx context.Context, r io.Reader, opts ImportNodesOptions) ([]ImportedNode, error)
- func (k *LocalKeg) Index(ctx context.Context, opts IndexOptions) error
- func (k *LocalKeg) IndexNode(ctx context.Context, id NodeId) error
- func (k *LocalKeg) Init(ctx context.Context) error
- func (k *LocalKeg) InvalidateDex()
- func (k *LocalKeg) ListFiles(ctx context.Context, id NodeId) ([]string, error)
- func (k *LocalKeg) ListImages(ctx context.Context, id NodeId) ([]string, error)
- func (k *LocalKeg) ListIndexes(ctx context.Context) ([]string, error)
- func (k *LocalKeg) ListNodes(ctx context.Context) ([]NodeId, error)
- func (k *LocalKeg) ListSchemas(ctx context.Context) ([]string, error)
- func (k *LocalKeg) ListSnapshots(ctx context.Context, id NodeId) ([]Snapshot, error)
- func (k *LocalKeg) Lock(ctx context.Context, id NodeId) (LockToken, error)
- func (k *LocalKeg) LockStatus(ctx context.Context, id NodeId) (LockInfo, error)
- func (k *LocalKeg) Move(ctx context.Context, src NodeId, dst NodeId) ([]NodeId, error)
- func (k *LocalKeg) Next(ctx context.Context) (NodeId, error)
- func (k *LocalKeg) Node(id NodeId) *Node
- func (k *LocalKeg) NodeExists(ctx context.Context, id NodeId) (bool, error)
- func (k *LocalKeg) Query(ctx context.Context, opts QueryOptions) ([]NodeIndexEntry, error)
- func (k *LocalKeg) ReadContentAt(ctx context.Context, id NodeId, rev RevisionID) ([]byte, error)
- func (k *LocalKeg) ReadFile(ctx context.Context, id NodeId, name string) ([]byte, error)
- func (k *LocalKeg) ReadImage(ctx context.Context, id NodeId, name string) ([]byte, error)
- func (k *LocalKeg) ReadIndex(ctx context.Context, name string) ([]byte, error)
- func (k *LocalKeg) ReadNode(ctx context.Context, id NodeId) (*NodeView, error)
- func (k *LocalKeg) ReadSchema(ctx context.Context, typeName string) ([]byte, error)
- func (k *LocalKeg) Remove(ctx context.Context, id NodeId) ([]NodeId, error)
- func (k *LocalKeg) RestoreSnapshot(ctx context.Context, id NodeId, rev RevisionID) error
- func (k *LocalKeg) RunSnapshotPolicy(ctx context.Context) (SnapshotPolicyResult, error)
- func (k *LocalKeg) SetConfig(ctx context.Context, data []byte) error
- func (k *LocalKeg) SetContent(ctx context.Context, id NodeId, data []byte) error
- func (k *LocalKeg) SetMeta(ctx context.Context, id NodeId, meta *NodeMeta) error
- func (k *LocalKeg) SetTarget(target *Target)
- func (k *LocalKeg) Summary(ctx context.Context) (*KegSummary, error)
- func (k *LocalKeg) Target() *Target
- func (k *LocalKeg) Touch(ctx context.Context, id NodeId) error
- func (k *LocalKeg) Unlock(ctx context.Context, id NodeId, token LockToken) error
- func (k *LocalKeg) UpdateConfig(ctx context.Context, f func(*Config)) error
- func (k *LocalKeg) UpdateMeta(ctx context.Context, id NodeId, f func(*NodeMeta)) error
- func (k *LocalKeg) ValidateNode(ctx context.Context, id NodeId) (*SchemaValidationResult, error)
- func (k *LocalKeg) ValidateNodePayload(ctx context.Context, payload NodeValidationPayload) (*SchemaValidationResult, error)
- func (k *LocalKeg) Watch(ctx context.Context, ids ...NodeId) (<-chan NodeEvent, error)
- func (k *LocalKeg) WriteFile(ctx context.Context, id NodeId, name string, data []byte) error
- func (k *LocalKeg) WriteImage(ctx context.Context, id NodeId, name string, data []byte) error
- func (k *LocalKeg) WriteSchema(ctx context.Context, typeName string, data []byte) error
- type LockInfo
- type LockToken
- type MarkdownSchema
- type MarkdownSection
- type MaturityWeightSchema
- type MemoryRepo
- func (r *MemoryRepo) AcquireLock(ctx context.Context, id NodeId) (LockToken, error)
- func (r *MemoryRepo) AppendSnapshot(ctx context.Context, id NodeId, in SnapshotWrite) (Snapshot, error)
- func (r *MemoryRepo) ClearDex() error
- func (r *MemoryRepo) ClearIndexes(ctx context.Context) error
- func (r *MemoryRepo) ClearNodeLock(ctx context.Context, id NodeId) error
- func (r *MemoryRepo) DeleteAsset(ctx context.Context, id NodeId, kind AssetKind, name string) error
- func (r *MemoryRepo) DeleteFile(ctx context.Context, id NodeId, name string) error
- func (r *MemoryRepo) DeleteImage(ctx context.Context, id NodeId, name string) error
- func (r *MemoryRepo) DeleteNode(ctx context.Context, id NodeId) error
- func (r *MemoryRepo) DeleteSchema(ctx context.Context, typeName string) error
- func (r *MemoryRepo) Emit(ev NodeEvent)
- func (r *MemoryRepo) ForceReleaseLock(ctx context.Context, id NodeId) error
- func (r *MemoryRepo) GetIndex(ctx context.Context, name string) ([]byte, error)
- func (r *MemoryRepo) GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (Snapshot, []byte, []byte, *NodeStats, error)
- func (r *MemoryRepo) HasNode(ctx context.Context, id NodeId) (bool, error)
- func (r *MemoryRepo) ListAssets(ctx context.Context, id NodeId, kind AssetKind) ([]string, error)
- func (r *MemoryRepo) ListFiles(ctx context.Context, id NodeId) ([]string, error)
- func (r *MemoryRepo) ListImages(ctx context.Context, id NodeId) ([]string, error)
- func (r *MemoryRepo) ListIndexes(ctx context.Context) ([]string, error)
- func (r *MemoryRepo) ListNodes(ctx context.Context) ([]NodeId, error)
- func (r *MemoryRepo) ListSchemas(ctx context.Context) ([]string, error)
- func (r *MemoryRepo) ListSnapshots(ctx context.Context, id NodeId) ([]Snapshot, error)
- func (r *MemoryRepo) LockNode(ctx context.Context, id NodeId, retryInterval time.Duration) (func() error, error)
- func (r *MemoryRepo) LockStatus(ctx context.Context, id NodeId) (LockInfo, error)
- func (r *MemoryRepo) MoveNode(ctx context.Context, id NodeId, dst NodeId) error
- func (r *MemoryRepo) Name() string
- func (r *MemoryRepo) Next(ctx context.Context) (NodeId, error)
- func (r *MemoryRepo) NodeFilesExist(ctx context.Context, id NodeId) (bool, bool, error)
- func (r *MemoryRepo) ReadConfig(ctx context.Context) (*Config, error)
- func (r *MemoryRepo) ReadContent(ctx context.Context, id NodeId) ([]byte, error)
- func (r *MemoryRepo) ReadContentAt(ctx context.Context, id NodeId, rev RevisionID) ([]byte, error)
- func (r *MemoryRepo) ReadFile(ctx context.Context, id NodeId, name string) ([]byte, error)
- func (r *MemoryRepo) ReadImage(ctx context.Context, id NodeId, name string) ([]byte, error)
- func (r *MemoryRepo) ReadMeta(ctx context.Context, id NodeId) ([]byte, error)
- func (r *MemoryRepo) ReadSchema(ctx context.Context, typeName string) ([]byte, error)
- func (r *MemoryRepo) ReadStats(ctx context.Context, id NodeId) (*NodeStats, error)
- func (r *MemoryRepo) ReleaseLock(ctx context.Context, id NodeId, token LockToken) error
- func (r *MemoryRepo) RestoreSnapshot(ctx context.Context, id NodeId, rev RevisionID, createRestoreSnapshot bool) error
- func (r *MemoryRepo) Runtime() *toolkit.Runtime
- func (r *MemoryRepo) Watch(ctx context.Context, ids ...NodeId) (<-chan NodeEvent, error)
- func (r *MemoryRepo) WithNodeLock(ctx context.Context, id NodeId, fn func(context.Context) error) error
- func (r *MemoryRepo) WriteAsset(ctx context.Context, id NodeId, kind AssetKind, name string, data []byte) error
- func (r *MemoryRepo) WriteConfig(ctx context.Context, config *Config) error
- func (r *MemoryRepo) WriteContent(ctx context.Context, id NodeId, data []byte) error
- func (r *MemoryRepo) WriteFile(ctx context.Context, id NodeId, name string, data []byte) error
- func (r *MemoryRepo) WriteImage(ctx context.Context, id NodeId, name string, data []byte) error
- func (r *MemoryRepo) WriteIndex(ctx context.Context, name string, data []byte) error
- func (r *MemoryRepo) WriteMeta(ctx context.Context, id NodeId, data []byte) error
- func (r *MemoryRepo) WriteSchema(ctx context.Context, typeName string, data []byte) error
- func (r *MemoryRepo) WriteStats(ctx context.Context, id NodeId, stats *NodeStats) error
- type MetadataMaturitySchema
- type Node
- func (n *Node) Accessed(ctx context.Context) (time.Time, error)
- func (n *Node) Changed(ctx context.Context) (bool, error)
- func (n *Node) ClearCache()
- func (n *Node) Created(ctx context.Context) (time.Time, error)
- func (n *Node) Init(ctx context.Context) error
- func (n *Node) Lead(ctx context.Context) (string, error)
- func (n *Node) Links(ctx context.Context) ([]NodeId, error)
- func (n *Node) ListImages(ctx context.Context) ([]string, error)
- func (n *Node) ListItems(ctx context.Context) ([]string, error)
- func (n *Node) Ref(ctx context.Context) (NodeIndexEntry, error)
- func (n *Node) Save(ctx context.Context) error
- func (n *Node) Stats(ctx context.Context) (*NodeStats, error)
- func (n *Node) String() string
- func (n *Node) Tags(ctx context.Context) ([]string, error)
- func (n *Node) Touch(ctx context.Context) error
- func (n *Node) Update(ctx context.Context) error
- func (n *Node) Updated(ctx context.Context) (time.Time, error)
- type NodeContent
- type NodeData
- func (n *NodeData) Accessed() time.Time
- func (n *NodeData) ContentChanged() bool
- func (n *NodeData) ContentHash() string
- func (n *NodeData) Created() time.Time
- func (n *NodeData) Format() string
- func (n *NodeData) Lead() string
- func (n *NodeData) Links() []NodeId
- func (n *NodeData) MetaHash() string
- func (n *NodeData) Ref() NodeIndexEntry
- func (n *NodeData) Tags() []string
- func (n *NodeData) Title() string
- func (n *NodeData) Touch(ctx context.Context, now *time.Time)
- func (n *NodeData) UpdateMeta(ctx context.Context, now *time.Time) error
- func (n *NodeData) Updated() time.Time
- type NodeEvent
- type NodeEventKind
- type NodeId
- func (n NodeId) Compare(other NodeId) int
- func (n NodeId) Equals(other NodeId) bool
- func (n NodeId) Gt(other NodeId) bool
- func (n NodeId) Gte(other NodeId) bool
- func (n NodeId) Increment() NodeId
- func (n NodeId) Lt(other NodeId) bool
- func (n NodeId) Lte(other NodeId) bool
- func (id NodeId) Path() string
- func (id NodeId) PathNumeric() string
- func (id NodeId) String() string
- func (id NodeId) Valid() bool
- type NodeIndex
- func (idx *NodeIndex) Add(ctx context.Context, data *NodeData) error
- func (idx *NodeIndex) Data(ctx context.Context) ([]byte, error)
- func (idx *NodeIndex) Get(ctx context.Context, node NodeId) *NodeIndexEntry
- func (idx *NodeIndex) List(ctx context.Context) []NodeIndexEntry
- func (idx *NodeIndex) Next(ctx context.Context) NodeId
- func (idx *NodeIndex) Rm(ctx context.Context, node NodeId) error
- type NodeIndexEntry
- type NodeMeta
- func (m *NodeMeta) AddTag(tag string)
- func (m *NodeMeta) Get(key string) (string, bool)
- func (m *NodeMeta) RmTag(tag string)
- func (m *NodeMeta) Set(ctx context.Context, key string, val any) error
- func (m *NodeMeta) SetAttrs(ctx context.Context, attrs map[string]any) error
- func (m *NodeMeta) SetTags(tags []string)
- func (m *NodeMeta) Tags() []string
- func (m *NodeMeta) ToYAML() string
- func (m *NodeMeta) ToYAMLWithStats(stats *NodeStats) string
- type NodeRef
- type NodeStats
- func (s *NodeStats) AccessCount() int
- func (s *NodeStats) Accessed() time.Time
- func (s *NodeStats) ClearOmega()
- func (s *NodeStats) Created() time.Time
- func (s *NodeStats) EnsureTimes(now time.Time)
- func (s *NodeStats) Hash() string
- func (s *NodeStats) IncrementAccessCount()
- func (s *NodeStats) Lead() string
- func (s *NodeStats) Links() []NodeId
- func (s *NodeStats) Omega() (float64, bool)
- func (s *NodeStats) SetAccessCount(count int)
- func (s *NodeStats) SetAccessed(t time.Time)
- func (s *NodeStats) SetCreated(t time.Time)
- func (s *NodeStats) SetHash(hash string, now *time.Time)
- func (s *NodeStats) SetLead(lead string)
- func (s *NodeStats) SetLinks(links []NodeId)
- func (s *NodeStats) SetOmega(omega float64)
- func (s *NodeStats) SetTitle(title string)
- func (s *NodeStats) SetUpdated(t time.Time)
- func (s *NodeStats) Title() string
- func (s *NodeStats) ToJSON() ([]byte, error)
- func (s *NodeStats) UpdateFromContent(content *NodeContent, now *time.Time)
- func (s *NodeStats) UpdateFromSource(rt *toolkit.Runtime, content *NodeContent, meta *NodeMeta, now *time.Time)
- func (s *NodeStats) Updated() time.Time
- type NodeValidationPayload
- type NodeView
- type Option
- type QueryExpr
- type QueryFilteredIndex
- func (idx *QueryFilteredIndex) Add(ctx context.Context, data *NodeData) error
- func (idx *QueryFilteredIndex) Clear(ctx context.Context) error
- func (idx *QueryFilteredIndex) Data(ctx context.Context) ([]byte, error)
- func (idx *QueryFilteredIndex) Name() string
- func (idx *QueryFilteredIndex) Remove(ctx context.Context, node NodeId) error
- type QueryFilteredSortOrder
- type QueryOptions
- type RateLimitError
- type RefForm
- type RelationSchema
- type RemoteKeg
- func (k *RemoteKeg) AppendSnapshot(ctx context.Context, id NodeId, msg string) (Snapshot, error)
- func (k *RemoteKeg) BaseURL() string
- func (k *RemoteKeg) Commit(ctx context.Context, id NodeId) error
- func (k *RemoteKeg) Config(ctx context.Context) (*Config, error)
- func (k *RemoteKeg) Create(ctx context.Context, opts *CreateOptions) (NodeId, error)
- func (k *RemoteKeg) DeleteFile(ctx context.Context, id NodeId, name string) error
- func (k *RemoteKeg) DeleteImage(ctx context.Context, id NodeId, name string) error
- func (k *RemoteKeg) DeleteSchema(ctx context.Context, typeName string) error
- func (k *RemoteKeg) Dex(ctx context.Context) (*Dex, error)
- func (k *RemoteKeg) ExportNodes(ctx context.Context, opts ExportNodesOptions) (io.ReadCloser, error)
- func (k *RemoteKeg) ForceUnlock(ctx context.Context, id NodeId) error
- func (k *RemoteKeg) GetContent(ctx context.Context, id NodeId) ([]byte, error)
- func (k *RemoteKeg) GetMeta(ctx context.Context, id NodeId) (*NodeMeta, error)
- func (k *RemoteKeg) GetMetaRaw(ctx context.Context, id NodeId) ([]byte, error)
- func (k *RemoteKeg) GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (Snapshot, []byte, []byte, *NodeStats, error)
- func (k *RemoteKeg) GetStats(ctx context.Context, id NodeId) (*NodeStats, error)
- func (k *RemoteKeg) Grep(ctx context.Context, opts GrepOptions) ([]GrepMatch, error)
- func (k *RemoteKeg) ImportNodes(ctx context.Context, r io.Reader, opts ImportNodesOptions) ([]ImportedNode, error)
- func (k *RemoteKeg) Index(ctx context.Context, opts IndexOptions) error
- func (k *RemoteKeg) Init(ctx context.Context) error
- func (k *RemoteKeg) ListFiles(ctx context.Context, id NodeId) ([]string, error)
- func (k *RemoteKeg) ListImages(ctx context.Context, id NodeId) ([]string, error)
- func (k *RemoteKeg) ListIndexes(ctx context.Context) ([]string, error)
- func (k *RemoteKeg) ListNodes(ctx context.Context) ([]NodeId, error)
- func (k *RemoteKeg) ListSchemas(ctx context.Context) ([]string, error)
- func (k *RemoteKeg) ListSnapshots(ctx context.Context, id NodeId) ([]Snapshot, error)
- func (k *RemoteKeg) Lock(ctx context.Context, id NodeId) (LockToken, error)
- func (k *RemoteKeg) LockStatus(ctx context.Context, id NodeId) (LockInfo, error)
- func (k *RemoteKeg) Move(ctx context.Context, src NodeId, dst NodeId) ([]NodeId, error)
- func (k *RemoteKeg) Next(ctx context.Context) (NodeId, error)
- func (k *RemoteKeg) NodeExists(ctx context.Context, id NodeId) (bool, error)
- func (k *RemoteKeg) Query(ctx context.Context, opts QueryOptions) ([]NodeIndexEntry, error)
- func (k *RemoteKeg) ReadContentAt(ctx context.Context, id NodeId, rev RevisionID) ([]byte, error)
- func (k *RemoteKeg) ReadFile(ctx context.Context, id NodeId, name string) ([]byte, error)
- func (k *RemoteKeg) ReadImage(ctx context.Context, id NodeId, name string) ([]byte, error)
- func (k *RemoteKeg) ReadIndex(ctx context.Context, name string) ([]byte, error)
- func (k *RemoteKeg) ReadNode(ctx context.Context, id NodeId) (*NodeView, error)
- func (k *RemoteKeg) ReadSchema(ctx context.Context, typeName string) ([]byte, error)
- func (k *RemoteKeg) Remove(ctx context.Context, id NodeId) ([]NodeId, error)
- func (k *RemoteKeg) RestoreSnapshot(ctx context.Context, id NodeId, rev RevisionID) error
- func (k *RemoteKeg) SetConfig(ctx context.Context, data []byte) error
- func (k *RemoteKeg) SetContent(ctx context.Context, id NodeId, data []byte) error
- func (k *RemoteKeg) SetMeta(ctx context.Context, id NodeId, meta *NodeMeta) error
- func (k *RemoteKeg) SetTarget(target *Target)
- func (k *RemoteKeg) SetTokenFn(fn func() string)
- func (k *RemoteKeg) Summary(ctx context.Context) (*KegSummary, error)
- func (k *RemoteKeg) Target() *Target
- func (k *RemoteKeg) Token() string
- func (k *RemoteKeg) Touch(ctx context.Context, id NodeId) error
- func (k *RemoteKeg) Unlock(ctx context.Context, id NodeId, token LockToken) error
- func (k *RemoteKeg) ValidateNode(ctx context.Context, id NodeId) (*SchemaValidationResult, error)
- func (k *RemoteKeg) ValidateNodePayload(ctx context.Context, payload NodeValidationPayload) (*SchemaValidationResult, error)
- func (k *RemoteKeg) Watch(ctx context.Context, ids ...NodeId) (<-chan NodeEvent, error)
- func (k *RemoteKeg) WriteFile(ctx context.Context, id NodeId, name string, data []byte) error
- func (k *RemoteKeg) WriteImage(ctx context.Context, id NodeId, name string, data []byte) error
- func (k *RemoteKeg) WriteSchema(ctx context.Context, typeName string, data []byte) error
- type RenderOptions
- type Repository
- type RepositoryEvents
- type RepositoryFiles
- type RepositoryImages
- type RepositoryLock
- type RepositorySchemas
- type RepositorySnapshots
- type RevisionID
- type SchemaDefinition
- type SchemaPolicy
- type SchemaValidationError
- type SchemaValidationResult
- type Snapshot
- type SnapshotConfig
- type SnapshotContentKind
- type SnapshotContentWrite
- type SnapshotPolicyResult
- type SnapshotReadOptions
- type SnapshotWrite
- type TagIndex
- type Target
- type TargetOption
- type TokenResolver
- type TransientError
- type ValidationActor
- type ValidationIssue
- type ValidationMode
Constants ¶
const ( SnapshotModeAuto = "auto" SnapshotModeOff = "off" DefaultSnapshotIdleAfter = time.Hour )
const ( RemoteCodeNotFound = "NOT_FOUND" RemoteCodeExist = "EXIST" RemoteCodeDestExists = "DEST_EXISTS" RemoteCodeConflict = "CONFLICT" RemoteCodeInvalid = "INVALID" RemoteCodeSchemaInvalid = "SCHEMA_INVALID" RemoteCodeInvalidImage = "INVALID_IMAGE" RemoteCodeLockMismatch = "LOCK_MISMATCH" RemoteCodeNotLocked = "NOT_LOCKED" RemoteCodeLock = "LOCK" RemoteCodeLockTimeout = "LOCK_TIMEOUT" RemoteCodeNotSupported = "NOT_SUPPORTED" RemoteCodeForbidden = "FORBIDDEN" RemoteCodeBadRequest = "BAD_REQUEST" RemoteCodeInternal = "INTERNAL" )
Remote error codes carried in the hub's JSON error envelope ({"error": msg, "code": CODE}). The table below is the single source of truth for both directions: the hub maps sentinel errors to (code, status) when writing a response, and RemoteKeg maps (code, status) back to the sentinel when decoding one. Keep the two sides symmetric.
const ( MarkdownContentFilename = "README.md" YAMLMetaFilename = "meta.yaml" JSONStatsFilename = "stats.json" KegCurrentEnvKey = "KEG_CURRENT" KegLockFile = ".keg-lock" NodeImagesDir = "images" NodeAttachmentsDir = "assets" )
const ( SchemasDir = "schemas" SchemaFileSuffix = ".schema.yaml" // KegSchemaDefinitionSchemaURL is the public JSON Schema used by editor // modelines for keg schema definition YAML. KegSchemaDefinitionSchemaURL = "https://raw.githubusercontent.com/jlrickert/tapper/main/schemas/keg-schema-definition.json" )
const ( RelationDirectionLinks = "links" RelationDirectionBacklinks = "backlinks" )
const ( TimelineIndexName = "timeline" DirtyIndexName = "dirty" )
const ( SchemeMemory = "memory" SchemeFile = "file" SchemeGit = "git" SchemeSSH = "ssh" SchemeHTTP = "http" SchemeHTTPs = "https" SchemeAlias = "keg" SchemeS3 = "s3" )
const DefaultLockTTL = 5 * time.Minute
DefaultLockTTL is the default time-to-live for a cross-process lock.
const (
KegConfigSchemaURL = "https://raw.githubusercontent.com/jlrickert/tapper/main/schemas/keg-config.json"
)
const (
KegCrossLockFile = ".keg-cross-lock"
)
Variables ¶
var ( // ConfigV1VersionString is the initial KEG configuration version identifier. ConfigV1VersionString = "2023-01" // ConfigV2VersionString is the current KEG configuration version identifier. ConfigV2VersionString = "2025-07" // FormatMarkdown is the short format identifier for Markdown content. FormatMarkdown = "markdown" // FormatRST is the short format identifier for reStructuredText content. FormatRST = "rst" )
var ( ErrInvalid = os.ErrInvalid // invalid argument ErrExist = os.ErrExist // file already exists ErrNotExist = os.ErrNotExist // file does not exist ErrPermission = os.ErrPermission // permission denied ErrParse = errors.New("unable to parse") ErrConflict = errors.New("conflict") ErrQuotaExceeded = errors.New("quota exceeded") ErrRateLimited = errors.New("rate limited") ErrNotSupported = errors.New("not supported") ErrSchemaInvalid = errors.New("schema validation failed") // ErrInvalidAssetName is returned when a node asset name is not a single safe // path component (empty, ".", "..", contains a path separator, or absolute). // Such names could let filepath.Join resolve outside the keg root, so they // are rejected at the repository boundary. ErrInvalidAssetName = errors.New("invalid asset name") // ErrDestinationExists is returned when a move/rename cannot proceed because // the destination node id already exists. Prefer returning a typed // DestinationExistsError that unwraps to this sentinel when callers may need // structured information. ErrDestinationExists = errors.New("destination already exists") // ErrLockTimeout indicates acquiring a repository or node lock timed out or // was canceled. Lock-acquiring helpers should wrap context/cancellation // information while preserving this sentinel for callers that need to detect // timeout semantics via errors.Is. ErrLockTimeout = errors.New("lock acquire timeout") // ErrLock indicates a generic failure to acquire a repository or node // lock. Use errors.Is(err, ErrLock) to detect non-timeout lock acquisition // failures. ErrLock = errors.New("cannot acquire lock") )
Sentinel errors used for simple equality-style checks.
var ( // credentials (HTTP 401). ErrUnauthorized = errors.New("unauthorized") // ErrForbidden indicates the authenticated user lacks permission for the // requested operation (HTTP 403). ErrForbidden = errors.New("forbidden") )
Sentinel errors for remote-API-specific failure conditions.
var ErrInvalidImage = errors.New("invalid image")
var ErrLockTokenMismatch = errors.New("lock token mismatch")
ErrLockTokenMismatch indicates the provided token does not match the held lock.
var ErrNotLocked = errors.New("node is not locked")
ErrNotLocked indicates no lock is held on the node.
var RawZeroNodeContent = `` /* 229-byte string literal not displayed */
RawZeroNodeContent is the fallback content used when a node has no content. It serves as a friendly placeholder indicating the content is planned but not yet available. Callers may display this as the node README. If you want the content created sooner, open an issue describing the request.
var StatsFieldNames = []string{
"updated",
"created",
"accessed",
"hash",
"accessCount",
"lead",
"omega",
}
StatsFieldNames lists the dot-prefix stats field names recognized by the query expression parser. These correspond to fields in stats.json and NodeIndexEntry.
Functions ¶
func AutoSnapshotMessage ¶ added in v0.28.0
AutoSnapshotMessage returns the deterministic message used for policy snapshots at a given idle window.
func EvaluateQueryExpression ¶ added in v0.18.0
func EvaluateQueryExpression( expr QueryExpr, universe map[string]struct{}, resolve func(tag string) map[string]struct{}, ) map[string]struct{}
EvaluateQueryExpression evaluates expr against a universe of string identifiers. universe is the full candidate set (e.g. node paths). resolve maps a tag name to the subset of universe that carries that tag. Returns the subset of universe that satisfies the expression.
func EvaluateQueryExpressionWithCompare ¶ added in v0.18.0
func EvaluateQueryExpressionWithCompare( expr QueryExpr, universe map[string]struct{}, resolve func(tag string) map[string]struct{}, resolveCompare CompareResolver, ) map[string]struct{}
EvaluateQueryExpressionWithCompare evaluates expr with full support for dot-prefix stats comparisons. resolveCompare handles ".field op value" predicates. When resolveCompare is nil, dot-prefix comparisons match nothing.
func IsBackendError ¶
IsBackendError reports whether err is (or wraps) a BackendError.
func IsConflict ¶
IsConflict returns true if err is a conflict error.
func IsCoreIndex ¶ added in v0.2.0
IsCoreIndex reports whether the given index file name is one of the built-in protected index names (e.g. "changes.md").
func IsDestinationExists ¶
IsDestinationExists returns true if err represents a destination-exists condition.
func IsInvalidConfig ¶
IsInvalidConfig reports whether err is (or wraps) an invalid-config condition.
func IsPermissionDenied ¶
IsPermissionDenied returns true if err indicates a permission problem.
func IsRetryable ¶
IsRetryable inspects the error chain for a Retryable() bool implementation and returns its result (false if none found).
func IsSchemaInvalid ¶ added in v0.25.0
func IsSystemIndex ¶ added in v0.23.0
IsSystemIndex reports whether name is a required generated index.
func IsTemporary ¶
IsTemporary inspects the error chain for a Temporary() bool implementation and returns its result (false if none found).
func NewAliasNotFoundError ¶
NewAliasNotFoundError constructs a typed AliasNotFoundError.
func NewBackendError ¶
NewBackendError constructs a *BackendError describing an operation against a backend.
func NewInvalidConfigError ¶
NewInvalidConfigError creates an InvalidConfigError with a human message.
func NewRateLimitError ¶
NewRateLimitError constructs a *RateLimitError with a suggested retry duration.
func NewTransientError ¶
NewTransientError constructs a *TransientError wrapping the provided cause.
func NormalizeTag ¶
NormalizeTag normalizeTag lowercases, trims, and tokenizes a tag string into a hyphen-separated token.
func NormalizeTags ¶
func ParseStatsTime ¶ added in v0.18.0
ParseStatsTime parses a time string using the same format layouts accepted by stats.json timestamps: RFC3339Nano, RFC3339, and several date-only and datetime variants. Returns the zero time if raw is empty or unparseable.
func ParseTags ¶
ParseTags accepts a comma/semicolon/newline separated list of tags (or a whitespace-separated string when no explicit separators are present) and returns a normalized, deduplicated, sorted slice of tags.
Behavior: - Trims whitespace around tokens. - Lowercases tokens and converts internal whitespace to hyphens via NormalizeTag. - Splits on commas, semicolons, CR/LF, or newlines when present; otherwise splits on whitespace. - Deduplicates tokens and returns them in lexicographic order.
func RandomCode ¶
func RemoteErrorCode ¶ added in v0.23.0
RemoteErrorCode maps err to its wire (code, status). Unrecognized errors map to (INTERNAL, 500).
func RemoteErrorFromCode ¶ added in v0.23.0
RemoteErrorFromCode maps a wire (code, status, message) back to an error wrapping the matching sentinel. Codes without a sentinel (UNAUTHORIZED, FORBIDDEN, BAD_REQUEST, INTERNAL, unknown) map by status: 401→ ErrUnauthorized, 403→ErrForbidden, 429→RateLimitError, 5xx→ transient BackendError, anything else → a plain error with the message.
func RenderMarkdown ¶ added in v0.11.0
func RenderMarkdown(src []byte, opts RenderOptions) ([]byte, error)
RenderMarkdown converts raw markdown bytes to HTML, rewriting node-relative link and image destinations to site paths per opts. The returned bytes are the inner HTML content (no <html> or <body> wrapper).
func RepoContainsKeg ¶
func RepoContainsKeg(ctx context.Context, repo Repository) (bool, error)
RepoContainsKeg checks if a keg has been properly initialized within a repository. It verifies both that a keg config exists and that a zero node (node ID 0) is present. Returns true only if both conditions are met, indicating a fully initialized keg.
func ResolveNodeLink ¶ added in v0.23.0
func ResolveNodeLink(dest string, opts RenderOptions) (string, bool)
ResolveNodeLink resolves one raw markdown destination against opts. It returns the rewritten destination and true, or ("", false) when the destination should be left unchanged (absolute URLs, fragments, unparseable input, keg: links with no resolver, ...).
func SchemaFilename ¶ added in v0.25.0
func UpdateConfig ¶ added in v0.23.0
UpdateConfig applies f to the keg's configuration via a read-then-set over the Keg interface. Unlike LocalKeg.UpdateConfig this is not atomic — a concurrent writer between the read and the set is lost — which is an accepted trade-off for rare admin operations over remote kegs.
func UpdateMeta ¶ added in v0.23.0
UpdateMeta applies f to a node's metadata via read-then-set over the Keg interface. Not atomic across concurrent writers; see UpdateConfig.
func ValidSchemaTypeName ¶ added in v0.25.0
func ValidateAssetName ¶ added in v0.23.0
ValidateAssetName reports whether name is a single safe node asset filename.
func ValidateImage ¶ added in v0.24.0
ValidateImage decodes data enough to prove it is one of Tapper's supported image formats. It preserves caller bytes; it does not transcode or normalize.
func ValidationContextFromHeaders ¶ added in v0.25.0
func ValidationHeaderValues ¶ added in v0.25.0
func WithValidationActor ¶ added in v0.25.0
func WithValidationActor(ctx context.Context, actor ValidationActor) context.Context
func WithValidationMode ¶ added in v0.25.0
func WithValidationMode(ctx context.Context, mode ValidationMode) context.Context
Types ¶
type AliasNotFoundError ¶
type AliasNotFoundError struct {
Alias string
}
AliasNotFoundError is a typed error that carries the missing alias for callers that need richer diagnostic information.
func (*AliasNotFoundError) Error ¶
func (e *AliasNotFoundError) Error() string
type AssetSummary ¶ added in v0.23.0
type AssetSummary struct {
Supported bool `json:"supported" yaml:"supported"`
NodesWithAssets int `json:"nodes_with_assets" yaml:"nodes_with_assets"`
TotalAssets int `json:"total_assets" yaml:"total_assets"`
}
AssetSummary aggregates one asset kind for KegSummary.
type BackendError ¶
type BackendError struct {
Backend string // e.g. "s3", "http", "postgres", "fs"
Op string // operation, e.g. "WriteContent", "GetMeta"
StatusCode int // optional HTTP / backend status
Cause error
Transient bool // whether this is a transient error (retryable)
}
BackendError wraps errors coming from an external backend (API, DB, object store). It exposes Retryable() to indicate transient failures.
func ParseBackendError ¶
func ParseBackendError(err error) *BackendError
func (*BackendError) Error ¶
func (e *BackendError) Error() string
func (*BackendError) Retryable ¶
func (e *BackendError) Retryable() bool
Retryable reports whether the backend error is transient.
func (*BackendError) Unwrap ¶
func (e *BackendError) Unwrap() error
Unwrap returns the wrapped cause.
type BacklinkIndex ¶
type BacklinkIndex struct {
// contains filtered or unexported fields
}
BacklinkIndex maps a destination node path to the list of source nodes that link to that destination. The underlying map keys are node.Path() values (string). The index is used to construct the "backlinks" index artifact.
The type is intended for in-memory, single-process use. Concurrency control is the caller's responsibility.
func ParseBacklinksIndex ¶
func ParseBacklinksIndex(ctx context.Context, data []byte) (*BacklinkIndex, error)
ParseBacklinksIndex parses the raw bytes of a backlinks index into a BacklinkIndex.
Expected on-disk format is one line per destination:
"<dst>\t<src1> <src2> ...\n"
Behavior:
- Empty or nil input yields an empty BacklinkIndex with no error.
- Lines are split on tab to separate destination from space-separated sources.
- Duplicate sources for a destination are tolerated and may be deduped by callers of Data.
- This function does not modify any external state.
func (*BacklinkIndex) Add ¶
func (idx *BacklinkIndex) Add(ctx context.Context, data *NodeData) error
Add incorporates backlink information derived from the provided NodeData. For each outgoing link listed in data.Links the function will add the source node (data.ID) to the corresponding destination entry in the index.
Behavior expectations:
- If idx is nil the call is a no-op and returns nil.
- If idx.data is nil it will be initialized.
- The method should avoid introducing duplicate source entries for a given destination when possible.
This method only mutates in-memory state and does not perform I/O.
func (*BacklinkIndex) Data ¶
func (idx *BacklinkIndex) Data(ctx context.Context) ([]byte, error)
Data serializes the index into the canonical on-disk format.
Serialization rules:
- Each non-empty destination produces a line: "<dst>\t<src1> <src2> ...\n"
- Source lists are deduplicated and sorted in a deterministic order.
- Destination keys are emitted in a deterministic, parse-aware order (numeric node ids sorted numerically when possible, otherwise lexicographic).
- An empty index returns an empty byte slice.
The returned bytes are owned by the caller and may be written atomically by the repository layer.
func (*BacklinkIndex) Rm ¶
func (idx *BacklinkIndex) Rm(ctx context.Context, node NodeId) error
Rm removes any backlink references introduced by the given node. It removes the node as a source from any destination lists and may remove the entry for a destination if it ends up with no sources.
Behavior expectations:
- If idx is nil the call is a no-op and returns nil.
- If idx.data is nil it will be initialized to an empty map.
- After removal, entries with no sources may either remain as empty slices or be deleted; callers should tolerate either representation.
This method only mutates in-memory state and does not perform I/O.
type ChangesIndex ¶ added in v0.2.0
type ChangesIndex struct {
// contains filtered or unexported fields
}
ChangesIndex is an in-memory index of all nodes sorted by updated time in reverse-chronological order (newest first). It is used to build the dex/changes.md index artifact.
Concurrency note: ChangesIndex does not perform internal synchronization. Callers that require concurrent access should guard an instance with a mutex.
func ParseChangesIndex ¶ added in v0.2.0
func ParseChangesIndex(ctx context.Context, data []byte) (ChangesIndex, error)
ParseChangesIndex parses the serialized dex/changes.md bytes into a ChangesIndex. Each non-empty line must be in the format:
- YYYY-MM-DD HH:MM:SSZ [TITLE](../ID)
Malformed lines are silently skipped. An empty input yields an empty ChangesIndex with no error.
func (*ChangesIndex) Add ¶ added in v0.2.0
func (idx *ChangesIndex) Add(ctx context.Context, data *NodeData) error
Add inserts or updates the node in the index, maintaining reverse- chronological sort order (newest Updated first). If a node with the same ID already exists it is replaced.
func (*ChangesIndex) Clear ¶ added in v0.2.0
func (idx *ChangesIndex) Clear(ctx context.Context) error
Clear resets the index to an empty state.
func (*ChangesIndex) Data ¶ added in v0.2.0
func (idx *ChangesIndex) Data(ctx context.Context) ([]byte, error)
Data serializes the ChangesIndex to the canonical dex/changes.md format. Each entry is emitted as:
- YYYY-MM-DD HH:MM:SSZ [TITLE](../ID)
Entries are in reverse-chronological order (newest first). An empty index returns an empty byte slice.
func (ChangesIndex) Entries ¶ added in v0.23.0
func (idx ChangesIndex) Entries(ctx context.Context) []NodeIndexEntry
Entries returns a copy of the parsed node-list entries.
type CompareResolver ¶ added in v0.18.0
CompareResolver is an optional callback for evaluating comparison predicates (e.g., ".created>2026-01-01" or "entity!=plan"). When set, the evaluator calls it with dotPrefix, field, op, and value and expects the set of matching identifiers. dotPrefix is true for dot-prefix stats fields (e.g., ".created>2026-01-01") and false for plain attribute comparisons (e.g., "entity!=plan"). When nil, comparisons match nothing.
type Config ¶
type Config = ConfigV2
Config KegConfig is an alias for the latest configuration version. Update this alias when introducing a newer configuration version.
func NewConfig ¶
func NewConfig(options ...ConfigOption) *Config
func ParseKegConfig ¶
ParseKegConfig parses raw YAML config data into the latest Config version. It detects the "kegv" version field and performs migration from earlier versions when necessary.
func ParseKegConfigStrict ¶ added in v0.23.0
ParseKegConfigStrict parses raw user-supplied config data for persistence. It rejects user-defined index entries that collide with required system indexes or duplicate another user index.
func (*Config) Location ¶ added in v0.15.0
Location returns the *time.Location for the configured Timezone. It returns time.UTC if the Timezone field is empty or invalid.
func (*Config) SnapshotPolicy ¶ added in v0.28.0
SnapshotPolicy resolves the effective snapshot policy for this config.
func (*Config) UserIndexEntries ¶ added in v0.23.0
func (kc *Config) UserIndexEntries() []IndexEntry
UserIndexEntries returns the user-defined indexes from a runtime config.
type ConfigOption ¶
type ConfigOption = func(cfg *Config)
type ConfigV1 ¶
type ConfigV1 struct {
// Kegv is the version of the specification.
Kegv string `yaml:"kegv"`
// Updated indicates when the keg was last indexed.
Updated string `yaml:"updated,omitempty"`
// Title is the title of the KEG worklog or project.
Title string `yaml:"title,omitempty"`
// URL is the main URL where the KEG can be found.
URL string `yaml:"url,omitempty"`
// Creator is the URL or identifier of the creator of the KEG.
Creator string `yaml:"creator,omitempty"`
// State indicates the current state of the KEG (e.g., living, archived).
State string `yaml:"state,omitempty"`
// Summary provides a brief description or summary of the KEG content.
Summary string `yaml:"summary,omitempty"`
// Indexes is a list of index entries that link to related files or nodes.
Indexes []IndexEntry `yaml:"indexes,omitempty"`
// contains filtered or unexported fields
}
ConfigV1 KegConfigV1 represents the initial version of the KEG configuration specification.
type ConfigV2 ¶
type ConfigV2 struct {
// Kegv is the version of the specification.
Kegv string `yaml:"kegv" json:"kegv"`
// Updated indicates when the keg was last indexed.
Updated string `yaml:"updated,omitempty" json:"updated,omitempty"`
// Title is the title of the KEG worklog or project.
Title string `yaml:"title,omitempty" json:"title,omitempty"`
// URL is the main URL where the KEG can be found.
URL string `yaml:"url,omitempty" json:"url,omitempty"`
// Creator is the URL or identifier of the creator of the KEG.
Creator string `yaml:"creator,omitempty" json:"creator,omitempty"`
// State indicates the current state of the KEG (e.g., living, archived).
State string `yaml:"state,omitempty" json:"state,omitempty"`
// Summary provides a brief description or summary of the KEG content.
Summary string `yaml:"summary,omitempty" json:"summary,omitempty"`
// Instructions are KEG-level guidance shown to agents when orienting to
// this keg.
Instructions string `yaml:"instructions,omitempty" json:"instructions,omitempty"`
// Links holds a list of LinkEntry objects representing related links or
// references in the configuration.
Links []LinkEntry `yaml:"links,omitempty" json:"links,omitempty"`
// Indexes is a list of index entries that link to related files or nodes.
Indexes []IndexEntry `yaml:"indexes,omitempty" json:"indexes,omitempty"`
// Timezone is the IANA timezone for resolving ambiguous timestamps
// within this keg (e.g. "America/Chicago"). Defaults to "UTC".
Timezone string `yaml:"timezone,omitempty" json:"timezone,omitempty"`
// Snapshots controls automatic snapshot behavior for this keg.
Snapshots *SnapshotConfig `yaml:"snapshots,omitempty" json:"snapshots,omitempty"`
// SchemaPolicy controls whether schema validation warns, blocks, or is
// disabled for different write actors. When omitted, human writes warn while
// agent and API writes block. Archive imports and snapshot restores always
// skip node-schema enforcement.
SchemaPolicy *SchemaPolicy `yaml:"schemaPolicy,omitempty" json:"schemaPolicy,omitempty"`
// contains filtered or unexported fields
}
ConfigV2 KegConfigV2 represents the second (current) version of the KEG configuration specification. It extends V1 with additional fields such as Links.
func (*ConfigV2) MaterializeSystemIndexes ¶ added in v0.23.0
func (kc *ConfigV2) MaterializeSystemIndexes()
MaterializeSystemIndexes ensures required system indexes are present in the runtime config view and removes any legacy persisted declarations of those indexes.
type CreateOptions ¶
type CreateOptions struct {
// Title is the human-readable title for the node
Title string
// Lead is a one-line summary
Lead string
// Tags are searchable labels for the node
Tags []string
// Body is the raw markdown content; if empty, default content is generated from Title/Lead
Body []byte
// Attrs are arbitrary key-value attributes attached to the node
Attrs map[string]any
}
CreateOptions specifies parameters for creating a new node
type Dex ¶
type Dex struct {
// contains filtered or unexported fields
}
Dex provides a high-level, in-memory view of the repository's generated dex indices: nodes, tags, links, backlinks, and changes. It is a convenience wrapper used by index builders and other tooling to read or inspect index data without dealing directly with repository I/O. Dex does not perform any I/O itself; callers are responsible for providing a Repository when writing indices.
func NewDexFromRepo ¶
NewDexFromRepo loads available index artifacts ("nodes.tsv", "tags", "links", "backlinks", "changes.md") from the provided repository and returns a Dex populated with parsed indexes. Missing or empty index files are treated as empty datasets and do not cause an error. Additional DexOptions (e.g. WithConfig) can be supplied to configure optional behaviour such as tag-filtered custom indexes.
All 5 index files are read and parsed concurrently for faster loading.
func (*Dex) Add ¶
Add adds the provided node to all managed indexes. This implements the IndexBuilder contract for convenience when using Dex as an aggregated builder.
func (*Dex) Backlinks ¶
Backlinks returns the parsed backlinks index (map[dst] -> []src). NOTE: not intended to be mutated
func (*Dex) Changes ¶ added in v0.23.0
func (dex *Dex) Changes(ctx context.Context) []NodeIndexEntry
Changes returns a copy of the parsed changes index, newest entry first.
func (*Dex) NodeListIndex ¶ added in v0.23.0
NodeListIndex returns a node-list-compatible system index by filename.
func (*Dex) Nodes ¶
func (dex *Dex) Nodes(ctx context.Context) []NodeIndexEntry
Nodes returns a copy of the parsed nodes index (slice of NodeRef).
func (*Dex) Remove ¶
Remove removes the node identified by id from all managed indexes. This implements the IndexBuilder contract for convenience when using Dex.
func (*Dex) Write ¶
func (dex *Dex) Write(ctx context.Context, repo Repository) error
Write serializes the in-memory indexes and writes them atomically to the provided repository using WriteIndex. If any write operation fails the error chain is returned (errors.Join is used to aggregate multiple errors).
Serialization is performed under a read lock so concurrent readers are not blocked. The actual file writes happen after the lock is released, since they operate on independent byte buffers and repository WriteIndex calls are self-synchronizing (atomic file writes).
type DexOption ¶ added in v0.2.0
DexOption is a functional option for NewDexFromRepo.
func WithConfig ¶ added in v0.2.0
WithConfig builds DexOptions from a keg Config. It iterates cfg.Indexes and creates a QueryFilteredIndex for each entry that:
- has a non-empty Query field, and
- is not one of the core protected index names.
IndexEntry.File is the bare filename (e.g. "concepts.md"); the on-disk path is under the keg's dex/ directory.
By default, the index evaluates tag expressions against node tag sets. To support richer query terms (e.g. key=value attribute predicates), pass WithQueryResolver to inject a custom resolver callback.
func WithQueryResolver ¶ added in v0.15.0
WithQueryResolver sets a custom query term resolver for config-driven custom indexes. When set, each term in a query expression is resolved by calling resolve(term, data) for each node, instead of the default tag-only resolver. This enables key=value attribute predicates and other term types defined in higher-level packages (e.g. pkg/tapper).
type ExportNodesOptions ¶ added in v0.23.0
type ExportNodesOptions struct {
// NodeIDs selects nodes to export; empty exports every node.
NodeIDs []NodeId
// WithHistory includes snapshot revisions.
WithHistory bool
// WithAssets includes per-node files and images.
WithAssets bool
// Source labels the archive manifest with the origin keg reference.
Source string
}
ExportNodesOptions configures Keg.ExportNodes.
type FsRepo ¶
type FsRepo struct {
// Root is the base directory path containing all KEG node directories
Root string
// ContentFilename specifies the filename for node content (typically README.md)
ContentFilename string
// MetaFilename specifies the filename for node metadata (typically meta.yaml)
MetaFilename string
StatsFilename string
// SnapshotCheckpointInterval controls how many patch revisions may occur
// after a checkpoint before the next snapshot is stored as a full blob.
SnapshotCheckpointInterval int
// contains filtered or unexported fields
}
FsRepo implements Repository using the local filesystem as storage. It manages KEG nodes as directories under [Root], with each node containing content files, metadata, and optional attachments. Thread-safe operations are coordinated through the embedded mutex.
func NewFsRepoFromEnvOrSearch ¶
NewFsRepoFromEnvOrSearch tries to locate a keg file using the order: 1) KEG_CURRENT env var (file or directory) 2) current working directory 3) if inside a git project, search the project tree for a keg file 4) recursive search from current working directory 5) fallback to default config location (~/.config/keg or XDG equivalent)
Returns a pointer to an initialized FsRepo and the path of the discovered keg file (or "" if using fallback path).
func (*FsRepo) AcquireLock ¶ added in v0.11.0
AcquireLock implements RepositoryLock.
func (*FsRepo) AppendSnapshot ¶ added in v0.4.0
func (*FsRepo) ContentFilePath ¶ added in v0.6.0
ContentFilePath returns the absolute filesystem path to a node's content file.
func (*FsRepo) DeleteAsset ¶
DeleteAsset implements Repository.
func (*FsRepo) DeleteFile ¶
func (*FsRepo) DeleteImage ¶
func (*FsRepo) DeleteNode ¶
DeleteNode implements Repository.
func (*FsRepo) DeleteSchema ¶ added in v0.25.0
DeleteSchema removes schemas/<type>.schema.yaml.
func (*FsRepo) Emit ¶ added in v0.23.0
Emit implements RepositoryEvents. It broadcasts a programmatic event (access bumps, test simulation) to all active Watch subscribers whose filters match.
func (*FsRepo) ForceReleaseLock ¶ added in v0.11.0
ForceReleaseLock implements RepositoryLock.
func (*FsRepo) GetSnapshot ¶ added in v0.4.0
func (*FsRepo) ListAssets ¶
ListAssets implements Repository.
func (*FsRepo) ListImages ¶
func (*FsRepo) ListIndexes ¶
ListIndexes implements Repository.
func (*FsRepo) ListSchemas ¶ added in v0.25.0
ListSchemas lists schema type names stored under schemas/*.schema.yaml.
func (*FsRepo) ListSnapshots ¶ added in v0.4.0
func (*FsRepo) LockStatus ¶ added in v0.11.0
LockStatus implements RepositoryLock.
func (*FsRepo) MetaFilePath ¶ added in v0.6.0
MetaFilePath returns the absolute filesystem path to a node's metadata file.
func (*FsRepo) NodeDirPath ¶ added in v0.6.0
NodeDirPath returns the absolute filesystem path to a node's directory.
func (*FsRepo) NodeFilesExist ¶
func (*FsRepo) ReadConfig ¶
ReadConfig implements Repository.
func (*FsRepo) ReadContent ¶
ReadContent implements Repository.
func (*FsRepo) ReadContentAt ¶ added in v0.4.0
func (*FsRepo) ReadSchema ¶ added in v0.25.0
ReadSchema reads schemas/<type>.schema.yaml.
func (*FsRepo) ReleaseLock ¶ added in v0.11.0
ReleaseLock implements RepositoryLock.
func (*FsRepo) RestoreSnapshot ¶ added in v0.4.0
func (*FsRepo) Watch ¶ added in v0.23.0
Watch implements RepositoryEvents for FsRepo using fsnotify. When no IDs are given, the entire keg root is watched and events for any node are emitted. Events are delivered on the returned channel until ctx is cancelled, at which point the channel is closed.
func (*FsRepo) WithNodeLock ¶
WithNodeLock executes fn while holding an exclusive lock for node id. The lock uses atomic mkdir with optional process metadata for stale lock detection. When process info is available (via runtime.Process()), a JSON metadata file is written inside the lock directory. If the lock directory already exists and the owning process is dead, the stale lock is removed and acquisition is retried.
func (*FsRepo) WriteAsset ¶
func (f *FsRepo) WriteAsset(ctx context.Context, id NodeId, kind AssetKind, name string, data []byte) error
WriteAsset implements Repository.
func (*FsRepo) WriteConfig ¶
WriteConfig implements Repository.
func (*FsRepo) WriteContent ¶
WriteContent implements Repository.
func (*FsRepo) WriteImage ¶
func (*FsRepo) WriteIndex ¶
WriteIndex implements Repository.
func (*FsRepo) WriteSchema ¶ added in v0.25.0
WriteSchema writes schemas/<type>.schema.yaml atomically.
type GrepMatch ¶ added in v0.23.0
type GrepMatch struct {
Entry NodeIndexEntry
// Lines are rendered "lineno:text" match lines.
Lines []string
}
GrepMatch reports one node's content matches for Keg.Grep.
type GrepOptions ¶ added in v0.23.0
type GrepOptions struct {
// Pattern is a Go regular expression matched against content lines.
Pattern string
// IgnoreCase makes the match case-insensitive.
IgnoreCase bool
// MaxLines caps matched lines per node. 0 means no cap.
MaxLines int
}
GrepOptions configures Keg.Grep.
type HTTPOption ¶ added in v0.20.0
type HTTPOption = func(t *Target)
func WithBasicAuth ¶ added in v0.20.0
func WithBasicAuth(user, pass string) HTTPOption
func WithToken ¶ added in v0.20.0
func WithToken(token string) HTTPOption
type ImportNodesOptions ¶ added in v0.23.0
type ImportNodesOptions struct {
// AssignNewIDs allocates fresh sequential node ids for the archive's
// nodes instead of landing them on their archive ids. Links between
// imported nodes are rewritten to the new ids.
AssignNewIDs bool
// SourceAlias, when set, rewrites relative links that point at
// un-imported source nodes to keg:SourceAlias/N cross-keg links.
SourceAlias string
// TargetAlias, when set, rewrites keg:TargetAlias/N links in imported
// content to relative ../N links.
TargetAlias string
}
ImportNodesOptions configures Keg.ImportNodes.
type ImportedNode ¶ added in v0.23.0
ImportedNode maps an archive source id to the node id it landed on.
type IndexBuilder ¶
type IndexBuilder interface {
// Name returns the bare index filename used with repo.WriteIndex
// (for example "tags" or "concepts.md"). The "dex/" directory prefix
// is implicit and applied by the repository at write time.
Name() string
// Add incorporates information from a node into the index's in-memory state.
Add(ctx context.Context, node *NodeData) error
// Remove deletes node-related state from the index.
Remove(ctx context.Context, node NodeId) error
// Clear resets the index to an empty state.
Clear(ctx context.Context) error
// Data returns the serialized index bytes to be written to storage.
Data(ctx context.Context) ([]byte, error)
}
IndexBuilder is an interface for constructing a single index artifact (for example: nodes.tsv, tags, links, backlinks). Implementations maintain in-memory state via Add / Remove / Clear and produce the serialized bytes to write via Data.
type IndexEntry ¶
type IndexEntry struct {
File string `yaml:"file" json:"file"`
Summary string `yaml:"summary" json:"summary"`
Query string `yaml:"query,omitempty" json:"query,omitempty"` // boolean query expression; omit for core/unfiltered indexes
Sort string `yaml:"sort,omitempty" json:"sort,omitempty"` // sort order for query-filtered indexes: "updated" (default), "id", "created", "accessed"
}
IndexEntry represents an entry in the indexes list in the KEG configuration.
File is the bare filename of the generated index artifact, e.g. "backlinks" or "concepts.md". The on-disk path is always under the keg's dex/ directory (the prefix is implicit and applied at write time).
The Query field holds a boolean query expression used to filter index contents (tag names, key=value attribute predicates, boolean operators).
func SystemIndexEntries ¶ added in v0.23.0
func SystemIndexEntries() []IndexEntry
SystemIndexEntries returns the required indexes that every keg has at runtime. Callers receive a fresh slice so entries can be appended safely.
type IndexOptions ¶
type IndexOptions struct {
NoUpdate bool
}
type InvalidConfigError ¶
type InvalidConfigError struct {
Msg string
}
InvalidConfigError represents a validation or parse failure for tapper config.
func (*InvalidConfigError) Error ¶
func (e *InvalidConfigError) Error() string
func (*InvalidConfigError) Unwrap ¶
func (e *InvalidConfigError) Unwrap() error
type Keg ¶
type Keg interface {
// Target returns the keg's resolved location, or nil for anonymous
// (memory-backed) kegs.
Target() *Target
// Init bootstraps an empty keg: config file plus zero node. Remote kegs
// are created through the hub's keg-creation endpoint instead and return
// ErrNotSupported.
Init(ctx context.Context) error
// Config returns the keg-level configuration (the `keg` file).
Config(ctx context.Context) (*Config, error)
// SetConfig replaces the keg configuration with the supplied raw YAML.
// Raw bytes preserve user formatting for round-trip editing.
SetConfig(ctx context.Context, data []byte) error
// Schemas describe valid note types for this keg. Filesystem repositories
// store them under schemas/<type>.schema.yaml; remote repositories expose the
// same logical surface through the hub API.
ListSchemas(ctx context.Context) ([]string, error)
ReadSchema(ctx context.Context, typeName string) ([]byte, error)
WriteSchema(ctx context.Context, typeName string, data []byte) error
DeleteSchema(ctx context.Context, typeName string) error
ValidateNode(ctx context.Context, id NodeId) (*SchemaValidationResult, error)
ValidateNodePayload(ctx context.Context, payload NodeValidationPayload) (*SchemaValidationResult, error)
// Create allocates a node id and writes initial content, meta, and stats.
Create(ctx context.Context, opts *CreateOptions) (NodeId, error)
// Next reports the next node id that Create would allocate.
Next(ctx context.Context) (NodeId, error)
// ListNodes returns all node ids present in the keg.
ListNodes(ctx context.Context) ([]NodeId, error)
// NodeExists reports whether id is a fully written node (content
// present), as opposed to a bare reservation directory.
NodeExists(ctx context.Context, id NodeId) (bool, error)
// Move relocates src to dst and rewrites inbound links. It returns the
// ids of nodes whose content was rewritten to follow the move.
Move(ctx context.Context, src NodeId, dst NodeId) ([]NodeId, error)
// Remove deletes a node and rewrites or drops inbound links. It returns
// the ids of nodes whose content was rewritten.
Remove(ctx context.Context, id NodeId) ([]NodeId, error)
// Commit creates a snapshot revision of the node's current state.
Commit(ctx context.Context, id NodeId) error
// ReadNode returns the node's full state in one operation: content, raw
// meta, stats, and asset name lists.
ReadNode(ctx context.Context, id NodeId) (*NodeView, error)
// GetContent returns the node's primary content (README.md).
GetContent(ctx context.Context, id NodeId) ([]byte, error)
// SetContent replaces the node's primary content and refreshes derived
// state (stats, dex) as the implementation requires.
SetContent(ctx context.Context, id NodeId, data []byte) error
// GetMeta returns the node's parsed metadata.
GetMeta(ctx context.Context, id NodeId) (*NodeMeta, error)
// GetMetaRaw returns the node's metadata bytes exactly as stored,
// preserving formatting for round-trip editing.
GetMetaRaw(ctx context.Context, id NodeId) ([]byte, error)
// SetMeta replaces the node's metadata.
SetMeta(ctx context.Context, id NodeId, meta *NodeMeta) error
// GetStats returns the node's programmatic stats.
GetStats(ctx context.Context, id NodeId) (*NodeStats, error)
// Touch marks the node accessed, updating access stats.
Touch(ctx context.Context, id NodeId) error
// Dex returns the keg's current index aggregate. The returned dex
// reflects committed state at call time (always-fresh semantics).
Dex(ctx context.Context) (*Dex, error)
// Query evaluates a boolean query expression (tags, key=value attribute
// predicates, .field stats predicates) and returns matching index
// entries in dex order.
Query(ctx context.Context, opts QueryOptions) ([]NodeIndexEntry, error)
// Grep scans node content for a regular expression and returns per-node
// line matches in dex order.
Grep(ctx context.Context, opts GrepOptions) ([]GrepMatch, error)
// Index rebuilds all dex indexes from node state.
Index(ctx context.Context, opts IndexOptions) error
// ListIndexes returns available index artifact names.
ListIndexes(ctx context.Context) ([]string, error)
// ReadIndex returns a raw index artifact by name (e.g. "nodes.tsv").
ReadIndex(ctx context.Context, name string) ([]byte, error)
// Summary returns keg-level diagnostics: node count and asset totals.
Summary(ctx context.Context) (*KegSummary, error)
ListFiles(ctx context.Context, id NodeId) ([]string, error)
ReadFile(ctx context.Context, id NodeId, name string) ([]byte, error)
WriteFile(ctx context.Context, id NodeId, name string, data []byte) error
DeleteFile(ctx context.Context, id NodeId, name string) error
ListImages(ctx context.Context, id NodeId) ([]string, error)
ReadImage(ctx context.Context, id NodeId, name string) ([]byte, error)
WriteImage(ctx context.Context, id NodeId, name string, data []byte) error
DeleteImage(ctx context.Context, id NodeId, name string) error
// AppendSnapshot records the node's current state as a new revision.
AppendSnapshot(ctx context.Context, id NodeId, msg string) (Snapshot, error)
// ListSnapshots returns the node's revisions in order.
ListSnapshots(ctx context.Context, id NodeId) ([]Snapshot, error)
// GetSnapshot returns revision metadata and, per opts, resolved payloads.
GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (Snapshot, []byte, []byte, *NodeStats, error)
// ReadContentAt reconstructs node content at a revision.
ReadContentAt(ctx context.Context, id NodeId, rev RevisionID) ([]byte, error)
// RestoreSnapshot restores live node state to a revision.
RestoreSnapshot(ctx context.Context, id NodeId, rev RevisionID) error
// ExportNodes streams a keg-archive (gzip tar) of the selected nodes.
// The caller must Close the returned reader.
ExportNodes(ctx context.Context, opts ExportNodesOptions) (io.ReadCloser, error)
// ImportNodes loads a keg-archive stream into the keg, replacing
// existing nodes with matching ids, and rebuilds derived state.
ImportNodes(ctx context.Context, r io.Reader, opts ImportNodesOptions) ([]ImportedNode, error)
// Lock acquires a cross-process advisory lock on a node.
Lock(ctx context.Context, id NodeId) (LockToken, error)
// Unlock releases a lock acquired by Lock; the token must match.
Unlock(ctx context.Context, id NodeId, token LockToken) error
// LockStatus reports the node's current lock state; a zero LockInfo
// means unheld.
LockStatus(ctx context.Context, id NodeId) (LockInfo, error)
// ForceUnlock removes a lock regardless of token ownership.
ForceUnlock(ctx context.Context, id NodeId) error
// Watch streams node change events until ctx is canceled. With no ids,
// all nodes are watched.
Watch(ctx context.Context, ids ...NodeId) (<-chan NodeEvent, error)
}
Keg is the single-keg business API. It is the abstraction boundary between callers (the Tap layer, the hub's HTTP handlers) and keg storage: every method is one logical operation, and implementations own their orchestration internally (locking discipline, dex/index maintenance, stats touching).
Two implementations exist:
- LocalKeg orchestrates a Repository (FsRepo, MemoryRepo, or the hub's PgRepo) and maintains derived state itself.
- RemoteKeg speaks the tapper-hub operation API; each method is a single HTTP round trip and all orchestration happens server-side.
Capability errors: methods backed by optional storage features (files, images, snapshots, locks, events) return ErrNotSupported when the backend lacks the capability.
func NewKegFromTarget ¶
func NewKegFromTarget(ctx context.Context, target Target, rt *toolkit.Runtime, opts ...KegOption) (Keg, error)
NewKegFromTarget constructs a Keg implementation from a Target. It automatically selects the appropriate repository implementation based on the target's scheme:
- memory:// targets use an in-memory repository
- file:// targets use a filesystem repository
- http:// and https:// targets use a RemoteKeg speaking the hub's operation API
- hub targets use a RemoteKeg resolved from repo/user/keg fields
Returns an error if the target scheme is not supported.
type KegOption ¶ added in v0.20.0
type KegOption func(*kegOptions)
KegOption customises NewKegFromTarget without breaking existing callers. Variadic options keep the common case (no resolver, no extras) a zero-cost invocation.
func WithTokenResolver ¶ added in v0.20.0
func WithTokenResolver(r TokenResolver) KegOption
WithTokenResolver installs a TokenResolver consulted as the third and final fallback when a remote target has neither a TokenEnv-sourced value nor an inline Token. Pass a nil resolver to explicitly opt out of fallback; the option itself is a no-op in that case.
type KegSummary ¶ added in v0.23.0
type KegSummary struct {
NodeCount int `json:"node_count" yaml:"node_count"`
Files AssetSummary `json:"assets" yaml:"assets"`
Images AssetSummary `json:"images" yaml:"images"`
}
KegSummary is keg-level diagnostic data returned by Keg.Summary.
type LinkEntry ¶
type LinkEntry struct {
Alias string `yaml:"alias" json:"alias"` // Alias for the link
URL string `yaml:"url" json:"url"` // URL of the link
}
LinkEntry represents a named link in the KEG configuration.
type LinkIndex ¶
type LinkIndex struct {
// contains filtered or unexported fields
}
LinkIndex maps a source node path to the list of destination nodes that the source links to. It is used to construct the "links" index artifact.
The underlying map keys are node.Path() values (string). The index is expected to be small enough to be kept in memory for index-building tooling.
The type has unexported fields and is safe for in-memory, single-process use. Concurrency control is the caller's responsibility.
func ParseLinkIndex ¶
ParseLinkIndex parses the raw bytes of a links index into a LinkIndex. The expected on-disk format is one line per source:
"<src>\t<dst1> <dst2> ...\n"
Behavior:
- Empty or nil input yields an empty LinkIndex with no error.
- Lines are split on tab to separate source from space-separated destinations.
- Duplicate destinations for a source are tolerated and may be deduped by callers of Data.
This function does not modify any external state.
func (*LinkIndex) Add ¶
Add incorporates link information from the provided NodeData into the index. The NodeData.ID value is used as the source key (via NodeId.Path semantics) and NodeData.Links is treated as the list of destination nodes.
Behavior expectations (not enforced here but callers may rely on them):
- If idx is nil the call is a no-op and returns nil.
- If idx.data is nil it will be initialized.
- The method should avoid introducing duplicate destination entries for a given source when possible.
This method only mutates in-memory state and does not perform I/O.
func (*LinkIndex) Data ¶
Data serializes the index into the canonical on-disk format.
Serialization rules:
- Each non-empty source produces a line: "<src>\t<dst1> <dst2> ...\n"
- Destination lists are deduplicated and sorted in a deterministic order.
- Source keys are emitted in a deterministic, parse-aware order (numeric node ids sorted numerically when possible, otherwise lexicographic).
- An empty index returns an empty byte slice.
The returned bytes are owned by the caller and may be written atomically by the repository layer.
func (*LinkIndex) Rm ¶
Rm removes any references introduced by the given node as a source and removes the node from any destination lists where it appears.
Behavior expectations:
- If idx is nil the call is a no-op and returns nil.
- If idx.data is nil it will be initialized to an empty map.
- After removal, entries with no destinations may either remain as empty slices or be deleted; callers should tolerate either representation.
This method only mutates in-memory state and does not perform I/O.
type LocalKeg ¶ added in v0.23.0
type LocalKeg struct {
// Repo is the storage backend implementation
Repo Repository
// Runtime provides clock/hash/fs helpers used by high-level keg operations.
Runtime *toolkit.Runtime
// contains filtered or unexported fields
}
LocalKeg is the concrete high-level service providing KEG node operations backed by a Repository. It abstracts storage implementation details, allowing operations over nodes to work uniformly across memory and filesystem backends. LocalKeg delegates low-level storage operations to its underlying repository and maintains an in-memory dex for indexing.
func NewLocalKeg ¶ added in v0.23.0
func NewLocalKeg(repo Repository, rt *toolkit.Runtime, opts ...Option) *LocalKeg
NewLocalKeg returns a LocalKeg service backed by the provided repository. Functional options can be provided to customize LocalKeg behavior.
func (*LocalKeg) AppendSnapshot ¶ added in v0.23.0
func (*LocalKeg) Commit ¶ added in v0.23.0
Commit finalizes a temporary node by allocating a permanent ID and moving it from its temporary location (with Code suffix) to the canonical numeric ID. For nodes without a Code (already permanent), Commit is a no-op.
func (*LocalKeg) Create ¶ added in v0.23.0
Create creates a new node: allocates an ID, parses content, generates metadata, and indexes the node in the dex. The node is immediately persisted to the repository. If Body is empty, default markdown content is generated from Title and Lead.
func (*LocalKeg) DeleteFile ¶ added in v0.23.0
DeleteFile removes a file attachment from a node.
func (*LocalKeg) DeleteImage ¶ added in v0.23.0
DeleteImage removes an image from a node.
func (*LocalKeg) DeleteSchema ¶ added in v0.25.0
func (*LocalKeg) Dex ¶ added in v0.23.0
Dex returns the keg's index with always-fresh semantics: the cached dex is reused only while it is provably current (see dexStale), otherwise it is reloaded from the repository. Config-driven query-filtered indexes are applied automatically via WithConfig. Safe for both short-lived CLI invocations and long-lived processes (serve handlers, MCP servers) where another process may update the index between calls.
func (*LocalKeg) ExportNodes ¶ added in v0.23.0
func (k *LocalKeg) ExportNodes(ctx context.Context, opts ExportNodesOptions) (io.ReadCloser, error)
ExportNodes streams a keg-archive (gzip tar) of the selected nodes. With empty opts.NodeIDs every node is exported. The archive is produced incrementally through a pipe; the caller must Close the returned reader, and a mid-stream failure surfaces as the reader's error.
func (*LocalKeg) ForceUnlock ¶ added in v0.23.0
ForceUnlock unconditionally removes a cross-process lock regardless of token ownership. Escape hatch for stuck or stale locks.
func (*LocalKeg) GetContent ¶ added in v0.23.0
GetContent retrieves the raw markdown content for a node.
func (*LocalKeg) GetMetaRaw ¶ added in v0.23.0
GetMetaRaw returns the node's metadata bytes exactly as stored, preserving formatting for round-trip editing. A missing meta file returns ErrNotExist.
func (*LocalKeg) GetSnapshot ¶ added in v0.23.0
func (k *LocalKeg) GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (Snapshot, []byte, []byte, *NodeStats, error)
GetSnapshot returns revision metadata and, per opts, resolved content, meta, and stats payloads.
func (*LocalKeg) Grep ¶ added in v0.23.0
Grep scans node content for a regular expression and returns per-node line matches in dex order. Nodes without matches are omitted.
func (*LocalKeg) ImportNodes ¶ added in v0.23.0
func (k *LocalKeg) ImportNodes(ctx context.Context, r io.Reader, opts ImportNodesOptions) ([]ImportedNode, error)
ImportNodes loads a keg-archive stream into the keg. Nodes land on their archive ids, replacing existing nodes (whose assets are preserved unless the archive carries its own). Derived state (dex, config updated stamp) is rebuilt once after all nodes import.
func (*LocalKeg) Index ¶ added in v0.23.0
func (k *LocalKeg) Index(ctx context.Context, opts IndexOptions) error
Index rebuilds all keg indices from scratch. Every node is scanned, metadata and stats are refreshed (unless NoUpdate is set), and the full dex is regenerated.
func (*LocalKeg) IndexNode ¶ added in v0.23.0
IndexNode updates a node's metadata by re-parsing its content and extracting properties like title, lead, and content hash. The dex is also updated to reflect any changes. If content hasn't changed, this is a no-op.
func (*LocalKeg) Init ¶ added in v0.23.0
Init initializes a new keg by creating the config file, zero node with default content, and updating the dex. It returns an error if the keg already exists. Init is idempotent in the sense that it checks for existing kegs first.
func (*LocalKeg) InvalidateDex ¶ added in v0.23.0
func (k *LocalKeg) InvalidateDex()
InvalidateDex clears the cached dex so the next Dex() call reloads from the repository. This is useful when external processes may have modified the index files.
func (*LocalKeg) ListFiles ¶ added in v0.23.0
ListFiles lists file attachment names for a node. Returns ErrNotSupported when the backend lacks file storage.
func (*LocalKeg) ListImages ¶ added in v0.23.0
ListImages lists image names for a node. Returns ErrNotSupported when the backend lacks image storage.
func (*LocalKeg) ListIndexes ¶ added in v0.23.0
ListIndexes returns available index artifact names.
func (*LocalKeg) ListSchemas ¶ added in v0.25.0
func (*LocalKeg) ListSnapshots ¶ added in v0.23.0
func (*LocalKeg) Lock ¶ added in v0.23.0
Lock acquires a cross-process advisory lock on a node. Returns ErrNotSupported when the backend lacks cross-process locking.
func (*LocalKeg) LockStatus ¶ added in v0.23.0
LockStatus reports the node's current cross-process lock state. A zero LockInfo means no live lock is held.
func (*LocalKeg) Move ¶ added in v0.23.0
Move renames a node from src to dst and rewrites in-content links that target src (../N) across the keg. It returns the ids of nodes whose content was rewritten to follow the move.
func (*LocalKeg) Next ¶ added in v0.23.0
Next reserves and returns the next available node ID from the repository.
func (*LocalKeg) Node ¶ added in v0.23.0
Node returns a Node handle bound to this keg's repository and runtime for the given id. It performs no I/O; content, metadata, and stats are loaded lazily by the Node's own methods.
func (*LocalKeg) NodeExists ¶ added in v0.23.0
NodeExists reports whether id is a fully written node (content present), as opposed to a bare reservation directory left behind by FsRepo.Next() or FsRepo.WithNodeLock(). It holds no node lock; mutating operations re-check under lock.
func (*LocalKeg) Query ¶ added in v0.23.0
func (k *LocalKeg) Query(ctx context.Context, opts QueryOptions) ([]NodeIndexEntry, error)
Query evaluates a boolean query expression against the keg's index entries and returns the matching entries in dex order. The expression grammar supports plain tag names, key=value attribute predicates, attribute comparisons (omega>=0.5), and .field stats predicates (.updated>2026-01-01); see ParseQueryExpression.
func (*LocalKeg) ReadContentAt ¶ added in v0.23.0
func (*LocalKeg) ReadIndex ¶ added in v0.23.0
ReadIndex returns a raw index artifact by name (e.g. "nodes.tsv").
func (*LocalKeg) ReadNode ¶ added in v0.23.0
ReadNode assembles the node's full state: content (required), raw meta and stats (optional, zero-valued when absent), and asset name lists (nil when the backend lacks the capability).
func (*LocalKeg) ReadSchema ¶ added in v0.25.0
func (*LocalKeg) Remove ¶ added in v0.23.0
Remove deletes a node from the repository and updates dex/config artifacts. It returns the ids of nodes whose content was rewritten to drop links to the removed node.
func (*LocalKeg) RestoreSnapshot ¶ added in v0.23.0
func (*LocalKeg) RunSnapshotPolicy ¶ added in v0.28.0
func (k *LocalKeg) RunSnapshotPolicy(ctx context.Context) (SnapshotPolicyResult, error)
RunSnapshotPolicy scans all nodes in deterministic order and appends automatic snapshots for nodes whose live content has drifted from the latest snapshot after the configured idle window.
func (*LocalKeg) SetConfig ¶ added in v0.23.0
SetConfig parses and writes keg configuration from raw bytes. Prefer UpdateConfig for most use cases as it handles read-modify-write atomically.
func (*LocalKeg) SetContent ¶ added in v0.23.0
SetContent writes content for a node and updates its metadata by re-indexing. This ensures the node's title, lead, and other metadata are kept in sync with content changes.
func (*LocalKeg) SetMeta ¶ added in v0.23.0
SetMeta writes metadata for a node and updates the dex. If the new meta bytes are identical to the existing on-disk meta, the write and dex/config update are skipped entirely.
func (*LocalKeg) SetTarget ¶ added in v0.23.0
SetTarget records the keg's resolved location. Construction paths that cannot pass the target through a literal (e.g. the hub opening a keg by namespace/alias) use this to label the keg after the fact.
func (*LocalKeg) Summary ¶ added in v0.23.0
func (k *LocalKeg) Summary(ctx context.Context) (*KegSummary, error)
Summary returns keg-level diagnostics: node count plus per-kind asset totals. Asset kinds report Supported=false when the backend lacks the capability.
func (*LocalKeg) Target ¶ added in v0.23.0
Target returns the keg's resolved location, or nil for anonymous (memory-backed) kegs.
func (*LocalKeg) Touch ¶ added in v0.23.0
Touch updates the access time of a node to the current time.
func (*LocalKeg) Unlock ¶ added in v0.23.0
Unlock releases a cross-process lock; the token must match the holder's.
func (*LocalKeg) UpdateConfig ¶ added in v0.23.0
UpdateConfig reads the keg config, applies the provided mutation function, and writes the result back to the repository. This is the preferred way to modify keg configuration to ensure updates are atomically persisted.
func (*LocalKeg) UpdateMeta ¶ added in v0.23.0
UpdateMeta reads the node's metadata, applies the provided mutation function, and writes the result back to the repository with dex updates.
func (*LocalKeg) ValidateNode ¶ added in v0.25.0
func (*LocalKeg) ValidateNodePayload ¶ added in v0.25.0
func (k *LocalKeg) ValidateNodePayload(ctx context.Context, payload NodeValidationPayload) (*SchemaValidationResult, error)
func (*LocalKeg) Watch ¶ added in v0.23.0
Watch streams node change events until ctx is canceled. With no ids, all nodes are watched. Returns ErrNotSupported when the backend cannot emit events.
func (*LocalKeg) WriteImage ¶ added in v0.23.0
WriteImage stores an image payload for a node.
type LockInfo ¶ added in v0.11.0
type LockInfo struct {
Token LockToken `json:"token"`
AcquiredAt time.Time `json:"acquired_at"`
TTLSeconds int `json:"ttl_seconds"`
Holder string `json:"holder"`
}
LockInfo describes the current state of a cross-process node lock.
type LockToken ¶ added in v0.11.0
type LockToken string
LockToken is an opaque string identifying lock ownership.
type MarkdownSchema ¶ added in v0.25.0
type MarkdownSchema struct {
RequireTitle bool `yaml:"requireTitle,omitempty" json:"requireTitle,omitempty"`
Ordered bool `yaml:"ordered,omitempty" json:"ordered,omitempty"`
Sections []MarkdownSection `yaml:"sections,omitempty" json:"sections,omitempty"`
}
type MarkdownSection ¶ added in v0.25.0
type MaturityWeightSchema ¶ added in v0.28.0
type MaturityWeightSchema struct {
Direction string `yaml:"direction,omitempty" json:"direction,omitempty"`
Attribute string `yaml:"attribute,omitempty" json:"attribute,omitempty"`
Weight float64 `yaml:"weight,omitempty" json:"weight,omitempty"`
Enum map[string]float64 `yaml:"enum,omitempty" json:"enum,omitempty"`
}
type MemoryRepo ¶
type MemoryRepo struct {
// contains filtered or unexported fields
}
MemoryRepo is an in-memory implementation of Repository intended for tests and lightweight tooling that doesn't require persistent storage.
Concurrency / locking:
- MemoryRepo uses an internal sync.RWMutex (mu) to guard all internal maps and per-node structures. Readers should use RLock/RUnlock; mutating operations use Lock/Unlock.
- The implementation is safe for concurrent use by multiple goroutines.
Semantics / behavior:
- NodeId entries are created on demand when writing content, meta, items, or images.
- Index files are kept in-memory by name (for example "nodes.tsv") and are accessible via WriteIndex/GetIndex.
- Methods return sentinel or typed errors defined in the package to match the Repository contract (for example NewNodeNotFoundError, ErrNotFound).
func NewMemoryRepo ¶
func NewMemoryRepo(rt *toolkit.Runtime) *MemoryRepo
NewMemoryRepo constructs a ready-to-use in-memory repository.
func (*MemoryRepo) AcquireLock ¶ added in v0.11.0
AcquireLock implements RepositoryLock.
func (*MemoryRepo) AppendSnapshot ¶ added in v0.4.0
func (r *MemoryRepo) AppendSnapshot(ctx context.Context, id NodeId, in SnapshotWrite) (Snapshot, error)
func (*MemoryRepo) ClearDex ¶
func (r *MemoryRepo) ClearDex() error
ClearDex removes all stored index artifacts.
func (*MemoryRepo) ClearIndexes ¶
func (r *MemoryRepo) ClearIndexes(ctx context.Context) error
ClearIndexes removes all stored index artifacts.
func (*MemoryRepo) ClearNodeLock ¶
func (r *MemoryRepo) ClearNodeLock(ctx context.Context, id NodeId) error
ClearNodeLock removes an active per-node lock marker and wakes any waiters that were blocked on it.
func (*MemoryRepo) DeleteAsset ¶
DeleteAsset removes an asset by name for a node.
func (*MemoryRepo) DeleteFile ¶
func (*MemoryRepo) DeleteImage ¶
func (*MemoryRepo) DeleteNode ¶
func (r *MemoryRepo) DeleteNode(ctx context.Context, id NodeId) error
DeleteNode removes the node and all associated content/metadata/items. If the node does not exist, NewNodeNotFoundError is returned.
func (*MemoryRepo) DeleteSchema ¶ added in v0.25.0
func (r *MemoryRepo) DeleteSchema(ctx context.Context, typeName string) error
func (*MemoryRepo) Emit ¶ added in v0.23.0
func (r *MemoryRepo) Emit(ev NodeEvent)
Emit implements RepositoryEvents. It broadcasts a programmatic event to all active Watch subscribers whose filters match. Test code uses this to simulate repository changes.
func (*MemoryRepo) ForceReleaseLock ¶ added in v0.11.0
func (r *MemoryRepo) ForceReleaseLock(ctx context.Context, id NodeId) error
ForceReleaseLock implements RepositoryLock.
func (*MemoryRepo) GetIndex ¶
GetIndex reads a stored index by name. If not present, ErrNotFound is returned. The returned bytes are a copy.
func (*MemoryRepo) GetSnapshot ¶ added in v0.4.0
func (r *MemoryRepo) GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (Snapshot, []byte, []byte, *NodeStats, error)
func (*MemoryRepo) ListAssets ¶
ListAssets lists asset names for a node and asset kind, sorted lexicographically.
func (*MemoryRepo) ListImages ¶
func (*MemoryRepo) ListIndexes ¶
func (r *MemoryRepo) ListIndexes(ctx context.Context) ([]string, error)
ListIndexes returns the names of stored index files sorted lexicographically.
func (*MemoryRepo) ListNodes ¶
func (r *MemoryRepo) ListNodes(ctx context.Context) ([]NodeId, error)
ListNodes returns all known NodeIDs sorted in ascending numeric order.
func (*MemoryRepo) ListSchemas ¶ added in v0.25.0
func (r *MemoryRepo) ListSchemas(ctx context.Context) ([]string, error)
func (*MemoryRepo) ListSnapshots ¶ added in v0.4.0
func (*MemoryRepo) LockNode ¶
func (r *MemoryRepo) LockNode(ctx context.Context, id NodeId, retryInterval time.Duration) (func() error, error)
LockNode attempts to acquire a per-node lock, blocking until the lock is released by the current holder or the context is cancelled. On success it returns an unlock function which the caller MUST call to release the lock.
Behavior notes:
- The retryInterval argument is retained for API compatibility but is no longer used. Waiters are woken directly by the releasing goroutine via a per-entry channel, eliminating the need for wall-clock polling and making contention handling deterministic under a frozen test clock.
- If ctx is cancelled while waiting, ErrLockTimeout is returned.
func (*MemoryRepo) LockStatus ¶ added in v0.11.0
LockStatus implements RepositoryLock.
func (*MemoryRepo) MoveNode ¶
MoveNode renames or moves a node from id to dst.
- If the source node does not exist, ErrNodeNotFound is returned. - If the destination already exists, a DestinationExistsError is returned. The move is performed by transferring the in-memory node pointer.
func (*MemoryRepo) Name ¶
func (r *MemoryRepo) Name() string
func (*MemoryRepo) Next ¶
func (r *MemoryRepo) Next(ctx context.Context) (NodeId, error)
Next returns a new NodeID and reserves it by inserting an empty node entry. This prevents concurrent callers from receiving the same ID.
func (*MemoryRepo) NodeFilesExist ¶
func (*MemoryRepo) ReadConfig ¶
func (r *MemoryRepo) ReadConfig(ctx context.Context) (*Config, error)
ReadConfig returns the repository-level config previously written with WriteConfig. If no config has been written, ErrNotFound is returned. A copy of the stored Config is returned to avoid external mutation.
func (*MemoryRepo) ReadContent ¶
ReadContent returns the primary content for the given node id.
- If the node does not exist, ErrNodeNotFound is returned. - If the node exists but has no content, (nil, nil) is returned. - The returned slice is a copy to prevent caller-visible mutation.
func (*MemoryRepo) ReadContentAt ¶ added in v0.4.0
func (r *MemoryRepo) ReadContentAt(ctx context.Context, id NodeId, rev RevisionID) ([]byte, error)
func (*MemoryRepo) ReadMeta ¶
ReadMeta returns the serialized node metadata (usually meta.yaml).
- If the node does not exist, ErrNodeNotFound is returned. - If meta is absent, ErrNotFound is returned. - The returned bytes are a copy.
func (*MemoryRepo) ReadSchema ¶ added in v0.25.0
func (*MemoryRepo) ReleaseLock ¶ added in v0.11.0
ReleaseLock implements RepositoryLock.
func (*MemoryRepo) RestoreSnapshot ¶ added in v0.4.0
func (r *MemoryRepo) RestoreSnapshot(ctx context.Context, id NodeId, rev RevisionID, createRestoreSnapshot bool) error
func (*MemoryRepo) Runtime ¶
func (r *MemoryRepo) Runtime() *toolkit.Runtime
func (*MemoryRepo) Watch ¶ added in v0.23.0
Watch implements RepositoryEvents for MemoryRepo. Events are delivered on the returned channel until ctx is cancelled, at which point the channel is closed.
func (*MemoryRepo) WithNodeLock ¶
func (r *MemoryRepo) WithNodeLock(ctx context.Context, id NodeId, fn func(context.Context) error) error
WithNodeLock executes fn while holding an exclusive lock for node id.
func (*MemoryRepo) WriteAsset ¶
func (r *MemoryRepo) WriteAsset(ctx context.Context, id NodeId, kind AssetKind, name string, data []byte) error
WriteAsset stores a named asset blob for a node.
func (*MemoryRepo) WriteConfig ¶
func (r *MemoryRepo) WriteConfig(ctx context.Context, config *Config) error
WriteConfig stores the provided Config in-memory. A copy of the value is kept.
func (*MemoryRepo) WriteContent ¶
WriteContent writes the primary content for the given node id, creating the node if necessary.
Note: this implementation stores the provided slice reference in-memory. Callers should avoid mutating the provided slice after calling this method.
func (*MemoryRepo) WriteImage ¶
func (*MemoryRepo) WriteIndex ¶
WriteIndex writes or replaces an in-memory index file.
func (*MemoryRepo) WriteMeta ¶
WriteMeta sets the node metadata (meta.yaml bytes), creating the node if needed.
Note: the provided slice is stored as-is in-memory; do not modify it after writing.
func (*MemoryRepo) WriteSchema ¶ added in v0.25.0
func (*MemoryRepo) WriteStats ¶
WriteStats writes programmatic stats while preserving manually edited meta fields.
type MetadataMaturitySchema ¶ added in v0.28.0
type Node ¶
type Node struct {
ID NodeId
Repo Repository
Runtime *toolkit.Runtime
// contains filtered or unexported fields
}
Node provides operations and lifecycle management for a single KEG node. It holds the node identifier, repository reference, and lazily-loaded node data.
func (*Node) ClearCache ¶
func (n *Node) ClearCache()
type NodeContent ¶
type NodeContent struct {
// Hash is the stable content hash computed by the repository hasher.
Hash string
// Title is the canonical title for the content. For Markdown this is the
// first H1; for RST it is the detected title.
Title string
// Lead is the first paragraph immediately following the title. It is used
// as a short summary or preview of the content.
Lead string
// Links is the list of numeric outgoing node links discovered in the
// content (for example "../42"). Entries are normalized NodeId values.
Links []NodeId
// Format is a short hint of the detected format. Typical values are
// "markdown", "rst", or "empty".
Format string
// Body is the content body with Markdown frontmatter removed when present.
// For non-Markdown formats this is the original file content.
Body string
// Frontmatter is the parsed YAML frontmatter when present. It is non-nil
// only for Markdown documents that include a leading YAML block.
Frontmatter map[string]any
}
NodeContent holds the extracted pieces of a node's primary content file (README.md or README.rst).
Fields:
- Hash: stable content hash computed by the repository hasher.
- Title: canonical title (first H1 for Markdown, or RST title detected).
- Lead: first paragraph immediately following the title (used as a short summary).
- Links: numeric outgoing node links discovered in the content (../N).
- Format: short hint of the detected format ("markdown", "rst", or "empty").
- Frontmatter: parsed YAML frontmatter when present (Markdown only).
- Body: the raw body bytes of the content file with frontmatter removed for Markdown (or the original bytes for other formats), represented as a string.
func ParseContent ¶
ParseContent extracts a NodeContent value from raw file bytes.
The format parameter is a filename hint (e.g., "README.md", "README.rst"). When format is ambiguous the function applies simple heuristics to choose between Markdown and reStructuredText. The returned NodeContent contains a deterministic, deduplicated, sorted list of discovered numeric links.
ParseContent uses the provided runtime hasher to compute content Hash. If the input is empty or only whitespace, a NodeContent with Format == "empty" is returned.
type NodeData ¶
type NodeData struct {
// ID is the node identifier as a string (for example "42" or "42-0001").
// Keep this lightweight while other fields are exposed via accessors.
ID NodeId
Content *NodeContent
Meta *NodeMeta
Stats *NodeStats
// Ancillary names (attachments and images). Implementations may populate these
// from the repository.
Items []string
Images []string
}
NodeData is a high-level representation of a KEG node. Implementations may compose this from repository pieces such as meta, content, and ancillary items.
func (*NodeData) ContentChanged ¶
ContentChanged reports whether the source state has changed since stats were refreshed.
func (*NodeData) ContentHash ¶
ContentHash returns the content hash if content is present, otherwise the empty string.
func (*NodeData) Lead ¶
Lead returns the short lead/summary for the node. Prefer stats then content.
func (*NodeData) Links ¶
Links returns the outgoing links discovered for the node. Prefer stats and fall back to parsed content links when stats are unavailable.
func (*NodeData) Ref ¶
func (n *NodeData) Ref() NodeIndexEntry
Ref builds a NodeIndexEntry from the NodeData. If the NodeData.ID is malformed ParseNode may fail and the function will fall back to a zero NodeId.
func (*NodeData) Tags ¶
Tags returns a copy of the normalized tag list from metadata or nil if not set.
func (*NodeData) Title ¶
Title returns the canonical title for the node. Prefer stats title and fall back to parsed content title when available.
func (*NodeData) UpdateMeta ¶
type NodeEvent ¶ added in v0.6.0
type NodeEvent struct {
Kind NodeEventKind
NodeID NodeId
Field string // "content", "meta", "stats", or ""
}
NodeEvent describes a single change or access observed on a node. Field identifies which part of the node was affected: "content" for README.md, "meta" for meta.yaml, "stats" for stats.json, or "" when the event applies to the node as a whole (e.g. creation or deletion of the entire directory).
type NodeEventKind ¶ added in v0.6.0
type NodeEventKind int
NodeEventKind identifies the type of change that occurred on a node.
const ( // NodeEventCreated indicates a new node was created. NodeEventCreated NodeEventKind = iota + 1 // NodeEventModified indicates an existing node file was modified. NodeEventModified // NodeEventDeleted indicates a node or node file was removed. NodeEventDeleted // NodeEventAccessed indicates a node's content or metadata was read. NodeEventAccessed )
func (NodeEventKind) String ¶ added in v0.6.0
func (k NodeEventKind) String() string
String returns a human-readable label for the event kind.
type NodeId ¶
type NodeId struct {
ID int
Alias string
// Code is an additional random identifier used to signify an uncommitted node.
Code string
}
NodeId is the stable numeric identifier for a KEG node. The ID field is the canonical non-negative integer identifier. The optional Code field is a zero-padded 4-digit numeric suffix used to represent an uncommitted or temporary variant of the node.
func NewTempNode ¶
NewTempNode creates a new NodeId using the provided base id string and a 4-digit numeric code. The function attempts to parse the base id via ParseNode; if that fails it will try to parse the string as a non-negative integer. If the id is empty or cannot be parsed as a non-negative integer the returned NodeId will have ID set to 0.
The Code is generated with crypto/rand when available and falls back to the current nanotime if random bytes cannot be obtained. The code is returned as a zero-padded 4-digit string.
The context parameter is accepted to allow future callers to pass context without changing the signature. It is not used by the current implementation.
func ParseNode ¶
ParseNode converts a string into a *NodeId.
Accepted forms:
"0" or a non-negative integer without leading zeros (for example "1", "23")
"<id>-<code>" where <id> follows the rules above and <code> is exactly 4 digits
"keg:<alias>/<id>" or "keg:<alias>/<id>-<code>" to include an alias.
Examples:
"42" -> &NodeId{ID:42, Code:""}, nil
"42-0001" -> &NodeId{ID:42, Code:"0001"}, nil
"keg:work/23" -> &NodeId{ID:23, Keg:"work"}, nil
"keg:work/23-0001" -> &NodeId{ID:23, Keg:"work", Code:"0001"}, nil
"0023" -> nil, error (leading zeros not allowed)
"" -> nil, error
func (NodeId) Increment ¶
Increment returns a new NodeId with the ID value increased by one while preserving the Code.
func (NodeId) Path ¶
Path returns the path component for this NodeId suitable for use in file names or URLs.
Examples:
NodeId{ID:42, Code:""} -> "42"
NodeId{ID:42, Code:"0001"} -> "42-0001"
NodeId{ID:42, Keg:"work"} -> "keg:work/42"
func (NodeId) PathNumeric ¶ added in v0.23.0
PathNumeric returns just the "<id>" or "<id>-<code>" portion of the node identifier, without any "keg:<alias>/" prefix. It is the canonical tail shared by every reference form.
type NodeIndex ¶
type NodeIndex struct {
// contains filtered or unexported fields
}
NodeIndex is an in-memory index of node descriptors used to construct the `nodes.tsv` index artifact.
The index stores a slice of `NodeIndexEntry` values in a deterministic order (ascending by numeric node id, with codes used to break ties). It provides helpers to parse a serialized index, mutate the in-memory list, and produce the canonical serialized bytes.
Concurrency note: NodeIndex itself does not perform internal synchronization. Callers that require concurrent access should guard an instance with a mutex.
func ParseNodeIndex ¶
ParseNodeIndex parses the serialized nodes index bytes into a NodeIndex.
Expected input is zero or more lines separated by newline. Each non-empty line represents a node entry in the canonical TSV format used by the repo. Parsers should tolerate empty input and skip malformed lines while continuing to parse the remainder. An empty input yields an empty NodeIndex and no error.
Parsing rules and leniency:
- Each valid line is expected to contain at least the ID field. Additional columns (for example updated timestamp and title) are accepted when present.
- Lines that cannot be parsed into a valid NodeIndexEntry are skipped and do not cause the entire parse to fail. This allows forward compatibility when new columns are added to the on-disk format.
- The returned NodeIndex contains entries in the order they were parsed; it is the caller's responsibility to sort or normalize ordering if desired.
Returns:
- a NodeIndex containing parsed NodeIndexEntry values.
- a non nil error only for unexpected conditions preventing parsing of the entire input (for example severe encoding issues). Minor line-level parse problems are tolerated and do not cause an error.
Example input (5-column format):
"42\t2025-01-02T15:04:05Z\t2024-06-01T10:00:00Z\t2025-01-03T08:00:00Z\tMy Title\n"
Column order: id<TAB>updated<TAB>created<TAB>accessed<TAB>title
func (*NodeIndex) Add ¶
Add inserts the provided node into the index. The index should remain sorted by ascending node id after the operation.
Behavior expectations:
- If idx is nil the call is a no-op and returns nil.
- The method should ensure idx.data is initialized when first used.
- Adding an existing node id should be idempotent: the existing entry should be updated or replaced rather than producing duplicates.
- The operation is in-memory only and does not perform I/O.
Typical callers: - Index builders that aggregate node metadata into the nodes index. - Tests that need to construct an in-memory nodes list.
Note: This method does not acquire any synchronization; callers should hold a lock if concurrent mutations are possible.
Implementation note:
The function should insert or update the NodeIndexEntry derived from the supplied NodeData. After modification, idx.data must be ordered so that Next and serialized output are stable and deterministic.
func (*NodeIndex) Data ¶
Data serializes the NodeIndex into the canonical on-disk TSV representation.
Serialization rules:
- Each entry produces a single line in the form used by the repository's nodes index. Column order is: id<TAB>updated<TAB>created<TAB>accessed<TAB>title<LF>.
- Entries must be emitted in ascending node id order.
- An empty index returns an empty byte slice.
The returned bytes are owned by the caller and may be written atomically by the repository layer. The function should not modify idx.data.
Implementation note:
The function should not rely on external state. It must produce stable, deterministic output suitable for writing to an index file.
func (*NodeIndex) Get ¶
func (idx *NodeIndex) Get(ctx context.Context, node NodeId) *NodeIndexEntry
Get returns the NodeIndexEntry pointer for the provided node if present. The lookup uses node.Path() to match the ID field of entries.
Returns:
- *NodeIndexEntry when the entry is present.
- nil when the entry is not present or idx is nil.
The returned pointer points into the internal slice. Callers that need to modify the entry should copy it first to avoid data races.
func (*NodeIndex) List ¶
func (idx *NodeIndex) List(ctx context.Context) []NodeIndexEntry
List returns the in-memory slice of NodeIndexEntry. The returned slice is the underlying data and callers should not mutate it to avoid data races.
func (*NodeIndex) Next ¶
Next returns the next available NodeId id based on the current index contents.
Semantics:
- If the index is empty, Next returns NodeId{ID:0, Code:""} (the zeroth id).
- Otherwise Next returns a NodeId whose ID is one greater than the highest numeric ID present in the index. If entries contain code suffixes the numeric portion is used for ordering.
- The function does not modify the index.
Implementation note:
The function should examine idx.data to determine the maximal numeric id and return the subsequent id. It should not allocate or write any external state.
func (*NodeIndex) Rm ¶
Rm removes the node identified by id from the index.
Behavior expectations: - If idx is nil the call is a no-op and returns nil. - If the node is not present the call should not error. - After removal the index slice should remain in a stable, sorted state. - This method only mutates in-memory state and does not perform I/O.
Typical callers: - Index maintenance routines that remove entries for deleted nodes. - Tests cleaning up expected state.
Implementation note:
The function should locate the entry whose ID equals node.Path() and remove it from the slice. The remaining slice should preserve deterministic order.
type NodeIndexEntry ¶
type NodeIndexEntry struct {
ID string `json:"id" yaml:"id"`
Title string `json:"title" yaml:"title"`
Updated time.Time `json:"updated" yaml:"updated"`
Created time.Time `json:"created" yaml:"created"`
Accessed time.Time `json:"accessed" yaml:"accessed"`
}
NodeIndexEntry is a small descriptor for a node used by repository listings and indices. It contains the node id as a string, a human-friendly title, and timestamps for updated, created, and accessed.
type NodeMeta ¶
type NodeMeta struct {
// contains filtered or unexported fields
}
NodeMeta holds manually edited node metadata and helpers to read/update it.
Programmatic fields (title/hash/timestamps/lead/links) are represented by NodeStats. NodeMeta focuses on human-editable yaml data and comment-preserving writes.
func ParseMeta ¶
ParseMeta parses raw yaml bytes into NodeMeta. Empty input returns an empty NodeMeta.
func (*NodeMeta) Set ¶
Set updates known NodeMeta keys (tags) and preserves unknown keys in the yaml node when available.
func (*NodeMeta) ToYAMLWithStats ¶
ToYAMLWithStats serializes metadata while optionally merging programmatic NodeStats fields into the emitted yaml.
type NodeRef ¶ added in v0.23.0
type NodeRef struct {
Form RefForm
Node NodeId
Alias string // RefAlias only
Namespace string // RefQualified only, "@" sigil stripped
KegName string // RefQualified only
}
NodeRef is a parsed node reference. Node always carries the numeric id and optional 4-digit code. Form selects how the owning keg is addressed:
- RefLocal: Node only; resolves against the current keg.
- RefAlias: Alias set; resolves against the current keg's Links table then the tap-config kegs map. Node.Alias mirrors Alias.
- RefQualified: Namespace+KegName set; the hub is implied from context.
func ParseNodeRef ¶ added in v0.23.0
ParseNodeRef parses any of the three node-reference forms. It is a superset of ParseNode: bare ids and "keg:<alias>/<id>" parse identically, and the qualified "keg:@<namespace>/<keg>/<id>" form is additionally recognized.
The forms are disambiguated purely textually: a leading "keg:@" with two slashes is qualified; "keg:" with one slash is an alias; anything else is a bare local id.
type NodeStats ¶
type NodeStats struct {
// contains filtered or unexported fields
}
NodeStats contains programmatic node data derived by tooling.
func ParseStats ¶
ParseStats extracts programmatic node stats from raw JSON bytes.
func (*NodeStats) AccessCount ¶
func (*NodeStats) ClearOmega ¶ added in v0.28.0
func (s *NodeStats) ClearOmega()
func (*NodeStats) EnsureTimes ¶
func (*NodeStats) IncrementAccessCount ¶
func (s *NodeStats) IncrementAccessCount()
func (*NodeStats) SetAccessCount ¶
func (*NodeStats) SetAccessed ¶
func (*NodeStats) SetCreated ¶
func (*NodeStats) SetUpdated ¶
func (*NodeStats) UpdateFromContent ¶
func (s *NodeStats) UpdateFromContent(content *NodeContent, now *time.Time)
func (*NodeStats) UpdateFromSource ¶ added in v0.28.0
type NodeValidationPayload ¶ added in v0.25.0
type NodeView ¶ added in v0.23.0
type NodeView struct {
ID NodeId
// Content is the node's primary content (README.md).
Content []byte
// Meta is the raw metadata bytes as stored (may be empty).
Meta []byte
// Stats is the parsed programmatic stats (zero-value when absent).
Stats *NodeStats
// Files and Images list asset names; nil when the backend lacks the
// capability.
Files []string
Images []string
}
NodeView is a node's full state assembled in one operation.
type Option ¶
type Option func(*LocalKeg)
Option is a functional option for configuring LocalKeg behavior
type QueryExpr ¶ added in v0.18.0
type QueryExpr struct {
// contains filtered or unexported fields
}
QueryExpr is an opaque compiled tag boolean expression. Callers obtain one via ParseQueryExpression and pass it to EvaluateQueryExpression. The underlying AST is unexported; external packages cannot inspect or implement it.
func ParseQueryExpression ¶ added in v0.18.0
ParseQueryExpression compiles raw into a QueryExpr that can be evaluated with EvaluateQueryExpression. Returns an error if raw is empty or syntactically invalid.
type QueryFilteredIndex ¶ added in v0.15.0
type QueryFilteredIndex struct {
// contains filtered or unexported fields
}
func NewQueryFilteredIndex ¶ added in v0.15.0
func NewQueryFilteredIndex(name, query string, resolve func(term string, data *NodeData) bool) (*QueryFilteredIndex, error)
NewQueryFilteredIndex creates a QueryFilteredIndex for the given index file name and boolean query string. The optional resolve callback enables key=value attribute predicates and other term types.
When resolve is nil, terms are evaluated as tag names against the node's tag set.
name should be the bare filename used when writing to the repository, e.g. "golang.md".
func NewQueryFilteredIndexWithSort ¶ added in v0.18.0
func NewQueryFilteredIndexWithSort(name, query string, resolve func(term string, data *NodeData) bool, sortOrder QueryFilteredSortOrder) (*QueryFilteredIndex, error)
NewQueryFilteredIndexWithSort creates a QueryFilteredIndex with an explicit sort order. The sortOrder parameter accepts "id", "created", "accessed", or empty string (default: sort by Updated descending).
func (*QueryFilteredIndex) Add ¶ added in v0.15.0
func (idx *QueryFilteredIndex) Add(ctx context.Context, data *NodeData) error
Add evaluates the query expression against the node and, if it matches, inserts or updates the node entry maintaining the configured sort order.
func (*QueryFilteredIndex) Clear ¶ added in v0.15.0
func (idx *QueryFilteredIndex) Clear(ctx context.Context) error
Clear resets the index to an empty state.
func (*QueryFilteredIndex) Data ¶ added in v0.15.0
func (idx *QueryFilteredIndex) Data(ctx context.Context) ([]byte, error)
Data serializes the QueryFilteredIndex to the same markdown format as ChangesIndex.Data. Entries are in reverse-chronological order.
func (*QueryFilteredIndex) Name ¶ added in v0.15.0
func (idx *QueryFilteredIndex) Name() string
Name returns the short index filename used with repo.WriteIndex.
type QueryFilteredSortOrder ¶ added in v0.18.0
type QueryFilteredSortOrder string
QueryFilteredIndex is an in-memory index of nodes that match a boolean query expression. It supports the full query expression system: tag names, key=value attribute predicates, boolean operators (and/or/not), and parenthesized grouping.
The resolve callback, when non-nil, is called for each term in the query expression with each candidate node. This allows higher-level packages (e.g. pkg/tapper) to inject attribute predicate support without creating a dependency from pkg/keg to pkg/tapper.
When resolve is nil, the index falls back to tag-only matching (each term is evaluated as a tag name against the node's tag set).
Concurrency note: QueryFilteredIndex does not perform internal synchronization. Callers should guard access with a mutex when needed. QueryFilteredSortOrder controls the sort order of entries in a QueryFilteredIndex.
const ( // QFSortUpdated sorts by Updated descending (newest first). This is the // default when no sort order is specified. QFSortUpdated QueryFilteredSortOrder = "" // QFSortID sorts by node ID ascending. QFSortID QueryFilteredSortOrder = "id" // QFSortCreated sorts by Created descending (newest first). QFSortCreated QueryFilteredSortOrder = "created" // QFSortAccessed sorts by Accessed descending (newest first). QFSortAccessed QueryFilteredSortOrder = "accessed" )
type QueryOptions ¶ added in v0.23.0
type QueryOptions struct {
// Expr is the boolean query expression, e.g. "project and .updated>2026-01-01".
Expr string
}
QueryOptions configures Keg.Query.
type RateLimitError ¶
type RateLimitError struct {
RetryAfter time.Duration // suggested wait time
Message string
Cause error
}
RateLimitError represents a throttling response that includes a suggested RetryAfter duration and an optional message. It is always considered retryable.
func (*RateLimitError) Error ¶
func (e *RateLimitError) Error() string
func (*RateLimitError) Retryable ¶
func (e *RateLimitError) Retryable() bool
func (*RateLimitError) Unwrap ¶
func (e *RateLimitError) Unwrap() error
type RefForm ¶ added in v0.23.0
type RefForm int
RefForm enumerates the three shapes a node reference may take.
const ( // RefLocal is a bare "<id>" or "<id>-<code>" resolving against the current keg. RefLocal RefForm = iota // RefAlias is "keg:<alias>/<id>[-<code>]" — the alias resolves against the // current keg's Links table (then the tap-config kegs map). RefAlias // RefQualified is "keg:@<namespace>/<keg>/<id>[-<code>]" — fully qualified; // the hub is implied from the current keg's hub. RefQualified )
type RelationSchema ¶ added in v0.25.0
type RelationSchema struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Required bool `yaml:"required,omitempty" json:"required,omitempty"`
Maturity []MaturityWeightSchema `yaml:"maturity,omitempty" json:"maturity,omitempty"`
}
type RemoteKeg ¶ added in v0.23.0
type RemoteKeg struct {
// contains filtered or unexported fields
}
RemoteKeg implements Keg over tapper-hub's operation-level HTTP API. Each Keg method is a single HTTP round trip against the per-keg base URL (`<hub>/api/v1/@{namespace}/kegs/{keg}`); all orchestration — locking discipline, dex/index maintenance, stats touching — happens server-side inside the hub's LocalKeg.
func NewRemoteKeg ¶ added in v0.23.0
NewRemoteKeg constructs a RemoteKeg speaking the hub's operation API at baseURL (the per-keg prefix, trailing slash trimmed) with bearer token authentication.
func (*RemoteKeg) AppendSnapshot ¶ added in v0.23.0
AppendSnapshot implements Keg via POST /nodes/{id}/snapshots. The body carries only the message — the hub computes the snapshot payloads from the node's current server-side state.
func (*RemoteKeg) BaseURL ¶ added in v0.23.0
BaseURL returns the per-keg API prefix this client targets.
func (*RemoteKeg) Create ¶ added in v0.23.0
Create implements Keg via a single POST /nodes carrying the composed content (and meta when tags/attrs are set). The node payload is composed client-side exactly as LocalKeg composes it; the hub assigns the id.
func (*RemoteKeg) DeleteFile ¶ added in v0.23.0
DeleteFile implements Keg via DELETE /nodes/{id}/assets/{name}.
func (*RemoteKeg) DeleteImage ¶ added in v0.23.0
DeleteImage implements Keg via DELETE /nodes/{id}/images/{name}.
func (*RemoteKeg) DeleteSchema ¶ added in v0.25.0
DeleteSchema implements Keg via DELETE /schemas/{type}.
func (*RemoteKeg) Dex ¶ added in v0.23.0
Dex implements Keg via GET /dex, which returns every index artifact in one response. The artifacts are loaded into a scratch in-memory repo and parsed through the same NewDexFromRepo path LocalKeg uses.
func (*RemoteKeg) ExportNodes ¶ added in v0.23.0
func (k *RemoteKeg) ExportNodes(ctx context.Context, opts ExportNodesOptions) (io.ReadCloser, error)
ExportNodes implements Keg via GET /archive. The hub's response body is the keg-archive stream and is returned directly without buffering; the caller must Close it.
func (*RemoteKeg) ForceUnlock ¶ added in v0.23.0
ForceUnlock implements Keg via DELETE /nodes/{id}/lock?force=1.
func (*RemoteKeg) GetContent ¶ added in v0.23.0
GetContent implements Keg via GET /nodes/{id}/content.
func (*RemoteKeg) GetMeta ¶ added in v0.23.0
GetMeta implements Keg. Absent meta yields an empty meta rather than an error, matching LocalKeg semantics.
func (*RemoteKeg) GetMetaRaw ¶ added in v0.23.0
GetMetaRaw implements Keg via GET /nodes/{id}/meta. Missing meta propagates ErrNotExist.
func (*RemoteKeg) GetSnapshot ¶ added in v0.23.0
func (k *RemoteKeg) GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (Snapshot, []byte, []byte, *NodeStats, error)
GetSnapshot implements Keg via GET /nodes/{id}/snapshots/{rev}, passing resolve_content when opts request materialized payloads.
func (*RemoteKeg) GetStats ¶ added in v0.23.0
GetStats implements Keg via GET /nodes/{id}/stats. Stats are server-managed; there is no write counterpart.
func (*RemoteKeg) ImportNodes ¶ added in v0.23.0
func (k *RemoteKeg) ImportNodes(ctx context.Context, r io.Reader, opts ImportNodesOptions) ([]ImportedNode, error)
ImportNodes implements Keg via POST /archive, streaming r as the request body.
func (*RemoteKeg) Index ¶ added in v0.23.0
func (k *RemoteKeg) Index(ctx context.Context, opts IndexOptions) error
Index implements Keg via POST /index/rebuild.
func (*RemoteKeg) Init ¶ added in v0.23.0
Init implements Keg. Remote kegs are created through the hub's keg-creation endpoint (POST /api/v1/@{namespace}/kegs) at the Tap layer, not through the per-keg operation API.
func (*RemoteKeg) ListImages ¶ added in v0.23.0
ListImages implements Keg via GET /nodes/{id}/images.
func (*RemoteKeg) ListIndexes ¶ added in v0.23.0
ListIndexes implements Keg via GET /indexes.
func (*RemoteKeg) ListSchemas ¶ added in v0.25.0
ListSchemas implements Keg via GET /schemas.
func (*RemoteKeg) ListSnapshots ¶ added in v0.23.0
ListSnapshots implements Keg via GET /nodes/{id}/snapshots.
func (*RemoteKeg) Lock ¶ added in v0.23.0
Lock implements Keg via POST /nodes/{id}/lock. The hub owns the lease; no client-side renewal goroutine runs.
func (*RemoteKeg) LockStatus ¶ added in v0.23.0
LockStatus implements Keg via GET /nodes/{id}/lock; a zero LockInfo means unheld.
func (*RemoteKeg) NodeExists ¶ added in v0.23.0
NodeExists implements Keg via HEAD /nodes/{id}.
func (*RemoteKeg) Query ¶ added in v0.23.0
func (k *RemoteKeg) Query(ctx context.Context, opts QueryOptions) ([]NodeIndexEntry, error)
Query implements Keg via POST /query.
func (*RemoteKeg) ReadContentAt ¶ added in v0.23.0
ReadContentAt implements Keg via GET /nodes/{id}/snapshots/{rev}/content.
func (*RemoteKeg) ReadFile ¶ added in v0.23.0
ReadFile implements Keg via GET /nodes/{id}/assets/{name}.
func (*RemoteKeg) ReadImage ¶ added in v0.23.0
ReadImage implements Keg via GET /nodes/{id}/images/{name}.
func (*RemoteKeg) ReadNode ¶ added in v0.23.0
ReadNode implements Keg via GET /nodes/{id}: the node's full state in one round trip.
func (*RemoteKeg) ReadSchema ¶ added in v0.25.0
ReadSchema implements Keg via GET /schemas/{type}.
func (*RemoteKeg) RestoreSnapshot ¶ added in v0.23.0
RestoreSnapshot implements Keg via POST /nodes/{id}/snapshots/{rev}/restore.
func (*RemoteKeg) SetConfig ¶ added in v0.23.0
SetConfig implements Keg via PUT /config with the raw config bytes.
func (*RemoteKeg) SetContent ¶ added in v0.23.0
SetContent implements Keg via PUT /nodes/{id}/content with the raw bytes.
func (*RemoteKeg) SetMeta ¶ added in v0.23.0
SetMeta implements Keg via PUT /nodes/{id}/meta with the meta's YAML.
func (*RemoteKeg) SetTokenFn ¶ added in v0.28.1
SetTokenFn installs a per-request token source. Each request calls fn and uses its return value for the Authorization header; an empty return sends the request unauthenticated. Pass nil to revert to the static token.
func (*RemoteKeg) Summary ¶ added in v0.23.0
func (k *RemoteKeg) Summary(ctx context.Context) (*KegSummary, error)
Summary implements Keg via GET /summary.
func (*RemoteKeg) Target ¶ added in v0.23.0
Target returns the keg's resolved location, or nil when unknown.
func (*RemoteKeg) Token ¶ added in v0.23.0
Token returns the bearer token used for authentication ("" when none).
func (*RemoteKeg) Unlock ¶ added in v0.23.0
Unlock implements Keg via DELETE /nodes/{id}/lock with the X-Lock-Token header proving ownership.
func (*RemoteKeg) ValidateNode ¶ added in v0.25.0
ValidateNode implements Keg via POST /nodes/{id}/validate.
func (*RemoteKeg) ValidateNodePayload ¶ added in v0.25.0
func (k *RemoteKeg) ValidateNodePayload(ctx context.Context, payload NodeValidationPayload) (*SchemaValidationResult, error)
ValidateNodePayload implements Keg via POST /validate.
func (*RemoteKeg) Watch ¶ added in v0.23.0
Watch implements Keg by subscribing to the hub's per-node websocket event stream (/nodes/{id}/events) for each requested node.
func (*RemoteKeg) WriteFile ¶ added in v0.23.0
WriteFile implements Keg via PUT /nodes/{id}/assets/{name}.
func (*RemoteKeg) WriteImage ¶ added in v0.23.0
WriteImage implements Keg via PUT /nodes/{id}/images/{name}.
type RenderOptions ¶ added in v0.11.0
type RenderOptions struct {
// BaseURL is the keg-root URL prefix for rewritten node links; node N
// lives at {BaseURL}N. Defaults to "/".
BaseURL string
// NodeID identifies the node being rendered. When set, every relative
// destination is resolved as if the page were {BaseURL}{NodeID}/README.md,
// which covers ./images/X, ./assets/X, and ../N/README.md in addition to
// ../N. When empty, only the legacy ../N shape is rewritten and other
// relative links pass through unchanged.
NodeID string
// NoTrailingSlash emits node hrefs as {BaseURL}N instead of {BaseURL}N/.
NoTrailingSlash bool
// KegResolver maps keg:-scheme references to hrefs. namespace is "" for
// the bare-alias form keg:ALIAS/N. Returning "" leaves the link
// untouched, as does a nil resolver.
KegResolver func(namespace, alias, nodeID string) string
}
RenderOptions configures markdown-to-HTML rendering.
type Repository ¶
type Repository interface {
// Name returns a short, human-friendly backend identifier.
Name() string
// HasNode reports whether id exists as a node in the backend.
// Missing nodes should return (false, nil). Backend/storage failures should
// be returned as non-nil errors.
HasNode(ctx context.Context, id NodeId) (bool, error)
// Next returns the next available node id allocation candidate.
// Implementations should honor ctx cancellation where applicable.
Next(ctx context.Context) (NodeId, error)
// ListNodes returns all node ids present in the backend.
// Returned ids should be deterministic (stable ordering) when possible.
ListNodes(ctx context.Context) ([]NodeId, error)
// MoveNode renames or relocates a node from id to dst.
// Implementations should return typed/sentinel errors when source is missing
// or destination already exists.
MoveNode(ctx context.Context, id NodeId, dst NodeId) error
// DeleteNode removes the node and all associated persisted data.
// If id does not exist, implementations should return a typed/sentinel
// not-exist error.
DeleteNode(ctx context.Context, id NodeId) error
// WithNodeLock executes fn while holding an exclusive lock for node id.
// Implementations should block until the lock is acquired or ctx is
// canceled, and must release the lock after fn returns.
WithNodeLock(ctx context.Context, id NodeId, fn func(context.Context) error) error
// ReadContent reads the primary node content bytes (for example README.md).
// Missing nodes should return a typed/sentinel not-exist error.
ReadContent(ctx context.Context, id NodeId) ([]byte, error)
// WriteContent writes primary node content bytes for id.
// Implementations should perform atomic writes when possible.
WriteContent(ctx context.Context, id NodeId, data []byte) error
// ReadMeta reads raw node metadata bytes (for example meta.yaml).
// Missing nodes should return a typed/sentinel not-exist error.
ReadMeta(ctx context.Context, id NodeId) ([]byte, error)
// WriteMeta writes raw node metadata bytes.
// Implementations should preserve atomicity when possible.
WriteMeta(ctx context.Context, id NodeId, data []byte) error
// ReadStats returns parsed programmatic node stats for id.
// Backends that persist stats inside meta.yaml should parse and return those
// fields while preserving any manual metadata concerns at higher layers.
ReadStats(ctx context.Context, id NodeId) (*NodeStats, error)
// WriteStats writes programmatic node stats for id.
// Implementations should preserve manually edited metadata fields when stats
// and metadata share a storage representation.
WriteStats(ctx context.Context, id NodeId, stats *NodeStats) error
// GetIndex reads an index artifact by name (for example "nodes.tsv").
// Callers should treat returned bytes as immutable.
GetIndex(ctx context.Context, name string) ([]byte, error)
// WriteIndex writes an index artifact by name.
// Implementations should prefer atomic file replacement semantics.
WriteIndex(ctx context.Context, name string, data []byte) error
// ListIndexes returns available index artifact names.
// Results should be deterministic when possible.
ListIndexes(ctx context.Context) ([]string, error)
// ClearIndexes removes or resets index artifacts in the backend.
// This method should be idempotent and context-aware.
ClearIndexes(ctx context.Context) error
// ReadConfig reads repository-level keg configuration.
// Missing config should return typed/sentinel not-exist errors.
ReadConfig(ctx context.Context) (*Config, error)
// WriteConfig persists repository-level keg configuration.
// Implementations should perform atomic writes when possible.
WriteConfig(ctx context.Context, config *Config) error
}
Repository is the storage backend contract used by KEG. Implementations are responsible for moving node data between storage and the service layer.
type RepositoryEvents ¶ added in v0.6.0
type RepositoryEvents interface {
Watch(ctx context.Context, ids ...NodeId) (<-chan NodeEvent, error)
// Emit sends a NodeEvent to all active subscribers whose filters match.
// This is used for programmatic events (e.g. access tracking) that
// cannot be detected by filesystem watchers.
Emit(ev NodeEvent)
}
RepositoryEvents is an optional interface that Repository implementations may satisfy to provide live change notifications. Consumers use a type assertion to check whether the underlying repository supports events.
Watch begins observing changes for the specified node IDs (or all nodes when no IDs are given). The watch is scoped to ctx: events are delivered on the returned channel until ctx is cancelled, and implementations must close the channel when observation ends. There is no separate teardown — cancelling ctx releases all per-watch resources.
type RepositoryFiles ¶
type RepositoryFiles interface {
// ListFiles lists file attachment names for a node.
ListFiles(ctx context.Context, id NodeId) ([]string, error)
// ReadFile reads a file attachment for a node.
ReadFile(ctx context.Context, id NodeId, name string) ([]byte, error)
// WriteFile stores a file attachment for a node.
WriteFile(ctx context.Context, id NodeId, name string, data []byte) error
// DeleteFile removes a file attachment from a node.
DeleteFile(ctx context.Context, id NodeId, name string) error
}
RepositoryFiles provides optional per-node file attachment access.
type RepositoryImages ¶
type RepositoryImages interface {
// ListImages lists image names for a node.
ListImages(ctx context.Context, id NodeId) ([]string, error)
// ReadImage reads an image payload for a node.
ReadImage(ctx context.Context, id NodeId, name string) ([]byte, error)
// WriteImage stores an image payload for a node.
WriteImage(ctx context.Context, id NodeId, name string, data []byte) error
// DeleteImage removes an image from a node.
DeleteImage(ctx context.Context, id NodeId, name string) error
}
RepositoryImages provides optional per-node image access.
type RepositoryLock ¶ added in v0.11.0
type RepositoryLock interface {
// AcquireLock acquires a cross-process lock on a node. Returns a token
// that proves ownership. If the node is already locked by a non-stale
// lock, blocks until the lock is released or ctx is canceled.
AcquireLock(ctx context.Context, id NodeId) (LockToken, error)
// ReleaseLock releases a cross-process lock. The token must match the
// token returned by AcquireLock. Returns an error if the token does not
// match or no lock is held.
ReleaseLock(ctx context.Context, id NodeId, token LockToken) error
// LockStatus returns the current lock state for a node. If no lock is
// held (or the lock is stale), returns a zero LockInfo with no error.
LockStatus(ctx context.Context, id NodeId) (LockInfo, error)
// ForceReleaseLock unconditionally removes a lock regardless of token
// ownership. Use as an escape hatch for stuck or stale locks.
ForceReleaseLock(ctx context.Context, id NodeId) error
}
RepositoryLock provides cross-process token-based node locking. This is an optional interface (like RepositoryFiles, RepositoryImages, RepositorySnapshots). Not all repository implementations need cross-process locking.
Cross-process locks are separate from the process-scoped WithNodeLock on the core Repository interface. WithNodeLock serializes concurrent goroutines within a single process; RepositoryLock coordinates across separate CLI invocations or MCP server sessions.
type RepositorySchemas ¶ added in v0.25.0
type RepositorySchemas interface {
ListSchemas(ctx context.Context) ([]string, error)
ReadSchema(ctx context.Context, typeName string) ([]byte, error)
WriteSchema(ctx context.Context, typeName string, data []byte) error
DeleteSchema(ctx context.Context, typeName string) error
}
RepositorySchemas provides optional keg-level schema storage.
Implementations persist raw YAML keyed by schema type. LocalKeg owns parsing, type checks, JSON schema validation, and write policy; repositories only persist and retrieve schema bytes.
type RepositorySnapshots ¶
type RepositorySnapshots interface {
// AppendSnapshot appends a new revision with optimistic parent check.
// Implementations should preserve SnapshotWrite.CreatedAt when supplied and
// otherwise stamp the revision with the current runtime clock time.
AppendSnapshot(ctx context.Context, id NodeId, in SnapshotWrite) (Snapshot, error)
// GetSnapshot returns snapshot metadata and optional state payloads.
// When opts.ResolveContent is true, returned content must be fully materialized.
GetSnapshot(ctx context.Context, id NodeId, rev RevisionID, opts SnapshotReadOptions) (snap Snapshot, content []byte, meta []byte, stats *NodeStats, err error)
// ListSnapshots returns revisions for a node in deterministic order.
ListSnapshots(ctx context.Context, id NodeId) ([]Snapshot, error)
// ReadContentAt reconstructs content at a specific revision.
ReadContentAt(ctx context.Context, id NodeId, rev RevisionID) ([]byte, error)
// RestoreSnapshot restores live node state to rev. Implementations may append
// a restore snapshot when createRestoreSnapshot is true.
RestoreSnapshot(ctx context.Context, id NodeId, rev RevisionID, createRestoreSnapshot bool) error
}
RepositorySnapshots provides revision-based history operations.
type RevisionID ¶
type RevisionID int64
type SchemaDefinition ¶ added in v0.25.0
type SchemaDefinition struct {
Version int `yaml:"version,omitempty" json:"version,omitempty"`
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Summary string `yaml:"summary,omitempty" json:"summary,omitempty"`
Meta map[string]any `yaml:"meta,omitempty" json:"meta,omitempty"`
Markdown MarkdownSchema `yaml:"markdown,omitempty" json:"markdown,omitempty"`
// Maturity is deprecated legacy compatibility. Prefer property-scoped
// metadata maturity rows under meta.properties.<property>.maturity.
Maturity []MetadataMaturitySchema `yaml:"maturity,omitempty" json:"maturity,omitempty"`
Relations []RelationSchema `yaml:"relations,omitempty" json:"relations,omitempty"`
}
func ParseSchemaDefinition ¶ added in v0.25.0
func ParseSchemaDefinition(data []byte) (*SchemaDefinition, error)
func (*SchemaDefinition) MetadataMaturityWeights ¶ added in v0.28.0
func (s *SchemaDefinition) MetadataMaturityWeights() []MetadataMaturitySchema
type SchemaPolicy ¶ added in v0.25.0
type SchemaPolicy struct {
Human ValidationMode `yaml:"human,omitempty" json:"human,omitempty"`
Agent ValidationMode `yaml:"agent,omitempty" json:"agent,omitempty"`
API ValidationMode `yaml:"api,omitempty" json:"api,omitempty"`
}
type SchemaValidationError ¶ added in v0.25.0
type SchemaValidationError struct {
NodeID string
Type string
Issues []ValidationIssue
}
func (*SchemaValidationError) Error ¶ added in v0.25.0
func (e *SchemaValidationError) Error() string
func (*SchemaValidationError) Unwrap ¶ added in v0.25.0
func (e *SchemaValidationError) Unwrap() error
type SchemaValidationResult ¶ added in v0.25.0
type SchemaValidationResult struct {
NodeID string `json:"node_id,omitempty" yaml:"node_id,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Valid bool `json:"valid" yaml:"valid"`
Issues []ValidationIssue `json:"issues,omitempty" yaml:"issues,omitempty"`
}
type Snapshot ¶
type Snapshot struct {
ID RevisionID
Node NodeId
Parent RevisionID // 0 for root
CreatedAt time.Time
Message string
// Integrity + retrieval hints
ContentHash string
MetaHash string
StatsHash string
IsCheckpoint bool // full content stored instead of patch
}
type SnapshotConfig ¶ added in v0.28.0
type SnapshotConfig struct {
// Mode controls whether the hub should create idle snapshots automatically.
// Supported values are "auto" and "off".
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
// IdleAfter is a Go-style duration string. Nodes become eligible for auto
// snapshots only after their last edit has been idle for at least this long.
IdleAfter string `yaml:"idleAfter,omitempty" json:"idleAfter,omitempty"`
}
SnapshotConfig holds per-keg automatic snapshot policy settings.
func DefaultSnapshotConfig ¶ added in v0.28.0
func DefaultSnapshotConfig() *SnapshotConfig
type SnapshotContentKind ¶
type SnapshotContentKind string
SnapshotContentKind describes how snapshot content bytes are stored.
const ( // SnapshotContentKindPatch stores content as a diff from a base revision. SnapshotContentKindPatch SnapshotContentKind = "patch" // SnapshotContentKindFull stores full reconstructed content bytes. SnapshotContentKindFull SnapshotContentKind = "full" )
type SnapshotContentWrite ¶
type SnapshotContentWrite struct {
Kind SnapshotContentKind
Base RevisionID
// Algorithm identifies the patch format, for example "xdiff-v1".
Algorithm string
Data []byte
// Hash is the digest of fully materialized content at this revision.
Hash string
}
SnapshotContentWrite describes content payload for a new snapshot revision.
type SnapshotPolicyResult ¶ added in v0.28.0
type SnapshotPolicyResult struct {
Mode string
IdleAfter time.Duration
Scanned int
Created []Snapshot
}
SnapshotPolicyResult summarizes one automatic snapshot-policy scan.
func (SnapshotPolicyResult) CreatedCount ¶ added in v0.28.0
func (r SnapshotPolicyResult) CreatedCount() int
CreatedCount returns the number of snapshots appended during the scan.
type SnapshotReadOptions ¶
type SnapshotReadOptions struct {
// ResolveContent reconstructs full content bytes for the selected revision.
ResolveContent bool
}
SnapshotReadOptions configures how snapshots are loaded.
type SnapshotWrite ¶
type SnapshotWrite struct {
ExpectedParent RevisionID
Message string
// CreatedAt preserves an externally supplied revision timestamp. When zero,
// repositories stamp the snapshot with the current runtime clock time.
CreatedAt time.Time
Meta []byte
Stats *NodeStats
Content SnapshotContentWrite
}
SnapshotWrite describes append parameters for a new node snapshot.
type TagIndex ¶
type TagIndex struct {
// contains filtered or unexported fields
}
TagIndex is an in-memory index mapping a normalized tag string to the list of nodes that declare that tag.
The index format (used by ParseTagIndex and Data) is line-oriented. Each line represents a tag and its node list in the form:
<tag>\t<node1> <node2> ...\n
Where <nodeN> is the node.Path() string representation (for example "42" or "42-0001"). Parsers should tolerate empty input and skip empty lines. When serializing, the implementation should produce stable output by sorting tag keys and de-duplicating and sorting node lists.
Note: TagIndex does not perform internal synchronization. Callers that need concurrent access should guard the index with a mutex.
func ParseTagIndex ¶
ParseTagIndex parses the serialized tag index bytes into a TagIndex.
Expected input is zero or more lines separated by newline. Each non-empty line must contain a tag, a tab, and a space-separated list of node ids. Invalid or malformed lines should be handled gracefully by ignoring the offending line and continuing parsing. An empty input yields an empty TagIndex and no error.
func (*TagIndex) Add ¶
Add incorporates the node into the index for each tag present on the node.
Behavior notes: - If idx is nil this is a no-op. - The method should ensure idx.data is initialized when first used. - Duplicate entries for a given tag should be avoided (idempotent add). - The node should be added using node.Path() as the identifier.
func (*TagIndex) Data ¶
Data serializes the TagIndex to the canonical byte representation described for ParseTagIndex.
Serialization requirements:
- Tags (map keys) must be emitted in a stable, deterministic order. When a tag token can be parsed as a NodeId id it may be ordered numerically; otherwise fall back to lexicographic ordering.
- NodeId lists for each tag must be de-duplicated and sorted by numeric id then by code (the same ordering ParseNode/NodeId.Compare implies).
- Lines must use a single tab between tag and the node list, and a single space between node ids. Each line must be terminated with a newline.
- If the index is empty return an empty byte slice and no error.
type Target ¶ added in v0.20.0
type Target struct {
// File is the file to use when the Target is a file
File string `yaml:"file,omitempty"`
// Hub is an optional explicit hub pin for a keg reference. It is normally
// empty: the hub is resolved from the Namespace via the tapper config's
// namespaces map. The canonical keg reference does not carry a hub.
Hub string `yaml:"hub,omitempty"`
// HubURL is the resolved base URL for the hub (for example
// "https://atlas.foldwise.ai"). It is derived at resolution time from the
// tapper config's hubs map and is intentionally not serialized. A keg
// reference that reaches NewKegFromTarget without it was never resolved
// against a hub and is rejected.
HubURL string `yaml:"-"`
// Url is the url for the target when represented as a scalar or explicit
// mapping value. Url is used when the target was http/s, git, ssh, etc
Url string `yaml:"url,omitempty"`
Memory bool
// Namespace is the namespace owner for hub targets. The "@" sigil is
// implied; do not store it. A user's default namespace shares their
// username; organizations and other namespace types use the same field.
Namespace string `yaml:"namespace,omitempty"`
// KegName is the keg's name within the Namespace.
KegName string `yaml:"kegName,omitempty"`
// BasicAuthUser is the HTTP basic-auth username for URL targets.
// Distinct from Namespace, which addresses a hub-scheme namespace owner.
BasicAuthUser string `yaml:"basicAuthUser,omitempty"`
Password string `yaml:"password,omitempty"`
Token string `yaml:"token,omitempty"`
TokenEnv string `yaml:"tokenEnv,omitempty"`
// Readonly specifies in the target is readonly. Only api and file are
// writable
Readonly bool `yaml:"readonly,omitempty"`
}
Target describes a resolved KEG repository target.
Schema is the URI scheme when the target was written as a URL (for example "file", "http", "https"). Path is the URL path component or an absolute filesystem path when the target was supplied as a file path.
The Target type is the canonical, minimal shape used by tooling. Valid input forms that map into Target include:
- File targets:
- Scalar file paths such as "/abs/path", "./rel/path", "../rel/path", "~/path", or Windows drive paths.
- Mapping form with a "file" key. File values are cleaned with filepath.Clean; Expand will attempt to expand a leading tilde.
- API or HTTP targets:
- Full URL scalars (http:// or https://).
- Mapping form with "url" and optional user/password/token/tokenEnv. Query params like "readonly", "token", and "token-env" are honored.
- Keg reference shorthand and structured form:
- Compact scalar shorthand "keg:@namespace/keg" (canonical; namespace optional as "keg:keg"). The hub is resolved from the namespace, never encoded. "keg:/@namespace/keg" is accepted as an input variant.
- Mapping form with "namespace" and "kegName" (and an optional "hub" pin).
Fields:
- File: filesystem path for a local keg target.
- Hub: hub name when using an API style target.
- Url: canonical URL when provided or parsed from a scalar.
- Namespace/KegName: structured hub pieces used to compose API paths. Namespace is the owner — a user's default namespace shares their username, but organizations and other namespace types are also valid. The "@" sigil is implied and not stored.
- BasicAuthUser: HTTP basic-auth username for URL targets. Distinct from Namespace, which addresses a hub-scheme namespace owner.
- Password/Token/TokenEnv: credential hints. TokenEnv is preferred for production usage.
- Readonly: when true the target was requested read only.
func NewApi ¶ added in v0.20.0
func NewApi(hub string, namespace, kegName string, opts ...TargetOption) Target
NewApi constructs a Target representing a keg API endpoint. namespace is the namespace owner (no "@" sigil); kegName is the keg's name within it.
func NewFile ¶ added in v0.20.0
func NewFile(path string, opts ...TargetOption) Target
NewFile constructs a file target for a local filesystem path. The path is cleaned using filepath.Clean.
func NewMemory ¶ added in v0.20.0
func NewMemory(kegalias string, opts ...TargetOption) Target
func Parse ¶ added in v0.20.0
Parse parses a user-supplied target scalar into a Target.
Accepted input forms:
- File paths (absolute, ./, ../, ~, Windows drive). These produce File targets.
- Canonical keg reference "keg:@namespace/keg" (namespace optional as "keg:keg"); "keg:/@namespace/keg" is an accepted variant. The leading "@" sigil marks the namespace and is stripped on parse so the stored namespace never carries it; Path() and String() re-apply it. The hub is resolved from the namespace, never encoded in the reference.
- HTTP/HTTPS URL scalars.
- Any URL-like scalar parsed by url.Parse.
The function is permissive with common variants (extra whitespace, duplicate slashes). It returns an error for empty or malformed keg references.
func (*Target) Expand ¶ added in v0.20.0
Expand replaces environment variables and expands a leading tilde in File and Hub-related fields. It uses std.ExpandEnv and std.ExpandPath so behavior matches the rest of the code base.
Errors from ExpandPath are collected and returned as a joined error so callers can see expansion issues.
func (*Target) Host ¶ added in v0.20.0
Host returns the hostname portion for HTTP/HTTPS targets. For file targets it returns an empty string.
func (*Target) Scheme ¶ added in v0.20.0
Scheme reports the inferred scheme for this Target value. A keg reference (identified by a Namespace owner, or an explicit Hub pin) implies the keg scheme. File implies a local file scheme. Otherwise we fall back to detectScheme on the Url.
func (*Target) String ¶ added in v0.20.0
String returns a human-friendly representation of the target. A keg reference renders in the canonical "keg:@namespace/kegName" form (namespace omitted as "keg:kegName" when unset). The hub is NOT part of the reference — it is resolved from the namespace via config — so the scheme is always the real "keg" scheme, never a hub name. File targets return the file path; HTTP targets return the canonical Url.
func (*Target) UnmarshalYAML ¶ added in v0.20.0
UnmarshalYAML accepts either a scalar string (the URL or shorthand or file) or a mapping node that decodes into the full Target struct. Mapping form may include structured hub/user/keg or an explicit file field.
When a scalar is provided the value is parsed via Parse which recognizes file scalars, shorthand hub forms, and URL scalars.
type TargetOption ¶ added in v0.20.0
type TargetOption = func(t *Target)
func WithHubURL ¶ added in v0.23.0
func WithHubURL(hubURL string) TargetOption
WithHubURL sets the resolved hub base URL on a hub Target. The tapper layer uses this to push the URL looked up from the configured hubs map down into the Target so NewKegFromTarget composes the API endpoint against it.
func WithReadonly ¶ added in v0.20.0
func WithReadonly() TargetOption
type TokenResolver ¶ added in v0.20.0
TokenResolver supplies bearer tokens for remote targets when no token is configured inline on the target or via TokenEnv. Implementations typically look up credentials in a persistent auth store keyed by the target's hub root. A resolver returns "" when no credential is available; a nil TokenResolver is legal and means "no fallback".
type TransientError ¶
type TransientError struct {
Cause error
}
TransientError marks a transient (retryable) failure, e.g. network timeout, DB deadlock. It implements both Temporary() and Retryable().
func (*TransientError) Error ¶
func (e *TransientError) Error() string
func (*TransientError) Retryable ¶
func (e *TransientError) Retryable() bool
func (*TransientError) Temporary ¶
func (e *TransientError) Temporary() bool
func (*TransientError) Unwrap ¶
func (e *TransientError) Unwrap() error
type ValidationActor ¶ added in v0.25.0
type ValidationActor string
const ( ValidationActorHuman ValidationActor = "human" ValidationActorAgent ValidationActor = "agent" ValidationActorAPI ValidationActor = "api" ValidationActorImport ValidationActor = "import" ValidationActorRestore ValidationActor = "restore" )
func ValidationActorFromContext ¶ added in v0.25.0
func ValidationActorFromContext(ctx context.Context) ValidationActor
type ValidationIssue ¶ added in v0.25.0
type ValidationMode ¶ added in v0.25.0
type ValidationMode string
const ( ValidationModeAuto ValidationMode = "" ValidationModeOff ValidationMode = "off" ValidationModeWarn ValidationMode = "warn" ValidationModeBlock ValidationMode = "block" )
func ValidationModeFromContext ¶ added in v0.25.0
func ValidationModeFromContext(ctx context.Context) ValidationMode
Source Files
¶
- archive.go
- asset_name.go
- constants.go
- content.go
- dex.go
- dex_backlinks.go
- dex_changes.go
- dex_links.go
- dex_nodes.go
- dex_tags.go
- errors.go
- image_validate.go
- indexes.go
- keg.go
- keg_config.go
- keg_helpers.go
- keg_iface.go
- keg_local_assets.go
- keg_local_commit.go
- keg_local_config.go
- keg_local_content.go
- keg_local_create.go
- keg_local_dex.go
- keg_local_events.go
- keg_local_index.go
- keg_local_lock.go
- keg_local_move.go
- keg_local_node.go
- keg_local_view.go
- keg_omega.go
- keg_query.go
- keg_remote.go
- keg_remote_events.go
- keg_snapshots.go
- node.go
- node_data.go
- node_id.go
- node_meta.go
- node_ref.go
- node_stats.go
- query_expr.go
- remote_errors.go
- render.go
- repo_events.go
- repo_filesystem.go
- repo_filesystem_lock.go
- repo_filesystem_snapshots.go
- repo_fs_events.go
- repo_lock.go
- repo_memory.go
- repo_memory_events.go
- repo_memory_lock.go
- repo_memory_snapshots.go
- repository.go
- repository_capabilities.go
- schema.go
- snapshot_indexes.go
- snapshot_patch.go
- snapshot_policy.go
- snapshots.go
- tags.go
- target.go