Skip to main content

Overview

Who To Bother uses Valibot for runtime schema validation and type inference. All company data files must conform to the schema defined in src/data/companies/schema.ts. The schema ensures data integrity with strict validation rules for company information, contact details, and social media handles.

Schema Architecture

Single Source of Truth

Valibot Schema (schema.ts)

TypeScript Types (inferred)

JSON Schema (generated for IDE support)

Runtime Validation (build-time checks)
The Valibot schema serves as the single source of truth. TypeScript types are automatically inferred, and a JSON schema is generated for IDE autocomplete support.

Company Schema

The top-level schema representing a complete company entry.
$schema
string
JSON Schema reference for IDE autocomplete support
id
string
required
Unique company identifier. Must be lowercase with only letters, numbers, and hyphens.Validation: Regex /^[a-z0-9-]+$/Error: “Company ID must be lowercase with only letters, numbers, and hyphens”
name
string
required
Display name of the company.Validation: Minimum 1 characterError: “Company name is required”
description
string
required
Brief description of the company and its products/services.Validation: Minimum 1 characterError: “Company description is required”
logoType
string
required
Type of logo used for display. References logo files in the project.Validation: Minimum 1 characterError: “Logo type is required”
Optional logo URL or path reference
website
string
Company website URL.Validation: Must be a valid URLError: “Must be a valid URL”
docs
string
Documentation website URL.Validation: Must be a valid URLError: “Must be a valid URL”
github
string
GitHub organization or repository URL.Validation: Must be a valid URLError: “Must be a valid URL”
discord
string
Discord community invite URL.Validation: Must be a valid URLError: “Must be a valid URL”
categories
Category[]
required
Array of contact categories. Must contain at least one category.Validation: Minimum 1 categoryError: “At least one category is required”

Category Schema

Represents a category of contacts grouped by product, team, or functional area.
name
string
required
Category name (e.g., “Frameworks & OSS”, “AI”, “Support”).Validation: Minimum 1 characterError: “Category name is required”
contacts
Contact[]
required
Array of contacts within this category. Must contain at least one contact.Validation: Minimum 1 contactError: “At least one contact is required per category”

Contact Schema

Represents an individual contact or role with associated social handles.
product
string
required
Product name, role, or area of responsibility (e.g., “Next.js”, “Community Manager”).Validation: Minimum 1 characterError: “Product name is required”
handles
string[]
required
Array of X (Twitter) handles. Must start with @ and contain only letters, numbers, and underscores.Validation:
  • Regex /^@[a-zA-Z0-9_]+$/ per handle
  • Minimum 1 handle required
Errors:
  • “Handle must start with @ and contain only letters, numbers, and underscores”
  • “At least one handle is required”
email
string
Optional contact email address.Validation: Must be a valid email formatError: “Must be a valid email address”
discord
string
Optional Discord profile or server URL.Validation: Must be a valid URLError: “Must be a valid URL”

TypeScript Types

The schema automatically generates TypeScript types using Valibot’s InferOutput utility:
import type { InferOutput } from "valibot";

// Inferred types
export type Contact = InferOutput<typeof ContactSchema>;
export type Category = InferOutput<typeof CategorySchema>;
export type Company = InferOutput<typeof CompanySchema>;

Type Definitions

Valibot Schema Source

Example: Valid Company JSON

{
  "$schema": "./schema.json",
  "id": "vercel",
  "name": "Vercel",
  "description": "Frontend cloud platform for deploying web applications",
  "logoType": "vercel",
  "website": "https://vercel.com",
  "docs": "https://vercel.com/docs",
  "github": "https://github.com/vercel",
  "categories": [
    {
      "name": "Frameworks & OSS",
      "contacts": [
        {
          "product": "Next.js",
          "handles": ["@timneutkens"]
        },
        {
          "product": "Turborepo",
          "handles": ["@anthonysheww"]
        }
      ]
    },
    {
      "name": "v0 & AI",
      "contacts": [
        {
          "product": "v0",
          "handles": [
            "@max_leiter",
            "@EstebanSuarez",
            "@rickeyswuave"
          ]
        },
        {
          "product": "AI SDK",
          "handles": ["@nishimiya", "@nicoalbanese10"]
        }
      ]
    }
  ]
}

Validation

Build-Time Validation

All company JSON files are validated before deployment:
# Run validation manually
pnpm validate

# Automatically runs before build
pnpm build
The validation script (src/scripts/validate-companies.ts) checks all JSON files in src/data/companies/ against the Valibot schema.

Common Validation Errors

Handle Format Error
error
Message: “Handle must start with @ and contain only letters, numbers, and underscores”Fix: Ensure all X handles start with @ and only contain alphanumeric characters and underscores.
// ❌ Invalid
"handles": ["timneutkens", "@user-name"]

// ✅ Valid
"handles": ["@timneutkens", "@user_name"]
URL Validation Error
error
Message: “Must be a valid URL”Fix: Ensure URLs include the protocol (https://) and are properly formatted.
// ❌ Invalid
"website": "vercel.com"

// ✅ Valid
"website": "https://vercel.com"
Empty Array Error
error
Message: “At least one handle is required” or “At least one contact is required per category”Fix: Ensure arrays are not empty.
// ❌ Invalid
"contacts": []

// ✅ Valid
"contacts": [
  {
    "product": "Support",
    "handles": ["@support"]
  }
]

JSON Schema Generation

Generate a JSON schema file for IDE autocomplete support:
pnpm generate-schema
This creates src/data/companies/schema.json from the Valibot schema, enabling IntelliSense in editors when editing company JSON files.

Build docs developers (and LLMs) love