187 lines
7.9 KiB
Markdown
187 lines
7.9 KiB
Markdown
# Design: `@suaveplan/utils` Migration — genesis
|
|
|
|
**Date:** 2026-04-20
|
|
**Branch:** genesis
|
|
**Source:** `@suaveplan/utils` from main (`/mnt/s/web/suaveplan/packages/universal/utils`)
|
|
**Reference:** `/mnt/s/web/suaveplan/enterprise/utils.md`
|
|
|
|
---
|
|
|
|
## Context
|
|
|
|
The old `@suaveplan/utils` package is a 14-module grab-bag imported by 109 reverse-consumer workspaces. On genesis, we rewrite it fresh at enterprise quality and split it into four packages, each with a clear, single responsibility. Nothing is ported mechanically — every module is rewritten to meet the genesis enterprise checklist.
|
|
|
|
---
|
|
|
|
## Decision: Split into 4 packages
|
|
|
|
| Package | Domain path | Purpose |
|
|
|---------|-------------|---------|
|
|
| `@suaveplan/utils` | `universal/data/utils` | Zero-external-dep odds-and-sods utilities |
|
|
| `@suaveplan/json` | `universal/data/json` | Prototype-pollution-safe JSON parse/stringify |
|
|
| `@suaveplan/bytes` | `universal/primitives/bytes` | Byte encoding / format conversion |
|
|
| `@suaveplan/locale-data` | `universal/i18n/locale-data` | ISO country + language static data |
|
|
|
|
**Scrapped:** `string/parseTemplate` only — duplicate of `@suaveplan/templates` which already handles `{{var}}` interpolation. `string/parseTextWithLinks` is distinct (link annotation, not template interpolation) and is retained in `@suaveplan/utils`.
|
|
|
|
---
|
|
|
|
## Package 1: `@suaveplan/utils`
|
|
|
|
**Principle:** Zero external deps beyond the genesis standard (`zod`, `@opentelemetry/api`, `@suaveplan/error`, `@suaveplan/types`). Odds-and-sods utilities that are not worth a dedicated package.
|
|
|
|
### Modules
|
|
|
|
| Module | Key exports |
|
|
|--------|-------------|
|
|
| `debug` | `debug.log/warn/error` — dedup-buffered console logger (suppresses repeated messages within a rolling 10-item buffer) |
|
|
| `object` | `deepMerge`, `deepMergeAll`, `deepClone`, `pick`, `omit`, `flattenObject`, `getNestedValue`, `setNestedValue`, `hasPath`, `isEmpty`, `isObject`, `isPlainObject`, `isObjectOrArray`, `keepKeys`, `removeKeys` |
|
|
| `platform` | `getPlatform`, `getMemoryUsage`, `getCpuUsage`, `isNode`, `isBrowser`, `isBun` — injectable platform adapter |
|
|
| `number` | `packFloat16/32/64`, `unpackFloat16/32/64`, `isInFloat16/32/64Range`, `min16/32/64`, `max16/32/64` |
|
|
| `random` | `pseudoRandom<T>(arr, index, seed?)` — seeded deterministic array element selection |
|
|
| `email` | `normalizeEmail` — Gmail dots/plus, Yahoo dashes, Microsoft plus, generic normalization |
|
|
| `sound` | `parseSoundVariations`, `getSoundKey`, `convertSprites` — audio sprite key parsing + variation selection |
|
|
| `string` | `generateId`, `parseTextWithLinks` |
|
|
| `validate` | `isHex` |
|
|
| `validation` | `validateSize`, `formatSize`, `parseSize`, `truncateToSize`, `isWithinSizeLimit`, `getDataSize`, `MessageSizeError`, `SIZE_LIMITS`, `DEFAULT_MAX_MESSAGE_SIZE` |
|
|
|
|
### Dependencies
|
|
|
|
```text
|
|
@suaveplan/error workspace:^
|
|
@suaveplan/types workspace:^
|
|
zod catalog:zod
|
|
@opentelemetry/api catalog:otel-api
|
|
```
|
|
|
|
---
|
|
|
|
## Package 2: `@suaveplan/json`
|
|
|
|
**Principle:** Safe, hardened JSON operations. No external deps.
|
|
|
|
### Modules
|
|
|
|
| Module | Key exports |
|
|
|--------|-------------|
|
|
| `safe-json` | `safeParse`, `safeStringify`, `tryParse`, `isValidJSON`, `getStringifySize`, `SafeJSONError` |
|
|
|
|
### Features
|
|
|
|
- Prototype pollution guard: rejects `__proto__`, `constructor`, `prototype` keys by default (configurable)
|
|
- Circular reference detection with structured `SafeJSONError`
|
|
- `tryParse` returns `undefined` instead of throwing
|
|
- `getStringifySize` measures serialised byte length without full allocation
|
|
- All errors extend `@suaveplan/error` with stable codes (`JSON.PARSE_FAILED`, `JSON.CIRCULAR`, `JSON.PROTOTYPE_POLLUTION`)
|
|
|
|
### Dependencies
|
|
|
|
```text
|
|
@suaveplan/error workspace:^
|
|
@suaveplan/types workspace:^
|
|
zod catalog:zod
|
|
@opentelemetry/api catalog:otel-api
|
|
```
|
|
|
|
---
|
|
|
|
## Package 3: `@suaveplan/bytes`
|
|
|
|
**Principle:** Single canonical home for byte encoding and format conversion in the monorepo. `@suaveplan/crypto-utils` currently duplicates some of this; a follow-up task updates `crypto-utils` to consume `@suaveplan/bytes` instead.
|
|
|
|
### Modules
|
|
|
|
| Module | Key exports |
|
|
|--------|-------------|
|
|
| `encoding` | `bytesToHex`, `hexToBytes`, `bytesToBase64`, `base64ToBytes`, `bytesToUtf8`, `utf8ToBytes` |
|
|
| `uint8` | `concatUint8Arrays`, `sliceUint8Array`, `uint8ArraysEqual`, `inputToUint8Array`, `detectInputFormat`, `validateInputTypeFormat`, `formatOutput`, `convertDataFormat` |
|
|
| `uuid` | `uint8ArrayToUuid`, `uuidToUint8Array`, `generateUuid` — uses `crypto.randomUUID()` natively; no `uuid` npm package needed |
|
|
|
|
### Features
|
|
|
|
- Format auto-detection (`detectInputFormat`: hex, base64, utf8, Uint8Array)
|
|
- Round-trip guarantees tested via fast-check property tests
|
|
- All errors extend `@suaveplan/error` with stable codes (`BYTES.INVALID_FORMAT`, `BYTES.ENCODE_FAILED`, etc.)
|
|
|
|
### Dependencies
|
|
|
|
```text
|
|
@suaveplan/error workspace:^
|
|
@suaveplan/types workspace:^
|
|
zod catalog:zod
|
|
@opentelemetry/api catalog:otel-api
|
|
```
|
|
|
|
### Follow-up
|
|
|
|
After `@suaveplan/bytes` is published, open an OpenSpec change to update `@suaveplan/crypto-utils` to depend on `@suaveplan/bytes` and remove the duplicate hex/base64/utf8/bytes/concat encoding utilities. **`base58` stays in `crypto-utils`** — it is blockchain/crypto-specific (Bitcoin address encoding) and not a general-purpose byte encoding concern; moving it to `bytes` would introduce a crypto-domain concept into a general primitive.
|
|
|
|
---
|
|
|
|
## Package 4: `@suaveplan/locale-data`
|
|
|
|
**Principle:** Static ISO reference data. Too large and domain-specific to be an odds-and-sods utility. Feeds `@suaveplan/i18n`.
|
|
|
|
### Modules
|
|
|
|
| Module | Key exports |
|
|
|--------|-------------|
|
|
| `countries` | `CountryItem` type, per-country named exports (`AD`, `AE`, ...), `getCountry(code)`, `getAllCountries()`, `getCountriesByContinent(continent)`, `getCountriesByCurrency(currency)` |
|
|
| `languages` | `LanguageItem` type, `getLanguages()`, `getLanguage(code)`, `getRtlLanguages()`, `isRtlLanguage(code)` |
|
|
|
|
### Features
|
|
|
|
- All data typed with Zod schemas
|
|
- Lookup helpers with structured errors for unknown codes
|
|
- Zero runtime deps — data is bundled at build time, not fetched
|
|
|
|
### Dependencies
|
|
|
|
```text
|
|
@suaveplan/error workspace:^
|
|
@suaveplan/types workspace:^
|
|
zod catalog:zod
|
|
@opentelemetry/api catalog:otel-api
|
|
```
|
|
|
|
---
|
|
|
|
## Build sequence
|
|
|
|
All four packages share the same dependency set (genesis standard), so they can land in parallel or any order. Recommended sequence:
|
|
|
|
1. `@suaveplan/bytes` — unblocks `crypto-utils` refactor
|
|
2. `@suaveplan/json` — self-contained
|
|
3. `@suaveplan/locale-data` — self-contained; enables `i18n` to consume it
|
|
4. `@suaveplan/utils` — self-contained; the catch-all
|
|
|
|
---
|
|
|
|
## Enterprise checklist (applies to all four)
|
|
|
|
- [ ] 100% statement + branch + function + line coverage (Istanbul)
|
|
- [ ] 100% docs coverage (`bun run docs:check`)
|
|
- [ ] Every `.ts` implementation file has a sibling `.md` (≥200 words, simple + advanced examples, API reference)
|
|
- [ ] All public types have Zod schemas in sibling `*.schemas.ts`
|
|
- [ ] All thrown errors extend `@suaveplan/error` with stable `PACKAGE.DOMAIN.REASON` codes
|
|
- [ ] Injectable `clock`, `rng`, `signal` where applicable
|
|
- [ ] `AbortSignal` on every iterative helper
|
|
- [ ] OTel counters + histograms + spans on public entrypoints
|
|
- [ ] fast-check property tests for pure functions
|
|
- [ ] mitata benchmarks with CI regression gate
|
|
- [ ] `sideEffects: false`; one subpath export per feature module
|
|
- [ ] `@vitest/coverage-istanbul` in `devDependencies`
|
|
- [ ] OpenSpec change created, verified, archived
|
|
|
|
---
|
|
|
|
## OpenSpec changes to create
|
|
|
|
| Change ID | Scope |
|
|
|-----------|-------|
|
|
| `enterprise-bytes` | New `@suaveplan/bytes` package |
|
|
| `enterprise-json` | New `@suaveplan/json` package |
|
|
| `enterprise-locale-data` | New `@suaveplan/locale-data` package |
|
|
| `enterprise-utils` | New `@suaveplan/utils` package (genesis rewrite) |
|
|
| `crypto-utils-bytes-refactor` | Update `@suaveplan/crypto-utils` to consume `@suaveplan/bytes` (follow-up) |
|