Node 26.10 fs.openAsBlobSync: upload a local file with Sume uploadFile

Node 26.10 adds fs.openAsBlobSync. Open a file as a typed Blob and pass it to the Sume SDK's uploadFile to get a durable HTTPS URL for a Format input.

5 min readSume
All posts

To upload a local file to Sume from Node, open it as a Blob with a content type and hand it to uploadFile from @sume-com/sdk. Node 26.10.0, the Current release of September 22, adds fs.openAsBlobSync() alongside the existing fs.openAsBlob() (Node.js 26.10.0 release notes, read 2026-10-04). Either returns a Blob, so the code below prefers the sync form when it exists and falls back to the async one on older lines.

uploadFile returns a durable HTTPS URL you can pass as input to a Format or a generation request. The SDK reads the Blob's size and type itself, which is why opening the file with a type matters: contentType is required unless the Blob carries a non-empty type.

What uploadFile does in three calls

The helper follows the asset flow in three steps: it reserves a presigned upload with POST /v1/assets/upload-url, PUTs the bytes straight to storage, then calls POST /v1/assets/{id}/complete. Only the completion step mints the durable public URL. The separate download-url endpoint returns a short-lived presigned link, which is not what a Format input should receive. The asset routes are implemented but are hidden from the public OpenAPI document, and the API reference says to prefer public HTTPS media URLs in generation requests when you already have one (API reference).

The three steps inside uploadFile and the error step name (Sume SDK source, read 2026-10-04)
StepCallSumeUploadError.step on failure
1POST /v1/assets/upload-url with content type and sizecreate
2PUT bytes to the presigned URL, only the presigned headers plus content typeput
3POST /v1/assets/{id}/complete with the sizecomplete

Open, upload, print the URL

The script takes a path and a MIME type from the command line, so it never guesses the type from the extension. It exits before any network call if the key is missing.

import fs from "node:fs";
import { createSumeClient, uploadFile, SumeUploadError } from "@sume-com/sdk";

const apiKey = process.env.SUME_API_KEY ?? "";
const [path, type] = process.argv.slice(2);
if (!apiKey || !path || !type) {
  console.error("usage: SUME_API_KEY=... node upload.mts <path> <mime/type>");
  process.exit(1);
}

const fsAny = fs as any;
const blob: Blob = typeof fsAny.openAsBlobSync === "function"
  ? fsAny.openAsBlobSync(path, { type })
  : await fsAny.openAsBlob(path, { type });

const client = createSumeClient({ apiKey });
try {
  const asset = await uploadFile({ client, file: blob, filename: path.split("/").pop() });
  console.log(asset.url, asset.size_bytes);
} catch (error) {
  if (error instanceof SumeUploadError) {
    console.error("upload failed at", error.step, error.status);
    process.exit(2);
  }
  throw error;
}

Notes for production use

  • A failure at the put step happened while sending bytes to storage. Call uploadFile again to reserve a fresh upload rather than reusing the old one.
  • Keep the file in place until the upload resolves, since the Blob is backed by the file on disk.
  • Do not log the presigned URL. Log the returned asset_id and the Sume request id instead.
  • Pin the Node version in CI. The fallback keeps older lines working, but you should test the path you deploy.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume