@kaged/utils

Shared foundation utilities — fs guards, type guards, formatting, async/stream helpers, Snowflake IDs, fetch-retry, rotating logger, XDG dirs, and more

22
source files
21
test files
~5.0k
lines
✓ 327 pass
tests
pass
typecheck
clean
lint

Test results 327

AbortError > captures signal reason in message [0.210ms]
AbortError > defaults to Cancelled for non-Error reasons [0.040ms]
createAbortableStream > returns stream unchanged when no signal [0.920ms]
createAbortableStream > wraps stream in a transform with signal [1.61ms]
untilAborted > resolves normally without signal [0.140ms]
untilAborted > resolves normally with non-aborted signal [0.180ms]
untilAborted > rejects immediately if signal already aborted [0.100ms]
untilAborted > rejects when signal fires during execution [11.14ms]
untilAborted > accepts a function returning a promise [0.240ms]
untilAborted > calls function lazily [0.140ms]
once > calls function only once [0.090ms]
once > caches undefined return value [0.040ms]
withTimeout > resolves when promise completes before timeout [0.230ms]
withTimeout > rejects when timeout fires first [10.27ms]
withTimeout > propagates promise rejection [0.150ms]
withTimeout > rejects immediately if signal already aborted [0.100ms]
withTimeout > rejects when signal aborts during wait [11.03ms]
withTimeout > cleans up timeout on early resolution [5.42ms]
XDG / platform dirs > getDataDir returns a path containing kaged [1.97ms]
XDG / platform dirs > getStateDir returns a path containing kaged [0.080ms]
XDG / platform dirs > getCacheDir returns a path containing kaged [0.050ms]
XDG / platform dirs > getConfigDir returns a path containing kaged [0.040ms]
XDG / platform dirs > getLogsDir is under state dir [0.070ms]
XDG / platform dirs > getDbDir is under data dir [0.060ms]
XDG / platform dirs > getSessionsDir is under data dir [0.050ms]
XDG / platform dirs > getRuntimeDir returns a path containing kaged [0.070ms]
getProjectConfigDir > defaults to cwd/.kaged [0.120ms]
getProjectConfigDir > uses provided root [0.040ms]
resolveEquivalentPath > resolves relative paths [0.150ms]
resolveEquivalentPath > resolves symlinks when possible [0.070ms]
resolveEquivalentPath > returns resolved path for nonexistent paths [0.090ms]
normalizePathForComparison > normalizes to absolute path [0.110ms]
pathIsWithin > child is within root [0.130ms]
pathIsWithin > same path is within [0.070ms]
pathIsWithin > parent is not within child [0.060ms]
pathIsWithin > sibling is not within [0.060ms]
pathIsWithin > rejects path traversal [0.060ms]
shortenHome > replaces home prefix with ~ [0.110ms]
shortenHome > leaves non-home paths unchanged [0.040ms]
shortenHome > does not shorten home dir itself without trailing slash [0.030ms]
hashPath > returns 7-char hex string [0.400ms]
hashPath > same path produces same hash [0.050ms]
hashPath > different paths produce different hashes [0.040ms]
isValidEnvName > valid names [0.130ms]
isValidEnvName > invalid names [0.060ms]
isSafeEnvName > safe names [0.070ms]
isSafeEnvName > unsafe names [0.050ms]
isSafeEnvValue > safe values [0.070ms]
isSafeEnvValue > null byte is unsafe [0.020ms]
filterProcessEnv > filters out unsafe keys and undefined values [0.180ms]
filterProcessEnv > filters out values with null bytes [0.050ms]
parseEnvFile > parses simple key=value [0.280ms]
parseEnvFile > strips quotes [0.060ms]
parseEnvFile > skips comments and blank lines [0.050ms]
parseEnvFile > skips lines without = [0.030ms]
parseEnvFile > skips invalid env names [0.040ms]
parseEnvFile > handles values with equals signs [0.040ms]
parseEnvFile > trims whitespace around key and value [0.030ms]
pickEnv > returns first found non-empty value [0.160ms]
pickEnv > returns undefined when none found [0.040ms]
envPosInt > returns parsed value when valid positive integer [0.090ms]
envPosInt > returns default for missing var [0.030ms]
envPosInt > returns default for non-numeric [0.040ms]
envPosInt > returns default for zero or negative [0.060ms]
envFlag > truthy values [0.160ms]
envFlag > falsy values [0.060ms]
envFlag > missing returns default [0.040ms]
isBunTestRuntime > detects test runtime [0.060ms]
extractRetryHint > returns undefined for null/undefined source [0.470ms]
extractRetryHint > extracts from Retry-After header (numeric seconds) [0.110ms]
extractRetryHint > extracts from Retry-After header (zero) [0.060ms]
extractRetryHint > extracts from x-ratelimit-reset-after header [0.060ms]
extractRetryHint > extracts from quota reset body pattern [0.160ms]
extractRetryHint > extracts from 'Please retry in' body pattern [0.140ms]
extractRetryHint > extracts from retryDelay JSON field [0.120ms]
extractRetryHint > extracts from 'try again in' body pattern [0.100ms]
extractRetryHint > returns undefined when no signal found [0.060ms]
extractRetryHint > headers take priority over body [0.070ms]
isRetryableStatus > retryable statuses [0.080ms]
isRetryableStatus > non-retryable statuses [0.060ms]
extractHttpStatusFromError > extracts from status field [0.180ms]
extractHttpStatusFromError > extracts from statusCode field [0.040ms]
extractHttpStatusFromError > extracts from response.status [0.040ms]
extractHttpStatusFromError > extracts from string status [0.040ms]
extractHttpStatusFromError > extracts from error message [0.270ms]
extractHttpStatusFromError > follows cause chain [0.090ms]
extractHttpStatusFromError > returns undefined for non-objects [0.060ms]
extractHttpStatusFromError > limits cause depth to 2 [0.050ms]
isRetryableError > AbortError is retryable [0.130ms]
isRetryableError > timeout messages are retryable [0.070ms]
isRetryableError > retryable HTTP statuses [0.060ms]
isRetryableError > 4xx (non-408/429) is not retryable [0.060ms]
isRetryableError > validation messages are not retryable [0.100ms]
isRetryableError > transient messages are retryable [0.360ms]
isUnexpectedSocketCloseMessage > matches socket close messages [0.050ms]
isUnexpectedSocketCloseMessage > rejects non-matching messages [0.050ms]
fetchWithRetry > returns response on success [1.02ms]
fetchWithRetry > retries on retryable status [2.66ms]
fetchWithRetry > returns last response after maxAttempts [1.43ms]
fetchWithRetry > throws on network error after maxAttempts [1.76ms]
fetchWithRetry > throws immediately on abort [0.320ms]
fetchWithRetry > supports URL function [1.49ms]
fetchWithRetry > supports prepareInit for header refresh [0.480ms]
fetchWithRetry > supports array defaultDelayMs [3.63ms]
fetchWithRetry > returns early when server hint exceeds maxDelayMs [0.420ms]
formatDuration > milliseconds [1.36ms]
formatDuration > seconds [0.140ms]
formatDuration > minutes [0.070ms]
formatDuration > hours [0.060ms]
formatDuration > days [0.070ms]
formatNumber > small numbers unchanged [0.150ms]
formatNumber > thousands [0.140ms]
formatNumber > millions [0.060ms]
formatNumber > billions [0.060ms]
formatBytes > bytes [0.110ms]
formatBytes > kilobytes [0.050ms]
formatBytes > megabytes [0.060ms]
formatBytes > gigabytes [0.060ms]
truncate > short strings unchanged [0.130ms]
truncate > long strings truncated with ellipsis [0.060ms]
truncate > custom ellipsis [0.040ms]
truncate > maxLen smaller than ellipsis [0.040ms]
pluralize > singular [0.110ms]
pluralize > regular plural [0.140ms]
pluralize > sibilant endings (-ch, -sh, -s, -x, -z) [0.090ms]
pluralize > consonant+y → ies [0.080ms]
pluralize > vowel+y → ys [0.060ms]
formatCount > singular [0.090ms]
formatCount > plural [0.040ms]
formatCount > zero [0.040ms]
formatCount > non-finite falls back to 0 [0.060ms]
formatAge > null/undefined/0 returns empty [0.180ms]
formatAge > just now [0.040ms]
formatAge > minutes [0.040ms]
formatAge > hours [0.030ms]
formatAge > days [0.050ms]
formatAge > weeks [0.050ms]
formatAge > months [0.030ms]
formatPercent > formats ratio as percentage [0.110ms]
parseFrontmatter > parses basic frontmatter [2.38ms]
parseFrontmatter > returns empty frontmatter when no --- delimiter [0.110ms]
parseFrontmatter > returns body unchanged when no closing --- [0.060ms]
parseFrontmatter > normalizes kebab-case keys to camelCase [0.300ms]
parseFrontmatter > strips HTML comments [0.110ms]
parseFrontmatter > normalizes CRLF to LF [0.110ms]
parseFrontmatter > merges with fallback values [0.120ms]
parseFrontmatter > normalize=false skips HTML comment stripping and CRLF [0.090ms]
parseFrontmatter > level=fatal throws on invalid YAML [0.690ms]
parseFrontmatter > level=warn falls back to simple parsing on invalid YAML [0.580ms]
parseFrontmatter > handles empty frontmatter block [0.090ms]
parseFrontmatter > handles complex YAML values [0.180ms]
parseFrontmatter > normalizes nested kebab-case keys [0.140ms]
FrontmatterError > has correct name and message [0.130ms]
isFsError > returns true for Error with string code [0.270ms]
isFsError > returns false for plain Error [0.060ms]
isFsError > returns false for non-Error objects [0.130ms]
isFsError > returns false when code is not a string [0.090ms]
isEnoent > matches ENOENT [0.090ms]
isEnoent > rejects other codes [0.050ms]
isEnoent > rejects non-errors [0.060ms]
isEacces > matches EACCES [0.080ms]
isEacces > rejects other codes [0.040ms]
isEisdir > matches EISDIR [0.090ms]
isEisdir > rejects other codes [0.040ms]
isEnotdir > matches ENOTDIR [0.090ms]
isEnotdir > rejects other codes [0.060ms]
isEexist > matches EEXIST [0.080ms]
isEexist > rejects other codes [0.040ms]
isEnotempty > matches ENOTEMPTY [0.070ms]
isEnotempty > rejects other codes [0.050ms]
hasFsCode > matches arbitrary code [0.070ms]
hasFsCode > rejects mismatched code [0.060ms]
hasFsCode > rejects non-errors [0.040ms]
real fs error > identifies a real ENOENT from fs [0.700ms]
globPaths > matches files by glob pattern [4.25ms]
globPaths > supports multiple patterns [0.850ms]
globPaths > excludes .git by default [0.730ms]
globPaths > excludes node_modules by default [0.820ms]
globPaths > includes node_modules when pattern mentions it [0.630ms]
globPaths > respects custom exclude patterns [1.00ms]
globPaths > respects dot option [0.930ms]
globPaths > respects abort signal [1.61ms]
globPaths > respects timeout [0.800ms]
loadGitignorePatterns > parses .gitignore patterns [1.77ms]
loadGitignorePatterns > skips comments and empty lines [2.26ms]
loadGitignorePatterns > skips negation patterns [0.810ms]
loadGitignorePatterns > returns empty array when no .gitignore exists [0.510ms]
snowflake > returns a 16-char hex string [1.22ms]
snowflake > generates unique ids [2.34ms]
snowflake > accepts custom timestamp [0.080ms]
isValidSnowflake > valid snowflakes [0.140ms]
isValidSnowflake > invalid snowflakes [0.070ms]
snowflakeLowerBound / snowflakeUpperBound > lower bound has zero sequence [0.100ms]
snowflakeLowerBound / snowflakeUpperBound > upper bound has max sequence [0.100ms]
snowflakeLowerBound / snowflakeUpperBound > lower < upper for same timestamp [0.050ms]
snowflakeLowerBound / snowflakeUpperBound > accepts Date objects [0.110ms]
snowflakeTimestamp / snowflakeDate > round-trips through generate [0.200ms]
snowflakeTimestamp / snowflakeDate > snowflakeDate returns a Date [0.220ms]
SnowflakeSource > custom initial sequence [0.140ms]
SnowflakeSource > sequence wraps at MAX_SEQ [0.070ms]
SnowflakeSource > independent sources produce different ids [0.070ms]
tryParseJson > parses valid JSON object [1.13ms]
tryParseJson > parses valid JSON array [0.130ms]
tryParseJson > parses valid JSON primitives [0.080ms]
tryParseJson > returns null on invalid JSON [0.110ms]
tryParseJson > preserves generic type parameter [0.060ms]
logger > writes JSON log entries [3.41ms]
logger > writes all levels [0.700ms]
logger > respects minimum level [0.440ms]
logger > includes context fields [0.430ms]
logger > context does not override reserved fields [0.390ms]
logger > creates log directory if it does not exist [0.390ms]
getLogPath > returns path for today [0.250ms]
getLogPath > returns path for specific date [0.120ms]
getLogDir > returns configured directory [0.110ms]
log rotation > prunes old log files beyond maxFiles [0.660ms]
SUPPORTED_IMAGE_MIME_TYPES > contains expected types [0.180ms]
parseImageMetadata > returns null for unrecognized data [1.14ms]
parseImageMetadata > parses PNG with IHDR (RGBA) [0.580ms]
parseImageMetadata > parses PNG with IHDR (RGB) [0.170ms]
parseImageMetadata > parses PNG with IHDR (grayscale) [0.130ms]
parseImageMetadata > detects PNG magic without IHDR [0.100ms]
parseImageMetadata > parses JPEG with SOF0 [0.260ms]
parseImageMetadata > detects JPEG magic even with minimal header [0.120ms]
parseImageMetadata > parses GIF89a header [0.180ms]
parseImageMetadata > parses GIF87a header [0.150ms]
parseImageMetadata > detects WebP RIFF container [0.150ms]
readImageMetadataSync > reads PNG metadata from file [1.20ms]
readImageMetadataSync > returns null for non-image file [0.320ms]
readImageMetadata > reads GIF metadata from file (async) [3.86ms]
peekFileSync > reads first N bytes of a file [0.660ms]
peekFileSync > reads fewer bytes if file is shorter than maxBytes [0.390ms]
peekFileSync > returns op(empty) when maxBytes is 0 [0.290ms]
peekFileSync > passes header to op and returns its result [0.330ms]
peekFile > reads first N bytes of a file (async) [2.98ms]
peekFile > reads fewer bytes if file is shorter [0.800ms]
peekFile > returns op(empty) when maxBytes is 0 [0.500ms]
registerCleanup > returns a cancel function [1.64ms]
cleanup > returns a promise [0.560ms]
RingBuffer > starts empty [1.67ms]
RingBuffer > push and length [0.220ms]
RingBuffer > push returns undefined when not full [0.090ms]
RingBuffer > push returns overwritten item when full [0.200ms]
RingBuffer > shift removes oldest [0.180ms]
RingBuffer > shift returns undefined when empty [0.070ms]
RingBuffer > pop removes newest [0.160ms]
RingBuffer > pop returns undefined when empty [0.050ms]
RingBuffer > unshift adds to front [0.170ms]
RingBuffer > unshift overwrites newest when full [0.090ms]
RingBuffer > at with positive index [0.160ms]
RingBuffer > at with negative index [0.090ms]
RingBuffer > at returns undefined for out-of-bounds [0.080ms]
RingBuffer > peek and peekBack [0.240ms]
RingBuffer > clear resets buffer [0.180ms]
RingBuffer > iterator yields in FIFO order [0.730ms]
RingBuffer > iterator after wraparound [0.210ms]
RingBuffer > toArray after wraparound [0.100ms]
RingBuffer > mixed push/shift operations [0.100ms]
RingBuffer > works with string type [0.100ms]
sanitizeText > passes through clean text unchanged [1.75ms]
sanitizeText > preserves tabs and newlines [0.110ms]
sanitizeText > strips ANSI escape sequences [0.160ms]
sanitizeText > removes C0 control characters (except tab and newline) [0.100ms]
sanitizeText > removes DEL character [0.060ms]
sanitizeText > removes C1 control characters [0.070ms]
sanitizeText > handles mixed ANSI and control characters [0.060ms]
sanitizeText > handles empty string [0.060ms]
sanitizeText > preserves U+FFFD in already well-formed strings [0.090ms]
readLines > splits on newlines [6.03ms]
readLines > handles chunks split mid-line [1.10ms]
readLines > yields trailing data without final newline [0.570ms]
readLines > empty stream yields nothing [0.390ms]
readTextLines > yields decoded strings [0.930ms]
readJsonl > parses JSONL lines [0.960ms]
readJsonl > skips blank lines [0.630ms]
parseJsonlLenient > parses valid lines [0.260ms]
parseJsonlLenient > skips malformed lines [0.210ms]
parseJsonlLenient > skips blank lines [0.080ms]
parseJsonlLenient > returns empty for empty input [0.070ms]
readSseEvents > parses basic SSE events [1.95ms]
readSseEvents > parses named events [0.660ms]
readSseEvents > concatenates multi-line data with newlines [0.670ms]
readSseEvents > handles \r\n line endings [0.600ms]
readSseEvents > skips comment lines [0.730ms]
readSseEvents > flushes trailing event without final blank line [0.600ms]
readSseJson > parses JSON from SSE data [1.11ms]
readSseJson > stops at [DONE] sentinel [0.700ms]
readSseJson > skips empty data events [0.500ms]
readSseJson > calls onEvent observer [0.600ms]
readSseJson > observer errors do not break stream [0.720ms]
TempDir > createSync creates a directory [0.680ms]
TempDir > create creates a directory [0.850ms]
TempDir > path returns the directory path [0.210ms]
TempDir > absolute returns an absolute path [0.200ms]
TempDir > join appends to the temp path [0.230ms]
TempDir > toString returns the path [0.170ms]
TempDir > removeSync removes the directory [0.270ms]
TempDir > remove removes the directory [0.690ms]
TempDir > remove is idempotent [0.390ms]
TempDir > custom prefix with @ [0.170ms]
TempDir > default prefix uses kaged-temp- [0.130ms]
TempDir > Symbol.dispose cleans up [0.230ms]
TempDir > Symbol.asyncDispose cleans up [0.670ms]
isRecord > returns true for plain objects [1.57ms]
isRecord > returns true for Object.create(null) [0.080ms]
isRecord > returns false for arrays [0.070ms]
isRecord > returns false for null and undefined [0.070ms]
isRecord > returns false for primitives [0.070ms]
isRecord > returns true for class instances [0.110ms]
asRecord > returns the value for records [0.100ms]
asRecord > returns null for non-records [0.080ms]
toError > returns Error instances as-is [0.100ms]
toError > wraps strings in Error [0.070ms]
toError > wraps numbers in Error [0.060ms]
toError > wraps null in Error [0.060ms]
toError > wraps undefined in Error [0.060ms]
toError > preserves Error subclasses [0.090ms]
structuredCloneJSON > clones plain objects [0.310ms]
structuredCloneJSON > clones arrays [0.120ms]
structuredCloneJSON > returns primitives as-is [0.090ms]
structuredCloneJSON > handles objects that structuredClone rejects [0.230ms]
$which > finds common binaries on PATH [1.83ms]
$which > returns null for nonexistent binary [0.390ms]
$which > caches results with Cached policy [0.330ms]
$which > bypasses cache with Bypass policy [0.200ms]
$which > respects custom PATH [0.070ms]
$which > finds bun binary [0.210ms]

Mentioned in

Type Document
adr ADR-0029: Structured operational logging
spec Spec: Operational Logging
spec Spec: Project Terminals