From c1fc387719ef138b68dcd22e323cea0dfb759457 Mon Sep 17 00:00:00 2001 From: Eirini Galati Date: Thu, 3 Sep 2026 11:08:37 +0200 Subject: [PATCH] feat: add Format constants for convert media types Adds a Format constant object so the media types accepted by convert() are discoverable at runtime as well as in the type system, matching the other Tinify client libraries. SupportedImageTypes is now derived from Format rather than duplicating the literal list, so the two cannot drift apart. The derived union is equivalent to the old one: it still rejects unknown media types and still excludes the "*/*" wildcard from array form. --- CHANGES.md | 4 ++++ README.md | 4 ++-- src/index.ts | 2 ++ src/tinify.ts | 2 ++ src/tinify/Format.ts | 42 ++++++++++++++++++++++++++++++++++++++ src/tinify/Source.ts | 13 ++++++------ test/tinify-typing-test.ts | 9 ++++++++ 7 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 src/tinify/Format.ts diff --git a/CHANGES.md b/CHANGES.md index fab3f36..54f6b6c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,7 @@ +## Unreleased + +* Added `tinify.Format` constants for the media types `convert` accepts. `SupportedImageTypes` is now derived from them. + ## 1.8.3 * add JXL to supported image formats * add node 26 as test target diff --git a/README.md b/README.md index 675f503..82d91ea 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ # Tinify API client for Node.js -A lightweight Node.js client for the Tinify API, used for [tinypng API](https://tinypng.com) and [TinyJPG](https://tinyjpg.com). This library lets you intelligently **compress**, **resize**, **convert**, and **store** images (AVIF, WebP, JPEG, PNG) with minimal effort. Read more at [http://tinify.com](http://tinify.com). +A lightweight Node.js client for the Tinify API, used for [tinypng API](https://tinypng.com) and [TinyJPG](https://tinyjpg.com). This library lets you intelligently **compress**, **resize**, **convert**, and **store** images (AVIF, JXL, WebP, JPEG, PNG) with minimal effort. Read more at [http://tinify.com](http://tinify.com). ## 🚀 Features -- Compress and optimize images in AVIF, WebP, JPEG, and PNG formats +- Compress and optimize images in AVIF, JXL, WebP, JPEG, and PNG formats - Resize with intelligent cropping - Convert between formats - Preserve metadata (copyright, GPS, creation time) diff --git a/src/index.ts b/src/index.ts index b17619d..10e3af7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import tinify from "./tinify" import Client from "./tinify/Client" +import Format from "./tinify/Format" import Result from "./tinify/Result" import ResultMeta from "./tinify/ResultMeta" import Source from "./tinify/Source" @@ -14,6 +15,7 @@ import { } from "./tinify/Error" tinify.Client = Client +tinify.Format = Format tinify.ResultMeta = ResultMeta tinify.Result = Result tinify.Source = Source diff --git a/src/tinify.ts b/src/tinify.ts index 5027434..db73199 100644 --- a/src/tinify.ts +++ b/src/tinify.ts @@ -1,6 +1,7 @@ import {nodeify, Callback} from "./tinify/compat" import Client from "./tinify/Client" +import Format from "./tinify/Format" import Result from "./tinify/Result" import ResultMeta from "./tinify/ResultMeta" import Source from "./tinify/Source" @@ -19,6 +20,7 @@ class Tinify { compressionCount?: number Client!: typeof Client + Format!: typeof Format Source!: typeof Source Result!: typeof Result ResultMeta!: typeof ResultMeta diff --git a/src/tinify/Format.ts b/src/tinify/Format.ts new file mode 100644 index 0000000..9dfafa2 --- /dev/null +++ b/src/tinify/Format.ts @@ -0,0 +1,42 @@ +/** + * Media types that images can be converted to. + * + * ```js + * const tinify = require("tinify") + * + * tinify.fromFile("input.png") + * .convert({type: tinify.Format.JXL}) + * .toFile("output.jxl") + * ``` + * + * Multiple types may be supplied, in which case the API returns the smallest + * result: + * + * ```js + * .convert({type: [tinify.Format.JXL, tinify.Format.WEBP]}) + * ``` + */ +const Format = { + /** WebP. */ + WEBP: "image/webp", + + /** PNG. */ + PNG: "image/png", + + /** JPEG. */ + JPEG: "image/jpeg", + + /** JPEG, an alias of `JPEG`. */ + JPG: "image/jpg", + + /** AVIF. */ + AVIF: "image/avif", + + /** JPEG XL. */ + JXL: "image/jxl", + + /** Wildcard, returns the smallest of the supported types. */ + ANY: "*/*", +} as const + +export default Format diff --git a/src/tinify/Source.ts b/src/tinify/Source.ts index e1fab71..3b5a924 100644 --- a/src/tinify/Source.ts +++ b/src/tinify/Source.ts @@ -2,18 +2,17 @@ import tinify from "../tinify" import {readFile, Callback} from "./compat" import Client from "./Client" +import Format from "./Format" import Result from "./Result" import ResultMeta from "./ResultMeta" -export type SupportedImageTypes = "image/webp" - | "image/png" - | "image/jpg" - | "image/jpeg" - | "image/jxl" - | "image/avif"; +type FormatValues = (typeof Format)[keyof typeof Format]; +export type SupportedImageTypes = Exclude; + +// The wildcard "*/*" returns the smallest of Tinify's supported image types. export type WildcardOrSupportedImageTypes = SupportedImageTypes - | "*/*"; // The wildcard "*/*" returns the smallest of Tinify's supported image types, currently JPEG, PNG and WebP. + | typeof Format.ANY; export type ConvertOptions = { type: WildcardOrSupportedImageTypes | SupportedImageTypes[]; diff --git a/test/tinify-typing-test.ts b/test/tinify-typing-test.ts index bc2311e..06b9078 100644 --- a/test/tinify-typing-test.ts +++ b/test/tinify-typing-test.ts @@ -15,8 +15,17 @@ async function run() { await tinify.fromFile("/foo/bar").convert({ type: "image/webp" }) await tinify.fromFile("/foo/bar").convert({ type: "image/png" }) await tinify.fromFile("/foo/bar").convert({ type: "image/jpg" }) + await tinify.fromFile("/foo/bar").convert({ type: "image/jxl" }) + await tinify.fromFile("/foo/bar").convert({ type: "image/avif" }) await tinify.fromFile("/foo/bar").convert({ type: "*/*" }) + // The Format constants are accepted everywhere a literal is. + await tinify.fromFile("/foo/bar").convert({ type: tinify.Format.JXL }) + await tinify.fromFile("/foo/bar").convert({ type: tinify.Format.ANY }) + await tinify.fromFile("/foo/bar").convert({ + type: [tinify.Format.JXL, tinify.Format.WEBP], + }) + await tinify.fromBuffer("foo") .resize({method: "fit", width: 150, height: 100}) .preserve("copyright", "creation")