This FRD defines the work to ship @dmwd-io/storage as an optional package that re-exports @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner as the platform standard for S3-compatible file storage via AWS SDK v3. Per ADR-014 (Open Source First), the value delivered is standards and drift prevention — not a custom abstraction. Platform conventions (env var names, defaults) are layered on top of the library’s own API.
Introduction
Overview
Per ADR-014, @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner are designated as the platform community library for S3-compatible file storage. Rather than building a custom StorageProvider interface, this FRD ships @dmwd-io/storage as a thin re-export of those libraries with platform conventions documented alongside. The canonical env var names (S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) are the platform standard — consuming applications configure the AWS SDK directly using these variables.
Goals
Designate @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner as the platform standard for S3-compatible file storage.
Re-export both libraries via @dmwd-io/storage so consumers have a single platform import.
Document S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY as the canonical platform env var names.
Provide pre-signed URL generation for secure, time-limited direct access (via the library’s own getSignedUrl).
Non-Goals
CDN configuration or edge caching.
Image processing or thumbnail generation.
Building a custom provider interface or adapter layer — the library’s own API is the interface (per ADR-014).
Scope
In Scope
Item
Description
packages/@dmwd-io/storage/src/index.ts
Re-export @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner.
packages/@dmwd-io/storage/package.json
Package manifest with peer dependencies on both AWS SDK v3 packages.
Platform env var documentation
Document S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY as canonical names.
.env.example
Add the canonical env var names.
Out of Scope
Item
Reason
Custom StorageProvider interface
ADR-014: library’s own API is the interface.
Azure Blob Storage adapter
No current requirement.
GCS adapter
No current requirement.
Multipart upload resumption
Complex; deferred to follow-up if large file uploads become a need.
Users and Pain Points
User
Pain Point
Application developer
No platform standard for S3 storage means teams make inconsistent choices about SDK usage and env var names.
Platform maintainer
No designated library means drift across apps using different AWS SDK versions or configuration patterns.
Operations
No standardized env var names means inconsistent bucket naming and credential configuration across apps.
Definitions
Term
Definition
@dmwd-io/storage
The platform thin re-export package for S3-compatible file storage.
S3-compatible
Any object storage service that implements the AWS S3 API (AWS S3, MinIO, DigitalOcean Spaces, Cloudflare R2).
Pre-signed URL
A time-limited URL that grants temporary access to a private object without requiring credentials.
Current State
Applications needing file storage call the AWS SDK directly without a platform-designated standard. There is no canonical set of env var names, no shared package, and no documented convention for MinIO vs. AWS S3 endpoint configuration. Teams make independent choices, leading to drift.
Proposed Solution
@dmwd-io/storage re-export package
Create packages/@dmwd-io/storage with a single entry point:
No custom interface is built — the library’s API is the interface.
Platform env var conventions
The following env var names are the platform standard for all apps using @dmwd-io/storage:
Env Var
Purpose
S3_BUCKET
Target bucket name.
S3_REGION
AWS region (e.g. us-east-1).
AWS_ACCESS_KEY_ID
AWS access key (standard AWS env var name).
AWS_SECRET_ACCESS_KEY
AWS secret key (standard AWS env var name).
S3_ENDPOINT
Optional. Override for MinIO, R2, or Spaces.
For MinIO local dev, set S3_ENDPOINT to the MinIO instance URL (e.g. http://localhost:9000). The AWS SDK’s endpoint config option accepts this directly.
Requirements
ID
Priority
Requirement
STOR-01
P0
@dmwd-io/storage re-exports @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner.
STOR-02
P0
Platform env var names (S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) are documented and added to .env.example.
STOR-03
P0
Package uses peer dependencies so applications control the AWS SDK version.
STOR-04
P1
S3_ENDPOINT is documented as the optional override for MinIO/R2/Spaces.
Functional Requirements
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, ListObjectsV2Command } from '@dmwd-io/storage' resolves to the @aws-sdk/client-s3 equivalents.
import { getSignedUrl } from '@dmwd-io/storage' resolves to the @aws-sdk/s3-request-presigner equivalent.
The package adds no runtime logic — it is a pure re-export.
Consuming applications construct S3Client directly using the platform env var names.
Non-Functional Requirements
Category
Requirement
Dependency size
No additional runtime overhead — re-export only. @aws-sdk/client-s3 (modular SDK v3) is ~50 kB.
Secrets
AWS credentials passed via environment variables. Never logged. Canonical names documented in .env.example.
Versioning
AWS SDK packages are peer dependencies. Applications pin the version they need.
API/Interface Requirements
The library’s own API is the interface. No custom types are defined in @dmwd-io/storage. Consumers use the AWS SDK v3 API directly:
Should @dmwd-io/storage also re-export @aws-sdk/lib-storage (the managed multipart upload helper)? Leaning toward yes to keep the platform import consistent.
Should we publish a recommended createS3Client(env) helper that reads from the canonical env vars? Leaning toward deferring — the env vars are documented and the pattern is simple.
Should delete() accept an array of keys for batch deletion? Leaning toward deferring — the AWS SDK’s DeleteObjectsCommand is available directly.
Acceptance Criteria
packages/@dmwd-io/storage/src/index.ts re-exports @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner.
import { S3Client, PutObjectCommand, getSignedUrl } from '@dmwd-io/storage' resolves correctly.
@aws-sdk/client-s3 and @aws-sdk/s3-request-presigner are listed as peer dependencies in package.json.
S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and S3_ENDPOINT are added to .env.example.
Platform usage example (constructing S3Client from env vars) is documented.
pnpm typecheck passes.
LLM Handoff Instructions
When implementing this FRD:
Create the packages directory if it does not exist: packages/@dmwd-io/storage/.
Create packages/@dmwd-io/storage/package.json with @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner as peer dependencies (not direct dependencies).
Create packages/@dmwd-io/storage/src/index.ts with export * from '@aws-sdk/client-s3' and export * from '@aws-sdk/s3-request-presigner'.
Add S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and S3_ENDPOINT to .env.example with brief comments.
Add a usage example to the package README or docs showing how to construct S3Client from the platform env vars.
Run pnpm typecheck.
Decision Log
Date
Decision
Rationale
2026-05-26
Single S3-compatible adapter covering AWS S3 and MinIO.
The S3 API is the de facto standard. MinIO, R2, and Spaces all implement it. One adapter covers all.
2026-05-26
AWS SDK v3 over v2.
v3 is modular (tree-shakeable), actively maintained, and the recommended SDK.
2026-05-26
Defer multipart upload.
Single-part upload handles the current file-size requirements. Multipart adds significant complexity.
2026-06-02
Reframed per ADR-014 (Open Source First): adopt @aws-sdk/client-s3 / @aws-sdk/s3-request-presigner as thin re-export rather than building a custom provider interface. Library API is the interface.
ADR-014 requires designating the community library as the standard and avoiding custom abstractions that duplicate library capabilities.
Document History
Version
Date
Author
Changes
0.1
2026-05-26
David Holmes
Initial draft.
0.2
2026-06-02
David Holmes
Reframed per ADR-014: ship as thin re-export of @aws-sdk/client-s3 / @aws-sdk/s3-request-presigner, drop custom interface.