Shared utilities from @fuzdev/fuz_util.
@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));| Export | Purpose |
|---|---|
OK | Frozen {ok: true} constant for results with no extra data |
NOT_OK | Frozen {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 |
ResultError | Custom 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.
{ok: true, ...data} — not
{ok: true, value: {data: ...}}{value} when unwrap() is expected; {message} for errors (used by
ResultError)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] connectednew Logger(label?: string, options?: LoggerOptions)| Option | Type | Default | Purpose |
|---|---|---|---|
level | LogLevel | Inherited or env-detected | Log level for this instance |
colors | boolean | Inherited or env-detected | Whether to use ANSI colors |
console | LogConsole | Inherited or global console | Console interface for output |
Override via PUBLIC_LOG_LEVEL env var. Default detection order:
PUBLIC_LOG_LEVEL env var (if set)'off' when running under Vitest'debug' in development (DEV from esm-env)'info' in production| Level | Value | Purpose |
|---|---|---|
off | 0 | No output |
error | 1 | Errors only |
warn | 2 | Errors and warnings |
info | 3 | Normal operational messages |
debug | 4 | Detailed diagnostic information |
| Method | Level | Console method | Use case |
|---|---|---|---|
log.error() | error | console.error | Failures requiring attention |
log.warn() | warn | console.warn | Potential issues |
log.info() | info | console.log | Normal operations |
log.debug() | debug | console.log | Diagnostic details |
log.raw() | (none) | console.log | Unfiltered, 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.
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 againThe 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.
| Export | Purpose |
|---|---|
log_level_to_number | Converts a LogLevel to its numeric value (0-4) |
log_level_parse | Validates a log level string, throws on invalid |
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();| Method/Property | Signature | Purpose |
|---|---|---|
constructor | new Timings(decimals?: number) | Optional decimal precision for rounding |
start() | (key: TimingsKey, decimals?) => () => number | Start a timing, returns stop function |
get() | (key: TimingsKey) => number | Get recorded duration for a key |
entries() | () => IterableIterator<[TimingsKey, number \| undefined]> | Iterate all timings |
merge() | (timings: Timings) => void | Merge other timings, summing shared keys |
TimingsKey is string | number. Duplicate keys are auto-suffixed
(operation, operation_2, operation_3, etc.).
print_timings(timings, log) from @fuzdev/fuz_util/print.ts outputs timing
data at debug level after task execution. Timings itself does not log.
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@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.
@fuzdev/fuz_util/dom.ts — browser DOM utilities.
swallowClaims 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_valueWraps 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)} />