registry

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Overview

Package registry loads the realm/database/collection tree from CONFIG_DIR into an immutable, validated registry used by routing, validation and provisioning.

Index

Constants

View Source
const (
	ErasureDelete    = "delete"
	ErasureAnonymize = "anonymize"
)

Erasure actions on the documents a user owns.

View Source
const (
	MatchEmail = "email"
	MatchID    = "id"
)

What a `pull` or `unset` field holds: the user's email or their id.

View Source
const (
	FunctionsDir = "_functions" // one Deno project per database
	BuildDir     = ".build"     // bundles and their manifest, written by `backd functions build`
	ManifestFile = "manifest.json"
	FunctionFile = "function.yaml"

	InputSchemaFile  = "input.schema.json"
	OutputSchemaFile = "output.schema.json"
)

Function layout inside a database directory.

View Source
const (
	ModeSync    = "sync"
	ModeAsync   = "async"
	ModeWebhook = "webhook"
)

Function modes.

View Source
const (
	DefaultSyncTimeout  = 10 * time.Second
	DefaultAsyncTimeout = 15 * time.Minute
	MaxSyncTimeout      = 60 * time.Second
	MaxAsyncTimeout     = 24 * time.Hour

	DefaultMemory = 128 << 20

	DefaultMaxOutput = 1 << 20

	MaxSyncOutput = 64 << 20
	// MaxAsyncOutput keeps an async job's result within one MongoDB
	// document (16 MiB, minus room for the job's other fields).
	MaxAsyncOutput     = 15 << 20
	DefaultConcurrency = 10
)

Defaults and bounds of function.yaml values.

View Source
const (
	SignupOpen   = "open"
	SignupInvite = "invite"
	SignupClosed = "closed"
)

Signup modes.

View Source
const (
	DefaultIdleTimeout    = 30 * 24 * time.Hour
	DefaultMaxLifetime    = 90 * 24 * time.Hour
	DefaultAuditRetention = 365 * 24 * time.Hour

	// DefaultLogRetention is functions.log_retention's default: a short
	// debugging window, not a log archive (see the docs).
	DefaultLogRetention = 7 * 24 * time.Hour

	// DefaultJobRetention is functions.job_retention's default: how long
	// an async job's result is kept once done (roadmap F11).
	DefaultJobRetention = 24 * time.Hour

	DefaultPasswordMinLength = 12
)

Defaults for realm settings left out of realm.yaml.

View Source
const (
	DefaultEmailPerKindPerHour = 3
	DefaultEmailPerDay         = 10
	DefaultEmailPerIPPerHour   = 20
	// The caps of custom emails from functions.
	DefaultEmailPerFunctionPerHour   = 200
	DefaultEmailPerInvocation        = 50
	DefaultEmailRecipientsPerMessage = 10
	// DefaultLocale is email.default_locale when not set.
	DefaultLocale = "en"
)

Defaults of email.limits.

View Source
const CollectionFile = "collection.yaml"

CollectionFile is the optional file next to a collection's schema.json holding its data policy for an erased user.

View Source
const DefaultRedirectDelay = 3 * time.Second

DefaultRedirectDelay is email.redirect_delay when not set.

View Source
const DefaultResetPasswordTTL = time.Hour

DefaultResetPasswordTTL is account.tokens.reset_password when not set.

View Source
const DefaultVerifyEmailTTL = 48 * time.Hour

DefaultVerifyEmailTTL is account.tokens.verify_email when not set.

View Source
const DenoVersion = "2.9.7"

DenoVersion is the Deno version functions are bundled and run with. `backd functions build` requires exactly this version, and the executor image is built from it.

View Source
const MaxCallChain = 4

MaxCallChain is the longest chain of functions calling each other, the entry function included.

View Source
const RealmFile = "realm.yaml"

RealmFile is the name of the required realm settings file.

View Source
const (

	// SchemaFile is the name of a collection's schema file.
	SchemaFile = schemaFile
)
View Source
const SystemDatabaseSuffix = "___system"

SystemDatabaseSuffix is appended to a realm name to form the MongoDB database holding the realm's users, sessions and keys.

Variables

ReservedDirs are folders of a realm that hold something other than a database: they are never read as databases.

View Source
var SystemFields = []string{"id", "_meta.created_at", "_meta.updated_at", "_meta.version", "_meta.owner", "_meta.created_by", "_meta.updated_by"}

SystemFields are the server-owned fields that can be queried, sorted and indexed in addition to the schema's fields.

Functions

func NormalizeEmail

func NormalizeEmail(v string) (string, error)

NormalizeEmail trims and lowercases an email address and checks its basic shape (one "@" with text on both sides, no spaces). The reserved ".invalid" top-level domain (RFC 2606) is refused: it never receives mail, and erased users' placeholder addresses live there, so nobody may take one. Characters that delimit addresses or break a header (commas, angle brackets, quotes, control characters...) are refused as well: a delivery function that joins recipients with commas must never see one address that is really two.

func ParseDuration

func ParseDuration(v string) (time.Duration, error)

ParseDuration parses a Go duration ("12h", "90m") or a whole number of days ("30d").

func ParseSize

func ParseSize(v string) (int64, error)

ParseSize parses a size such as 128MB (decimal) or 1MiB (binary).

func SourceHash

func SourceHash(dir string) (string, error)

SourceHash hashes every file of a functions project, except hidden entries (such as .build), so any change to code, shared lib/, deno.json, deno.lock or schemas changes it.

func ValidName

func ValidName(name string) bool

ValidName reports whether name is a valid realm, database or collection name.

func ValidSecretName

func ValidSecretName(name string) bool

ValidSecretName reports whether name is a valid secret NAME (upper-case letters, digits and _, starting with a letter) — the same rule function.yaml's secrets list is checked against, without the leading "realm." a reference may carry.

Types

type AccountSettings added in v0.4.0

type AccountSettings struct {
	// RequireVerifiedEmail: no session until the address is verified.
	RequireVerifiedEmail bool
	// WelcomeEmail sends the welcome email once the address is verified.
	WelcomeEmail bool
	// VerifyEmailTTL is how long a verification link works (account.tokens.verify_email).
	VerifyEmailTTL time.Duration
	// AllowEmailChange lets users change their own address (`POST /_auth/email`).
	AllowEmailChange bool
	// ChangeEmailTTL and RevertEmailChangeTTL are how long the confirmation
	// and the undo link of an email change work.
	ChangeEmailTTL, RevertEmailChangeTTL time.Duration
	// ResetPasswordTTL is how long a reset link works (account.tokens.reset_password).
	ResetPasswordTTL time.Duration
	// PurgeUnverifiedAfter deletes accounts that never verified; 0 is off.
	PurgeUnverifiedAfter time.Duration
}

AccountSettings are the account lifecycle settings of a realm.

func (AccountSettings) TokenLifetime added in v0.4.0

func (a AccountSettings) TokenLifetime(p email.Purpose) time.Duration

TokenLifetime is how long a token of this purpose works in the realm.

type Collection

type Collection struct {
	Realm         string
	Database      string
	MongoDatabase string // <realm>__<database>
	Name          string
	SchemaPath    string             // path of schema.json, for error messages
	RawSchema     map[string]any     // decoded schema.json (numbers as json.Number)
	Schema        *jsonschema.Schema // compiled draft 2020-12 schema
	Fields        map[string]Field   // dot path → field info, for query checks
	Indexes       []Index            // declared in indexes.json
	IndexPath     string             // path of indexes.json, when present
	Rules         *rules.Set         // from rules.yaml; nil allows nothing
	Erasure       *ErasurePolicy     // from collection.yaml; nil: an erase leaves the collection alone
	ErasurePath   string             // path of collection.yaml, for error messages
}

Collection is a set of documents validated by one JSON Schema.

func (*Collection) ArrayField

func (c *Collection) ArrayField(path string) bool

ArrayField reports whether path is declared as an array (only), with no array on the way to it.

func (*Collection) IsKnownField

func (c *Collection) IsKnownField(path string) bool

IsKnownField reports whether path is a system field or declared in the schema.

func (*Collection) ScalarField

func (c *Collection) ScalarField(path string) bool

ScalarField reports whether path holds a single value: a system field, or a declared field whose types exclude "array", with no array on the way to it.

type Database

type Database struct {
	Realm       string
	Name        string
	MongoName   string // <realm>__<database>
	Collections map[string]*Collection
	Functions   *Functions // from _functions/; nil when the database has none
}

Database is one application's data, stored in one MongoDB database.

func (*Database) SortedCollections

func (d *Database) SortedCollections() []*Collection

SortedCollections returns the database's collections sorted by name.

type EmailLimits added in v0.4.0

type EmailLimits struct {
	PerKindPerHour int // emails of one kind to one recipient, per hour
	PerDay         int // emails to one recipient, per day
	PerIPPerHour   int // email-sending requests from one client address, per hour
	// The caps of custom emails from functions (ctx.email.send), whoever the
	// recipients are.
	PerFunctionPerHour   int // messages one function sends, per hour
	PerInvocation        int // messages one invocation sends
	RecipientsPerMessage int // to, cc and bcc of one message
}

EmailLimits bound how many emails one address, and one client address, can cause.

type EmailSettings added in v0.4.0

type EmailSettings struct {
	Function      string // <database>/<function>: internal and async
	From          string // "Name <address>" or an address
	ReplyTo       string // optional
	PublicURL     string // overrides BACKD_URL for this realm's links; no trailing slash
	DefaultLocale string
	Locales       []string // every one needs every required template
	Limits        EmailLimits
	// RedirectDelay is how long a hosted result page waits before it sends the
	// user on (email.redirect_delay).
	RedirectDelay time.Duration
	// Redirects are where the hosted pages send users afterwards, by flow
	// (verify_email, reset_password, change_email, invitation), when the
	// request that caused the email named no other place.
	Redirects map[string]string
	// AllowedRedirects are the origins (https://app.example.com) and app
	// schemes (acme://) that redirect_to, redirects and links may point at.
	AllowedRedirects []string
	// Links replace the hosted page of a flow with a page of the app: the
	// link in the email is this URL, with {token} replaced.
	Links map[string]string
	// Timeout is the delivery function's own timeout, set when the config is
	// loaded; email jobs lease for it.
	Timeout time.Duration
}

EmailSettings are the email settings of a realm: which function delivers its messages and who they come from. backd renders the messages and never sends one itself.

func (EmailSettings) AllowedRedirect added in v0.4.0

func (e EmailSettings) AllowedRedirect(raw string) bool

AllowedRedirect reports whether raw is an absolute URL on one of the allowed origins or app schemes: where a page may send a user.

func (EmailSettings) DatabaseAndName added in v0.4.0

func (e EmailSettings) DatabaseAndName() (string, string)

DatabaseAndName splits Function into the database and the function name.

type ErasurePolicy added in v0.4.0

type ErasurePolicy struct {
	// Action applies to the documents whose _meta.owner is the user: "" leaves
	// them, ErasureDelete removes them, ErasureAnonymize applies Remove and
	// Replace and clears the owner.
	Action  string
	Remove  []string       // fields removed (anonymize)
	Replace map[string]any // fields set to a fixed value (anonymize)
	// Pull and Unset act on every document of the collection, whoever owns it:
	// the user is removed from the array field / cleared from the field. The
	// value says what the field holds: MatchEmail or MatchID.
	Pull  map[string]string
	Unset map[string]string
}

ErasurePolicy is what an erase does to a collection (collection.yaml's on_owner_delete). A collection without the file is left alone.

func (*ErasurePolicy) Fields added in v0.4.0

func (p *ErasurePolicy) Fields() []string

Fields lists every field the policy touches, for the indexes it needs.

func (*ErasurePolicy) IndexedFields added in v0.4.0

func (p *ErasurePolicy) IndexedFields() []string

IndexedFields are the fields an erase searches by: the arrays and fields that hold the user (pull and unset), which need an index to be found without scanning the collection.

type Field

type Field struct {
	Types     []string // JSON Schema types; empty when the schema doesn't constrain it
	ItemTypes []string // for arrays: the types of the items, when declared
}

Field describes one property path declared in a collection schema.

func (Field) Has

func (f Field) Has(t string) bool

Has reports whether the field's declared types include t. An unconstrained field (no declared types) accepts every type.

type Function

type Function struct {
	Realm, Database, Name string
	Dir                   string // the function's folder
	Entry                 string // index.js or index.ts, relative to the project (slash-separated)
	Mode                  string
	Timeout               time.Duration
	Memory                int64 // bytes
	MaxOutput             int64 // bytes
	Concurrency           int
	RateLimit             *RateLimit     // nil: none
	Retry                 *Retry         // nil: a single attempt
	Idempotency           string         // optional or required
	Invoke                *rules.Rule    // nil: only API keys may invoke
	Admin                 bool           // ctx.admin.db with full access
	Internal              bool           // no HTTP route: only backd, scheduled runs and other functions call it
	Email                 bool           // ctx.email.send: may send custom emails through the realm's templates and delivery function
	DevOnly               bool           // backd refuses to start with it unless BACKD_DEV=true (development helpers)
	Calls                 []string       // functions of the same database this one may ctx.call
	Schedule              *cron.Schedule // nil: not scheduled
	ScheduleExpr          string
	Secrets               []SecretRef
	Network               []string // hosts (host or host:port) the function may reach
	InputSchema           *jsonschema.Schema
	OutputSchema          *jsonschema.Schema
}

Function is one function, from its folder in _functions/.

type Functions

type Functions struct {
	Dir       string               // the _functions directory
	Functions map[string]*Function // by name
}

Functions is a database's Deno project of functions (`_functions/`).

func (*Functions) BundlePath

func (f *Functions) BundlePath(m Manifest, fn string) string

BundlePath returns the file of fn's bundle, as recorded in the manifest.

type Index

type Index struct {
	Keys   []IndexKey
	Unique bool
}

Index is one index declared in indexes.json.

func (Index) String

func (ix Index) String() string

String renders the key list in order_by notation, e.g. "status,-_meta.created_at".

type IndexKey

type IndexKey struct {
	Field string
	Desc  bool
}

IndexKey is one field of an index, in API terms (e.g. "id", "address.city").

type Manifest

type Manifest struct {
	Deno      string                    `json:"deno"`
	Source    string                    `json:"source"` // SourceHash of the project when built
	Functions map[string]ManifestBundle `json:"functions"`
}

Manifest describes the bundles `backd functions build` wrote for one functions project.

func ReadManifest

func ReadManifest(functionsDir string) (Manifest, error)

ReadManifest reads a project's .build/manifest.json.

type ManifestBundle

type ManifestBundle struct {
	Bundle string `json:"bundle"` // file name in .build
	SHA256 string `json:"sha256"`
}

ManifestBundle is one function's bundle.

type Networks

type Networks []netip.Prefix

Networks is a list of IP networks. An empty list restricts nothing.

func ParseNetworks

func ParseNetworks(list []string) (Networks, error)

ParseNetworks parses IP addresses and CIDR networks, IPv4 or IPv6.

func (Networks) Allows

func (n Networks) Allows(addr string) bool

Allows reports whether addr is in one of the networks; an empty list allows every address. addr is an IP address such as the one the HTTP layer resolves with TRUSTED_PROXIES; an unparsable one is refused by a non-empty list.

func (Networks) Equal

func (n Networks) Equal(o Networks) bool

Equal reports whether both lists hold the same networks in the same order.

func (Networks) Strings

func (n Networks) Strings() []string

Strings returns the networks in CIDR notation.

func (Networks) Within

func (n Networks) Within(outer Networks) bool

Within reports whether every network of n lies inside one of outer; always true when outer is empty.

type RateLimit

type RateLimit struct {
	Per    string // user or ip
	Limit  int
	Window time.Duration
}

RateLimit limits calls per caller (user or client address).

type Realm

type Realm struct {
	Name      string
	Settings  RealmSettings // from realm.yaml
	Databases map[string]*Database
	// Email holds the parsed email templates of <realm>/email/; nil when the
	// realm doesn't configure email.
	Email *email.Templates
	// Pages are the hosted pages the links in emails open (<realm>/pages/);
	// nil when the realm doesn't configure email.
	Pages *email.Pages
}

Realm groups databases and owns a user pool.

type RealmSettings

type RealmSettings struct {
	AuthEnabled       bool
	Signup            string
	IdleTimeout       time.Duration
	MaxLifetime       time.Duration
	PasswordMinLength int
	CORSOrigins       []string
	Roles             map[string]Role
	// AdminNetworks restricts every admin API request (admin.allowed_networks);
	// empty means unrestricted.
	AdminNetworks Networks
	// UserNetworks are the network restrictions realm.yaml sets per user
	// email (in a role's user entries).
	UserNetworks map[string]UserNetworks
	// AuditRetention is how long audit records are kept (audit.retention);
	// DefaultAuditRetention when not set.
	AuditRetention time.Duration
	// FunctionsMaxConcurrency caps how many function calls may run at once
	// on this backd instance (functions.max_concurrency); 0 means
	// unlimited. Applies whether or not auth is enabled.
	FunctionsMaxConcurrency int
	// FunctionsLogRetention is how long invocation records (roadmap F10)
	// are kept (functions.log_retention); DefaultLogRetention when not
	// set. Needs auth enabled, like the rest of functions.* except
	// max_concurrency: there's no system database to store them in
	// otherwise.
	FunctionsLogRetention time.Duration
	// FunctionsJobRetention is how long an async job's result (roadmap
	// F11) is kept once done (functions.job_retention); DefaultJobRetention
	// when not set. Needs auth enabled, like FunctionsLogRetention.
	FunctionsJobRetention time.Duration
	// Email is how the realm sends email (email in realm.yaml); nil when it
	// doesn't, and then no email is ever sent.
	Email *EmailSettings
	// Account is how the realm's accounts behave (account in realm.yaml).
	Account AccountSettings
}

RealmSettings are the realm-level settings from realm.yaml, with defaults applied.

func (RealmSettings) AdminRoles

func (s RealmSettings) AdminRoles() []string

AdminRoles returns the names of the roles declared with admin: true, sorted.

func (RealmSettings) BestLocale added in v0.4.0

func (s RealmSettings) BestLocale(tags ...string) string

BestLocale maps the languages a person asked for, most wanted first, to the best language the realm lists, without ever failing: an exact match (es-MX), then the same language with its region dropped (es), then the default. The first tag that matches either way wins, so ["fr-CA", "es"] on a realm that lists es and en gives es.

func (RealmSettings) IsAdmin

func (s RealmSettings) IsAdmin(roles []string) bool

IsAdmin reports whether roles include an admin role of the realm.

func (RealmSettings) Languages added in v0.4.0

func (s RealmSettings) Languages() (def string, list []string)

Languages returns a realm's default language and the languages it supports: email.default_locale and email.locales, or just English when it configures no email.

func (RealmSettings) ListedLocale added in v0.4.0

func (s RealmSettings) ListedLocale(tag string) string

ListedLocale returns the listed language equal to tag, ignoring case (es-mx finds es-MX), or "" when the realm doesn't list it.

type Registry

type Registry struct {
	Realms map[string]*Realm
	Root   string // the CONFIG_DIR it was loaded from
}

Registry is the loaded configuration. It is read-only after Load.

func Load

func Load(root string) (*Registry, error)

Load walks root and builds the registry. Every problem found is reported, each naming the offending path.

func (*Registry) AuthRealms added in v0.4.0

func (r *Registry) AuthRealms() []string

AuthRealms returns the realms with auth enabled (the ones with users, and so with jobs), sorted.

func (*Registry) CheckBundles

func (r *Registry) CheckBundles() error

CheckBundles reports functions projects whose bundles are missing, were built by another Deno version, don't match the sources, or were changed since the build. Startup refuses to run with any of them.

func (*Registry) Collection

func (r *Registry) Collection(realm, database, collection string) (*Collection, bool)

Collection returns the collection at realm/database/collection, if configured.

func (*Registry) Databases

func (r *Registry) Databases() []*Database

Databases returns every database, sorted by MongoDB name.

func (*Registry) Fingerprint

func (r *Registry) Fingerprint() (string, error)

Fingerprint identifies the config: a SHA-256 over every file backd reads from CONFIG_DIR — realm.yaml, each collection's schema.json, indexes.json and rules.yaml, and each functions project with its bundles — by relative path, length and content. Files backd ignores (hidden entries such as .git, stray files) don't change it, so the same checkout always has the same fingerprint, on any machine.

func (*Registry) FunctionRealms

func (r *Registry) FunctionRealms(authEnabled bool) []string

FunctionRealms returns the realms with at least one function, sorted.

func (*Registry) RealmNames

func (r *Registry) RealmNames() []string

RealmNames returns every configured realm's name, sorted.

func (*Registry) SortedRealms

func (r *Registry) SortedRealms() []*Realm

SortedRealms returns every realm, sorted by name.

type Retry added in v0.4.0

type Retry struct {
	Attempts   int           // total attempts, the first included
	Backoff    time.Duration // the wait after the first failure; doubles after each one
	MaxBackoff time.Duration // the longest single wait
}

Retry is an async function's retry policy: how often a failed attempt is repeated and how long to wait between attempts.

func (Retry) Wait added in v0.4.0

func (r Retry) Wait(failures int) time.Duration

Wait is how long to wait after the failures-th failed attempt (1 for the first failure): Backoff, doubled for each further failure, up to MaxBackoff.

type Role

type Role struct {
	Description string
	// Admin roles let the sessions of users holding them use the admin API.
	Admin bool
	// Users are seed assignments: normalized (trimmed, lowercased) emails.
	Users []string
}

Role is a role declared in realm.yaml.

type SecretRef

type SecretRef struct {
	Realm bool
	Name  string
}

SecretRef names a secret a function may read: its own database's (`NAME`) or the realm's (`realm.NAME`).

func (SecretRef) String

func (s SecretRef) String() string

type UserNetworks

type UserNetworks struct {
	Admin Networks // the user's admin API requests; within AdminNetworks
	Login Networks // login and every request with the user's session
}

UserNetworks restricts where one user may act from.

Jump to

Keyboard shortcuts

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