@focus-at/zs3

中文文档
0.1.0发布于 2026/11/07MITTypeScriptES Module零依赖近 30 天下载 4099

Zero-dependency 3 KB S3 client built on Web Standards for AWS, Edge, Cloudflare Workers, Bun, Node, and browser runtimes.

原始使用文档
文档目录11 节
  1. Overview
  2. Features
  3. Quick Start
  4. Useful operation patterns
  5. List objects page by page
  6. Work with object versions
  7. Set object metadata and tags
  8. Send a custom request
  9. Upload a large object in parts
  10. API coverage map
  11. Examples

ZS3

GitHub License npm version npm package minimized gzipped size no dependencies NPM Downloads

Zero runtime dependencies · only ~3 KB minified · built on Web Platform APIs

ZS3 is under active development; the public API may evolve.

Tests GitHub Stars

Overview

ZS3 is a lightweight S3-compatible client for JavaScript and TypeScript. At only ~3 KB minified, it signs AWS Signature Version 4 requests and communicates with object storage through standard Web Platform APIs such as fetch, Response, TextEncoder, and crypto.subtle.

Use exec() to sign and send a request, or sign() to create a pre-signed URL and send it with regular fetch(). Native Response objects make it easy to stream downloads, inspect headers, and integrate with web frameworks.

ZeroS3 targets Node.js, Bun, browsers, and edge runtimes such as Cloudflare Workers, wherever the required Web APIs are available.

Features

Ordered from package footprint and platform foundation to S3 capabilities:

  • Only ~3 KB minified — a compact client for performance-sensitive applications.
  • Zero dependencies — built on native Web APIs, without an SDK dependency tree.
  • TypeScript — typed configuration, request options, client methods, and S3 response shapes. Public types are available from @focus-at/zs3/types.
  • Web Platform APIs — uses fetch, Response, TextEncoder, and crypto.subtle.
  • Node.js, Bun, browsers, and edge runtimes — including Cloudflare Workers, where the required Web APIs are available.
  • S3-compatible API — a consistent request model for bucket operations, object listing and pagination, object CRUD, metadata, tags, and S3 subresources.
  • AWS Signature Version 4 — sign direct requests or generate pre-signed URLs.

Quick Start

npm install @focus-at/zs3

Generate a short-lived URL in a trusted server environment, then let the browser send the request with standard fetch(). Keep permanent credentials on the server; never expose the secret access key in browser code.

// Server: create a pre-signed URL.
import { zs3 } from "@focus-at/zs3";

const signer = zs3({
  endpoint: process.env.S3_ENDPOINT!,
  accessKeyId: process.env.S3_ACCESS_KEY_ID!,
  secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
  region: "us-east-1",
});

const url = await signer.sign(
  { method: "GET", bucket: "my-bucket", key: "reports/annual.pdf" },
  { expiresIn: 300 },
);

// Browser: use the URL with the standard Fetch API.
const response = await fetch(url);

console.log(response.status, await response.blob());

For direct server-side requests, exec() signs and sends the request and returns a native Response:

import { zs3 } from "@focus-at/zs3";
import type { ZS3Objects } from "@focus-at/zs3/types";

const client = zs3({
  endpoint: process.env.S3_ENDPOINT!,
  accessKeyId: process.env.S3_ACCESS_KEY_ID!,
  secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
  bucket: "my-bucket",
});

const response = await client.exec<ZS3Objects>({ method: "GET", prefix: "reports/" });

const { key, data }  = await response.json();

console.log(data);

Custom User-Side Flattening

import { zs3, handler } from 'zs3-sdk';

const s3 = zs3({
  handler: async (res: Response) => {
    const { key, data } = await handler(res);
    return data; // Manual flattening on the user side if they don't need the root key
  }
});

Useful operation patterns

List objects page by page

Use fetch-owner to include owner information in the listing. For the next page, pass NextContinuationToken as the continuation-token query parameter.

import type { ZS3Objects } from "@focus-at/zs3/types";

const firstResponse = await client.exec<ZS3Objects>(
  { method: "GET", prefix: "reports/" },
  { query: { delimiter: "/", "max-keys": 100, "fetch-owner": true } },
);

const { data: firstPage } = await firstResponse.json();

if (firstPage.IsTruncated && firstPage.NextContinuationToken) {
  const nextResponse = await client.exec<ZS3Objects>(
    { method: "GET", prefix: "reports/" },
    {
      query: {
        delimiter: "/",
        "max-keys": 100,
        "fetch-owner": true,
        "continuation-token": firstPage.NextContinuationToken,
      },
    },
  );

  const { data: nextPage } =await nextResponse.json();

  console.log(nextPage);
}

Work with object versions

Enable versioning for a bucket with the versioning subresource. Then list versions and use a returned VersionId to request a specific object version.

await client.exec(
  { method: "PUT", bucket: "my-bucket", key: "" },
  {
    query: { versioning: "" },
    headers: { "Content-Type": "application/xml" },
    body: "<VersioningConfiguration><Status>Enabled</Status></VersioningConfiguration>",
  },
);

const versionsResponse = await client.exec(
  { method: "GET", bucket: "my-bucket", key: "" },
  { query: { versions: "", prefix: "reports/" } },
);

const { data } = await versionsResponse.json();

// Use a VersionId returned by the version listing.
const objectVersion = await client.exec(
  { method: "GET", bucket: "my-bucket", key: "reports/annual.pdf" },
  { query: { versionId: "VERSION_ID" } },
);

Set object metadata and tags

User metadata is sent during upload with x-amz-meta-* headers and can be inspected with HEAD. Tags are managed separately through the tagging subresource.

await client.exec(
  { method: "PUT", key: "reports/annual.pdf", body: file },
  {
    headers: {
      "Content-Type": "application/pdf",
      "x-amz-meta-source": "finance",
    },
  },
);

const metadata = await client.exec({ method: "HEAD", key: "reports/annual.pdf" });

console.log(metadata.headers.get("x-amz-meta-source"));

await client.exec(
  { method: "PUT", key: "reports/annual.pdf", body: taggingXml },
  {
    query: { tagging: "" },
    headers: { "Content-Type": "application/xml" },
  },
);

To inspect or change an object's ACL, use the separate acl subresource:

const acl = await client.exec(
  { method: "GET", key: "reports/annual.pdf" },
  { query: { acl: "" } },
);

Send a custom request

Use a custom path with query parameters, headers, and a body—for example, to call an application-specific endpoint:

const response = await adminClient.exec(
  {
    method: "PUT",
    key: "admin/v3/add-user",
    body: JSON.stringify({ accessKey, status: "enabled" }),
  },
  {
    query: { source: "dashboard" },
    headers: { "Content-Type": "application/json" },
  },
);

See examples/custom-request.ts for the complete example.

Upload a large object in parts

Multipart uploads are split into requests to initiate the upload, send each part, and complete it. Keep the uploadId and each uploaded part's ETag for the completion request.

const initiated = await client.exec(
  { method: "POST", key: "archives/backup.zip" },
  { query: { uploads: "" } },
);

const { data: { UploadId } } = await initiated.json();

const partResponse = await client.exec(
  { method: "PUT", key: "archives/backup.zip", body: part },
  { query: { uploadId: UploadId, partNumber: 1 } },
);

const etag = partResponse.headers.get("etag");

const partsXml = `<CompleteMultipartUpload>
  <Part><PartNumber>1</PartNumber><ETag>${etag}</ETag></Part>
</CompleteMultipartUpload>`;

await client.exec(
  { method: "POST", key: "archives/backup.zip", body: partsXml },
  {
    query: { uploadId: UploadId },
    headers: { "Content-Type": "application/xml" },
  },
);

For listing parts and aborting an upload too, see examples/multipart.ts.

API coverage map

AreaCovered scenarios
SigningAWS4 signing, pre-signed URL, standard fetch after signing
Bucketslist/create/delete; ACL, versioning, lifecycle, policy, tags, CORS, encryption, website, notifications, logging, replication, public access block, object lock
Object listsprefix, delimiter, max-keys, start-after, fetch-owner, continuation-token pagination
ObjectsGET, PUT, HEAD, DELETE, ACL, tags, user metadata, attributes, restore, retention/legal hold, object versions (list/get/delete)
Multipartinitiate, upload part, list parts, complete, abort
Custom requestscustom path, query parameters, headers, body
Errorsstatus handling and parsed S3 XML error payloads

Examples

The examples/ directory contains complete examples grouped by workflow:

  • presigned-fetch.ts — create a pre-signed URL on the server and send the request with standard fetch().
  • custom-request.ts — custom endpoint path with query parameters, headers, and a request body.
  • buckets.ts — list, create, and delete buckets; ACL, versioning, lifecycle, policy, tags, CORS, encryption, website, notifications, logging, replication, public access, and object lock.
  • objects.ts — list and paginate objects; prefix, delimiter, fetch-owner, list from a starting key, CRUD, ACL, tags, metadata, copy, attributes, restore, retention, legal hold, and list/get/delete object versions.
  • multipart.ts — initiate, upload parts, list parts, complete, and abort multipart uploads.

Examples use placeholder credentials and endpoints. Supply your own configuration when adapting them; avoid running destructive operations such as bucket or object deletion against production data.

版本与发布记录

@focus-at/zs3 共发布 21 个版本,首次发布于 2026/11/02;过去 12 个月发布了 21 个版本。

版本发布日期距今
0.1.0latest2026/11/079 天前
0.0.362026/11/0510 天前
0.0.352026/11/0510 天前
0.0.342026/11/0510 天前
0.0.322026/11/0510 天前
0.0.312026/11/0511 天前

关于 @focus-at/zs3 的常见问题

@focus-at/zs3 是什么?

Zero-dependency 3 KB S3 client built on Web Standards for AWS, Edge, Cloudflare Workers, Bun, Node, and browser runtimes.

如何安装 @focus-at/zs3?

在项目目录运行 npm install @focus-at/zs3,或使用 pnpm add / yarn add / bun add。

@focus-at/zs3 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@focus-at/zs3 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@focus-at/zs3 可以商用吗?

@focus-at/zs3 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@focus-at/zs3 的下载量有多少?

根据 npm 官方下载统计,@focus-at/zs3 在 2026/10/15 – 2026/11/13 这 30 天内被下载 4,099 次,日均约 137 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@focus-at/zs3 还在维护吗?

最新版本 0.1.0 发布于 2026/11/07(9 天前);至今共发布 21 个版本,其中过去 12 个月发布了 21 个;首次发布于 2026/11/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。