dimah-s3v0.4.1

Helpers

Helpers for progress, validation, and file naming.

Import from @dimah-s3/react or @dimah-s3/core.

Upload UX helpers

Format upload progress

Returns human-readable progress like "1.2 MB / 5.6 MB (21%)".

import { formatUploadProgress } from "@dimah-s3/react";

formatUploadProgress(1_200_000, 5_600_000, 21);
// "1.2 MB / 5.6 MB (21%)"

formatUploadProgress(1_200_000, 0, 0);
// "1.2 MB"

Format speed

Bytes per second to text like "1.2 MB/s".

import { formatSpeed } from "@dimah-s3/react";

formatSpeed(1_200_000); // "1.2 MB/s"
formatSpeed(512); // "512 B/s"

Format ETA

Remaining time from bytes-left and speed. Returns null when not calculable.

import { formatEta } from "@dimah-s3/react";

formatEta(4_400_000, 450_000); // "9s"
formatEta(90_000_000, 1_500_000); // "1m"
formatEta(5_400_000_000, 500_000); // "3h"
formatEta(0, 450_000); // null

Create speed tracker

Sliding-window speed tracker in bytes/second.

Use it inside onProgress and call reset() whenever an upload restarts.

import { createSpeedTracker, formatEta, formatSpeed } from "@dimah-s3/react";

const tracker = createSpeedTracker(); // default 3s window

onProgress: ({ loaded, total }) => {
  const speed = tracker.update(loaded);

  formatSpeed(speed); // "450 KB/s"
  formatEta(total - loaded, speed); // "9s"
};

Format accept labels

Normalizes HTML accept entries to short display labels. Returns labels only — no sentences — so you can build localized copy in your UI.

import { formatAcceptLabels } from "@dimah-s3/react";

formatAcceptLabels(["image/*", ".pdf", ".txt"]);
// ["Images", "PDF", "TXT"]

formatAcceptLabels([
  ".png",
  ".gif",
  ".webp",
  ".pdf",
  ".docx",
  ".txt",
  ".csv",
  "image/*",
  "video/mp4",
  "audio/mpeg",
]);
// ["PNG", "GIF", "WEBP", "PDF", "DOCX", "TXT", "CSV", "Images", "MP4", "MPEG"]
InputLabel
.pngPNG
.jpg / .jpegJPEG (both extensions map to one label)
image/*Images
video/mp4MP4

In a component, call formatAcceptLabels directly and build your own localized sentence:

import { formatAcceptLabels } from "@dimah-s3/react";

function MyDropzone({ accept }: { accept?: string[] }) {
  const labels = formatAcceptLabels(accept);
  // ["Images", "PDF", "TXT"]

  return <p>Accepted {labels.join(", ")}.</p>;
}

UploadDropzone from @dimah-s3/ui does the same and adds English hint copy in the UI layer.

Validation and display helpers

Validate file

Checks accept and maxFileSize. Returns an error message or null.

Mirror these checks in upload.presignGuard. Client validation is not a security boundary.

import { validateFile } from "@dimah-s3/core";

validateFile(file, { accept: ["image/*"] });
// null | 'File type ".pdf" is not allowed'

validateFile(file, { accept: [".png", ".jpg"] });
// null | 'File type ".gif" is not allowed'

validateFile(file, { maxFileSize: 10 * 1024 * 1024 });
// null | "File size exceeds 10.0 MB limit"

Format file size

import { formatFileSize } from "@dimah-s3/core";

formatFileSize(0); // "0 B"
formatFileSize(1_500); // "1.5 KB"
formatFileSize(1_500_000); // "1.4 MB"

Truncate filename

Shortens long names while preserving extension. Default max is 26 chars.

import { truncateFileName } from "@dimah-s3/core";

truncateFileName("very-long-document-name.pdf");
// "very-long-documen… .pdf"

truncateFileName("short.pdf");
// "short.pdf"

Sanitize filename

Replaces ", \, and newlines for safer query params.

createS3Client applies this automatically when you pass fileName for download requests.

import { sanitizeFileName } from "@dimah-s3/core";

sanitizeFileName('file"name.pdf'); // file_name.pdf
sanitizeFileName("report\r\n.pdf"); // report__.pdf

Parse file name

Extracts the original filename from Content-Disposition.

import { parseFileName } from "@dimah-s3/core";

parseFileName(res.headers.get("content-disposition"));
// "report.pdf" | undefined

parseFileName("attachment; filename*=UTF-8''%E6%8A%A5%E5%91%8A.pdf");
// "报告.pdf"

On this page