@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 |