zMesh / Storage
Storage
Object storage with presigned uploads and downloads. File bytes never transit the API — your client talks to the storage layer directly.
Upload a file
ts
const file = inputEl.files[0];
const obj = await zmesh.storage
.from("avatars")
.upload(`${user.id}/avatar.png`, file, {
contentType: file.type,
});
// → { id, name, size, owner_end_user_id, ... }Two-step flow under the hood: presigned PUT → direct upload → server writes metadata + enforces quota.
Temporary download URL
Share-safe — expires after the configured TTL.
ts
const { url } = await zmesh.storage
.from("avatars")
.createSignedUrl(`${user.id}/avatar.png`, { expiresIn: 600 });
// share `url` with anyone — expires in 10 minDownload bytes
ts
const blob = await zmesh.storage.from("avatars").download("alice/photo.jpg");
const imgUrl = URL.createObjectURL(blob);List + delete
ts
const files = await zmesh.storage
.from("avatars")
.list({ prefix: `${user.id}/`, limit: 50 });
await zmesh.storage.from("avatars").remove("alice/old.jpg");List buckets visible to the caller
Filtered by each bucket's read policy.
ts
const buckets = await zmesh.storage.listBuckets();
// public buckets show up for anonymous callers tooRaw HTTP — three-step upload
bash
# 1. Ask for a presigned upload URL
curl -X POST <api-url>/v1/sdk/storage/buckets/avatars/sign-upload \
-H "X-App-Id: <your-app-id>" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"object_name":"me/pic.jpg","content_type":"image/jpeg"}'
# 2. PUT the bytes directly
curl -X PUT "$PRESIGNED_URL" --data-binary @pic.jpg \
-H "Content-Type: image/jpeg"
# 3. Confirm to write metadata
curl -X POST <api-url>/v1/sdk/storage/buckets/avatars/objects/confirm \
-H "X-App-Id: <your-app-id>" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"object_name":"me/pic.jpg","size":12345,"mime_type":"image/jpeg"}'