purrlet
v0.0.9
Published
A lightweight, customizable, feature-rich drawbox and upload library built for React, Vue, Astro, SvelteKit, and modern JavaScript apps.
Downloads
96
Maintainers
Readme
Purrlet
Purrlet is a lightweight image upload library for modern JavaScript apps.
Version scope (v0.9)
v0.9 is focused on image uploading only.
- Included: upload providers, validation, events, framework helpers
- Not included yet: drawbox features
- Not included yet: save/export workflows
If you expected drawbox or save features, those are planned for later versions and are intentionally out of scope for v0.9.
We need your feedback
Please report bugs and share suggestions so we can harden the v1.0 release.
- Bug reports: https://github.com/BuddyWinte/Purrlet/issues
- Suggestions / feature ideas: https://github.com/BuddyWinte/Purrlet/issues
When reporting a bug, include:
- Runtime (
Browser,Node.js, framework) - Provider (
imgbb,imgur,cloudinary,localhost) - Example config used (without secrets)
- Exact error message and reproduction steps
Install
npm i purrletCore usage
import Purrlet from "purrlet";
const uploader = new Purrlet({
provider: "imgbb",
apiKey: process.env.IMGBB_KEY,
maxFileSize: 5 * 1024 * 1024,
allowedMimeTypes: ["image/jpeg", "image/png", "image/webp", "image/*"],
});
const url = await uploader.upload(file);
console.log(url);Supported providers
localhost(returns adata:URL; useful for local/dev workflows)imgbbimgurcloudinary
Constructor config (all supported options)
const uploader = new Purrlet({
provider: "imgbb", // "localhost" | "imgbb" | "imgur" | "cloudinary"
// Provider credentials
apiKey: "...", // used by imgbb, and as alias for imgur clientId
clientId: "...", // imgur preferred credential
cloudName: "...", // cloudinary required
uploadPreset: "...", // cloudinary required
folder: "optional-folder", // cloudinary optional
// Network behavior
requestTimeoutMs: 15000,
retries: 1,
retryDelayMs: 300,
// Validation
maxFileSize: 5 * 1024 * 1024, // bytes
allowedMimeTypes: ["image/jpeg", "image/png", "image/*"],
validateFile: async (file, context) => {
// return true, false, string, or { valid, reason, details }
return true;
},
// Hooks
onUpload: (url, payload) => {},
onUploadSuccess: (payload) => {},
onUploadError: (payload) => {},
onInit: (payload) => {},
onDestroy: (payload) => {},
// Logging
debug: false,
});Provider-specific minimum config
Imgbb
new Purrlet({
provider: "imgbb",
apiKey: process.env.IMGBB_KEY,
});Imgur
new Purrlet({
provider: "imgur",
clientId: process.env.IMGUR_CLIENT_ID,
// apiKey also works as a clientId alias
});Cloudinary
new Purrlet({
provider: "cloudinary",
cloudName: process.env.CLOUDINARY_CLOUD_NAME,
uploadPreset: process.env.CLOUDINARY_UPLOAD_PRESET,
folder: "optional-folder",
});Localhost
new Purrlet({ provider: "localhost" });What file inputs are supported
upload() and uploadMany() accept:
FileBlobBufferUint8ArrayArrayBuffer{ buffer, filename?, type? }{ path, filename?, type? }(Node.js)- file path string (Node.js)
Upload APIs
upload(file, options?)
const url = await uploader.upload(file, {
signal, // AbortSignal
timeoutMs: 10000,
retries: 2,
retryDelayMs: 250,
validateFile: (file, context) => true,
});uploadMany(files, options?)
const result = await uploader.uploadMany(files, {
concurrency: 3,
stopOnError: false,
timeoutMs: 10000,
retries: 2,
retryDelayMs: 250,
});
console.log(result.successful, result.failed);
console.log(result.results); // array of URLs or null
console.log(result.errors); // [{ index, error }]Events
Instance events
uploader.onInit((payload) => {});
uploader.onUploadStart((payload) => {});
uploader.onUploadSuccess((payload) => {});
uploader.onUploadError((payload) => {});
uploader.onUploadComplete((payload) => {});
uploader.onDestroy((payload) => {});Global events
import Purrlet from "purrlet";
Purrlet.onUploadSuccess((payload) => {
console.log(payload.provider, payload.url);
});Payload fields you can expect
providerpurrlet(instance)filefilenamemimeTypesizestartedAtdurationMsurl(success)error(failure)validation
Framework helpers
React
import { usePurrlet } from "purrlet/react";
const { client, upload, uploadMany, isUploading, error } = usePurrlet(config);Vue
import { usePurrlet } from "purrlet/vue";
const { client, upload, uploadMany, isUploading, error } = usePurrlet(config);Astro
import { createPurrlet, createAstroUploader } from "purrlet/astro";
const client = createPurrlet(config);
const helper = createAstroUploader(config); // { client, upload, uploadMany, destroy }SvelteKit
import { createPurrlet, createSvelteKitUploader } from "purrlet/sveltekit";
const client = createPurrlet(config);
const helper = createSvelteKitUploader(config); // { client, upload, uploadMany, isUploading, error, destroy }Runtime requirements
- Node.js
>=18
Development
npm run build
npm test
npm run lint