SDK — Files
apulodi.files maps 1:1 to the Files REST API. Every method returns the same
fully-typed object you get from the API (see the API reference).
Get a file
const file = await apulodi.files.get("file_8f2b…");
file.filename; // string
file.contentType; // string
file.status; // "uploaded"
file.version; // 1
file.metadata; // { userId: "u_123" } | null
file.createdAt; // ISO string
List files
const page = await apulodi.files.list({
path: "users/avatars",
limit: 50,
sortBy: "size",
order: "desc",
search: "avatar",
});
Filters mirror the REST query params: search, path, contentType,
status, plus sortBy/order. The response carries pagination.hasMore
and pagination.nextCursor.
Update (rename / move / metadata)
const updated = await apulodi.files.update("file_8f2b…", {
filename: "profile.jpg",
path: "users/profiles",
metadata: { verified: true },
});
Renames and moves are logical-only — no bytes are copied.
Copy
const copy = await apulodi.files.copy("file_8f2b…", {
path: "backups",
filename: "profile-backup.jpg",
});
Server-side copy; returns a new file id.
Download URL
const { url, expiresAt } = await apulodi.files.downloadUrl("file_8f2b…", {
expiresInSeconds: 300,
});
// fetch the bytes directly from storage
const res = await fetch(url);
Replace content (versioning)
const v2 = await apulodi.files.replace("file_8f2b…", {
data: newBytes, // Buffer / Uint8Array / Blob / …
contentType: "image/jpeg",
});
v2.version; // 2
replace() runs the initiate → PUT → complete steps for you; the previous
version stays intact server-side.
Delete
await apulodi.files.delete("file_8f2b…"); // { id, deleted: true }
Deletion soft-deletes the file: it disappears from all listings and reads
return 404, but the storage object is kept for a grace window
(APULODI_DELETE_GRACE_DAYS, default 7 days) before a periodic purge sweep
removes it.
Restore
restore() re-activates a soft-deleted file while it is still inside the
delete grace window. Immediately after a delete it succeeds:
await apulodi.files.delete("file_8f2b…");
const back = await apulodi.files.restore("file_8f2b…"); // status: "uploaded"
Once the purge sweep has removed the object (after the grace window), restore
fails with a typed ApulodiError (409, OBJECT_NOT_FOUND):
Image variants
Image files support variants — derived copies (thumbnails, resized renditions, format conversions) produced asynchronously without ever touching the original. Identical requests are idempotent: the same parameters always map to the same variant.
// Fire-and-forget: returns immediately with a pending variant.
const variant = await apulodi.files.transform("file_8f2b…", {
width: 256,
height: 256,
fit: "cover", // or "contain" / "inside"
format: "webp", // or "jpeg" / "png" / "avif"
quality: 80,
});
// Poll until ready (or subscribe to the file.processed webhook event).
const done = await apulodi.files.waitForVariant("file_8f2b…", variant.id);
// List every variant of a file.
const all = await apulodi.files.variants("file_8f2b…");
// Download the derivative directly from storage.
const { url } = await apulodi.files.variantDownloadUrl("file_8f2b…", done.id);
Every eligible image upload automatically gets a 256px webp thumbnail — the
file.uploaded event triggers it, and file.processed /
file.processing_failed report the outcome.
A note on identifiers
The API exposes filename and contentType (not name / mimeType) — the
SDK types match the REST contract exactly, avoiding surprises when switching
between raw API calls and the SDK.
Next: SDK — Uploads.