refactor: replace requireEnv/optionalEnv with env(name, fallback)

Bundles must run without env vars — env vars are overrides, not requirements.
Single function: env(name, fallback) always returns string with a default.

- Removed requireEnv and optionalEnv
- Updated bundle entries, tests, and skill docs

小橘 🍊
This commit is contained in:
2026-05-15 10:07:49 +00:00
parent 2b8707a706
commit b1a9d2ec3f
6 changed files with 41 additions and 81 deletions
+13 -37
View File
@@ -1,44 +1,20 @@
import { describe, expect, test } from "bun:test";
import { optionalEnv, requireEnv } from "../src/env.js";
import { describe, expect, it } from "bun:test";
import { env } from "../src/env.js";
describe("requireEnv", () => {
test("returns value when set", () => {
process.env.TEST_REQ = "hello";
expect(requireEnv("TEST_REQ", "missing")).toBe("hello");
delete process.env.TEST_REQ;
describe("env", () => {
it("returns env value when set", () => {
process.env.TEST_ENV_SET = "hello";
expect(env("TEST_ENV_SET", "default")).toBe("hello");
delete process.env.TEST_ENV_SET;
});
test("throws with message when missing", () => {
expect(() => requireEnv("TEST_MISSING_XYZ", "need this")).toThrow("need this");
it("returns fallback when missing", () => {
expect(env("TEST_ENV_MISSING_XYZ", "fallback")).toBe("fallback");
});
test("throws when empty string", () => {
process.env.TEST_EMPTY = "";
expect(() => requireEnv("TEST_EMPTY", "cannot be empty")).toThrow("cannot be empty");
delete process.env.TEST_EMPTY;
});
});
describe("optionalEnv", () => {
test("returns value when set", () => {
process.env.TEST_OPT = "world";
expect(optionalEnv("TEST_OPT")).toBe("world");
expect(optionalEnv("TEST_OPT", "default")).toBe("world");
delete process.env.TEST_OPT;
});
test("returns null when missing and no fallback", () => {
expect(optionalEnv("TEST_MISSING_ABC")).toBeNull();
});
test("returns fallback when missing", () => {
expect(optionalEnv("TEST_MISSING_ABC", "fallback")).toBe("fallback");
});
test("returns fallback when empty string", () => {
process.env.TEST_EMPTY2 = "";
expect(optionalEnv("TEST_EMPTY2", "fb")).toBe("fb");
expect(optionalEnv("TEST_EMPTY2")).toBeNull();
delete process.env.TEST_EMPTY2;
it("returns fallback when empty", () => {
process.env.TEST_ENV_EMPTY = "";
expect(env("TEST_ENV_EMPTY", "fb")).toBe("fb");
delete process.env.TEST_ENV_EMPTY;
});
});
+7 -16
View File
@@ -1,23 +1,14 @@
/**
* Read a required environment variable. Throws with `message` if missing or empty.
* Read an environment variable with a required fallback default.
* Returns the env value if set and non-empty, otherwise returns `fallback`.
*
* Every env var in a bundle must have a sensible default — bundles must run
* without any env vars set. Env vars are overrides, not requirements.
*/
export function requireEnv(name: string, message: string): string {
export function env(name: string, fallback: string): string {
const value = process.env[name];
if (value === undefined || value === "") {
throw new Error(message);
}
return value;
}
/**
* Read an optional environment variable. Returns `fallback` if missing or empty.
*/
export function optionalEnv(name: string, fallback: string): string;
export function optionalEnv(name: string): string | null;
export function optionalEnv(name: string, fallback?: string): string | null {
const value = process.env[name];
if (value === undefined || value === "") {
return fallback ?? null;
return fallback;
}
return value;
}
+1 -1
View File
@@ -6,7 +6,7 @@ export {
encodeCrockfordBase32Bits,
encodeUint64AsCrockford,
} from "./base32.js";
export { optionalEnv, requireEnv } from "./env.js";
export { env } from "./env.js";
export { createLogger } from "./logger.js";
export { mergeRefsWithContentHash, normalizeRefsField } from "./refs-field.js";
export { getDefaultWorkflowStorageRoot, getGlobalCasDir } from "./storage-root.js";