Documentation
¶
Index ¶
- Constants
- func Allowed(auth Authorizer, userID string, r Resource, a Action) bool
- func AnyGrant(grants []Grant, r Resource, a Action) bool
- func IsNil(v any) bool
- func IsZeroPtr(ptr any, ft FieldType) bool
- func ReadStringPtr(ptr any) (string, bool)
- func ReadValues(schema []Field, ptrs []any) []any
- func ValidateFields(action byte, f Fielder) error
- type Action
- type ArrayReader
- type ArrayWriter
- type Authorizer
- type Decodable
- type Definition
- type Encodable
- type Field
- type FieldDB
- type FieldReader
- type FieldType
- type FieldWriter
- type Fielder
- type FielderSlice
- type Fields
- type Grant
- type Kind
- type Model
- type ModuleNaming
- type Permitted
- type RawJSON
- type RefKind
- type Resource
- type RoleCode
- type SafeFields
- type Validator
Constants ¶
const ( ActionCreate byte = 'c' ActionRead byte = 'r' ActionUpdate byte = 'u' ActionDelete byte = 'd' )
CRUD action bytes — the single source of truth for the ecosystem-wide action convention used by Validator, ValidateFields, and downstream libraries (crudp HTTP mapping, mcp Tool.Action / RBAC, form).
Deliberately plain byte constants (not a named type) so every existing `action byte` signature accepts them unchanged.
Not to be confused with orm.Action (an int enum describing query execution plans) — that is a different, orm-internal concept.
const ( Wildcard Resource = "*" WildcardAction Action = "*" )
Wildcard matches every Resource, and WildcardAction every Action.
The wildcard is MECHANISM (how a permission is matched), never POLICY: a library may honour it when checking, but must never grant it on its own. Handing out "*:*" is a decision only the consumer can make, and it must cost an explicit, greppable line.
Variables ¶
This section is empty.
Functions ¶
func Allowed ¶ added in v0.0.9
func Allowed(auth Authorizer, userID string, r Resource, a Action) bool
Allowed is the safe way to consult an Authorizer: a missing one denies, instead of panicking or — far worse — letting the call through.
func AnyGrant ¶ added in v0.0.9
AnyGrant reports whether any grant covers the pair. An empty policy denies.
func IsNil ¶ added in v0.0.2
IsNil comprueba de forma segura y portable si un valor es nil o si es un puntero nil dentro de una interfaz Encodable o Decodable.
func ReadStringPtr ¶ added in v0.0.2
ReadStringPtr reads a string from a typed pointer. Returns the string value and true if the pointer is *string, or ("", false) otherwise.
func ReadValues ¶ added in v0.0.2
ReadValues reads field values through Pointers by dereferencing based on Storage type. Used by consumers that need []any (e.g., orm for SQL args). Hot-path consumers (json, form) should read through Pointers directly to avoid boxing.
func ValidateFields ¶ added in v0.0.2
ValidateFields validates all fields of a Fielder based on the action. For each FieldText field, reads the string value and calls Field.Validate. For non-text fields with NotNull, checks against zero value.
Common actions are ActionCreate, ActionUpdate, and ActionDelete.
This is the single validation entry point — ormc-generated Validate() methods call this function first.
Types ¶
type Action ¶ added in v0.0.9
type Action string
Action is the verb performed on a Resource: "read", "write", "orders:export". Readable and extensible on purpose; not a cryptic byte.
type ArrayReader ¶ added in v0.0.2
type ArrayReader interface {
Len() int
String(i int) string
Int(i int) int64
Float(i int) float64
Bool(i int) bool
Bytes(i int) []byte
Object(i int, into Decodable) bool
}
ArrayReader recorre un array tipado.
type ArrayWriter ¶ added in v0.0.2
type ArrayWriter interface {
String(val string)
Int(val int64)
Float(val float64)
Bool(val bool)
Bytes(val []byte)
Object(val Encodable)
// Close finaliza el array.
Close()
}
ArrayWriter empuja elementos tipados de un array (sin []any).
type Authorizer ¶ added in v0.0.9
Authorizer answers whether an identity may perform an action on a resource.
It is the single seam between the layer that ENFORCES access (a router, an MCP server) and the one that KNOWS it (an auth module). Enforcers depend on this function type, never on a concrete implementation.
A nil Authorizer denies: the absence of an answer is not permission.
type Decodable ¶ added in v0.0.2
type Decodable interface {
DecodeFields(r FieldReader)
IsNil() bool
}
Decodable: un valor que sabe leer SUS campos (lo genera ormc).
type Definition ¶ added in v0.0.3
type Definition struct {
Name string // model identity: table name, ModelName(), route key
Fields Fields // ordered schema; Kinds come from model (e.g. model.Text())
}
Definition is the hand-written, fully-typed source of truth for a model. From a Definition, the ormc generator produces the concrete Go struct and its zero-reflection plumbing (Schema/Pointers/EncodeFields/DecodeFields/List).
This inverts the previous flow (struct + string tags → generated schema): the schema literal is now authored by hand and everything else is derived.
type Encodable ¶ added in v0.0.2
type Encodable interface {
EncodeFields(w FieldWriter)
IsNil() bool
}
Encodable: un valor que sabe escribir SUS campos (lo genera ormc).
type Field ¶ added in v0.0.2
type Field struct {
Name string
Type Kind
NotNull bool
OmitEmpty bool // omit from JSON when zero value
DB *FieldDB // nil for formonly/transport structs
// Ref is the Definition of the table this column references (scalar foreign key).
// e.g. a "staff_id int64" field pointing to StaffModel. It drives DDL FK constraint
// generation (orm.FieldExt/SchemaExt) — see FieldDB.RefColumn/OnDelete.
// It does NOT change the field's Go type, which stays the plain scalar mapping from Type.
//
// Composition (FieldStruct/FieldStructSlice) no longer uses this slot; the nested
// Definition is now a mandatory parameter of the Kind constructor (model.Struct(ref)).
// Setting Field.Ref on a composition field is a contradiction and results in a
// generation error in ormc.
//
// A *Definition with a bidirectional Ref to another package-level Definition in the same
// package cannot be expressed as a single literal (Go rejects it: "initialization cycle") —
// this is a Go language limitation, not a model design gap. Two-phase assignment via init()
// is a workaround but is out of scope for ormc to auto-detect; report it if ever needed.
Ref *Definition
Exclude bool // field exists on the generated struct but is NOT part of
// Pointers()/EncodeFields()/DecodeFields() — no persistence, no wire codec.
// Use for hand-managed data the struct must carry but ormc must not touch
// (e.g. a password hash set via a side channel, never scanned/serialized).
Permitted // embedded: validation rules (characters, min/max)
}
Field describes a single field in a struct's schema. It provides type metadata, constraint flags, and validation rules used by database (orm), transport (json), UI (form), and validation layers.
Validation rules are provided by its Type (Kind) and embedded via Permitted. Field.Validate(value) checks both. A nil Type (Kind) is an error — the ecosystem is fail-closed by design.
Deterministic Field.Type.Storage() → Go type mapping:
| Storage | Go Type | |---|---| | FieldText, FieldRaw | string | | FieldInt | int64 | | FieldFloat | float64 | | FieldBool | bool | | FieldBlob | []byte | | FieldIntSlice | []int | | FieldStruct | type of the kind's ref — Struct(ref) | | FieldStructSlice | [] of the kind's ref — StructSlice(ref) |
func (Field) Validate ¶ added in v0.0.2
Validate checks a string value against this field's constraints. Checks NotNull first, then Kind, then Permitted (length and chars).
Security note: standard Kinds (Text, Int, Float, Bool) provide an input-boundary floor (A03 Injection/XSS) by using whitelists that exclude HTML-dangerous characters. ValidateFields provides implicit fail-closed protection for form-submitted data. Data from external sources (DB reads, API responses) bypasses this check and must be encoded at the output layer.
The base Text kind's charset is a DEFAULT floor, not a mandate: a field that declares its own positive whitelist (Letters/Numbers/Extra/...) REPLACES it — the author's explicit charset governs (e.g. a CSS-selector field permitting '#'). The author then owns the XSS exposure of any dangerous character it whitelists (encode at the output layer). Semantic kinds (email, ...) and non-text kinds (Int, Float, Bool) always validate.
type FieldDB ¶ added in v0.0.2
type FieldDB struct {
PK bool
Unique bool
AutoInc bool
// RefColumn/OnDelete apply only when the owning Field is a scalar foreign key
// (Field.Ref set — composition kinds carry their ref in the constructor and
// never set Field.Ref; see Field.Ref doc).
// Both are optional: RefColumn empty = auto-detect the PK of Ref's table;
// OnDelete empty = generator default (e.g. CASCADE).
RefColumn string
OnDelete string
}
FieldDB contains database-specific metadata. Extracted from Field to keep transport/UI structs lean.
type FieldReader ¶ added in v0.0.2
type FieldReader interface {
String(name string) (string, bool)
Int(name string) (int64, bool)
Float(name string) (float64, bool)
Bool(name string) (bool, bool)
Bytes(name string) ([]byte, bool)
Object(name string, into Decodable) bool
Array(name string) (ArrayReader, bool)
// Raw devuelve el valor crudo asociado al nombre.
Raw(name string) (string, bool)
}
FieldReader entrega los campos por nombre, TIPADOS. El bool indica presencia. Lee por nombre directo (NO construye un map).
type FieldType ¶ added in v0.0.2
type FieldType int
FieldType represents the abstract storage type of a struct field.
const ( FieldText FieldType = iota // Any string FieldInt // Any integer FieldFloat // Any float FieldBool // Boolean FieldBlob // Binary data ([]byte) FieldStruct // Nested struct (implements Fielder) FieldIntSlice // []int FieldStructSlice // []Fielder FieldRaw // Pre-serialized JSON — emitted inline, no quoting )
type FieldWriter ¶ added in v0.0.2
type FieldWriter interface {
String(name, val string)
Int(name string, val int64)
Float(name string, val float64)
Bool(name string, val bool)
Bytes(name string, val []byte)
Null(name string)
// Raw emite el valor directamente sin escapar.
Raw(name, val string)
// Anidado: objeto hijo que también es Encodable.
Object(name string, val Encodable)
// Arrays tipados sin []any: retorna ArrayWriter directo para evitar closures.
Array(name string, n int) ArrayWriter
}
FieldWriter recibe los campos de un valor por llamadas TIPADAS. Implementaciones: jsvalue (escribe js.Value), json (escribe bytes), etc. Reglas: cero `any`, cero `map`, cero asignación en el heap Go (el writer reusa su buffer).
type Fielder ¶ added in v0.0.2
Fielder describes any type that can expose its schema and writable pointers. It is the shared contract between orm (database), form (UI), and json layers, replacing runtime reflection.
Implementations are generated by code generators — never written by hand.
Contract:
- Schema() and Pointers() MUST return slices of the same length.
- The i-th element in each slice corresponds to the same struct field.
- Pointers() returns pointers to fields for reading (dereference) and writing (scan/sync).
type FielderSlice ¶ added in v0.0.2
FielderSlice is implemented by generated code to allow iteration over a slice of structs without reflection.
type Fields ¶ added in v0.0.3
type Fields = []Field
Fields is the ordered list of field definitions of a model. Alias (not a named type) so a []Field literal is assignable without conversion.
type Grant ¶ added in v0.0.9
Grant is one line of a policy: what a role may do to a resource. The zero value grants nothing — closed by default, like everything here.
func (Grant) Matches ¶ added in v0.0.9
Matches reports whether a Grant covers a (resource, action) pair.
This is the ONE place the wildcard is interpreted, so every enforcer agrees on what "*" means. Two implementations quietly disagreeing about that is a security hole nobody would ever see.
An Action is one verb: a role that may read and write holds two Grants. Packing several actions into one string would bring back the parsing this vocabulary exists to remove.
type Kind ¶ added in v0.0.7
type Kind interface {
Storage() FieldType // deterministic Go/DDL mapping
Name() string // semantic name: "text", "int", "email", ...
Validate(value string) error // ALWAYS present — fail-closed
}
Kind replaces the Field.Type enum slot + Field.Widget pair. Implementations are stateless templates, safe for concurrent reuse.
func Blob ¶ added in v0.0.7
func Blob() Kind
Blob returns the base Blob kind. No content validation (binary).
func Bool ¶ added in v0.0.7
func Bool() Kind
Bool returns the base Bool kind. Accepts "true", "false", "1", "0", "".
func Float ¶ added in v0.0.7
func Float() Kind
Float returns the base Float kind. Accepts digits, at most one '.', and an optional leading minus sign.
func Int ¶ added in v0.0.7
func Int() Kind
Int returns the base Int kind. Accepts digits and an optional leading minus sign.
func IntSlice ¶ added in v0.0.7
func IntSlice() Kind
IntSlice returns the base IntSlice kind. No string validation.
func Raw ¶ added in v0.0.7
func Raw() Kind
Raw returns the base Raw kind. No content validation (pre-serialized JSON).
func Struct ¶ added in v0.0.7
func Struct(ref *Definition) Kind
Struct returns the composition kind nesting the given Definition. The ref is REQUIRED: ormc derives the generated Go field type from it. No string validation (the nested Fielder validates itself, fail-closed).
func StructSlice ¶ added in v0.0.7
func StructSlice(ref *Definition) Kind
StructSlice returns the composition kind nesting a slice of the given Definition. Same contract as Struct.
type Model ¶
type Model interface {
Fielder
ModuleNaming
}
Model describes a resource with a schema and a name. Standard interface used by DB, Form, and API layers.
type ModuleNaming ¶ added in v0.0.2
type ModuleNaming interface {
ModelName() string
}
ModuleNaming is the minimal identity contract shared across the ecosystem: a stable model name used as route key, nav hash and DOM id. Consumers that need only identity (routing, layout shells) embed this; data models embed the richer Model.
type Permitted ¶ added in v0.0.2
type Permitted struct {
Letters bool // a-z, A-Z, ñ, Ñ
Tilde bool // á, é, í, ó, ú (and uppercase) — uses aL/aU from mapping.go
Numbers bool // 0-9
Spaces bool // ' '
BreakLine bool // '\n'
Tab bool // '\t'
Extra []rune // additional allowed characters (e.g., '@', '.', '-')
NotAllowed []string // forbidden substrings
Minimum int // min length (0 = no limit)
Maximum int // max length (0 = no limit)
StartWith *Permitted // rules for first character (nil = same as main rules)
}
Permitted validates strings character-by-character against a configurable whitelist.
Zero value = nothing permitted (strictest). Enable flags to allow character classes. Moved from form/input to fmt for cross-layer reuse.
Rule: if only Minimum/Maximum are configured (no character flags), Validate only checks length — it never rejects characters. To restrict characters, enable at least one flag (Letters, Numbers, etc.) or add entries to Extra/NotAllowed.
Security contract: the whitelist is positive — only explicitly enabled characters pass. HTML-dangerous characters (<, >, &, ", ') are not included in any standard widget's whitelist. Data validated through standard widgets is therefore safe for HTML output without additional escaping.
If a custom widget adds dangerous chars to Extra, it must document the XSS risk and the caller is responsible for output encoding (e.g., fmt.Convert(v).EscapeHTML()).
func (Permitted) NoHTML ¶ added in v0.0.2
NoHTML adds HTML-dangerous characters to NotAllowed as an explicit safety layer. Returns a modified copy. Use when Extra contains characters that could appear in HTML injection attempts and the widget cannot be restricted further.
Example:
t.Permitted = t.Permitted.NoHTML()
type RawJSON ¶ added in v0.0.2
type RawJSON = string
RawJSON is a type alias for string that signals pre-serialized JSON content. Like encoding/json.RawMessage, it tells the encoder to emit the value inline without quoting or re-serializing, avoiding linter warnings about the `json:",raw"` tag.
Usage:
type Result struct {
Content RawJSON // no tag needed; type itself conveys intent
Error RawJSON `json:",omitempty"`
}
The encoder detects RawJSON at code-generation time (ormc), marking the field as FieldRaw in the Schema(), and tinywasm/json handles it without re-serializing.
type RefKind ¶ added in v0.0.7
type RefKind interface {
Kind
Ref() *Definition
}
RefKind is implemented by composition kinds (Struct, StructSlice). Consumers (ormc, orm relations) read the nested Definition from here.
type Resource ¶ added in v0.0.9
type Resource string
Resource is the thing being protected: "service_catalog", "invoices". The consumer declares its own — a library that enforces access must never invent one.
func ResourceOf ¶ added in v0.0.9
func ResourceOf(m ModuleNaming) Resource
ResourceOf is the resource that protects a module: its own identity.
This is the whole point of putting the vocabulary next to ModuleNaming. The convention "a module's ID is its RBAC resource" used to be a line in a document that nothing enforced; here it is a function, so the two can no longer disagree.
type RoleCode ¶ added in v0.0.9
type RoleCode string
RoleCode is how a consumer names a role: "admin", "reception", "practitioner". The vocabulary belongs to the app. No library may hardcode one.
type SafeFields ¶ added in v0.0.2
SafeFields combines schema access with validation. Handlers that receive user input should accept SafeFields to enforce compile-time validation guarantees.