BunnyStorage is the Storage component’s Bunny backend. It implements the IStorage interface directly against the Bunny Storage SDK, uploading and downloading files to a regional storage zone over HTTPS — a good fit for edge file delivery paired with Bunny’s CDN. Because it shares the IStorage contract with the filesystem and S3-compatible backends, you can switch to or from Bunny without changing a single call site.
Why Bunny
- Edge delivery. Files live in a Bunny Storage zone close to your users and pair naturally with Bunny’s CDN.
- Same
IStorageinterface.put,getFile,getAsJson,delete,list, and more — identical to every other storage backend. - Regional zones. Pick from nine storage regions with a short region code.
- Flexible content.
put()accepts strings,ArrayBuffer,Blob,Request/Response, andBunFile/S3File, converting each to a stream for upload. - Container-managed. Registered with
@decorator.storage()and resolved from the container.
Installation
BunnyStorage ships with @ooneex/storage and depends on the Bunny Storage SDK.
Environment variables
| Variable | Required | Purpose |
|---|---|---|
STORAGE_BUNNY_ACCESS_KEY | Yes | Bunny storage access key. Missing throws StorageException (API_KEY_REQUIRED). |
STORAGE_BUNNY_STORAGE_ZONE | Yes | Bunny storage zone name. Missing throws StorageException (STORAGE_ZONE_REQUIRED). |
STORAGE_BUNNY_REGION | No | Region code. Defaults to de. |
BunnyStorage is constructed, so a missing key or zone fails fast at startup.
Regions
STORAGE_BUNNY_REGION accepts a short code that maps to a Bunny storage region:
| Code | Region |
|---|---|
de | Falkenstein (default) |
uk | London |
ny | New York |
la | Los Angeles |
sg | Singapore |
se | Stockholm |
br | São Paulo |
jh | Johannesburg |
syd | Sydney |
How it works
BunnyStorage connects to your storage zone with the access key and chosen region, then organizes files under a bucket. The active bucket becomes a path prefix: with bucket uploads, a key avatars/1.png is stored at /uploads/avatars/1.png. Content passed to put() is converted to a ReadableStream and uploaded through the Bunny SDK; reads stream back and are materialized as JSON, an ArrayBuffer, a stream, or written to disk.
| Method | Purpose |
|---|---|
getBucket() / setBucket(name) | Read or switch the active bucket (path prefix); setBucket chains. |
list() | List the file object names in the current bucket. |
clearBucket() | Delete every file in the current bucket. |
exists(key) | Whether an object exists. |
delete(key) | Remove one object (no-op if absent). |
put(key, content) | Upload content; returns the number of bytes written. |
putFile(key, localPath) | Upload a local file. |
putDir(bucket, options) | Upload a local directory recursively with an optional filter regex. |
getFile(key, options) | Download an object to options.outputDir (optionally renamed). |
getAsJson<T>(key) | Parse the object as JSON. |
getAsArrayBuffer(key) | Read the object as an ArrayBuffer. |
getAsStream(key) | Read the object as a ReadableStream. |
Usage
The API is the same as every other storage backend.Use in the app
In an@ooneex/app application, storage isn’t a dedicated App config slot — BunnyStorage registers itself with the container through @decorator.storage() as soon as the class is imported, and you inject it wherever you read or write files.
IStorage methods:
@decorator.storage():
STORAGE_BUNNY_ACCESS_KEY, STORAGE_BUNNY_STORAGE_ZONE, and (optionally) STORAGE_BUNNY_REGION in your .env.yml (or environment) so the backend can connect.
Exceptions
BunnyStorage throws StorageException on misconfiguration or a failed operation, carrying a machine-readable key.
| Key | When |
|---|---|
API_KEY_REQUIRED | Constructed without STORAGE_BUNNY_ACCESS_KEY. |
STORAGE_ZONE_REQUIRED | Constructed without STORAGE_BUNNY_STORAGE_ZONE. |
STORAGE_UPLOAD_FAILED | An upload to the storage zone failed. |
STORAGE_DOWNLOAD_FAILED | A download or read failed. |
STORAGE_LIST_FAILED | Listing the zone failed. |
UNSUPPORTED_CONTENT_TYPE | put() received content it cannot convert to a stream. |
Best practices
- Set the bucket first. Call
setBucket()before reads or writes so keys land under the right path prefix. - Pick the nearest region. Set
STORAGE_BUNNY_REGIONto the zone closest to your users for lower latency. - Use stable, namespaced keys. Group objects under prefixes like
avatars/123.pngsolist()andclearBucket()stay predictable. - Stream large files. Prefer
getAsStream()andputFile/putDirover loading whole files into memory. - Filter directory uploads. Pass a
filterregex toputDir()so you only ship the files you intend to. - Keep credentials in the environment. Load the access key and zone from
.env; never hard-code them.