NJ Municipality Lookup
CodebaseSrc

Lib

Reusable utilities, configuration, and metaprogramming patterns used across the application. No dependencies on domain or adapters.

Shared Libraries (lib/)

Reusable utilities, configuration, and metaprogramming patterns used across the application. No dependencies on domain or adapters.

Modules

Type Factories

  • branded-types.ts - Generic factory for creating type-safe branded types with validation
  • error-factory.ts - Generic factory for creating custom error classes with structured data

Validation & Parsing

  • validation.ts - Input validation utilities (Unicode normalization, XSS protection, address validation)
  • validation-builder.ts - Chainable validation builder pattern for composable rules
  • env-parser.ts - Type-safe environment variable parser with validators

Configuration & Infrastructure

  • config.ts - Application configuration from environment variables
  • logger.ts - Structured logging implementation (console-based, implements LoggerPort)
  • coordinates.ts - Geographic coordinate validation and utilities
  • formatting.ts - Locale-aware formatting utilities (dates, numbers, currency, percentages)
  • utils.ts - Tailwind CSS class merging utility (cn)

Key Patterns

Branded Types Factory

Create type-safe branded types to prevent string confusion:

const EmailFactory = createBrandedTypeFactory("Email", {
  validate: (value: string) => {
    if (!value.includes("@")) throw new Error("Invalid email");
  },
  normalize: (value: string) => value.toLowerCase().trim(),
});

type Email = typeof EmailFactory.__type;
const email = EmailFactory.create("user@example.com");

Error Factory

Eliminate error class boilerplate:

const CustomError = createCustomError<"CustomError", { code: number }>({
  name: "CustomError",
  messageBuilder: (data) => `Error ${data.code}: Something went wrong`,
});

throw new CustomError({ code: 404 });

Validation Builder

Compose validation rules fluently:

const validateUsername = validate<string>()
  .notEmpty("Username required")
  .minLength(3)
  .maxLength(20)
  .matchPattern(/^[a-z0-9_]+$/i, "Alphanumeric and underscore only")
  .build();

const result = validateUsername("john_doe");
if (!result.valid) {
  console.error(result.error);
}

Environment Parser

Type-safe environment variables with defaults and validation:

const port = parseEnv("PORT", {
  default: 3000,
  parser: envParsers.number,
  validator: (n) => n > 0 && n < 65536,
});

const features = parseEnv("FEATURES", {
  default: [],
  parser: envParsers.array,
});

Configuration Structure

config.ts exports typed configuration object:

export const config = {
  app: {
    name: string;
    port: number;
    nodeEnv: "development" | "production" | "test";
  },
  njApi: {
    baseUrl: string;
    timeoutMs: number;
    retryEnabled: boolean;
    maxRetries: number;
  },
  cache: {
    enabled: boolean;
    maxEntries: number;
    ttlDays: number;
  },
  logging: {
    level: "debug" | "info" | "warn" | "error";
  }
};

Logging

Structured logging with context:

import { logger } from "./lib/logger";

logger.info("Address geocoded", {
  address: "123 Main St",
  municipality: "Newark",
  score: 95,
});

logger.error("API request failed", {
  url: "https://api.example.com",
  error: error.message,
});

Testing

All lib utilities have 100% test coverage:

  • branded-types.test.ts - Type guard validation, normalization
  • env-parser.test.ts - All parser types, validators, error cases
  • validation-builder.test.ts - All validator methods, chaining, edge cases
  • validation.test.ts - Input validation, security checks
  • coordinates.test.ts - Coordinate validation
  • config.test.ts - Configuration loading

Design Principles

  1. Zero Dependencies: Lib has no dependencies on domain or adapters
  2. Pure Functions: Utilities are side-effect free (except logging)
  3. Type Safety: TypeScript types with generics
  4. Reusability: Generic patterns applicable beyond this project
  5. Testability: Isolated, easily testable functions

On this page