Minor Changes
-
ea6597e: Add
wellcrafted/logger— a structured, level-keyed logger for libraries that usedefineErrors.- Five levels (
trace/debug/info/warn/error), nofatal. Mirrors Rust'stracing. log.warn(err)/log.error(err)take a typed error unary (fromdefineErrors), accepting both the raw variant and theErr<>wrapper — level is a call-site decision, never a property of the variant.log.info/log.debug/log.traceare free-form (message + optional data).- DI-only: no global registry, no default logger singleton. Every consumer takes a
log?: Loggeroption. - Ships pure-JS sinks (
consoleSink,memorySink,composeSinks) and thetapErrResult-flow combinator (mirrors Rust's.inspect_err).tapErris re-exported from bothwellcrafted/logger(canonical use) andwellcrafted/result(where it structurally belongs).
Runtime-agnostic. Environment-specific sinks (e.g. a Bun JSONL file sink) belong in downstream packages.
The
LoggableError = AnyTaggedError | Err<AnyTaggedError>union is safe to discriminate via"name" in err:nameis already stamped (and reserved) bydefineErrorson every tagged error, andErr<E>has no top-levelname. No new field reservation was needed.import { createLogger, consoleSink, tapErr } from "wellcrafted/logger"; const log = createLogger("my-source"); // defaults to consoleSink const result = await tryAsync({ try: () => writeTable(path), catch: (cause) => MyError.WriteFailed({ path, cause }), }).then(tapErr(log.warn));
- Five levels (
Patch Changes
-
687485e: Fix
trySyncandtryAsynctype inference for catch handlers returning union Err typesWhen a catch handler returned multiple Err variants (e.g.,
Err<A> | Err<B>), TypeScript could not infer the union, requiring explicit return type annotations. Replaced three overloads per function with a single generic signature that infers the full catch return type.