Helpers
Formatter hooks, plain formatters, and the core helpers for validation, errors, and checksums.
Helpers come from three places:
@dimah-s3/react— formatter hooks that follow theS3Providerlocaleand translations.@dimah-s3/react/engine— plain formatters with no React import, such asformatFileSize.@dimah-s3/core— protocol helpers: validation, checksums, and errors.
Formatter hooks
Each hook returns a formatter. Digits and unit labels follow the
S3Provider locale and your translations; see
Internationalization. The built-in UI uses the same hooks.
"use client";
import {
useFormatDate,
useFormatEta,
useFormatFileSize,
useFormatNumber,
useFormatSpeed,
type UploadFileState,
} from "@dimah-s3/react";
export function FileLine({ file }: { file: UploadFileState }) {
const formatFileSize = useFormatFileSize();
const formatSpeed = useFormatSpeed();
const formatEta = useFormatEta();
const formatNumber = useFormatNumber();
const formatDate = useFormatDate();
const { speed } = file.progress;
return (
<p>
{file.fileName} · {formatFileSize(file.fileSize)} ·{" "}
{formatNumber(file.progress.percent)}%
{speed ? ` · ${formatSpeed(speed)}` : null}
{formatEta(file.progress) ? ` · ${formatEta(file.progress)}` : null}
{file.result?.lastModified
? ` · ${formatDate(file.result.lastModified)}`
: null}
</p>
);
}useFormatFileSize()—12.4 MB.useFormatNumber()— counts in the locale's digits.useFormatSpeed()—1.2 MB/s.useFormatEta()—9s left,4m left,1h 30m left. It takes aTransferProgressand returnsnulluntil the speed is known.useFormatDate()— aDate, an ISO string, or epoch milliseconds, with optionalIntl.DateTimeFormatoptions. Invalid input returns"".useFormatAcceptLabels()— short labels foraccepttokens, such as["Images", "PDF"]forupload.policy.accept. Group labels such asImagesare translated ("Images(file type group)").
Errors
Every error a hook reports is an APIError from @dimah-s3/core with a
stable code. useFormatDimahError() turns it into a translated message,
with sizes and counts in the provider's locale:
"use client";
import { useFormatDimahError, useUpload } from "@dimah-s3/react";
import { toast } from "@dimah-s3/ui";
export function AttachmentUploader() {
const formatError = useFormatDimahError();
const upload = useUpload({
route: "attachments",
onError: (error) => {
toast.add({ type: "error", title: formatError(error) });
},
});
return (
<>
<input {...upload.getInputProps()} />
<button type="button" onClick={() => upload.open()}>
Attach files
</button>
</>
);
}Codes it does not know, and plain Errors, return their message. To branch
on a code, use isS3ErrorCode from core:
import { isS3ErrorCode } from "@dimah-s3/core";
if (isS3ErrorCode(error, "FILE_TOO_LARGE")) {
console.log(error.params); // { size, maxFileSize }
}The full list of codes is in Errors. See also Outcomes and errors.
Plain formatters
These ship from the engine entry, so they work outside React and on the
server. The size formatters take a locale and unit labels; the hooks above
pass the provider's for you.
import {
formatAcceptLabels,
formatFileSize,
formatSpeed,
formatUploadProgress,
toTimestamp,
truncateFileName,
} from "@dimah-s3/react/engine";
formatFileSize(1_500_000); // "1.4 MB"
formatFileSize(1_500_000, { locale: "fa", units: { MB: "مگابایت" } }); // "۱٫۴ مگابایت"
formatUploadProgress(1_200_000, 2_000_000, 60); // "1.1 MB / 1.9 MB (60%)"
formatSpeed(1_200_000); // "1.1 MB/s"
formatAcceptLabels(["image/*", ".pdf", "application/zip"]); // ["Images", "PDF", "ZIP"]
formatAcceptLabels(["image/*"], { groups: { image: "Bilder" } }); // ["Bilder"]
truncateFileName("my-avatar-profile-picture-long-name.png", 20); // "my-avatar-profi….png"
toTimestamp("2026-10-31T12:00:00Z"); // 1793448000000, or null when invalidtruncateFileName is for plain text, such as a document title. In markup,
the UI's FileName shortens a name to the width it has and keeps the
extension visible.
Core helpers
import { validateFile } from "@dimah-s3/core";
// null when valid, otherwise an APIError:
// FILE_TYPE_NOT_ALLOWED, FILE_EMPTY, or FILE_TOO_LARGE
const error = validateFile(file, {
accept: ["image/*"],
maxFileSize: 2 * 1024 * 1024,
});Checksums and public URLs
import { buildPublicObjectUrl, sha256Blob } from "@dimah-s3/core";
// SHA-256 as unpadded base64, read in 1 MiB chunks
const hash = await sha256Blob(file);
// Public CDN URL. It does not sign; use it for public-read objects only.
const url = buildPublicObjectUrl({
baseUrl: "https://cdn.example.com",
key: "avatar/uuid/avatar.png",
});useUpload already validates files and sends checksums when the route asks
for them. Use these helpers in your own pickers or server code.