dimah-s3v1.3.0
Core

Core

Protocol SSOT — routes, createS3Client, shared helpers and APIError

@dimah-s3/core

Shared protocol types, the isomorphic HTTP client, and pure helpers used by @dimah-s3/server and @dimah-s3/react.

What lives here

  • S3_API_ROUTES / S3_API_BASE_PATH — route path SSOT
  • createS3Client — browser/isomorphic client implementing S3Api (+ client plugins). Exposes $ERROR_CODES, $fetch, $Infer. baseURL wins over basePath. Upload and download expiresIn default to 600 seconds (S3_DEFAULT_EXPIRES_IN) on the server.
  • APIError — better-call class (status, body); JSON { message, code?, params? }. Use APIError.from(status, S3_ERROR_CODES.FORBIDDEN) or isAPIError. Catalog: Errors.
  • s3FetchErrorSchema — Zod schema for that JSON (better-fetch errorSchema)
  • Client plugin helpers — defineClientPlugin, createS3Fetch, pluginPath
  • Pure file helpers — validateFile, formatFileSize, buildContentDisposition, …

The browser client (createS3Client) uses nested calls (api.download({ route, key }), api.multipart.init). The server s3.api is the better-call map (s3.api.download({ query }), plus nested aliases s3.api.multipart.init). Both share these paths (under basePath, default /api/s3):

ConstantMethodPath
uploadPOST/presign/upload
uploadConfirmPOST/presign/upload/confirm
downloadGET/presign/download
deleteDELETE/delete
multipartInitPOST/presign/multipart/init
multipartPartPOST/presign/multipart/part
multipartListPartsGET/presign/multipart/parts
multipartCompletePOST/presign/multipart/complete
multipartAbortPOST/presign/multipart/abort

Quick start

import { createS3Client } from "@dimah-s3/core";
import { dbClient } from "@dimah-s3/db/client";

export const api = createS3Client({
  basePath: "/api/s3",
  credentials: "include",
  plugins: [dbClient()],
});

await api.upload({
  route: "avatar",
  fileName: "avatar.png",
  contentType: "image/png",
  fileSize: 1024,
});
await api.db.listObjects({ limit: 20, offset: 0 });

For React apps prefer createS3Client from @dimah-s3/react — same options, plus a bound Provider / typed useApi on the client object.

Client plugins

import { defineClientPlugin, pluginPath } from "@dimah-s3/core";

export function myClient() {
  return defineClientPlugin({
    id: "my",
    getActions: ($fetch) => ({
      ping: () => $fetch(pluginPath("my", "ping"), { method: "GET" }),
    }),
  });
}

Paths must match the server plugin endpoint (e.g. createS3Endpoint("/my/ping", …)).

Validation

validateFile returns { code, message, params? } (or null). On the client, useFormatValidateFileError maps code to a UI string.

On this page