Files
2026-05-27 23:29:53 +01:00

3.5 KiB

OpenSpec Change: enterprise-server-caddy-imgproxy

  • Change ID: enterprise-server-caddy-imgproxy
  • Package: @suaveplan/caddy-imgproxy
  • Category: server/infra
  • Target path: server/infra/caddy-imgproxy
  • Status: PROPOSED
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/caddy-imgproxy.md

Summary

Deliver @suaveplan/caddy-imgproxy on the genesis branch from scratch at enterprise quality. The package provides a typed TypeScript client and URL-builder for imgproxy behind a Caddy reverse proxy. It generates HMAC-SHA256 signed imgproxy URLs for resize, crop, format conversion, quality, watermark, blur, and brightness operations. It does not spawn processes — it is a pure URL-generation and request-signing library with injectable @suaveplan/crypto for signing and Zod-validated option schemas.


Current-state audit (genesis)

Does not exist on genesis — fresh build.


Available workspace deps on genesis

Package Role
@suaveplan/error (workspace:^) Typed IMGPROXY.* error codes
@suaveplan/types (workspace:^) LoggerLike
@suaveplan/crypto (workspace:^) HMAC-SHA256 signing
zod (catalog:forms) Options validation
@opentelemetry/api (catalog:observability) Counters
tslib (catalog:build) Runtime helpers

Public API surface

class ImgproxyUrlBuilder {
  constructor(options: ImgproxyOptions)
  build(options: ImgproxyTransformOptions): string
  buildSigned(options: ImgproxyTransformOptions): string
}

function createImgproxyUrlBuilder(options: ImgproxyOptions): ImgproxyUrlBuilder

interface ImgproxyOptions {
  baseUrl: string
  key?: string        // hex-encoded signing key
  salt?: string       // hex-encoded salt
  defaultQuality?: number
}

interface ImgproxyTransformOptions {
  src: string         // source image URL or S3 path
  width?: number
  height?: number
  resizingType?: 'fit' | 'fill' | 'crop' | 'pad' | 'auto'
  format?: 'webp' | 'avif' | 'jpeg' | 'png' | 'gif' | 'ico' | 'svg'
  quality?: number
  blur?: number
  brightness?: number
  contrast?: number
  gravity?: 'sm' | 'ce' | 'no' | 'so' | 'ea' | 'we' | 'noea' | 'nowe' | 'soea' | 'sowe' | 'fp'
  watermark?: WatermarkOptions
  dpr?: number
  enlarge?: boolean
  extend?: boolean
}

interface WatermarkOptions {
  opacity: number
  position?: string
  xOffset?: number
  yOffset?: number
  scale?: number
}

const ImgproxyOptionsSchema: z.ZodSchema<ImgproxyOptions>
const ImgproxyTransformOptionsSchema: z.ZodSchema<ImgproxyTransformOptions>

type ImgproxyErrorCode =
  | 'IMGPROXY_INVALID_OPTIONS'
  | 'IMGPROXY_SIGN_FAILED'
  | 'IMGPROXY_INVALID_SOURCE_URL'

function registerImgproxyErrorCodes(): void

File layout

server/infra/caddy-imgproxy/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    error-codes.ts
    constants/index.ts
    types/
      imgproxy.types.ts
      imgproxy.types.md
    builder/
      imgproxy-url-builder/
        imgproxy-url-builder.ts
        imgproxy-url-builder.md
        imgproxy-url-builder.types.ts
        imgproxy-url-builder.test.ts
        index.ts
    utils/
      path-encoder.ts
      path-encoder.md
      path-encoder.test.ts
  tests/
    integration.test.ts

Impact

Downstream: any package needing image transformation URLs (file upload API, media service, CDN pipeline). Pure URL generation — no network required.

Prerequisites on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/crypto.