Skip to content

schema

go
import "github.com/nathabonfim59/pbvex/backend/internal/schema"

Package schema manages the PBVex reserved system collections and bootstrap state.

Index

Constants

go
const (
    CollectionDeployments      = "_pbvex_deployments"
    CollectionFunctions        = "_pbvex_functions"
    CollectionSchemaState      = "_pbvex_schemaState"
    CollectionJobs             = "_pbvex_jobs"
    CollectionComponents       = "_pbvex_components"
    CollectionStorageFiles     = "_pbvex_storage_files"
    CollectionStorageTokens    = "_pbvex_storage_tokens"
    CollectionStorageKeyring   = "_pbvex_storage_keyring"
    CollectionMigrationHistory = "_pbvex_migration_history"

    StateKeyActive = "active"

    FieldManifest             = "manifest"
    FieldBundleHash           = "bundle_hash"
    FieldBundleSize           = "bundle_size"
    FieldBundle               = "bundle"
    FieldActive               = "active"
    FieldPinCount             = "pinCount"
    FieldActivatedAt          = "activatedAt"
    FieldName                 = "name"
    FieldVersion              = "version"
    FieldProtocol             = "protocol"
    FieldFunctions            = "functions"
    FieldKey                  = "key"
    FieldActiveID             = "activeDeploymentId"
    FieldPreviousID           = "previousDeploymentId"
    FieldCursorSecret         = "cursorSecret"
    FieldCursorPreviousSecret = "cursorPreviousSecret"
    FieldCursorKeyID          = "cursorKeyId"
    // ID signing is deliberately independent from the rotating cursor key.
    // Cursor rotations may expire pagination tokens, but must never invalidate
    // a durable document capability or a persisted v.id reference.
    FieldIDSecret = "idSecret"
    FieldIDKeyID  = "idKeyId"
    // FieldLegacyIDSecret is a durable migration verifier for capabilities
    // emitted before ids received their own signing root.  It is copied once
    // from the pre-v1 cursor root and deliberately never follows cursor
    // rotation: old document ids and persisted v.id references must not expire
    // merely because pagination keys rotate.
    FieldLegacyIDSecret = "legacyIdSecret"
    FieldDeploymentID   = "deploymentId"
    FieldModulePath     = "modulePath"
    FieldExportName     = "exportName"
    FieldFunctionType   = "type"
    FieldHttpAction     = "httpAction"
    FieldVisibility     = "visibility"
    FieldArgs           = "args"
    FieldReturns        = "returns"
    FieldStatus         = "status"
    FieldPayload        = "payload"
    FieldType           = "type"
    FieldResult         = "result"
    FieldError          = "error"
    FieldStarted        = "started"
    FieldFinished       = "finished"
    FieldMetadata       = "metadata"
    FieldScheduledAt    = "scheduledAt"
    FieldLease          = "lease"
    FieldLeaseExpiresAt = "leaseExpiresAt"
    FieldAttempts       = "attempts"
    FieldCreated        = "created"
    FieldUpdated        = "updated"
    FieldMigrationID    = "migrationId"
    FieldChecksum       = "checksum"
    FieldSourceHash     = "sourceSchemaHash"
    FieldTargetHash     = "targetSchemaHash"
    FieldDirection      = "direction"
    FieldAppliedAt      = "appliedAt"

    FieldStorageID          = "storageId"
    FieldStorageSha256      = "sha256"
    FieldStorageSize        = "size"
    FieldStorageContentType = "contentType"
    FieldStorageFileKey     = "fileKey"
    FieldStorageFilename    = "filename"
    FieldStorageStatus      = "status"
    FieldStorageDeletedAt   = "deletedAt"
    FieldStorageCreatedBy   = "createdBy"
    FieldStorageOwner       = "leaseOwner"
    FieldStorageLeaseUntil  = "leaseUntil"
    FieldStoragePublicToken = "publicToken"
    FieldStorageMetadata    = "metadata"

    FieldToken               = "token"
    FieldTokenStorageID      = "storageId"
    FieldTokenExpiresAt      = "expiresAt"
    FieldTokenConsumed       = "consumed"
    FieldTokenCreatedBy      = "createdBy"
    FieldTokenMaxSize        = "maxSize"
    FieldTokenAllowedTypes   = "allowedTypes"
    FieldTokenFilename       = "filename"
    FieldTokenClaim          = "claim"
    FieldTokenClaimExpiresAt = "claimExpiresAt"
    FieldTokenPolicy         = "policy"

    FieldKeyringKeyID     = "keyId"
    FieldKeyringKey       = "key"
    FieldKeyringPurpose   = "purpose"
    FieldKeyringCreatedAt = "createdAt"
    FieldKeyringExpiresAt = "expiresAt"
)

go
const (
    MaxValidatorDepth = 128
    MaxValidatorNodes = 16 * 1024
    MaxValidatorBytes = 4 << 20
)

DocumentOrderField is an internal, hidden JSON projection of document values. SQLite's JSON comparison rules deliberately conflate missing and null and do not order the protocol's little-endian int64 or base64 bytes values. PBVex therefore indexes this canonical projection instead of the user document directly. The projection is written transactionally with the document and is never exposed to JavaScript.

go
const DocumentOrderField = "_pbvex_order"

Variables

AppContextKey carries the PocketBase app through request contexts.

go
var AppContextKey = appContextKey{}

InternalContextKey is used to mark PBVex service DB writes as internal.

go
var InternalContextKey = internalKey{}

func AppFromContext

go
func AppFromContext(ctx context.Context) (core.App, bool)

AppFromContext returns the PocketBase app stored in the context.

func Bootstrap

go
func Bootstrap(app core.App) error

Bootstrap ensures all PBVex system collections exist and creates the active state seed.

func CanonicalWire

go
func CanonicalWire(value any) bool

CanonicalWire validates the protocol wire-value subset independently of a particular validator.

func EqualityProjectionField

go
func EqualityProjectionField(path string) string

EqualityProjectionField returns the internal projection key for a declared q.field path. Document field names cannot begin with '$', so this cannot collide with a user-owned projection entry.

func FieldValidator

go
func FieldValidator(fields map[string]any, path string) (any, bool)

FieldValidator resolves a canonical q.field path against a table field shape. Top-level document fields and constrained-object segments reject literal dots, so splitting never falls back to a user-provided SQL path. Manifest validation, physical-index materialization and runtime querying all call this one resolver.

func GenericOrderKey

go
func GenericOrderKey(value any, present bool) (string, error)

GenericOrderKey is used for index bounds. The validator determines the id-vs-string distinction where applicable; all other scalar literals retain their protocol type rank.

func IndexableValidator

go
func IndexableValidator(validator any) bool

IndexableValidator reports whether a manifest validator has a stable, materializable scalar sort key. This is deliberately conservative: a SQLite index over an arbitrary union/object/array would have semantics that differ from the protocol evaluator.

func IsBackingCollection

go
func IsBackingCollection(c *core.Collection) bool

IsBackingCollection reports whether a collection has the PBVex backing storage fingerprint. It deliberately recognizes the internal fields even if an operator has drifted a rule/hidden flag: those fields must never become a raw PocketBase API escape hatch while activation is rejecting that drift. A non-PBVex collection which deliberately adopts this private ABI is also protected, which is the safe failure mode for reserved storage names.

func IsReservedCollection

go
func IsReservedCollection(name string) bool

IsReservedCollection reports whether the name belongs to the PBVex system.

func NormalizeDocument

go
func NormalizeDocument(fields map[string]any, doc map[string]any, partial, rejectSystem bool, check IDChecker) (map[string]any, error)

NormalizeDocument validates a document shape and applies defaults. When partial is true omitted fields are intentionally left untouched; otherwise required and defaulted fields are resolved. rejectSystem reserves document _id/_creationTime while allowing those ordinary names in nested objects.

func NormalizeValue

go
func NormalizeValue(validator, value any, check IDChecker) (any, error)

NormalizeValue validates one wire value and applies defaulted validators.

func ObjectFieldValidator

go
func ObjectFieldValidator(validator any, name string) (any, bool)

ObjectFieldValidator returns a direct child validator of a constrained object. It intentionally does not traverse an unconstrained object or a union: q.field paths are schema-addressable only when every requested segment is unambiguous and declared. Other wire-object keys remain valid application data but are not query-path syntax.

func OpaqueIDMAC

go
func OpaqueIDMAC(key, payload []byte) []byte

OpaqueIDMAC is shared by the runtime encoder and the activation verifier. Keeping the domain-separated primitive here prevents an ID written by one request path from using subtly different signing bytes than a v.id checked during migration.

func OpaqueIDOrderKey

go
func OpaqueIDOrderKey(table, raw string) string

OpaqueIDOrderKey is the canonical ordering representation of an ID value. The signed transport encoding intentionally changes when key versions or MACs change; ordering the capability text would make the same record move between pages after rotation. The table/raw-record tuple is immutable and is also what the system _id SQL expression projects.

func OpaqueIDVersionMAC

go
func OpaqueIDVersionMAC(root []byte, keyID int, payload []byte) []byte

OpaqueIDVersionMAC derives a stable signing key for the embedded version from the persistent ID root. The root is retained indefinitely, so changing the active version never makes a live document id or v.id reference expire.

func OrderData

go
func OrderData(fields map[string]any, document map[string]any) (map[string]any, error)

OrderData produces a total-order key for every declared table field. A field which is absent from the source document is deliberately different from a field whose value is null.

func OrderDataWithID

go
func OrderDataWithID(fields map[string]any, document map[string]any, check IDChecker) (map[string]any, error)

OrderDataWithID is OrderData with the request/activation ID authenticator. Passing it keeps an id|string union from classifying a merely id-shaped string as an ID rank; runtime writes and activation both use this form.

func OrderKey

go
func OrderKey(validator any, value any, present bool) (string, error)

OrderKey produces a lexical key whose byte order is the PBVex wire-value order. It intentionally supports only the scalar values that can be used by a declared SQLite index. Activation rejects an index over a compound or otherwise unsupported validator rather than silently using SQLite's incompatible JSON ordering.

func OrderKeyWithID

go
func OrderKeyWithID(validator any, value any, present bool, check IDChecker) (string, error)

OrderKeyWithID derives a protocol ordering key while preserving a validated id|string union distinction. IDChecker is optional for tooling that only has a serializable descriptor; request and activation paths must provide it.

func SQLiteJSONPathLiteral

go
func SQLiteJSONPathLiteral(field string) string

SQLiteJSONPathLiteral returns a SQL string literal containing a SQLite JSON path for one object key. The key is quoted at the JSON-path layer and the resulting path is quoted independently for SQL. Keeping this in one place prevents schema DDL and runtime queries from drifting or interpolating raw field fragments.

func SQLiteJSONPathLiteralPath

go
func SQLiteJSONPathLiteralPath(parts []string) string

SQLiteJSONPathLiteralPath is the nested-path counterpart used for canonical q.field("parent.child") traversal. Each segment is independently JSON-path quoted; callers never concatenate a user field name into SQL syntax.

func ValidateComponentValue

go
func ValidateComponentValue(validator, value any) bool

ValidateComponentValue applies structural validation for mount arguments. Legacy pbv1 capabilities are root-only and can never be mounted into a component namespace.

func ValidateDescriptor

go
func ValidateDescriptor(validator any) bool

ValidateDescriptor validates the serializable validator graph. It also validates default values against their child, rejects delayed descriptors (which cannot be serialized safely), bounds union width, and enforces the record-key contract.

func ValidateValue

go
func ValidateValue(validator, value any, check IDChecker) bool

ValidateValue is a convenience predicate used by callers that do not need normalized output.

func VerifyOpaqueID

go
func VerifyOpaqueID(value, namespace string, identityRoot, legacyRoot []byte, cursorKeyID int, cursorCurrent, cursorPrevious []byte) (string, string, bool)

VerifyOpaqueID authenticates a PBVex capability against the persisted namespace identity root. legacyRoot is a durable, one-time migration verifier for ids written by the historical cursor-key scheme. It is kept independently of cursor current/previous so those old ids survive arbitrary future cursor rotations and restarts. current/previous remain a short compatibility path for a rolling upgrade that has not yet persisted the anchor.

func WithApp

go
func WithApp(ctx context.Context, app core.App) context.Context

WithApp returns a context carrying the given PocketBase app and marked as internal.

func WithInternalContext

go
func WithInternalContext(ctx context.Context) context.Context

WithInternalContext returns a context marked for PBVex internal writes.

type IDChecker

IDChecker authenticates a table-bound opaque id. Nil retains structural validation for deployment-time schema checks, while runtime callers provide the persisted-key checker.

go
type IDChecker func(id, table string) bool

Generated by gomarkdoc

Generated API reference. Source of truth is the codebase.