Media Manager Contract
media-manager is dumb and generic: it only parses multipart streams and writes them to storage.
- The library never decides filenames, folders, MIME rules, limits, auth, URLs, or database writes.
- Each caller provides the full relative path (including filename) for every uploaded file, e.g.
tea/452/photo.jpg.
Storage Strategies
LOCAL_ONLY – persist only to local storage using <localRoot>/<localStoragePrefix>/<relativePath> (prefix defaults to local).
S3_ONLY – always stage the file locally, upload the staged file to S3 (key == relativePath), and delete the stage on success. Failure rolls back the stage and returns status=0.
S3_AND_LOCAL – stage locally and try to upload to S3. If S3 succeeds, both storages are considered written (status=1, storageStrategy='S3_AND_LOCAL'). If S3 fails, the local stage remains and the result downgrades to storageStrategy='LOCAL_ONLY' with savedPath pointing at the local file (status=1).
Inputs & Constraints
upload(storageStrategy, relativePath[], localStoragePrefix?) must include exactly one file stream and one relative path entry. If not, return failure before touching any storage.
- Every
relativePath entry must be strictly relative (no leading /, drive letters, or ..) and must include a filename.
- Mapping is 1:1 in order:
relativePath[i] corresponds to the ith file stream.
Outputs
{
status: 0 | 1,
storageStrategy: 'LOCAL_ONLY' | 'S3_ONLY' | 'S3_AND_LOCAL',
relativePath: string[],
savedPath: string // absolute local path or `s3://bucket/key`
}
storageStrategy should reflect what was actually persisted (downgrading to LOCAL_ONLY when S3 fails).
savedPath is the raw locator returned by the successful adapter: local absolute path for local persistence, or s3://bucket/key when S3 won.
Cleanup
cleanup(storageStrategy, relativePath[], localStoragePrefix?) deletes exactly the requested paths/keys according to the strategy.
- For
S3_AND_LOCAL, attempt both deletes; return status=1 only when every requested deletion succeeded.
- No recursive deletion, no filesystem traversal beyond resolving
<localStoragePrefix>/<relativePath>.