Anarchitecture Bricks Docs

Repository documentation hub for packages, guides, and generated references.

@anarchitects/forms-ts

Public HTTP authority belongs to anarchitecture-contracts under ADR-0016. This package consumes @anarchitects/forms-contracts@0.2.0 and Zod 4.5.0 through derived TypeBox compatibility bindings. Domain models remain local. Use export-aware TypeScript resolution (NodeNext, supported Node16, or bundler); legacy node10 resolution is no longer supported. Existing DTO names and ESM/CommonJS entry points remain. See the adoption record for exact scope, migration requirements and remaining host-conformance gates.

The next minor includes explicit .js relative declaration specifiers for strict NodeNext consumers. Existing public exports and ESM/CJS bundles are preserved. Packed Nest 11/12 consumers verify this contract through release-tools:test-forms-identity-nest-compatibility (#466). The declaration correction can also be backported to the previous maintenance minor.

Schema-first form configuration and validation library built with TypeBox. Define forms declaratively and generate runtime validation schemas automatically.

Developer + AI Agent Start Here

Features

Installation

npm install @anarchitects/forms-ts

@sinclair/typebox is installed transitively for the package runtime. Install it explicitly in your app only if you also import TypeBox helpers directly, for example @sinclair/typebox/value.

Usage

import { FormConfig, contactForm } from '@anarchitects/forms-ts';
import { schemaFromConfig } from '@anarchitects/forms-ts/builders';
import { Value } from '@sinclair/typebox/value';

// Use the predefined contact form configuration
console.log(contactForm);
// {
//   id: 'contact_default',
//   version: 1,
//   fields: [
//     { name: 'name', kind: 'string', required: true, minLength: 2, maxLength: 100, ui: { label: 'Name' } },
//     { name: 'email', kind: 'email', required: true, ui: { label: 'Email' } },
//     { name: 'message', kind: 'textarea', required: true, minLength: 10, maxLength: 3000, ui: { label: 'Message', rows: 6 } },
//     { name: 'consent', kind: 'boolean', required: true, ui: { label: 'I agree' } }
//   ],
//   security: { honeypot: 'website', captcha: 'none' },
//   delivery: { adminEmail: 'admin@site.tld', autoReply: { enabled: true, templateId: 'contact_autoreply' } }
// }

// Generate validation schema from form config
const schema = schemaFromConfig(contactForm);

// Validate form submission data
const formData = {
  name: 'John Doe',
  email: 'john@example.com',
  message: 'Hello world! This is a test message.',
  consent: true,
};

const isValid = Value.Check(schema, formData);
console.log(isValid); // true

// Get validation errors
const errors = [...Value.Errors(schema, formData)];
console.log(errors); // []

Submissions read contracts

The /dtos entry point exports the backend read contracts:

Transport responses contain ISO date strings. Use fromSubmissionResponseDTO from /mappers to obtain the Submission model with Date fields. Domain repository filters use SubmissionFilters from /models. HTTP query strings are coerced and validated by the Fastify route schema; direct TypeBox value checks expect a numeric formVersion.

Field Types

String Field

{
  name: 'username',
  kind: 'string',
  required: true,
  minLength: 3,
  maxLength: 20,
  pattern: '^[a-zA-Z0-9_]+$',
  ui: { label: 'Username', placeholder: 'Enter username' }
}

Email Field

{
  name: 'email',
  kind: 'email',
  required: true,
  ui: { label: 'Email Address' }
}

Textarea Field

{
  name: 'description',
  kind: 'textarea',
  required: false,
  maxLength: 500,
  ui: { label: 'Description', rows: 4, help: 'Optional description' }
}

Boolean Field

{
  name: 'subscribe',
  kind: 'boolean',
  required: true,
  ui: { label: 'Subscribe to newsletter' }
}

Select Field

{
  name: 'country',
  kind: 'select',
  required: true,
  options: [
    { value: 'us', label: 'United States' },
    { value: 'uk', label: 'United Kingdom' },
    { value: 'ca', label: 'Canada' }
  ],
  ui: { label: 'Country' }
}

File Upload Field

{
  name: 'attachment',
  kind: 'file',
  required: false,
  ui: { label: 'Upload File', help: 'Max 10MB' }
}

Using DTOs for API Integration

import { FormDefinitionRequestDTO, SubmissionRequestDTO } from '@anarchitects/forms-ts/dtos';

// Request a form definition
const formRequest: FormDefinitionRequestDTO = {
  formId: 'contact_default',
  formVersion: 1,
};

// Submit form data
const submission: SubmissionRequestDTO = {
  formId: 'contact_default',
  formVersion: 1,
  payload: {
    name: 'John Doe',
    email: 'john@example.com',
    message: 'Hello world!',
    consent: true,
  },
};

Security Configuration

const secureForm: FormConfig = {
  // ... other config
  validationRules: [
    {
      kind: 'matchFields',
      sourceField: 'password',
      targetField: 'confirmPassword',
      message: 'Passwords must match.',
    },
  ],
  security: {
    honeypot: 'website', // Honeypot field name
    captcha: 'turnstile', // 'turnstile' | 'hcaptcha' | 'none'
  },
};

Delivery Configuration

const formWithDelivery: FormConfig = {
  // ... other config
  delivery: {
    adminEmail: 'admin@example.com',
    subject: 'New Contact Form Submission',
    templateId: 'contact_template',
    autoReply: {
      enabled: true,
      subject: 'Thank you for contacting us',
      templateId: 'contact_autoreply',
    },
    webhooks: [
      {
        url: 'https://api.example.com/webhook',
        secret: 'webhook-secret',
      },
    ],
  },
};

API Reference

Types

Functions

Pre-defined Forms

Exports

The library provides subpath exports for better tree-shaking:

// Main exports (models and predefined forms)
import { FormConfig, FormField, contactForm } from '@anarchitects/forms-ts';

// Models only
import { FormField, FieldKind, FormConfig } from '@anarchitects/forms-ts/models';

// DTOs only
import { FormDefinitionRequestDTO, FormDefinitionResponseDTO, SubmissionRequestDTO, SubmissionResponseDTO } from '@anarchitects/forms-ts/dtos';

// Builders only
import { schemaFromConfig } from '@anarchitects/forms-ts/builders';

Development notes

Contributing

This library is part of the Anarchitecture Bricks monorepo. See the main repository for contribution guidelines.

License

Released under the Apache License 2.0.

Canonical public definition migration

Public HTTP reads use PublicFormDefinitionResponseDTO and PublicFormDefinitionEnvelopeResponseDTO, derived from the published canonical safe targets. Use toPublicFormDefinitionEnvelopeResponseDTO from /mappers; it selects public fields and regenerates the dynamic schema without delivery data. Legacy definition DTOs/mappers remain compatibility exports and must not be used to return delivery credentials, including in administrative read endpoints. toFormDeliveryStatusDTO provides only a configured indicator for restricted host management views. Internal FormConfig.delivery remains available to delivery code.

The dynamic builder now correctly marks optional fields optional and constrains select values to configured options. Nest validates actual submitted values against the exact definition/version before side effects, including cross-field rules. This is the approved D05/D08 security migration, with consumer and release impact recorded in the adoption audit. Canonical Forms capability blockers are still subject to upstream review; package adoption is not a deployment certification.

Canonical version and verification

This source line consumes @anarchitects/forms-contracts@0.2.0 through the domain TS compatibility bindings. See the canonical conformance guide for exact checks, configured-host obligations and remaining capability gates. Generated implementation OpenAPI and passing fixtures do not approve a deployed host's security profile. Existing runtime support and TypeBox exports remain.

Source Links