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

@mcdays/cloudflare-images-core

v0.1.0

Published

Core TypeScript logic for the Cloudflare Images family of tools: upload, dedupe, signed URLs, compression, AVIF conversion, metadata templating, list, delete. No editor or platform assumptions. Unofficial.

Downloads

244

Readme

@mcdays/cloudflare-images-core

Core TypeScript logic for the Cloudflare Images family of tools. Upload, dedupe, signed URLs, compression (via sharp), AVIF conversion, metadata templating, list, delete, variant management. No editor or platform assumptions, intended to be consumed by surface packages.

Unofficial. Not affiliated with Cloudflare, Inc.

Used by: the Cloudflare Images Raycast extension by the same author. If you want a ready-to-use surface, install that instead. This package is for developers building new surfaces (CLIs, MCP servers, plugins for other editors) over the same Cloudflare Images API.

Sibling project of the original cloudflare-images-upload VS Code extension.

Install

npm install @mcdays/cloudflare-images-core

Requires Node 20 or later (uses native fetch, FormData, Blob, crypto.subtle).

Public API

All functions are pure. No global state, no surface-specific dependencies. Pass a CloudflareConfig to anything that talks to the API; the surface is responsible for collecting credentials and dedupe-cache storage.

Upload

import { uploadImage } from "@mcdays/cloudflare-images-core";

const outcome = await uploadImage({
  source: { type: "file", path: "/tmp/screenshot.png", fileName: "screenshot.png" },
  // or: { type: "buffer", data: buf, fileName: "screenshot.png" }
  config: { accountId, apiToken, accountHash, defaultVariant: "/public", useSignedUrls: false, signingKey: "", signedUrlExpiration: 0 },
  compressionConfig: { enableCompression: true, maxFileSizeMB: 10, compressionQuality: 80, preservePngFormat: false },
  avifConversionFormat: "webp",
  metadataTemplate: { uploadedBy: "my-tool", uploadedAt: "${timestamp}" },
  metadataContext: { fileName: "screenshot.png", filePath: "/tmp/screenshot.png", surfaceVersion: "my-tool-1.0.0" },
  onProgress: (event) => {/* compression / avif-converted / uploading / metadata-warning */},
});
// outcome.imageId, outcome.url, outcome.wasCompressed, outcome.wasAvifConverted, etc.

List, delete, variants

import { listImages, deleteImage, listVariants } from "@mcdays/cloudflare-images-core";

const page = await listImages({ config: { accountId, apiToken }, perPage: 100, continuationToken: undefined });
// page.images[], page.continuationToken

const ok = await deleteImage("image-id", { accountId, apiToken });

const variants = await listVariants({ accountId, apiToken });
// [{ id: "public", options: {...}, neverRequireSignedURLs: false }, ...]

URL construction

import { buildDeliveryUrl, buildPublicUrl, generateSignedUrl, formatImageUrl } from "@mcdays/cloudflare-images-core";

// Chooses signed vs public based on config.useSignedUrls
const url = buildDeliveryUrl(imageId, "/public", config);

// Or the lower-level primitives
const publicUrl = buildPublicUrl(imageId, "/public", accountHash);
const signedUrl = generateSignedUrl(imageId, "/public", { ...config, signingKey, useSignedUrls: true });

// Format for paste
formatImageUrl(url, "screenshot.png", "markdown"); // ![screenshot.png](https://...)
formatImageUrl(url, "screenshot.png", "html");     // <img src="..." alt="..." />
formatImageUrl(url, "screenshot.png", "raw");      // https://...

Validation, hashing, image-id extraction

import { validateCredentials, calculateFileHash, extractImageIdFromUrl, fetchSigningKey } from "@mcdays/cloudflare-images-core";

const result = await validateCredentials({ accountId, apiToken, accountHash });
// { ok: true, imageCount } or { ok: false, reason: "auth-failed" | "account-not-found" | ..., detail }

const hash = calculateFileHash(buffer);                          // SHA-256 hex, used for dedupe cache keys
const imageId = extractImageIdFromUrl("https://imagedelivery.net/HASH/IMG/public"); // "IMG"
const key = await fetchSigningKey(accountId, apiToken);          // hits /accounts/:id/images/v1/keys

Metadata templating

import { resolveMetadataTemplate } from "@mcdays/cloudflare-images-core";

const resolved = resolveMetadataTemplate(
  { uploadedBy: "my-tool", uploadedAt: "${timestamp}", fileName: "${fileName}" },
  { fileName: "screenshot.png", filePath: "/tmp/screenshot.png", fileSize: 12345, surfaceVersion: "my-tool-1.0.0" },
);
// { uploadedBy: "my-tool", uploadedAt: "2026-05-13T10:00:00.000Z", fileName: "screenshot.png" }

Eight placeholders supported: ${fileName}, ${timestamp}, ${date}, ${time}, ${fileSize}, ${fileExtension}, ${surfaceVersion}, ${workspaceName}.

Compression

import { compressImageIfNeeded, convertAvifIfNeeded } from "@mcdays/cloudflare-images-core";

// Progressive-quality reduction until file fits under maxFileSizeMB
const result = await compressImageIfNeeded("/tmp/big.jpg", { enableCompression: true, maxFileSizeMB: 10, compressionQuality: 80, preservePngFormat: false });
// result.path (may be a temp file), result.wasCompressed, result.originalSize, result.newSize

// CF Images doesn't accept AVIF input; convert first
const avifResult = await convertAvifIfNeeded("/tmp/photo.avif", "webp", { enableCompression: false, maxFileSizeMB: 10, compressionQuality: 80, preservePngFormat: false });
// avifResult.path (temp .webp), avifResult.wasConverted

License

MIT.