@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.1k
lines
✓ 340 pass
tests
pass
typecheck
clean
lint

Test results 340

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

Mentioned in

Type Document
adr ADR-0029: Structured operational logging
adr ADR-0042: Package distribution, CI, and the release pipeline
spec Spec: Operational Logging
spec Spec: Project Terminals
spec Release pipeline