npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@moebel/image-url

v1.1.0

Published

Signierte imgproxy-URLs (URL-Bau + serverseitige Signierung) für den mde-images Bild-Service.

Readme

@moebel/image-url

Eine universelle TS-Lib zum Bauen signierter imgproxy-URLs (URL-Bau + serverseitige Signierung) — nutzbar in Next.js (Node & Edge) und beliebigen weiteren JS-Umgebungen.

Universell (Node + Edge + Browser-Worker)

Signiert mit Web Crypto (crypto.subtle) statt node:crypto, ohne Buffer. Läuft damit ohne Anpassung in jedem Runtime mit Web Crypto:

  • Next.js Node- und Edge-Runtime (Server Component, Route Handler, Middleware)
  • Deno, Cloudflare Workers, Browser/Worker (nur dort, wo der Key serverseitig bleibt)
  • Node ≥ 18

Da Web Crypto async ist, sind sign / signedImageUrl / buildPictureSources Promises (await). buildPath / base64url / formatFromAccept bleiben sync.

Modulformat (ESM und CommonJS)

Das Paket ist ein Dual-Package: per exports werden sowohl ein ESM- als auch ein CommonJS-Build ausgeliefert. Konsumenten brauchen also keinen import()-Shim:

import { signedImageUrl } from "@moebel/image-url";        // ESM / TS (module: esnext|nodenext)
const { signedImageUrl } = require("@moebel/image-url");   // CommonJS / ts-node (module: commonjs)

Die Typen (index.d.ts) liegen für beide Conditions vor.

Was sie macht

  • baut den imgproxy-Verarbeitungspfad (rs:auto:W:H, optional q:, dpr:)
  • kodiert die Quell-URL des Originals base64url als imgproxy-Quelle
  • signiert den Pfad (HMAC-SHA256, base64url) — imgproxy-Referenz-Schema
  • wählt das Format explizit per URL-Endung (.avif / .webp / .jpg)

Ergebnis-URL:

https://<host>/<sig>/rs:<resize>:<w>:<h>[/q:<q>][/dpr:<n>]/<base64url(originalUrl)>.<ext>

⚠️ Key-Safety (wichtig)

IMGPROXY_KEY und IMGPROXY_SALT sind Secrets und dürfen nie ins Browser-Bundle. Diese Lib daher ausschließlich serverseitig nutzen: Server Component, Route Handler / API, SSR oder Build-Step.

Ein next/image-loader läuft im Client und kann das Secret nicht halten — deshalb gibt es zwei sichere Wege (siehe examples/next/):

| Variante | Datei | Idee | |---|---|---| | A (empfohlen) | MdeImage.tsx | Server Component rendert <picture> mit fertig signierten AVIF/WebP/JPEG-Quellen. Browser wählt das Format. | | B | route-handler.ts | /api/img-Route signiert serverseitig und antwortet mit 302 auf die images.<zone>-URL; next/image zeigt auf diese Route. |

Format statt Custom Cache Key

Custom Cache Key ist bei Cloudflare Enterprise-only. Stattdessen ist jede Format-Variante eine eigene URL (Endung) und wird vom Edge per Default gecached. Format-Wahl:

  • serverseitig pro Request über den Accept-Header → formatFromAccept()
  • oder im Browser via <picture> (Variante A) — bevorzugt, kein Vary: Accept.

API

signedImageUrl({ host, originalUrl, width, height?, resize?, format?,
                 quality?, dpr?, key, salt }): Promise<string>
buildPath(opts): string            // sync — signierbarer Pfad ohne Host/Signatur
sign(path, keyHex, saltHex): Promise<string>
base64url(input): string           // sync
formatFromAccept(accept?): "avif"|"webp"|"jpg"   // sync
buildPictureSources(base, formats?, dprs?): Promise<{ sources, fallback }>

resize default auto (= contain-or-cover, skaliert nie hoch). quality weglassen ⇒ serverseitige FORMAT_QUALITY (avif=50, webp=70, jpeg=75).

Beispiel

import { signedImageUrl } from "@moebel/image-url";

const url = await signedImageUrl({
  host: "images.example.com",
  originalUrl: "https://img.example.com/produkt/123/sofa.jpg",
  width: 600,
  height: 450,
  format: "avif",          // pro Browser-Support wählen
  key: process.env.IMGPROXY_KEY!,
  salt: process.env.IMGPROXY_SALT!,
});

Build & Test

npm install
npm run build          # -> dist/esm + dist/cjs (je mit type-Marker)
npm test               # baut + node:test gegen dist/esm (ESM) UND dist/cjs (require)

Der Test sichert den Signatur-Algorithmus per deterministischem Golden gegen die öffentlichen imgproxy-Doku-Keys ab. Der authoritative End-to-End-Check ist eine mit den echten Secrets signierte URL gegen den Live-Endpoint (https://<host>/...200 + image/avif).

Hosts

  • host = der imgproxy-Serving-Host (images.<deine-domain>).
  • originalUrl = die Quell-URL des Originals; muss zu IMGPROXY_ALLOWED_SOURCES passen.