SDK for services
@env-master/sdk is what a service integrates. It fetches values at startup
and keeps them in process memory, not in environment variables.
bun add @env-master/sdk
Connecting
import { EnvMasterClient } from "@env-master/sdk";
const em = new EnvMasterClient({
baseUrl: process.env.ENVMASTER_URL!,
project: "billing-api",
environment: "production",
});
await em.loginMachine({
clientId: process.env.ENVMASTER_CLIENT_ID!,
clientSecret: process.env.ENVMASTER_CLIENT_SECRET!,
});
const dbPassword = await em.get("DB_PASSWORD");
The get() accessor is the recommended way. Writing into process.env is
also possible (injectIntoEnv()), but it requires a deliberate call:
environment variables are visible via /proc, inherited by child processes,
and end up in crash dumps.
How a value reaches the service
The client generates an x25519 key pair when created. The server wraps the environment's data key under its public half and returns the entries' ciphertext — decryption happens inside your process. Along this path the server never produces the plaintext value at all.
Methods
| Method | What it does |
|---|---|
loginMachine(creds) | Login and background token refresh |
get(key) | A key's value, NOT_FOUND if missing |
getVersion(key) | The value together with its version number |
secrets() | All values as a Map |
list() | Entries with metadata |
refresh() | Drop the cache and re-read |
mask(text) | Replace known values with *** |
dispose() | Stop the token refresh timer |
Rotation without a restart
The token is refreshed at 75% of its TTL; the entry cache lives for 15 minutes. To react to a new value, compare versions:
const { value, version } = await em.getVersion("DB_PASSWORD");
if (version !== lastSeen) await reconnectPool(value);
Logs
logger.info(em.mask(`connecting as ${user}:${password}`));
// connecting as billing:***
Longer values are replaced first — otherwise a nested substring would leave a tail behind.