Files
suaveplan/openspec/specs/utils/spec.md
2026-05-27 23:29:53 +01:00

4.1 KiB

@suaveplan/utils — Specification

Package: @suaveplan/utils
Version at graduation: 0.1.0
Layer: Universal — zero browser/React/Node-specific APIs
Published: 2026-04-20


Purpose

Zero-external-dependency utility library covering debugging, object manipulation, platform detection, IEEE 754 float packing, pseudo-random selection, email normalization, audio sprite management, string utilities, hex validation, and byte-size enforcement.


Modules

./errors

  • UtilsError — typed SuaveplanError<UtilsCode> subclass
  • UTILS_CODES — stable code registry keyed by dot-path
  • UtilsCode — union type of all code values

./debug

  • assertDefined<T>(val, message?) — throws if val is null/undefined
  • invariant(condition, message?) — throws if condition is false
  • unreachable(message?) — always throws (exhaustiveness check)
  • assert(condition, message?) — alias for invariant

./object

  • isObject(value) / isPlainObject(value) / isObjectOrArray(value) / isEmpty(obj)
  • deepMerge(a, b, skipUndefined?) / deepMergeAll(...objects)
  • pick(obj, keys) / omit(obj, keys) / keepKeys / removeKeys
  • flattenObject(obj, prefix?, separator?)
  • getNestedValue(obj, path, default?) / setNestedValue(obj, path, value) / hasPath(obj, path)
  • deepClone(obj)

./platform

  • isBrowser() / isNode() / isBun() / isEdge()
  • isSSR() / supportsWebWorkers() / supportsServiceWorkers()
  • getPlatform() — returns "browser" | "node" | "bun" | "edge" | "unknown"

./number

  • Constants: min16, max16, min32, max32, min64, max64
  • packFloat16(v) / unpackFloat16(buf) — IEEE 754 half-precision
  • packFloat32(v) / unpackFloat32(buf) — IEEE 754 single-precision
  • packFloat64(v) / unpackFloat64(buf) — IEEE 754 double-precision
  • isInFloat16Range(v) / isInFloat32Range(v) / isInFloat64Range(v)

./random

  • pseudoRandom<T>(arr, index, seed?, opts?) — deterministic element selection

./email

  • normalizeEmail(email) — provider-aware canonicalization (Gmail/Yahoo/Microsoft/generic)

./sound

  • parseSoundVariations(sprites) — group <name>_<n> keys by base name
  • getSoundKey(name, variations) — random variation selection; throws SOUND.NO_VARIATIONS
  • convertSprites(sprites) — alias for parseSoundVariations
  • Types: SoundSprites, SoundVariations

./string

  • generateId(opts?) — random hex identifier via crypto.randomUUID()
  • parseTextWithLinks(text) — extract HTTP/HTTPS URLs → TextLink[]
  • Types: GenerateIdOptions, TextLink

./validate

  • isHex(i) — type-guard: non-empty, even-length, hex-only string

./validation

  • Constants: SIZE_LIMITS, DEFAULT_MAX_MESSAGE_SIZE
  • getDataSize(data) — UTF-8 bytes for string, byteLength for binary, 8 for number
  • validateSize(data, maxSize?) — throws VALIDATION.SIZE_EXCEEDED
  • isWithinSizeLimit(data, maxSize?) — non-throwing boolean
  • formatSize(bytes, decimals?) — "1.50 KB" format
  • parseSize(str) — "1.5MB" → integer bytes; throws VALIDATION.PARSE_FAILED
  • truncateToSize(data, maxSize) — binary-search string truncation

Error Codes

Code Description
UTILS/OBJECT.PROTOTYPE_POLLUTION __proto__ / constructor key detected
UTILS/OBJECT.CIRCULAR Circular reference in deepClone
UTILS/NUMBER.OUT_OF_RANGE Float value outside target precision range
UTILS/RANDOM.EMPTY_ARRAY pseudoRandom called with empty array
UTILS/RANDOM.INDEX_OUT_OF_BOUNDS index >= array.length
UTILS/VALIDATION.SIZE_EXCEEDED Data exceeds maxSize bytes
UTILS/VALIDATION.PARSE_FAILED Invalid size string format
UTILS/PLATFORM.UNAVAILABLE Requested platform feature unavailable
UTILS/SOUND.NO_VARIATIONS getSoundKey called for unknown sound name

Quality Gates (at ship)

  • Istanbul coverage: 100% statements / branches / functions / lines
  • Docs coverage: 100% (12/12 files)
  • Lint: clean (biome, 0 errors)
  • TypeScript: clean (noEmit)
  • Tests: 169 passing