114 lines
4.1 KiB
Markdown
114 lines
4.1 KiB
Markdown
# @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
|