FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
lightweight
lightweightglimpse2-runbook-view-glimpse-save-login-react
Remix of lightweight/glimpse2-runbook-view-glimpse-save-login
Public
Like
glimpse2-runbook-view-glimpse-save-login-react
Home
Code
8
_townie
13
backend
7
frontend
9
shared
3
.vtignore
README.md
deno.json
H
main.tsx
Branches
2
Pull requests
Remixes
History
Environment variables
6
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
backend
/
utils
/
README.md
Code
/
backend
/
utils
/
README.md
Search
…
README.md

Utils

Pure utility functions with no external dependencies.

Separation of Concerns

Utils are pure functions that:

  • No external dependencies - Never interact with APIs, databases, or storage
  • Deterministic - Same input always produces same output
  • No side effects - Don't modify global state or external systems
  • Reusable - Can be used across controllers and services
  • Testable - Easy to unit test in isolation

Utils do NOT:

  • Make external API calls (use services instead)
  • Handle business workflows (controllers handle this)
  • Manage application state or configuration
  • Interact with databases or storage systems

Clear Distinction: Utils vs Services

Utils (Pure Functions)

  • Data formatting → utils/date.helpers.ts
  • Validation logic → utils/validation.helpers.ts
  • String manipulation → utils/string.helpers.ts
  • Mathematical calculations → utils/math.helpers.ts
  • Type conversions → utils/conversion.helpers.ts

Services (External Dependencies)

  • Notion API operations → services/notion/page.service.ts
  • Blob storage operations → services/blob.service.ts
  • Database operations → services/database.service.ts
  • Email sending → services/email.service.ts

Utility Characteristics

Pure Functions

// ✅ Good: Pure function export function formatDate(date: Date): string { return date.toISOString().split('T')[0]; } // ❌ Bad: Has side effects export function logAndFormatDate(date: Date): string { console.log('Formatting date'); // Side effect return date.toISOString().split('T')[0]; }

No External Dependencies

// ✅ Good: No external calls export function validateEmail(email: string): boolean { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } // ❌ Bad: External API call export async function validateEmailWithService(email: string): Promise<boolean> { const response = await fetch(`/api/validate-email/${email}`); return response.ok; }

Deterministic

// ✅ Good: Always returns same output for same input export function calculatePercentage(value: number, total: number): number { return (value / total) * 100; } // ❌ Bad: Output depends on external state export function calculatePercentageWithTimestamp(value: number, total: number): number { const timestamp = Date.now(); // Non-deterministic return ((value / total) * 100) + timestamp; }

Usage Patterns

Controller Usage

// Controllers use utils for data processing import { validateEmail, formatDate } from '../utils/validation.helpers.ts'; import { getPageById } from '../services/notion/page.service.ts'; export async function processUserData(email: string, pageId: string) { // 1. UTIL: Validate input data if (!validateEmail(email)) { return { success: false, error: "Invalid email format" }; } // 2. SERVICE: Get external data const pageResult = await getPageById(pageId); // 3. UTIL: Format data for response const formattedDate = formatDate(new Date(pageResult.data.created_time)); return { success: true, data: { ...pageResult.data, formattedDate } }; }

Service Usage

// Services can use utils for data transformation import { sanitizeInput } from '../utils/string.helpers.ts'; export async function createNotionPage(title: string) { // UTIL: Clean input before external API call const cleanTitle = sanitizeInput(title); // External API call const response = await notion.pages.create({ properties: { Title: { title: [{ text: { content: cleanTitle } }] } } }); return createSuccessResponse(response); }

Current Utility Files

Notion Helpers (notion.helpers.ts)

export function extractTextFromNotionProperty(property: any, propertyName: string): string; export function findPropertyByNames(properties: any, possibleNames: string[]): { name: string; property: any } | null; export function extractAgentProperties(agentPage: any): AgentProperties;

ID Helpers (id.helpers.ts)

export function generateSessionId(): string; export function generateBlobKey(type: string, id: string): string; export function parseBlobKey(key: string): { type: string; id: string } | null; export function generateRandomId(): string;

Validation Helpers (validation.helpers.ts)

export function validateEmail(email: string): boolean; export function validateUrl(url: string): boolean; export function validateUuid(id: string): boolean; export function isNotEmpty(value: string): boolean; export function validatePhoneNumber(phone: string): boolean;

Recommended Utility Categories

Data Validation (validation.helpers.ts)

export function validateEmail(email: string): boolean; export function validateUrl(url: string): boolean; export function validatePhoneNumber(phone: string): boolean; export function validateUuid(id: string): boolean; export function isNotEmpty(value: string): boolean;

Date/Time Helpers (date.helpers.ts)

export function formatDate(date: Date): string; export function parseIsoDate(isoString: string): Date; export function addDays(date: Date, days: number): Date; export function isExpired(date: Date, maxAgeMinutes: number): boolean; export function getTimestamp(): string;

String Manipulation (string.helpers.ts)

export function sanitizeInput(input: string): string; export function truncateText(text: string, maxLength: number): string; export function slugify(text: string): string; export function capitalizeWords(text: string): string; export function extractDomain(email: string): string;

Data Transformation (conversion.helpers.ts)

export function arrayToObject<T>(array: T[], keyField: string): Record<string, T>; export function objectToArray<T>(obj: Record<string, T>): T[]; export function filterObject<T>(obj: Record<string, T>, predicate: (value: T) => boolean): Record<string, T>; export function mapObjectValues<T, U>(obj: Record<string, T>, mapper: (value: T) => U): Record<string, U>;

Mathematical Helpers (math.helpers.ts)

export function clamp(value: number, min: number, max: number): number; export function roundToDecimals(value: number, decimals: number): number; export function calculatePercentage(value: number, total: number): number; export function generateRandomId(): string;

Type Guards (type.helpers.ts)

export function isString(value: unknown): value is string; export function isNumber(value: unknown): value is number; export function isObject(value: unknown): value is Record<string, unknown>; export function isArray(value: unknown): value is unknown[]; export function hasProperty<T extends Record<string, unknown>>(obj: T, key: string): key is keyof T;

Testing Utils

Since utils are pure functions, they're easy to test:

// validation.helpers.test.ts import { validateEmail } from './validation.helpers.ts'; describe('validateEmail', () => { test('returns true for valid email', () => { expect(validateEmail('user@example.com')).toBe(true); }); test('returns false for invalid email', () => { expect(validateEmail('invalid-email')).toBe(false); }); });

Best Practices

Keep Functions Small and Focused

  • Each function should do one thing well
  • Avoid complex multi-step operations
  • Prefer composition over large functions

Use TypeScript Types

  • Provide proper type annotations
  • Use generic types where appropriate
  • Export types alongside functions

Document Complex Logic

  • Add JSDoc comments for complex algorithms
  • Explain business rules or edge cases
  • Provide usage examples

Avoid Dependencies

  • Don't import services or external libraries
  • Keep functions self-contained
  • Use only built-in JavaScript/TypeScript features

Error Handling

  • Validate inputs and throw descriptive errors
  • Use type guards to ensure type safety
  • Handle edge cases gracefully
export function calculatePercentage(value: number, total: number): number { if (typeof value !== 'number' || typeof total !== 'number') { throw new Error('Both value and total must be numbers'); } if (total === 0) { throw new Error('Total cannot be zero'); } return (value / total) * 100; }
Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.