Forms

HTML form rendering with CSRF token injection, accessible labels, field-type dispatch, and shared-spec server-side validation.

b.forms.render(spec) emits a complete

element with auto-escaped attributes, a hidden CSRF input, and per-field markup for text / email / password / number / checkbox / radio / textarea / select / hidden / submit. Every attribute value is forced through escapeAttribute so a hostile field name or value can't break out of the double-quoted attribute context.

b.forms.validate(spec, body) walks the same field spec the renderer accepts and returns { valid, errors, values } — coerced types, required-field checks, length bounds, regex pattern, enum membership. Sharing the spec is the point: the operator's "this is what the form looks like" and "this is what the form expects" stay in lock-step, eliminating the drift class where a field gets added to the renderer but not the validator.

CSRF tokens are 32-byte hex strings from b.crypto.generateToken; verifyCsrfToken is constant-time. The middleware in b.middleware.csrfProtect does the actual request-time gating — this module supplies the issue / verify primitives.

b.forms.generateCsrfToken() #

stable0.1.0

Returns a 32-byte (64 hex char) random token suitable for embedding in a hidden form field. Entropy comes from b.crypto.generateToken, which routes through Node's crypto.randomBytes. The token is opaque to the framework — operators store it in the session and compare via verifyCsrfToken on submit.

var token = b.forms.generateCsrfToken();
// → "8f3a1c4b...e7d9"   (64 hex chars)

b.forms.verifyCsrfToken(submitted, expected) #

stable0.1.0

Constant-time comparison of a submitted token against the expected value. Returns false for any non-string input, mismatched length, or empty submitted token — never throws. Routes through b.crypto.timingSafeEqual so an attacker can't probe character positions via response-time differences.

var ok = b.forms.verifyCsrfToken(req.body.csrf, req.session.csrf);
// → true  (when both strings are non-empty and byte-identical)

b.forms.escapeAttribute(value) #

stable0.1.0

Escapes a value for safe interpolation into a double-quoted HTML attribute context. Stricter than b.template.escapeHtml: also escapes backtick (some browsers parse ` ` as an attribute delimiter under quirks mode) and = (defense-in-depth for any unquoted-attribute slips). null / undefined become the empty string. Used internally by b.forms.render` for every attribute value; exported for operators rendering their own form fragments.

var safe = b.forms.escapeAttribute('a"bd');
// → "a"b<c>d"

b.forms.render(spec) #

stable0.1.0

Renders a complete element from a typed spec — method, action, fields, optional CSRF token. Each field's type selects the input widget (text / email / password / number / checkbox / radio / textarea / select / hidden / submit). All attribute values pass through escapeAttribute; spec.csrfToken (if present) is embedded as a hidden _csrf input. Throws when spec.action is missing / empty or spec.fields isn't an array.

var html = b.forms.render({
  action:    "/login",
  method:    "POST",
  csrfToken: "8f3a1c4b...e7d9",
  fields: [
    { type: "email",    name: "email",    label: "Email",    required: true },
    { type: "password", name: "password", label: "Password", required: true },
    { type: "submit",   name: "submit",   value: "Sign in" },
  ],
});
// → "..."

b.forms.validate(spec, body) #

stable0.1.0

Walks the same spec the renderer accepts and validates a submitted body. Per field: required-field check, type coercion (string / number / boolean / email / url), minlength / maxlength bounds, numeric min / max bounds, regex pattern, enum membership. Returns { valid: boolean, errors: { field: msg, ... }, values: { ... } }. The values object holds coerced values keyed by field name — route handlers consume result.values directly without re-parsing.

var result = b.forms.validate(
  { fields: [
      { type: "email",  name: "email", required: true },
      { type: "number", name: "age",   min: 1 },
  ] },
  { email: "ada@example.com", age: "37" }
);
// → { valid: true, errors: {}, values: { email: "ada@example.com", age: 37 } }

Last updated 2026-08-08T16:39:49.652Z by seeder.