/skills/fuz-stack/references/common-utilities
  • docs
  • skills
  • fuz-stack
    • Async Patterns
    • Code Generation
    • Common Utilities
    • CSS Patterns
    • Dependency Injection
    • Documentation System
    • File Organization
    • mdz — Strict Markdown Dialect
    • Approved npm Dependencies
    • Path References in Documentation
    • Approved Rust Dependencies
    • Rust Patterns for the Fuz Ecosystem
    • Rust Performance Patterns
    • Rust Spine & Consumer Servers
    • Svelte 5 Patterns
    • Task Patterns
    • Testing Patterns
    • TSDoc Comment Style Guide
    • Twin Implementations (TS ↔ Rust)
    • Type Utilities
    • WASM Patterns for the Fuz Ecosystem
    • Zod Schemas
  • grimoire
  • tools
  • hash

Common Utilities

Shared utilities from @fuzdev/fuz_util.

Result Type

@fuzdev/fuz_util/result.ts — Result<TValue, TError> discriminated union for error handling without exceptions. Uses intersection: ({ok: true} & TValue) | ({ok: false} & TError), so properties go directly on the result object (not nested under .value/.error wrappers).

import type {Result} from '@fuzdev/fuz_util/result.ts'; import {unwrap} from '@fuzdev/fuz_util/result.ts'; function parse_config(text: string): Result<{value: Config}, {message: string}> { try { return {ok: true, value: JSON.parse(text)}; } catch (e) { return {ok: false, message: e.message}; } } // Usage - discriminated union narrows via .ok const result = parse_config(text); if (result.ok) { console.log(result.value); } else { console.error(result.message); } // Or unwrap (throws ResultError if not ok — requires {value} convention) const config = unwrap(parse_config(text));

Helper exports

ExportPurpose
OKFrozen {ok: true} constant for results with no extra data
NOT_OKFrozen {ok: false} constant for results with no extra data
unwrap()Returns result.value if ok, throws ResultError if not
unwrap_error()Returns the type-narrowed {ok: false} & TError result, throws if ok
ResultErrorCustom Error subclass thrown by unwrap, carries .result and supports ErrorOptions

unwrap signature:

const unwrap: <TValue extends {value?: unknown}, TError extends {message?: string}>( result: Result<TValue, TError>, message?: string, ) => TValue['value'];

unwrap_error returns the entire failed result (not just a value) — the opposite of unwrap returning just .value.

Conventions

  • Spread data directly on the result: {ok: true, ...data} — not {ok: true, value: {data: ...}}
  • Use {value} when unwrap() is expected; {message} for errors (used by ResultError)
  • Prefer Result over throwing for expected errors (parsing, validation); use exceptions for unexpected errors (programmer mistakes, system failures)

Logger

Hierarchical logging via @fuzdev/fuz_util/log.ts:

import {Logger} from '@fuzdev/fuz_util/log.ts'; const log = new Logger('my_module'); log.info('starting'); log.debug('details', {data}); // Child loggers inherit level, colors, and console from parent const child_log = log.child('submodule'); // label: 'my_module:submodule' child_log.info('connected'); // [my_module:submodule] connected

Constructor

new Logger(label?: string, options?: LoggerOptions)
OptionTypeDefaultPurpose
levelLogLevelInherited or env-detectedLog level for this instance
colorsbooleanInherited or env-detectedWhether to use ANSI colors
consoleLogConsoleInherited or global consoleConsole interface for output

Log Levels

Override via PUBLIC_LOG_LEVEL env var. Default detection order:

  1. PUBLIC_LOG_LEVEL env var (if set)
  2. 'off' when running under Vitest
  3. 'debug' in development (DEV from esm-env)
  4. 'info' in production
LevelValuePurpose
off0No output
error1Errors only
warn2Errors and warnings
info3Normal operational messages
debug4Detailed diagnostic information

Logger Methods

MethodLevelConsole methodUse case
log.error()errorconsole.errorFailures requiring attention
log.warn()warnconsole.warnPotential issues
log.info()infoconsole.logNormal operations
log.debug()debugconsole.logDiagnostic details
log.raw()(none)console.logUnfiltered, no prefix or level check

Each method except raw checks this.level before outputting. Prefixes include the bracketed label plus a level indicator for error, warn, and debug; info has no level prefix — just the label.

Inheritance

No static state — level, colors, and console are instance properties. Children inherit from parent, so changing a parent's level affects children that haven't set their own override.

const root = new Logger('app'); const child = root.child('db'); root.level = 'debug'; // child also becomes debug (inherits) child.level = 'warn'; // child overrides, root unaffected child.clear_level_override(); // child inherits from root again child.clear_colors_override(); // child inherits colors from root again child.clear_console_override(); // child inherits console from root again

The root getter walks the parent chain to find the root logger, useful for setting global configuration.

Colors automatically disabled when NO_COLOR or CLAUDECODE env vars are set.

Additional Logger Exports

ExportPurpose
log_level_to_numberConverts a LogLevel to its numeric value (0-4)
log_level_parseValidates a log level string, throws on invalid

Timings

Performance measurement via @fuzdev/fuz_util/timings.ts. Tracks multiple named timing operations; used in Gro's TaskContext for task performance.

import {Timings} from '@fuzdev/fuz_util/timings.ts'; const timings = new Timings(); // start() returns a stop function const stop = timings.start('operation'); await expensive_work(); const elapsed_ms = stop(); // returns elapsed milliseconds (does not log) // Nested timings const stop_outer = timings.start('outer'); const stop_inner = timings.start('inner'); await inner_work(); stop_inner(); await more_work(); stop_outer();

API

Method/PropertySignaturePurpose
constructornew Timings(decimals?: number)Optional decimal precision for rounding
start()(key: TimingsKey, decimals?) => () => numberStart a timing, returns stop function
get()(key: TimingsKey) => numberGet recorded duration for a key
entries()() => IterableIterator<[TimingsKey, number \| undefined]>Iterate all timings
merge()(timings: Timings) => voidMerge other timings, summing shared keys

TimingsKey is string | number. Duplicate keys are auto-suffixed (operation, operation_2, operation_3, etc.).

Integration with Logger

print_timings(timings, log) from @fuzdev/fuz_util/print.ts outputs timing data at debug level after task execution. Timings itself does not log.

Stopwatch

create_stopwatch(decimals?) — lower-level primitive returning a Stopwatch function that tracks elapsed time from creation. Call with true to reset; default decimals is 2.

import {create_stopwatch, type Stopwatch} from '@fuzdev/fuz_util/timings.ts'; const elapsed: Stopwatch = create_stopwatch(); await work(); console.log(elapsed()); // e.g., 142.37 — ms since creation console.log(elapsed(true)); // ms since creation, then resets start time console.log(elapsed()); // ms since reset

DAG Execution

@fuzdev/fuz_util/dag.ts — run_dag() executes dependency graphs concurrently (nodes declare depends_on; independent nodes run in parallel up to max_concurrency). See ./async-patterns for the full DAG API (DagOptions, DagResult, DagNode) and concurrency primitives, and ./type-utilities for nominal typing and strict utility types.

DOM Helpers

@fuzdev/fuz_util/dom.ts — browser DOM utilities.

swallow

Claims an event by preventing its default action and stopping propagation:

import {swallow} from '@fuzdev/fuz_util/dom.ts'; swallow(event); // preventDefault + stopImmediatePropagation swallow(event, false); // preventDefault + stopPropagation (non-immediate) swallow(event, true, false); // stopImmediatePropagation only (no preventDefault)

Design principle: if you preventDefault, you're claiming the event — use swallow to also stop propagation. Parents needing to observe before children claim should use the capture phase. See ./svelte-patterns §Event Handling for full guidance.

handle_target_value

Wraps an input event callback with value extraction and optional swallowing:

import {handle_target_value} from '@fuzdev/fuz_util/dom.ts'; // Swallows by default (preventDefault + stopImmediatePropagation) <input oninput={handle_target_value((value) => { name = value; })} /> // Without swallowing <input oninput={handle_target_value((value) => { name = value; }, false)} />