@filepack/storage-s3
v0.1.1
Published
S3-compatible ObjectStorage adapter for Filepack
Readme
@filepack/storage-s3
Direct S3-compatible ObjectStorage for AWS S3 and Cloudflare R2.
import { S3Client } from "@aws-sdk/client-s3";
import { s3Adapter } from "@filepack/storage-s3";
const storage = s3Adapter({
client: new S3Client({
region: "us-east-1",
}),
bucket: "private-files",
});The host owns client credentials, region, endpoint, retry behavior, and private
bucket policy. Filepack signs the accepted Content-Type, If-None-Match: *,
object key, and expiry. It disables optional SDK payload checksums only for
presigning because v0 browser uploads do not send a planned checksum.
Trusted terminal sealing uses server credentials to replace the exact key with
a zero-byte marker; browsers cannot invoke it.
Both factories expose provider-native multipart creation, signed part targets,
server-side conditional completion, and idempotent abort. Bucket CORS must
expose the ETag response header for part PUTs.
Community MinIO browser tests use an isolated server configured with
MINIO_API_CORS_ALLOW_ORIGIN=http://127.0.0.1:4173. They do not use unsupported
per-bucket CORS APIs. Production AWS S3 and R2 buckets still use explicit
bucket CORS rules for trusted application origins. Never use a wildcard origin
for private application data.
A final 409 ConditionalRequestConflict fails the upload attempt and requires
a new plan. On 412 PreconditionFailed, the adapter preserves the existing
object and aborts the losing multipart session before core inspection. Abort
failures propagate so a completion retry can finish settlement.
Cloudflare R2's default jurisdiction has a convenience factory using the same implementation:
import { r2Adapter } from "@filepack/storage-s3";
const storage = r2Adapter({
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
bucket: "private-files",
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
},
});Both factories require an existing private bucket. They do not create buckets
or configure CORS. Presigned URLs are bearer capabilities and must not be
logged or persisted. For EU or FedRAMP jurisdiction buckets, create an
S3Client with Cloudflare's jurisdiction endpoint and pass it to s3Adapter.
See the object storage setup guide.
That guide includes the real-browser MinIO CORS proof and the pending AWS
certification boundary.
