← All @molecule/* packages · App templates

@molecule/app-utilities

Core interface · utilities · App (browser) · v1.0.1 · Apache-2.0

Common utilities for molecule.dev frontend applications

npm install @molecule/app-utilities

npm · Source on GitHub

How it works

@molecule/app-utilities is the utilities core interface on the app (browser) side: the API your app calls, with no vendor inside.

Bond a provider to choose the implementation.

import { debounce, formatCurrency, getErrorMessage } from '@molecule/app-utilities'
import { t } from '@molecule/app-i18n'

const onSearch = debounce((q: unknown) => runSearch(q as string), 300)
const price = formatCurrency(1234.56, 'EUR', 'de-DE')

try {
  await saveThing()
} catch (error) {
  // Pass the app's `t` so the message is localized — defaults are English-only.
  showToast(getErrorMessage(error, undefined, t))
}

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Common utilities for molecule.dev frontend applications.

Framework-agnostic helpers for async control (debounce/throttle/retry/sleep), strings, dates, Intl-based formatting (currency/number/percent/file size), validation, clipboard, URLs/query strings, URL-safe base64, and user-friendly error messages. Prefer these over hand-rolling the same helpers in app code — they are dependency-free and already tested.

Quick Start

import { debounce, formatCurrency, getErrorMessage } from '@molecule/app-utilities'
import { t } from '@molecule/app-i18n'

const onSearch = debounce((q: unknown) => runSearch(q as string), 300)
const price = formatCurrency(1234.56, 'EUR', 'de-DE')

try {
  await saveThing()
} catch (error) {
  // Pass the app's `t` so the message is localized — defaults are English-only.
  showToast(getErrorMessage(error, undefined, t))
}

Type

core

Installation

npm install @molecule/app-utilities

API

Interfaces

AlphanumericOptions

Alphanumeric validation options.

interface AlphanumericOptions {
  /**
   * Allow spaces.
   */
  allowSpaces?: boolean

  /**
   * Allow dashes.
   */
  allowDashes?: boolean

  /**
   * Allow underscores.
   */
  allowUnderscores?: boolean

  /**
   * Minimum length.
   */
  minLength?: number

  /**
   * Maximum length.
   */
  maxLength?: number
}

PromiseState

State of an async operation.

interface PromiseState<T> {
  /**
   * Current status.
   */
  status: PromiseStatus

  /**
   * Resolved value.
   */
  value: T | null

  /**
   * Rejection error.
   */
  error: Error | null
}

Types

PromiseStatus

Status of an async operation.

type PromiseStatus = 'idle' | 'pending' | 'resolved' | 'rejected'

Functions

alphanumeric(value, options)

Strips non-alphanumeric characters from a string, keeping only letters and digits (plus optionally spaces, dashes, or underscores).

function alphanumeric(value: string, options?: AlphanumericOptions): string
  • value — The string to clean.
  • options — Optional flags to preserve spaces, dashes, or underscores.

Returns: The cleaned string with disallowed characters removed.

copyToClipboard(text)

Copies text to the system clipboard. Uses the Clipboard API when available, with a document.execCommand('copy') fallback for older browsers.

function copyToClipboard(text: string): Promise<boolean>
  • text — The text to copy to the clipboard.

Returns: true if the copy succeeded, false on failure.

debounce(fn, delay)

Wraps a function so that it is only invoked after it stops being called for the specified delay. Useful for search inputs and resize handlers.

function debounce(fn: T, delay: number): (...args: Parameters<T>) => void
  • fn — The function to debounce.
  • delay — The quiet period in milliseconds before the function fires.

Returns: A debounced version of fn that resets its timer on each call.

formatCurrency(value, currency, locale)

Formats a number as a currency string using Intl.NumberFormat.

function formatCurrency(value: number, currency?: string, locale?: string): string
  • value — The monetary amount.
  • currency — The ISO 4217 currency code (default: 'USD').
  • locale — The BCP 47 locale string (default: 'en-US').

Returns: The formatted currency string (e.g. "$1,234.56").

formatNumber(value, locale)

Formats a number with locale-appropriate thousand separators using Intl.NumberFormat.

function formatNumber(value: number, locale?: string): string
  • value — The number to format.
  • locale — The BCP 47 locale string (default: 'en-US').

Returns: The formatted number string (e.g. "1,234,567").

formatPercent(value, decimals, locale)

Formats a number as a percentage string using Intl.NumberFormat. The input value should be a decimal (e.g. 0.75 for 75%).

function formatPercent(value: number, decimals?: number, locale?: string): string
  • value — The decimal value to format as a percentage.
  • decimals — The number of decimal places (default: 0).
  • locale — The BCP 47 locale string (default: 'en-US').

Returns: The formatted percentage string (e.g. "75%").

getErrorMessage(error, customMessages, t)

Extracts a user-friendly error message from an unknown error value. Handles strings, Error instances, and objects with code/message/error properties. Recognizes TypeError (fetch failures) as network errors and AbortError as timeouts.

When a translation function t is provided, error messages are passed through it for i18n support.

function getErrorMessage(
  error: unknown,
  customMessages?: Record<string, string>,
  t?: TranslateFn,
): string
  • error — The error value (string, Error, or object with code/message).
  • customMessages — Optional map of error codes to custom message strings that override defaults.
  • t — Optional i18n translation function for localizing error messages.

Returns: A user-friendly error message string.

getHumanFileSize(bytes, decimals)

Formats a byte count as a human-readable file size string (e.g. "1.5 MB", "0 B", "-3.2 GB").

function getHumanFileSize(bytes: number, decimals?: number): string
  • bytes — The number of bytes to format (supports negative values).
  • decimals — The number of decimal places (default: 2).

Returns: A formatted file size string with the appropriate unit.

handleAnchorClick(event, navigate)

Intercepts an anchor element click for SPA client-side navigation. Skips interception when modifier keys are held, when target="_blank", or when the link points to an external URL.

function handleAnchorClick(event: MouseEvent, navigate: (url: string) => void): boolean
  • event — The mouse click event from a click listener.
  • navigate — The SPA router's navigation function to call with the href.

Returns: true if the click was intercepted and handled, false if it should proceed normally.

isAlphanumeric(value, options)

Tests whether a string contains only alphanumeric characters (and optionally spaces, dashes, or underscores). Supports length constraints via minLength and maxLength options.

function isAlphanumeric(value: string, options?: AlphanumericOptions): boolean
  • value — The string to test.
  • options — Optional flags to allow spaces, dashes, underscores, and length constraints.

Returns: true if the string matches the alphanumeric pattern.

isEmail(value)

Validates an email address against a simplified RFC 5322 pattern.

function isEmail(value: string): boolean
  • value — The string to validate as an email address.

Returns: true if the string matches the email pattern.

isInternalUrl(url)

Checks whether a URL points to the same origin as the current page. Relative URLs (not starting with http:// or https://) are considered internal.

function isInternalUrl(url: string): boolean
  • url — The URL to check (absolute or relative).

Returns: true if the URL is same-origin or relative.

isUrl(value)

Validates whether a string is a well-formed URL using the URL constructor.

function isUrl(value: string): boolean
  • value — The string to validate as a URL.

Returns: true if the string can be parsed as a valid URL.

openUrl(url, options)

Opens a URL by navigating in the current tab or opening a new window/tab with noopener,noreferrer for security.

function openUrl(url: string, options?: { newWindow?: boolean; target?: string }): void
  • url — The URL to open.
  • options — Navigation options.
  • options.newWindow — When true, opens in a new window/tab instead of navigating.
  • options.target — The window target name (default: '_blank' when newWindow is true).

parseQueryString(queryString)

Parses a URL query string into a key-value object. Keys that appear multiple times are returned as arrays.

function parseQueryString(queryString: string): Record<string, string | string[]>
  • queryString — The query string to parse (with or without leading ?).

Returns: An object where each key maps to a single string or an array of strings.

randomString(length, charset)

Generates a random string by picking characters from the given charset. Uses Math.random() — not suitable for cryptographic purposes.

function randomString(length?: number, charset?: string): string
  • length — The desired string length (default: 16).
  • charset — The character set to sample from (default: alphanumeric A-Z, a-z, 0-9).

Returns: A random string of the specified length.

readFromClipboard()

Reads text from the system clipboard using the Clipboard API.

function readFromClipboard(): Promise<string | null>

Returns: The clipboard text content, or null if reading is not supported or fails.

retry(fn, options)

Retries an async function with exponential backoff. Each failed attempt waits initialDelay * backoffFactor^(attempt-1) ms, capped at maxDelay.

function retry(
  fn: () => Promise<T>,
  options?: {
    maxAttempts?: number
    initialDelay?: number
    maxDelay?: number
    backoffFactor?: number
  },
): Promise<T>
  • fn — The async function to retry.
  • options — Retry configuration.
  • options.maxAttempts — Maximum number of attempts (default: 3).
  • options.initialDelay — Delay in ms before the first retry (default: 1000).
  • options.maxDelay — Maximum delay cap in ms (default: 30000).
  • options.backoffFactor — Multiplier applied to the delay after each attempt (default: 2).

Returns: The resolved value from the first successful attempt.

sleep(ms)

Returns a promise that resolves after the specified number of milliseconds.

function sleep(ms: number): Promise<void>
  • ms — The delay duration in milliseconds.

Returns: A promise that resolves after the delay.

throttle(fn, limit)

Wraps a function so that it fires at most once per limit milliseconds. Unlike debounce, the first call executes immediately.

function throttle(fn: T, limit: number): (...args: Parameters<T>) => void
  • fn — The function to throttle.
  • limit — The minimum interval in milliseconds between invocations.

Returns: A throttled version of fn that drops calls within the limit window.

timeAgo(time, abbreviate)

Formats the elapsed time since a given timestamp as a human-readable relative string (e.g. "3 hours ago" or "3h ago" when abbreviated).

function timeAgo(time: string | number | Date, abbreviate?: boolean): string
  • time — The timestamp as a Unix ms number, ISO date string, or Date object.
  • abbreviate — When true, uses short suffixes (m, h, d, w, y) instead of full words.

Returns: A relative time string like "just now", "5 minutes ago", or "2d ago".

toCamelCase(value)

Converts a kebab-case, snake_case, or space-separated string to camelCase (e.g. "my-variable" becomes "myVariable").

function toCamelCase(value: string): string
  • value — The string to convert.

Returns: The camelCased string, or an empty string if the input is falsy.

toKebabCase(value)

Converts a camelCase, PascalCase, snake_case, or space-separated string to kebab-case (e.g. "myVariable" becomes "my-variable").

function toKebabCase(value: string): string
  • value — The string to convert.

Returns: The kebab-cased string, or an empty string if the input is falsy.

toQueryString(params)

Converts a key-value object into a URL query string. Array values are appended as multiple entries for the same key. null and undefined values are skipped.

function toQueryString(params: Record<string, unknown>): string
  • params — The key-value pairs to serialize.

Returns: The query string including the leading ?, or an empty string if no params.

toTitleCase(value)

Converts a string to Title Case (capitalizes the first letter of each word).

function toTitleCase(value: string): string
  • value — The string to convert.

Returns: The title-cased string, or an empty string if the input is falsy.

truncate(value, maxLength, suffix)

Truncates a string to a maximum length, appending a suffix (default "...") when the string exceeds the limit.

function truncate(value: string, maxLength: number, suffix?: string): string
  • value — The string to truncate.
  • maxLength — The maximum total length including the suffix.
  • suffix — The truncation indicator appended when the string is shortened (default: "...").

Returns: The original string if within limits, or the truncated string with suffix.

uint8ArrayToUrlBase64(array)

Converts a Uint8Array to a URL-safe base64 string. The inverse of urlBase64ToUint8Array.

function uint8ArrayToUrlBase64(array: Uint8Array<ArrayBufferLike>): string
  • array — The byte array to encode.

Returns: The URL-safe base64-encoded string (trailing = padding removed).

urlBase64ToUint8Array(base64String)

Converts a URL-safe base64 string to a Uint8Array. Commonly used for decoding VAPID public keys for push notification subscriptions.

function urlBase64ToUint8Array(base64String: string): Uint8Array<ArrayBufferLike>
  • base64String — The URL-safe base64-encoded string (uses - and _ instead of + and /).

Returns: The decoded byte array.

uuid()

Generates a UUID v4 string. Uses crypto.randomUUID() when available, with a Math.random() fallback for environments that lack it.

function uuid(): string

Returns: A UUID v4 string (e.g. "550e8400-e29b-41d4-a716-446655440000").

Constants

defaultErrorMessages

Default English error messages for each error code, used as fallbacks when no translation function is provided.

const defaultErrorMessages: Record<string, string>

Injection Notes

  • randomString() and the uuid() fallback use Math.random() — NOT cryptographically secure. Never use them for tokens, secrets, or anything security-sensitive. uuid() is fine for element keys/optimistic ids (it prefers crypto.randomUUID() when available).
  • English output is a fallback, not i18n. getErrorMessage() localizes only when you pass the app's t — always pass it for UI surfaces. timeAgo() returns English-only strings ("3 hours ago"); use it for logs/dev tooling and format user-facing relative times through the app's i18n layer instead.
  • Browser-only helpers (copyToClipboard, readFromClipboard, openUrl, handleAnchorClick, isInternalUrl) touch window/document/navigator — guard them in SSR/native contexts. copyToClipboard resolves false on failure rather than throwing; check the result before showing a "Copied" state.
  • debounce/throttle return void-returning wrappers — do not await them. For async retries use retry(fn, { maxAttempts, initialDelay }) (exponential backoff).

Translations

Translation strings are provided by @molecule/app-locales-utilities.