Additional npm packages and Node.js APIs supported by Perry. All listed here are wired through Perry's well-known native bindings registry (#466) and compile to native code with no JavaScript runtime involvement.
Native bindings via perry-ext-sharp (v0.5.551). Resizes, format conversion,
and buffer/file output all work.
import sharp from "sharp";
const buf = await sharp("input.jpg")
.resize(1600, 900)
.jpeg({ quality: 80 })
.toBuffer();
await sharp("input.png")
.resize(300, 200)
.toFile("output.png");Native bindings via perry-ext-cheerio (v0.5.550).
import * as cheerio from "cheerio";
const html = "<html><body><h1>Hello</h1><p>World</p></body></html>";
const $ = cheerio.load(html);
console.log($("h1").text()); // "Hello"{{#include ../../examples/stdlib/other/snippets.ts:nodemailer}}Native bindings via perry-ext-zlib (v0.5.541).
import zlib from "zlib";
const compressed = zlib.gzipSync("Hello, World!");
const decompressed = zlib.gunzipSync(compressed);
console.log(decompressed.toString()); // "Hello, World!"Native bindings via perry-ext-cron (v0.5.564). Both cron and node-cron
package names route to the same backend.
import { CronJob } from "cron";
const job = new CronJob("*/5 * * * *", () => {
console.log("Runs every 5 minutes");
});
job.start();Native bindings via perry-ext-ethers (v0.5.556) — backed by
ethers-rs-style ABI plumbing through
perry-ffi's BigInt + Buffer surfaces.
import { ethers } from "ethers";
const wallet = ethers.Wallet.createRandom();
console.log("address:", wallet.address);
console.log("private key:", wallet.privateKey);Native bindings via perry-ext-events (v0.5.546). The EventEmitter shape
matches Node.js — on, off, once, emit, removeAllListeners.
import { EventEmitter } from "events";
const ee = new EventEmitter();
ee.on("data", (chunk) => console.log("got:", chunk));
ee.emit("data", "hello");Native bindings via perry-ext-exponential-backoff (v0.5.542).
import { backOff } from "exponential-backoff";
const result = await backOff(() => fetchUnstableEndpoint(), {
numOfAttempts: 5,
startingDelay: 200,
timeMultiple: 2,
});Native bindings via perry-ext-decimal (v0.5.547). Both package names route
to the same backend — Decimal and BigNumber are both exposed.
{{#include ../../examples/stdlib/other/snippets.ts:decimal}}Native bindings via perry-ext-dayjs (v0.5.548). Both package names route to
the same Rust backend — same parse/format/diff surface.
import dayjs from "dayjs";
const now = dayjs();
const tomorrow = now.add(1, "day");
console.log(tomorrow.format("YYYY-MM-DD"));Native bindings via perry-ext-moment (v0.5.549). moment is in maintenance
mode upstream — prefer dayjs for new code, but Perry supports both for
existing codebases.
import moment from "moment";
const m = moment().add(7, "days");
console.log(m.format());Native bindings via perry-ext-ratelimit (v0.5.552). In-memory limiter is
wired; Redis / cluster backing stores are follow-ups.
import { RateLimiterMemory } from "rate-limiter-flexible";
const limiter = new RateLimiterMemory({ points: 5, duration: 1 });
try {
await limiter.consume("ip-1.2.3.4");
} catch (rateLimitErr) {
console.warn("blocked:", rateLimitErr);
}Partially recognized at HIR-lowering time (parentPort / Worker shapes)
but full dispatch is incomplete. For data-parallel work today, prefer
parallelMap / parallelFilter / spawn from perry/thread
(see Threading).
import { Worker, parentPort, workerData } from "worker_threads";
if (parentPort) {
// Worker thread
const data = workerData;
parentPort.postMessage({ result: data.value * 2 });
} else {
// Main thread
const worker = new Worker("./worker.ts", {
workerData: { value: 21 },
});
worker.on("message", (msg) => {
console.log(msg.result); // 42
});
}
{{#include ../../examples/stdlib/other/snippets.ts:commander}}The wired constructor takes the npm v7+ options-object shape
(new LRUCache({ max: 100 })) — the older positional form
new LRUCache(100) falls through to a max=100 default.
{{#include ../../examples/stdlib/other/snippets.ts:lru-cache}}{{#include ../../examples/stdlib/other/snippets.ts:child-process}}Two packages live in their own GitHub repos with their own semver — they're
imported by bun add like any npm package, but Rust-backed and compiled
natively via perry-ffi:
@perryts/tursodb— Turso (libSQL fork) database client. See PerryTS/tursodb-bindings.@perryts/iroh— Iroh peer-to-peer networking. See PerryTS/iroh-bindings.
Pure-TypeScript drivers compiled via compilePackages:
@perryts/postgres,@perryts/mysql,@perryts/mongodb,@perryts/redis— wire-protocol clients that also run on Node.js and Bun unchanged.
See Native Bindings — Overview for the contract these external packages follow.
- Overview — All stdlib modules
- File System — fs and path APIs
- Native Bindings — Authoring your own