Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
# OpenSpec Change: enterprise-compress-image
- **Change ID**: enterprise-compress-image
- **Package**: `@suaveplan/compress-image`
- **Category**: universal
- **Target path**: `universal/compression/compress-image`
- **Status**: PROPOSED
- **Date**: 2026-04-19
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/compress-image.md`
## Summary
High-level image compression façade. Orchestrates format-specific encoders (JPEG/MozJPEG, PNG/OxiPNG, WebP, AVIF) behind a uniform `ImageCompressor.compress(input, options)` API. Accepts quality presets, format override, max-dimension resize, and returns a `CompressionResult` with before/after stats.
## Current-state audit (genesis)
Package does not exist yet — fresh build.
## Dependencies
- Workspace: `@suaveplan/error`, `@suaveplan/types`
- External (via catalog): `zod`, `tslib`, `@opentelemetry/api`, `@jsquash/jpeg`, `@jsquash/png`, `@jsquash/webp`, `@jsquash/avif`, `@jsquash/resize`
- Dev (via catalog): `vitest`, `@vitest/coverage-istanbul`, `fast-check`, `mitata`
## Preserved public surface
- `ImageCompressor` — `compress(input, options?): Promise<CompressionResult>`
- Errors: `CompressionError`, `CompressionErrorCode`, `CompressionErrorContext`, `compressionFailed`, `dimensionTooLarge`, `invalidQuality`, `unsupportedFormat`, `CompressImageErrorCode`, `COMPRESS_IMAGE_ERROR_METADATA`, `registerCompressImageErrorCodes`
- Types: `CompressionFormat`, `CompressionOptions`, `CompressionPlan`, `CompressionResult`, `CompressionStep`, `PresetConfig`, `QualityPreset`, `ResolvedCompressionOptions`
- Constants: `FORMAT_QUALITY_RANGES`, `MAX_DIMENSION`, `QUALITY_PRESETS`, `VALID_FORMATS`, `VALID_PRESETS`
## New genesis additions
- Additional codes: `COMPRESS_IMAGE.ENCODER_UNAVAILABLE`, `COMPRESS_IMAGE.INPUT_TOO_LARGE`, `COMPRESS_IMAGE.OUTPUT_LARGER_THAN_INPUT`.
- Zod schemas for every option / result type.
- OTel histogram `compress_image.compress.duration_ms{format, preset}`; counter for outcome; gauge `compress_image.bytes.saved`.
- Property tests: output byte length ≤ input byte length for any input under a fixed preset (or error thrown).
## Impact
- Adds one new package: `universal/compression/compress-image`
- Adds one new spec capability: `compress-image`

View File

@@ -0,0 +1,37 @@
# Capability Spec: compress-image
**Package**: `@suaveplan/compress-image`
**Version**: 0.0.0 (genesis)
**Status**: ADDED
---
## ADDED Requirements
### CI-01 — Format coverage
`VALID_FORMATS` MUST include `'jpeg' | 'png' | 'webp' | 'avif'`. Each format MUST have a working adapter invoked by the dispatcher.
### CI-02 — Compression API
`ImageCompressor.compress(input, options?)` MUST accept `Uint8Array | ArrayBuffer | Blob`, resolve options to a `ResolvedCompressionOptions`, build a `CompressionPlan`, and execute it to produce `CompressionResult { format, bytes, width, height, durationMs, steps: CompressionStep[], inputBytes, outputBytes, savedBytes }`.
### CI-03 — Quality presets
`QUALITY_PRESETS` MUST define `'maximum' | 'high' | 'balanced' | 'fast' | 'aggressive'` with deterministic per-format quality values obeying `FORMAT_QUALITY_RANGES`. Custom `options.quality` numeric values outside the format range MUST throw `COMPRESS_IMAGE.INVALID_QUALITY`.
### CI-04 — Max dimension
`options.maxDimension` MUST resize the longest side to at most the given pixel count. A resize step MUST appear in `CompressionPlan.steps`. Inputs exceeding `MAX_DIMENSION` (default 20 000) MUST throw `COMPRESS_IMAGE.DIMENSION_TOO_LARGE`.
### CI-05 — Degenerate output
If `outputBytes > inputBytes` and `options.preserveSmaller` is `true` (default), the compressor MUST return the original input with a `CompressionStep { action: 'skip', reason: 'output-larger-than-input' }`. Otherwise the larger compressed output is returned.
### CI-06 — Format selection
When `options.format` is omitted, the compressor MUST keep the input format. `options.format: 'auto'` MUST choose based on input type (`jpeg` → `webp` at lower size if supported; `png` with alpha → `webp`/`avif`; etc.).
### CI-07 — Observability
Every compress call MUST record `compress_image.compress.duration_ms{format, preset}`, `compress_image.compress.total{format, outcome}`, and `compress_image.bytes.saved{format}` gauge.

View File

@@ -0,0 +1,42 @@
# Tasks: enterprise-compress-image
## 1. Scaffold
- [x] 1.1 `universal/compression/compress-image/`; 100/100/100/100; guard tests; CLAUDE/README/FOLDERS.
## 2. Errors + schemas
- [x] 2.1 `src/error-codes.ts`, `src/errors/compression-errors.ts`.
- [x] 2.2 Zod schemas per type.
## 3. Format adapters
- [x] 3.1 `src/adapters/jpeg.ts` (jsquash/jpeg).
- [x] 3.2 `src/adapters/png.ts` (jsquash/png).
- [x] 3.3 `src/adapters/webp.ts` (jsquash/webp).
- [x] 3.4 `src/adapters/avif.ts` (jsquash/avif).
- [x] 3.5 Co-located `.md` + fixture tests.
## 4. Resize
- [x] 4.1 `src/resize/resize.ts` — max-dimension constraint via jsquash/resize.
## 5. Planner / compressor
- [x] 5.1 `src/planner/planner.ts` — build `CompressionPlan` from `ResolvedCompressionOptions`.
- [x] 5.2 `src/compressor/image-compressor.ts` — `ImageCompressor`.
- [x] 5.3 OTel histogram + counter + gauge.
## 6. Presets / constants
- [x] 6.1 `src/types/compression.types.ts` exports `QUALITY_PRESETS`, `VALID_FORMATS`, `VALID_PRESETS`, `FORMAT_QUALITY_RANGES`, `MAX_DIMENSION`.
## 7. Docs / barrel / subpath exports / README
## 8. Benchmarks
- [x] 8.1 Compress 1 MB / 10 MB test images per format.
## 9. Ship gate
- [x] 9.1 Verification sequence; fold + archive.