Zyora Labs
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 min
Download 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 too
Raw 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"}'