Shared utilities: FP helpers, formatting, slugs, caching, and logging.

Functional Programming

Curried utilities for data transformation: pipe, filter, map, reduce, compact, unique, and more.

Formatting

Currency formatting, phone normalization, markdown rendering, and timezone-aware date/time display.

Caching

TTL and LRU caches with a global registry for admin stats.

Functions

f
addPendingWork

Queue a promise that must complete before the response is sent

f
asString

Narrow an unknown value to string, defaulting to "" if not a string. Replaces typeof x === "string" ? x : "" at type boundaries.

f
bestEffort
No documentation available
f
bracket

Resource management pattern (like Haskell's bracket or try-with-resources). Ensures cleanup happens even if the operation throws.

f
byId

Key items by their own id, so a caller can look one up. Hand-rolled because @std/collections.associateBy keys by a string and gives back an object, while every caller here has number ids and wants a Map.

f
chunk

Split an array into chunks of a given size. Curried adapter over @std/collections.chunk (which throws for size < 1).

f
collectionCache

Create an in-memory collection cache with TTL. Loads all items via fetchAll on first access or after invalidation/expiry, then serves from memory until the TTL expires or invalidate() is called. Accepts an optional clock function for testing.

f
compact
No documentation available
f
createRequestTimer

Create a request timer for measuring duration

f
dayStartEpochMs

The epoch-ms instant of the START of a calendar day (00:00 local time) in the given timezone. Used to turn a YYYY-MM-DD filter bound into the integer occurred_at bound the ledger queries compare against, so a day range is interpreted in the operator's own timezone rather than UTC.

f
delay

Resolve after ms milliseconds — for retry backoff and similar waits.

f
emptyListsFor

A Map holding an empty list for each key, ready to be filled.

f
epochMsToTzDate

The YYYY-MM-DD calendar day an epoch-ms instant falls on in tz. The inverse direction of dayStartEpochMs, for labelling a stored occurred_at as the local day it belongs to.

f
expiresIn

Epoch seconds maxAgeSeconds from now — the expiry (e) that signed tokens carry, kept in one place so every builder computes it the same way.

f
extendedBy

A copy of base with extra entries merged on top (an extra key wins over the same key in base). Curried so a constant overlay (a fixed content type, a default set) can extend whatever record it is given.

f
fieldById

Index one field from each item by its id.

f
filter

Curried filter

f
firstIssueMessage

Run a valibot schema with abortPipeEarly and return the first error message or null.

f
firstMatch

Alternative combinator: try a sequence of producers in order and return the first that yields a defined value, or undefined if every one declines.

f
firstProblem

Check items in order and stop at the first reported problem.

f
flatMap

Curried flatMap

f
flushPendingWork

Await all queued work. Call before returning the response. Repeats until the queue stays empty: work already running can queue more (a background job that fails queues its error's activity-log write), and a single pass would discard those late arrivals unawaited.

f
formatCurrency

Format an amount in minor units (pence/cents) as a currency string. e.g. formatCurrency(1050) → "£10.50" (when the site currency is GBP). A stored provider amount passes its own currency so the symbol and minor-unit divisor describe that charge rather than today's site setting.

f
formatDatetimeInTz

Format a UTC ISO datetime string for display in the given timezone. Returns e.g. "Monday 15 June 2026 at 14:00 BST"

f
formatDatetimeShortInTz

Compact format for table cells: "yyyy-MM-dd HH:mm" in the given timezone. Delegates to the browser-compatible formatIsoForPreview helper so the same formatting runs on the server and in the admin JS bundle.

f
formatErrorMessage

Format the safe Sentry message and activity-log base.

f
formatOperatorMessage
No documentation available
f
formatRequestError

Format an error detail string with request context and error message

f
formatSignedCurrency

Format a signed change in minor units. Positive value is added, negative value is removed, and zero has no misleading sign.

f
generateSlug

Generate a random slug with at least 2 digits and 2 letters. Uses Fisher-Yates shuffle on the fixed positions to avoid bias.

f
generateUniqueSlug

Generate a unique slug by retrying random slugs until one is not taken.

f
getAllCacheStats

Collect stats from all registered caches

f
getDecimalPlaces

Get the number of decimal places for a currency code

f
getRequestId

Get the current request ID, or empty string if outside request context

f
groupToMap

Group rows by a key, keeping only the chosen value from each row. Keys appear in first-occurrence order and each value list preserves input order.

f
hasPendingWorkScope

True when running inside a runWithPendingWork scope (i.e. a request).

f
identity

Return a value unchanged.

f
invalidateCachesForTable

Fire every cache invalidator registered against table (no-op if none). The write narrows nothing, so column-gated entries fire too.

f
invalidateCachesForWrite

Fire registered cache invalidators for table, respecting column gates.

f
isNotNullish
No documentation available
f
isNullish

Remove null and undefined values from array

f
isoAfter

ISO timestamp a fixed duration after the current time — for a column that says when to do something next, rather than when something happened.

f
isoBefore

ISO timestamp a fixed duration before the current time.

f
isOneOf

Ask whether a value is one of a fixed list: isOneOf(["a", "b"])("a") is true. Curried, so a list of words becomes one named check.

f
isSafeUrl

True when a link/image URL is safe to render. Relative URLs (no scheme) are allowed; absolute URLs must use a scheme from SAFE_URL_SCHEMES. Leading ASCII control characters and spaces — which browsers strip before resolving a scheme — are removed first so java\tscript: can't sneak through.

f
isSimpleMarkdown

True when text is markdown so simple it renders as nothing more than a single <p> of plain text — no bold, italic, links, lists, headings, code, blockquotes, tables, or multiple paragraphs. When this returns true the question can safely be used as the clickable label of its control; when false the question should be rendered as a prose block above the control.

f
isValidDatetime

Check if a naive datetime-local string is a parseable datetime. Does not interpret timezone — purely a format check.

f
isValidTimezone

Validate that a string is a valid IANA timezone identifier.

f
keepAndTake

Keep the items a test accepts, then take one thing from each.

f
lazyRef

Resettable lazy reference - like once() but can be reset for testing. Returns [get, set] tuple where set(null) resets to uncomputed state.

f
localToUtc

Convert a naive datetime-local value (YYYY-MM-DDTHH:MM) to a UTC ISO string, interpreting the value as local time in the given timezone.

f
logDbError

Log a failed database operation under the standard DB_QUERY code.

f
logDebug

Log a debug message with category prefix For detailed debugging during development

f
logError

Log a classified error to console.error and persist to the activity log. Console output uses error codes and safe metadata (never PII). Activity log entry is encrypted and visible to admins on the log pages.

f
logErrorLocal

Log a classified error to console.error only (no ntfy, no activity log). Use this where calling logError would cause infinite recursion (e.g. ntfy.ts).

f
logRequest

Log a completed request to console.debug Path is automatically redacted for privacy

f
map

Curried map

f
mapBy

Index items by one field and chosen value. Keys keep first-occurrence order, while later matching items replace the stored value.

f
mapById

Index items by id and a chosen value.

f
mapNotNullish

Curried map that drops null/undefined results in one pass. Curried adapter over @std/collections.mapNotNullish. Replaces the two-step pattern: compact(map(fn)(array))

f
mapParallel

Map over a promise-returning function in parallel (Promise.all)

f
normalizePhone

Strip non-numeric characters from a phone number and normalize to +{prefix}{local}

f
normalizeSlug

Normalize a user-provided slug: trim, lowercase, replace spaces with hyphens

f
now

Current time as a Date

f
nowIso

Full ISO-8601 timestamp for created/logged_at fields

f
nowMs

Epoch milliseconds for numeric comparisons

f
nowSeconds

Current time in whole epoch seconds — the unit signed-token expiry uses.

f
once

Lazy evaluation - compute once on first call, cache forever. Use instead of let x = null; const getX = () => x ??= compute();

f
parseDateMs

The epoch milliseconds a written date names, or null when it names none — the safe wrapper around Date.parse, whose own failure mode (NaN) is easy to let leak into arithmetic by accident.

f
partition

Split an array into [matching, rest] by a predicate, keeping order. Curried adapter over @std/collections.partition.

f
pipe

Compose functions left-to-right (pipe).

f
range

Whole numbers counting up from start, stopping before end ([] when end is not past start). Hand-rolled because @std/collections has no numeric range helper. Iterating this bounded array replaces hand-counted loops, which a single slip in their step can make endless.

f
reduce

Curried reduce

f
registerDependencies

Register invalidate to fire whenever ownTable or any deps entry is written. Plain string entries are unconditional; object entries may carry whenColumns to gate on specific UPDATE columns (INSERT/DELETE always fire). Centralises the registration loop shared by cachedTable and cachedEntityTable.

f
registerTableInvalidation

Register invalidate to run whenever any of tables is written.

f
renderMarkdown

Renders block markdown, escaping raw HTML and stripping unsafe URLs.

f
requiredMapValue

Read a required map entry, failing where a broken completeness invariant is first observed instead of passing an undefined value onward.

f
resetAllCaches

Clear every registered cache: each table-registered invalidator once (a cache registered against several tables still only clears once) plus every extra reset hook. Runs after operations that bypass the normal write path — a full reset or a restore — where any warm cache is stale. A lazily-loaded cache module that never ran is absent from the registry, which is correct: it has no cache to clear.

f
sameOn

Whether two records hold the same value in every named field.

f
sameOrder

Whether two sequences hold the same values, in the same order. It stops at the first difference, so how long it takes says how much matched: never compare secrets with it.

f
setSuppressRequestLogs

Set module-level request log suppression (avoids env race in parallel tests).

f
slugify

Turn arbitrary text into a URL slug: lowercase, every run of non [a-z0-9] collapsed to a single hyphen, no leading/trailing hyphen. Shared by the news permalink builder and the provider-resource slug.

f
sort

Non-mutating sort with comparator

f
sortedNumbers

The numbers, each once, smallest first.

f
sortStrings

Sort strings in ascending locale order without changing the input.

f
sumByKey

Curried group-and-sum: accumulate valueOf(item) into a Map keyed by keyOf(item). Replaces the common pattern: const m = new Map(); for (const x of xs) m.set(k(x), (m.get(k(x)) ?? 0) + v(x))

f
sumOf

Curried sum-by-selector. Adds up the numbers produced by selector for each item. Curried adapter over @std/collections.sumOf. Replaces the common pattern: reduce((acc, x) => acc + selector(x), 0)

f
todayInTz

Get today's date as YYYY-MM-DD in the given timezone.

f
toMajorUnits

Convert minor units to major units string for form display. e.g. toMajorUnits(1050) → "10.50" (for GBP)

f
toMinorUnits

Convert major units (decimal) to minor units (integer). e.g. toMinorUnits(10.50) → 1050 (for GBP) currency defaults to the site's currency; a caller converting a charge taken in another currency passes that currency so the divisor matches it.

f
ttlCache

Create a TTL (Time-To-Live) cache. Entries expire after ttlMs milliseconds. Accepts an optional clock function for testing. Give maxEntries a value to bound the cache: storing a new key at the cap drops the oldest-stored entry first. Bound any cache whose keys can be chosen from outside (e.g. unknown session cookies), so a flood of unique keys cannot grow it without limit. Leave it unset for caches whose keyspace our own data already bounds — the keyed entity caches rely on holding every row of their table.

f
unique

Remove duplicate values (by reference/value equality), keeping first occurrences in order. Curried adapter over @std/collections.distinct.

f
uniqueBy

Remove duplicates by a key function, keeping first occurrences in order. Curried adapter over @std/collections.distinctBy.

f
uniqueSlugFromBase

Make a deterministic base slug unique by appending -2, -3, … until one is free. Unlike generateUniqueSlug (random 5-char slugs), this keeps a human-readable base — the news permalink yyyy-MM-dd-post-name — and only disambiguates on collision (two same-day posts with the same name).

f
utcToLocalInput

Convert a UTC ISO datetime string to a datetime-local input value (YYYY-MM-DDTHH:MM) in the given timezone. Used for pre-populating form inputs with timezone-adjusted values.

f
utcToZoned

Parse a UTC ISO string into a ZonedDateTime in the given timezone

f
validateSlug

Validate a normalized slug. Returns error message or null.

f
withoutLinksTo

Replace each markdown link whose target matches matcher with its plain text. Used to strip links the viewer isn't allowed to open (e.g. owner-only admin pages) before rendering — a rendered link is a promise that it works, so a viewer who can't follow it gets the words without the link.

Type Aliases

T
CacheInvalidation

Why cached data was cleared. Only a committed write needs primary refills.

T
CacheStat

A single cache's stats snapshot

T
CollectionCache

Collection cache returned by collectionCache()

T
DependsOnEntry

A dependsOn entry accepted by cachedTable / cachedEntityTable.

T
ErrorCodeType
No documentation available
T
ErrorContext

Error facts routed to the applicable sinks.

T
LogCategory

Log categories for debug logging

T
SlugWithIndex

Slug-with-index pair. Index is the blind-index type computeIndex produces (a BlindIndex for the real tables).

T
TtlCache

TTL cache returned by ttlCache()

T
Unregister

Remove one registration from the registry (handed back by the register functions; production callers register for the process's lifetime and drop it, tests must call it so their entries never outlive the test).

T
WriteInfo

What a write narrows to, for column-gated invalidation.

Variables

v
DAY_MS

Milliseconds in one day — for whole-day arithmetic on epoch times.

v
ErrorCode

Error code strings for use in logError calls

v
errorCodeLabel

Human-readable labels for error codes (shown in admin activity log)

v
joinStrings

Join an array of strings into a single string (curried reduce shorthand). Replaces the common pattern: reduce((acc: string, s: string) => acc + s, "")

v
registerCache

Register a cache stat provider (called at module load time)

v
registerCacheReset

Register an extra full-clear to run with a write cause when every cache is reset. Only needed by caches without a table registration; resetAllCaches already fires every table-registered invalidator.

v
runWithPendingWork

Run a function within a pending-work scope. Whatever fn resolves to, the queue is drained once more on the way out: an error logged after the request's own flush (e.g. while the response is finalised) still queues work, and work that outlived its request would complete during whatever runs next — on Bunny that's a killed fetch, in tests a sanitizer failure in an unrelated test.

v
runWithRequestId

Run a function with a request-scoped random ID for log correlation

v
sum

Sum an array of numbers (identity selector shorthand for sumOf). Replaces the common pattern: reduce((acc, n) => acc + n, 0)

v
withDeferredErrorReports

Keep non-critical error notifications behind a command's critical work. Nested callers join the outer queue so only the outermost boundary flushes.

Usage

import * as mod from "docs/utilities.ts";