@dimah-s3/core
Shared protocol routes, isomorphic client, error types, and pure helpers.
@dimah-s3/core is the protocol source of truth shared by
@dimah-s3/server and @dimah-s3/react.
What lives here
S3_API_ROUTES/S3_API_BASE_PATH— canonical route pathscreateS3Client— 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— error class withstatusandbody. Serialized as JSON{ message, code?, params? }. UseAPIError.from(status, S3_ERROR_CODES.FORBIDDEN)orisAPIError. Catalog: Errors.s3FetchErrorSchema— Zod schema for that JSON error body- 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
uses query-based handlers (s3.api.download({ query })) and the same nested
aliases (s3.api.multipart.init).
The protocol uses these paths under basePath (default /api/s3):
| Constant | Method | Path |
|---|---|---|
upload | POST | /presign/upload |
uploadConfirm | POST | /presign/upload/confirm |
download | GET | /presign/download |
file | GET | /file |
catalog | GET | /routes |
delete | DELETE | /delete |
deleteBatch | POST | /delete/batch |
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 |
file is the server-side proxy target returned by download when its mode is
"proxy"; it is not a separate S3Api client method.
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.