Bun and Deno load .env for a Sume script: Deno needs --allow-env
One submit script, three runtimes. Bun reads .env on its own; Deno needs --env-file plus --allow-env for each variable. Tested on Bun 1.4.0 and Deno 2.9.7.

The same ten-line submit.mjs that uses process.env.SUME_API_KEY runs unchanged on Node, Bun and Deno. What differs is how the variables get in. Bun auto-loads a .env from the working directory. Deno does not, and it also guards every read: a variable that is not on the --allow-env list throws a permission error, even when --env-file loaded it.
Results below are from Node 22.14.0, Bun 1.4.0 and Deno 2.9.7 running the script against a local stand-in server that answers 202, with a .env holding SUME_API_KEY and SUME_BASE.
| Runtime | Command | Result |
|---|---|---|
| Node 22.14 | node --env-file=.env submit.mjs | 202 |
| Bun 1.4.0 | bun submit.mjs | 202 (reads .env automatically) |
| Deno 2.9.7 | deno run --env-file=.env --allow-env=SUME_API_KEY,SUME_BASE --allow-net=127.0.0.1:8791 submit.mjs | 202 |
| Deno 2.9.7 | same, without --allow-env | permission error at the first env read |
| Deno 2.9.7 | --allow-env=SUME_API_KEY only | permission error when SUME_BASE is read |
The script they all ran
It stops early when the key is missing, then posts a 5-second Wan 3.0 clip at 480p with an Idempotency-Key, using the single x-api-key header Sume expects.
const key = process.env.SUME_API_KEY;
if (!key) throw new Error("SUME_API_KEY is empty: start with --env-file=.env or export it");
const res = await fetch(`${process.env.SUME_BASE ?? "https://api.sume.com"}/v1/videos`, {
method: "POST",
headers: { "x-api-key": key, "content-type": "application/json", "Idempotency-Key": "kite-env-1" },
body: JSON.stringify({ model: "wan-3.0", prompt: "a red kite", duration: 5, resolution: "480p" }),
});
console.log(res.status, (await res.json()).id);Which flags to give Deno in production
List exactly the variables the script reads, and pin the network permission to the host: --allow-net=api.sume.com. Downloading a finished clip is a separate story, because the content redirect can land on another host; the related Deno post covers that. A tight permission list is a cheap way to make sure a dependency cannot read your other secrets or call a host you did not name.
Sources
Related posts
More in Developers
- C with libcurl: POST /v1/images on Sume and read the status code
A 29-line C program that posts to Sume's image API with libcurl, prints the JSON body, and exits non-zero unless the status is 200 or 202.
- C# HttpClient: submit a Seedance 2.5 job and poll until completed
A .NET top-level-statements script that posts a seedance-2.5 job to Sume, polls every 30 seconds, and stops on completed, failed or cancelled.
- Call Sume video generation from Java 11 with HttpClient
Java 11 HttpClient against Sume /v1/videos: submit a sume/auto job, poll until completed, and see what a default 8-second clip costs. No SDK needed.
- callback_url or webhook_url: which field each Sume video route takes
POST /v1/videos takes callback_url; motion control, lip-sync and image routes take mode plus webhook_url. The field names and what they share.
Written by Sume