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 SSOTcreateS3Client— browser/isomorphic client implementingS3Api(+ client plugins). Exposes$ERROR_CODES,$fetch,$Infer.baseURLwins overbasePath. Upload and downloadexpiresIndefault to 600 seconds (S3_DEFAULT_EXPIRES_IN) on the server.APIError— better-call class (status,body); JSON{ message, code?, params? }. UseAPIError.from(status, S3_ERROR_CODES.FORBIDDEN)orisAPIError. Catalog: Errors.s3FetchErrorSchema— Zod schema for that JSON (better-fetcherrorSchema)- 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):
| Constant | Method | Path |
|---|---|---|
upload | POST | /presign/upload |
uploadConfirm | POST | /presign/upload/confirm |
download | GET | /presign/download |
delete | DELETE | /delete |
multipartInit | POST | /presign/multipart/init |
multipartPart | POST | /presign/multipart/part |
multipartListParts | GET | /presign/multipart/parts |
multipartComplete | POST | /presign/multipart/complete |
multipartAbort | POST | /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.