@samveys/env-crypt

Version
1.0.2Nov 5, 2026
Install
pnpm add @samveys/env-crypt

From packages/env-crypt/README.md in the framework repository.

svs env:encrypt and svs env:decrypt: keep an encrypted copy of your .env in git. The commands are added by a plugin, so @samveys/console stays unchanged. No runtime dependencies; encryption is AES-256-GCM from @samveys/core.

Set up

ts
import { envCrypt } from '@samveys/env-crypt'

export const plugin = envCrypt()

Add envCrypt() to the plugins in samveys.config.ts; svs --help then lists both commands.

Use

sh
svs env:encrypt                 # .env → .env.encrypted (the whole file is one encrypted blob)
svs env:encrypt --readable      # keep NAME= visible, encrypt each value: NAME=enc:v1:<base64>
svs env:decrypt                 # .env.encrypted → .env
FlagDefaultMeaning
--file.env / .env.encryptedinput file
--out.env.encrypted / .envoutput file
--readableoff(encrypt) keep names visible
--forceoffoverwrite an existing output file

The key is read from SAMVEYS_ENV_KEY (base64: followed by 32 random bytes). When it is missing, env:encrypt generates one, prints it once and tells you to store it; keep it in your password manager or CI secrets, never in the repository.

Guarantees

  • Byte-for-byte: decrypting gives back the original file exactly, in both modes, including comments, blank lines, line endings (\n, \r\n), quotes, trailing comments and multi-line quoted values.
  • Tamper-evident: any change to the encrypted file, a wrong key or a missing key is SVS_E118, and no plain file is written. In readable mode each value is bound to its name, so moving a value under another name also fails.
  • Private output: files are written with mode 0600.

From code

ts
import { decryptEnv, encryptEnv, generateEnvKey } from '@samveys/env-crypt'

const key = generateEnvKey()
const original = '# secrets\nDB_PASSWORD="p@ss word"   # prod\n'

export const readable = encryptEnv(original, key, { readable: true }) // DB_PASSWORD=enc:v1:…
export const restored = decryptEnv(readable, key) // === original