@stacksjs/env 0.74.3 → 0.74.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,31 +1,31 @@
1
1
  // @bun
2
- import{createCipheriv as ne,createDecipheriv as te,createHash as G,createPrivateKey as be,createPublicKey as re,diffieHellman as ie,generateKeyPairSync as se,hkdfSync as oe,randomBytes as H}from"crypto";var j="x25519-public:",X="x25519-private:",U="encrypted:v2:",Q="encrypted:",de=Buffer.from("stacks-env:v2","utf8"),ce="Environment decryption failed: authentication or format error";function ae(e){if(e.length===32)return e;return G("sha256").update(e).digest()}function vn(e,n){let t=H(16),r=ne("aes-256-gcm",ae(n),t);return{ciphertext:Buffer.concat([r.update(e,"utf8"),r.final()]).toString("hex"),iv:t.toString("hex"),authTag:r.getAuthTag().toString("hex")}}function Ke(e,n,t,r){try{let i=te("aes-256-gcm",ae(n),Buffer.from(t,"hex"));return i.setAuthTag(Buffer.from(r,"hex")),Buffer.concat([i.update(Buffer.from(e,"hex")),i.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function S(e){return e.toString("base64url")}function C(e,n,t){if(typeof e!=="string"||e.length>0&&!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`${n} is not canonical base64url`);let r=Buffer.from(e,"base64url");if(S(r)!==e)throw Error(`${n} is not canonical base64url`);if(t!==void 0&&r.length!==t)throw Error(`${n} has an invalid length`);return r}function Le(e){if(!e.startsWith(j))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let n=re({key:C(e.slice(j.length),"public key"),format:"der",type:"spki"});if(n.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return n}function ke(e){if(!e.startsWith(X))throw Error("Private key is not a version 2 X25519 key");let n=be({key:C(e.slice(X.length),"private key"),format:"der",type:"pkcs8"});if(n.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return n}function ue(e){return Buffer.from(`stacks-env:v2;${e.epk};${e.salt};${e.nonce}`,"utf8")}function k(){let{publicKey:e,privateKey:n}=se("x25519"),t=e.export({format:"der",type:"spki"}),r=n.export({format:"der",type:"pkcs8"});return{publicKey:`${j}${S(t)}`,privateKey:`${X}${S(r)}`}}function B(e,n){let t=Le(n),r=se("x25519"),i=S(r.publicKey.export({format:"der",type:"spki"})),s=H(16),o=H(12),d=ie({privateKey:r.privateKey,publicKey:t}),c=Buffer.from(oe("sha256",d,s,de,32)),u={epk:i,salt:S(s),nonce:S(o)};try{let a=ne("aes-256-gcm",c,o);a.setAAD(ue(u));let f=Buffer.concat([a.update(e,"utf8"),a.final()]),p={v:2,...u,ciphertext:S(f),tag:S(a.getAuthTag())};return`${U}${S(Buffer.from(JSON.stringify(p),"utf8"))}`}finally{d.fill(0),c.fill(0)}}function $e(e){let n=C(e.slice(U.length),"envelope").toString("utf8"),t=JSON.parse(n);if(!t||typeof t!=="object"||Array.isArray(t))throw Error("envelope is not an object");let r=Object.keys(t).sort(),i=["ciphertext","epk","nonce","salt","tag","v"];if(r.length!==i.length||r.some((s,o)=>s!==i[o]))throw Error("envelope fields are invalid");if(t.v!==2)throw Error("envelope version is unsupported");for(let s of["epk","salt","nonce","ciphertext","tag"])if(typeof t[s]!=="string")throw Error(`${s} is invalid`);return t}function we(e,n){try{let t=$e(e),r=ke(n),i=re({key:C(t.epk,"ephemeral public key"),format:"der",type:"spki"});if(i.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let s=C(t.salt,"salt",16),o=C(t.nonce,"nonce",12),d=C(t.ciphertext,"ciphertext"),c=C(t.tag,"tag",16),u=ie({privateKey:r,publicKey:i}),a=Buffer.from(oe("sha256",u,s,de,32));try{let f=te("aes-256-gcm",a,o);return f.setAAD(ue(t)),f.setAuthTag(c),Buffer.concat([f.update(d),f.final()]).toString("utf8")}finally{u.fill(0),a.fill(0)}}catch{throw Error(ce)}}function xe(e,n){try{if(!/^[0-9a-f]{64}$/.test(n))throw Error("invalid legacy private key");let t=Buffer.from(e.slice(Q.length),"base64");if(t.length<32)throw Error("invalid legacy payload");let r=G("sha256").update(Buffer.from(n,"hex")).digest(),i=G("sha256").update(r).digest();return Ke(t.subarray(32).toString("hex"),i,t.subarray(0,16).toString("hex"),t.subarray(16,32).toString("hex"))}catch{throw Error(ce)}}function An(e){return e.startsWith(Q)&&!e.startsWith(U)}function L(e,n){if(!e.startsWith(Q))return e;return e.startsWith(U)?we(e,n):xe(e,n)}function On(e,n,t){return B(L(e,n),t)}function In(e){let n=e.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return n&&n[1]?n[1].toLowerCase():""}function q(e=""){return e?process.env[`DOTENV_PRIVATE_KEY_${e.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}import{spawnSync as Ue}from"child_process";import{readFileSync as Be}from"fs";import{arch as Ve,hostname as Me,platform as fe,release as Fe,userInfo as We}from"os";import{basename as Ye,dirname as Ge,resolve as He}from"path";function I(e,n={}){let t={},r=[],i=[],s=e.split(`
2
+ import{createCipheriv as ne,createDecipheriv as te,createHash as G,createPrivateKey as be,createPublicKey as re,diffieHellman as ie,generateKeyPairSync as se,hkdfSync as oe,randomBytes as H}from"crypto";var j="x25519-public:",X="x25519-private:",x="encrypted:v2:",Q="encrypted:",de=Buffer.from("stacks-env:v2","utf8"),ce="Environment decryption failed: authentication or format error";function ae(e){if(e.length===32)return e;return G("sha256").update(e).digest()}function vn(e,n){let t=H(16),r=ne("aes-256-gcm",ae(n),t);return{ciphertext:Buffer.concat([r.update(e,"utf8"),r.final()]).toString("hex"),iv:t.toString("hex"),authTag:r.getAuthTag().toString("hex")}}function Le(e,n,t,r){try{let i=te("aes-256-gcm",ae(n),Buffer.from(t,"hex"));return i.setAuthTag(Buffer.from(r,"hex")),Buffer.concat([i.update(Buffer.from(e,"hex")),i.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function h(e){return e.toString("base64url")}function C(e,n,t){if(typeof e!=="string"||e.length>0&&!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`${n} is not canonical base64url`);let r=Buffer.from(e,"base64url");if(h(r)!==e)throw Error(`${n} is not canonical base64url`);if(t!==void 0&&r.length!==t)throw Error(`${n} has an invalid length`);return r}function Ke(e){if(!e.startsWith(j))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let n=re({key:C(e.slice(j.length),"public key"),format:"der",type:"spki"});if(n.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return n}function ke(e){if(!e.startsWith(X))throw Error("Private key is not a version 2 X25519 key");let n=be({key:C(e.slice(X.length),"private key"),format:"der",type:"pkcs8"});if(n.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return n}function ue(e){return Buffer.from(`stacks-env:v2;${e.epk};${e.salt};${e.nonce}`,"utf8")}function k(){let{publicKey:e,privateKey:n}=se("x25519"),t=e.export({format:"der",type:"spki"}),r=n.export({format:"der",type:"pkcs8"});return{publicKey:`${j}${h(t)}`,privateKey:`${X}${h(r)}`}}function B(e,n){let t=Ke(n),r=se("x25519"),i=h(r.publicKey.export({format:"der",type:"spki"})),s=H(16),o=H(12),d=ie({privateKey:r.privateKey,publicKey:t}),c=Buffer.from(oe("sha256",d,s,de,32)),u={epk:i,salt:h(s),nonce:h(o)};try{let a=ne("aes-256-gcm",c,o);a.setAAD(ue(u));let f=Buffer.concat([a.update(e,"utf8"),a.final()]),p={v:2,...u,ciphertext:h(f),tag:h(a.getAuthTag())};return`${x}${h(Buffer.from(JSON.stringify(p),"utf8"))}`}finally{d.fill(0),c.fill(0)}}function Ue(e){let n=C(e.slice(x.length),"envelope").toString("utf8"),t=JSON.parse(n);if(!t||typeof t!=="object"||Array.isArray(t))throw Error("envelope is not an object");let r=Object.keys(t).sort(),i=["ciphertext","epk","nonce","salt","tag","v"];if(r.length!==i.length||r.some((s,o)=>s!==i[o]))throw Error("envelope fields are invalid");if(t.v!==2)throw Error("envelope version is unsupported");for(let s of["epk","salt","nonce","ciphertext","tag"])if(typeof t[s]!=="string")throw Error(`${s} is invalid`);return t}function $e(e,n){try{let t=Ue(e),r=ke(n),i=re({key:C(t.epk,"ephemeral public key"),format:"der",type:"spki"});if(i.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let s=C(t.salt,"salt",16),o=C(t.nonce,"nonce",12),d=C(t.ciphertext,"ciphertext"),c=C(t.tag,"tag",16),u=ie({privateKey:r,publicKey:i}),a=Buffer.from(oe("sha256",u,s,de,32));try{let f=te("aes-256-gcm",a,o);return f.setAAD(ue(t)),f.setAuthTag(c),Buffer.concat([f.update(d),f.final()]).toString("utf8")}finally{u.fill(0),a.fill(0)}}catch{throw Error(ce)}}function we(e,n){try{if(!/^[0-9a-f]{64}$/.test(n))throw Error("invalid legacy private key");let t=Buffer.from(e.slice(Q.length),"base64");if(t.length<32)throw Error("invalid legacy payload");let r=G("sha256").update(Buffer.from(n,"hex")).digest(),i=G("sha256").update(r).digest();return Le(t.subarray(32).toString("hex"),i,t.subarray(0,16).toString("hex"),t.subarray(16,32).toString("hex"))}catch{throw Error(ce)}}function On(e){return e.startsWith(Q)&&!e.startsWith(x)}function K(e,n){if(!e.startsWith(Q))return e;return e.startsWith(x)?$e(e,n):we(e,n)}function An(e,n,t){return B(K(e,n),t)}function Sn(e){let n=e.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return n&&n[1]?n[1].toLowerCase():""}function q(e=""){return e?process.env[`DOTENV_PRIVATE_KEY_${e.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}import{spawnSync as xe}from"child_process";import{readFileSync as Be}from"fs";import{arch as Ve,hostname as Me,platform as fe,release as Fe,userInfo as Ye}from"os";import{basename as We,dirname as Ge,resolve as He}from"path";function S(e,n={}){let t={},r=[],i=[],s=e.split(`
3
3
  `);for(let o of s){let d=o.trim();if(!d||d.startsWith("#"))continue;if(d.startsWith("DOTENV_PUBLIC_KEY=")){let f=d.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(f&&f[1]!==void 0)t.DOTENV_PUBLIC_KEY=f[1];continue}let c=d.match(/^([^=]+)=(.*)$/);if(!c||c[1]===void 0||c[2]===void 0)continue;let u=c[1].trim(),a=c[2].trim();if(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'")){if(a=a.slice(1,-1),a.includes("\\n"))a=a.replace(/\\n/g,`
4
- `)}if(a.startsWith("encrypted:")||a.startsWith("enc:")){if(!n.privateKey){i.push(u);continue}try{let f=a.startsWith("enc:")?`encrypted:${a.slice(4)}`:a;a=L(f,n.privateKey)}catch(f){r.push(`Failed to decrypt ${u}: ${f instanceof Error?f.message:"Unknown error"}`)}}a=je(a,{...n.processEnv||process.env,...t}),a=ze(a),t[u]=a}return{parsed:t,errors:r,skippedEncrypted:i}}function je(e,n){return e.replace(/\$\{([^}]+)\}/g,(t,r)=>{let i=r.match(/^([^:\-+]+)(:-|-)(.+)$/);if(i){let[,o,d,c]=i,u=n[o];if(d===":-")return u||c;else return u!==void 0?u:c}let s=r.match(/^([^:\-+]+)(:?\+)(.+)$/);if(s){let[,o,d,c]=s,u=n[o];if(d===":+")return u?c:"";else return u!==void 0?c:""}return n[r]||""})}var Xe=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function Qe(e){let n=[],t="",r=null,i=!1;for(let s of e.trim()){if(i){t+=s,i=!1;continue}if(s==="\\"&&r!=="'"){i=!0;continue}if(r){if(s===r)r=null;else t+=s;continue}if(s==='"'||s==="'"){r=s;continue}if(/\s/.test(s)){if(t)n.push(t),t="";continue}t+=s}if(i||r)throw Error("Command substitution contains an unterminated escape or quote");if(t)n.push(t);return n}function qe(e){let[n,...t]=e,r=t.some((i)=>i.startsWith("-"));if(n==="echo"&&!r)return t.join(" ");if(n==="printf"&&t.length===1&&!t[0]?.includes("%"))return t[0];if(n==="hostname"&&t.length===0)return Me();if(n==="whoami"&&t.length===0)return We().username;if(n==="pwd"&&t.length===0)return process.cwd();if(n==="basename"&&t.length===1)return Ye(t[0]??"");if(n==="dirname"&&t.length===1)return Ge(t[0]??"");if(n==="cat"&&t.length>0&&!r)return t.map((i)=>Be(He(process.cwd(),i),"utf8")).join("");if(n==="uname"){let i=t[0]??"-s";if(t.length<=1&&i==="-m")return Ve();if(t.length<=1&&i==="-r")return Fe();if(t.length<=1&&i==="-s")return{aix:"AIX",android:"Android",cygwin:"CYGWIN",darwin:"Darwin",freebsd:"FreeBSD",haiku:"Haiku",linux:"Linux",netbsd:"NetBSD",openbsd:"OpenBSD",sunos:"SunOS",win32:"Windows_NT"}[fe()]??fe()}return}function ze(e){return e.replace(/\$\(([^)]+)\)/g,(n,t)=>{try{let r=Qe(t),i=r[0];if(!i||!Xe.has(i))return console.warn(`[env] Blocked command substitution for disallowed command: ${i}`),"";let s=qe(r);if(s!==void 0)return s.trim();let o=Ue(i,r.slice(1),{encoding:"utf8",env:process.env});if(o.status===0)return o.stdout.trim();let d=o.stderr.trim();console.warn(`[env] Command substitution failed (exit code ${o.status??"unknown"}): ${i}${d?`: ${d}`:""}`)}catch(r){console.warn(`[env] Command substitution error: ${r instanceof Error?r.message:String(r)}`)}return""})}async function bn(e,n={}){let t={},r=[],i=[];for(let s of e)try{let o=Bun.file(s);if(!o.size)continue;let d=await o.text(),{parsed:c,errors:u,skippedEncrypted:a}=I(d,n);r.push(...u),i.push(...a);for(let[f,p]of Object.entries(c)){if(!n.overload&&t[f]!==void 0)continue;t[f]=p}}catch(o){if(o?.code==="ENOENT")continue;r.push(`Failed to read ${s}: ${o instanceof Error?o.message:String(o)}`)}return{parsed:t,errors:r,skippedEncrypted:i}}import{existsSync as V}from"fs";import{readFileSync as z}from"fs";import{resolve as M}from"path";function w(e){return typeof e==="string"&&(e.startsWith("encrypted:")||e.startsWith("enc:"))}function b(e){if(!e||w(e))return;let n=e.trim().toLowerCase();if(!/^[a-z0-9_-]+$/.test(n))return;if(n==="prod")return"production";if(n==="stage")return"staging";if(n==="dev")return"development";return n}var F=null,W,Y;function Je(e,n,t=".env.keys"){let r=M(n,t);if(!V(r))return;try{let{parsed:i}=I(z(r,"utf-8"));if(e){let s=i[`DOTENV_PRIVATE_KEY_${e.toUpperCase()}`];if(s)return s}return i.DOTENV_PRIVATE_KEY}catch{return}}function J(e={}){return b(e.env)||Y||b("development")||b(process.env.DOTENV_ENV)||b(process.env.APP_ENV)||"development"}function Ze(e={}){let n=J(e),t=e.cwd||process.cwd();if(F===n)return W;let r=q(n);if(!r)r=process.env.DOTENV_PRIVATE_KEY;if(!r)r=Je(n,t);return F=n,W=r,r}function Un(){F=null,W=void 0,Y=void 0}function Ee(e,n={}){if(!w(e))return e;let t=Ze(n);if(!t)return;try{let r=e.startsWith("enc:")?`encrypted:${e.slice(4)}`:e;return L(r,t)}catch{return}}function le(e={}){let{path:n=[".env"],overload:t=!1,env:r,privateKey:i,keysFile:s=".env.keys",quiet:o=!1,cwd:d=process.cwd()}=e,c=Array.isArray(n)?n:[n],u=[],a=0,f=new Set(Object.entries(process.env).filter(([,E])=>E!==void 0&&!w(E)).map(([E])=>E)),p=i;if(!p&&s){let E=M(d,s);if(V(E))try{let l=z(E,"utf-8"),{parsed:T}=I(l);if(r){let v=`DOTENV_PRIVATE_KEY_${r.toUpperCase()}`;p=T[v]}else p=T.DOTENV_PRIVATE_KEY}catch(l){u.push(`Failed to load keys file: ${l instanceof Error?l.message:"Unknown error"}`)}}if(!p)p=q(r||"");for(let E of c){let l=M(d,E);if(!V(l)){if(!o)u.push(`File not found: ${l}`);continue}try{let T=z(l,"utf-8"),{parsed:v,errors:_,skippedEncrypted:y}=I(T,{privateKey:p,processEnv:process.env});if(u.push(..._),y.length>0){for(let D of y)if(w(process.env[D]))delete process.env[D];let R=r?`DOTENV_PRIVATE_KEY_${r.toUpperCase()}`:"DOTENV_PRIVATE_KEY",K=y.slice(0,5).join(", "),P=y.length>5?`, \u2026 +${y.length-5} more`:"";console.warn(`[env] warning: skipped ${y.length} encrypted value(s) in ${E} (${R} not set; defaults apply): ${K}${P}`)}let m=0;for(let[R,K]of Object.entries(v)){if(R==="DOTENV_PUBLIC_KEY")continue;let P=process.env[R],D=w(P)&&K!==P;if(t||!f.has(R)||D)process.env[R]=K,a++,m++}if(!o&&!process.env.__ENV_LOADED__)console.error(`[env] loaded ${m}/${Object.keys(v).length} variables from ${E}`),process.env.__ENV_LOADED__="1"}catch(T){u.push(`Failed to load ${l}: ${T instanceof Error?T.message:"Unknown error"}`)}}return{loaded:a,errors:u}}function en(e={}){return{name:"env-plugin",setup(n){le(e)}}}function Bn(e={}){let n=b(e.env)||b("development")||b(process.env.DOTENV_ENV)||b(process.env.APP_ENV)||"development",t=e.cwd||process.cwd();if(Y!==n)Y=n,F=null,W=void 0;let r=[],i=(d)=>{if(!r.includes(d)&&V(M(t,d)))r.push(d)};i(".env"),i(".env.local");let s=`.env.${n}`,o=`.env.${n}.local`;return i(s),i(o),le({...e,path:r,env:n})}var Mn=en;import{existsSync as N,readFileSync as O,renameSync as pe,rmSync as ge,writeFileSync as h}from"fs";import{basename as _e,dirname as Te,resolve as A}from"path";function Hn(e,n){if(e)return e;let t=String(n??"").trim();if(!t||t==="development"||t==="dev"||t==="local")return"";if(!/^[\w.-]+$/.test(t))return"";return`.env.${t}`}function ye(e,n){return(!n.key||e.includes(n.key))&&(!n.excludeKey||!e.includes(n.excludeKey))}function nn(e,n){let t=[];for(let r of e.split(`
4
+ `)}if(a.startsWith("encrypted:")||a.startsWith("enc:")){if(!n.privateKey){i.push(u);continue}try{let f=a.startsWith("enc:")?`encrypted:${a.slice(4)}`:a;a=K(f,n.privateKey)}catch(f){r.push(`Failed to decrypt ${u}: ${f instanceof Error?f.message:"Unknown error"}`)}}a=je(a,{...n.processEnv||process.env,...t}),a=ze(a),t[u]=a}return{parsed:t,errors:r,skippedEncrypted:i}}function je(e,n){return e.replace(/\$\{([^}]+)\}/g,(t,r)=>{let i=r.match(/^([^:\-+]+)(:-|-)(.+)$/);if(i){let[,o,d,c]=i,u=n[o];if(d===":-")return u||c;else return u!==void 0?u:c}let s=r.match(/^([^:\-+]+)(:?\+)(.+)$/);if(s){let[,o,d,c]=s,u=n[o];if(d===":+")return u?c:"";else return u!==void 0?c:""}return n[r]||""})}var Xe=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function Qe(e){let n=[],t="",r=null,i=!1;for(let s of e.trim()){if(i){t+=s,i=!1;continue}if(s==="\\"&&r!=="'"){i=!0;continue}if(r){if(s===r)r=null;else t+=s;continue}if(s==='"'||s==="'"){r=s;continue}if(/\s/.test(s)){if(t)n.push(t),t="";continue}t+=s}if(i||r)throw Error("Command substitution contains an unterminated escape or quote");if(t)n.push(t);return n}function qe(e){let[n,...t]=e,r=t.some((i)=>i.startsWith("-"));if(n==="echo"&&!r)return t.join(" ");if(n==="printf"&&t.length===1&&!t[0]?.includes("%"))return t[0];if(n==="hostname"&&t.length===0)return Me();if(n==="whoami"&&t.length===0)return Ye().username;if(n==="pwd"&&t.length===0)return process.cwd();if(n==="basename"&&t.length===1)return We(t[0]??"");if(n==="dirname"&&t.length===1)return Ge(t[0]??"");if(n==="cat"&&t.length>0&&!r)return t.map((i)=>Be(He(process.cwd(),i),"utf8")).join("");if(n==="uname"){let i=t[0]??"-s";if(t.length<=1&&i==="-m")return Ve();if(t.length<=1&&i==="-r")return Fe();if(t.length<=1&&i==="-s")return{aix:"AIX",android:"Android",cygwin:"CYGWIN",darwin:"Darwin",freebsd:"FreeBSD",haiku:"Haiku",linux:"Linux",netbsd:"NetBSD",openbsd:"OpenBSD",sunos:"SunOS",win32:"Windows_NT"}[fe()]??fe()}return}function ze(e){return e.replace(/\$\(([^)]+)\)/g,(n,t)=>{try{let r=Qe(t),i=r[0];if(!i||!Xe.has(i))return console.warn(`[env] Blocked command substitution for disallowed command: ${i}`),"";let s=qe(r);if(s!==void 0)return s.trim();let o=xe(i,r.slice(1),{encoding:"utf8",env:process.env});if(o.status===0)return o.stdout.trim();let d=o.stderr.trim();console.warn(`[env] Command substitution failed (exit code ${o.status??"unknown"}): ${i}${d?`: ${d}`:""}`)}catch(r){console.warn(`[env] Command substitution error: ${r instanceof Error?r.message:String(r)}`)}return""})}async function bn(e,n={}){let t={},r=[],i=[];for(let s of e)try{let o=Bun.file(s);if(!o.size)continue;let d=await o.text(),{parsed:c,errors:u,skippedEncrypted:a}=S(d,n);r.push(...u),i.push(...a);for(let[f,p]of Object.entries(c)){if(!n.overload&&t[f]!==void 0)continue;t[f]=p}}catch(o){if(o?.code==="ENOENT")continue;r.push(`Failed to read ${s}: ${o instanceof Error?o.message:String(o)}`)}return{parsed:t,errors:r,skippedEncrypted:i}}import{existsSync as V}from"fs";import{readFileSync as z}from"fs";import{resolve as M}from"path";function U(e){return typeof e==="string"&&(e.startsWith("encrypted:")||e.startsWith("enc:"))}function b(e){if(!e||U(e))return;let n=e.trim().toLowerCase();if(!/^[a-z0-9_-]+$/.test(n))return;if(n==="prod")return"production";if(n==="stage")return"staging";if(n==="dev")return"development";return n}var F=null,Y,W;function Je(e,n,t=".env.keys"){let r=M(n,t);if(!V(r))return;try{let{parsed:i}=S(z(r,"utf-8"));if(e){let s=i[`DOTENV_PRIVATE_KEY_${e.toUpperCase()}`];if(s)return s}return i.DOTENV_PRIVATE_KEY}catch{return}}function J(e={}){return b(e.env)||W||b("development")||b(process.env.DOTENV_ENV)||b(process.env.APP_ENV)||"development"}function Ze(e={}){let n=J(e),t=e.cwd||process.cwd();if(F===n)return Y;let r=q(n);if(!r)r=process.env.DOTENV_PRIVATE_KEY;if(!r)r=Je(n,t);return F=n,Y=r,r}function xn(){F=null,Y=void 0,W=void 0}function Ee(e,n={}){if(!U(e))return e;let t=Ze(n);if(!t)return;try{let r=e.startsWith("enc:")?`encrypted:${e.slice(4)}`:e;return K(r,t)}catch{return}}function le(e={}){let{path:n=[".env"],overload:t=!1,env:r,privateKey:i,keysFile:s=".env.keys",quiet:o=!1,cwd:d=process.cwd()}=e,c=Array.isArray(n)?n:[n],u=[],a=0,f=new Set(Object.entries(process.env).filter(([,E])=>E!==void 0&&!U(E)).map(([E])=>E)),p=i;if(!p&&s){let E=M(d,s);if(V(E))try{let l=z(E,"utf-8"),{parsed:T}=S(l);if(r){let v=`DOTENV_PRIVATE_KEY_${r.toUpperCase()}`;p=T[v]}else p=T.DOTENV_PRIVATE_KEY}catch(l){u.push(`Failed to load keys file: ${l instanceof Error?l.message:"Unknown error"}`)}}if(!p)p=q(r||"");for(let E of c){let l=M(d,E);if(!V(l)){if(!o)u.push(`File not found: ${l}`);continue}try{let T=z(l,"utf-8"),{parsed:v,errors:_,skippedEncrypted:y}=S(T,{privateKey:p,processEnv:process.env});if(u.push(..._),y.length>0){for(let D of y)if(U(process.env[D]))delete process.env[D];let R=r?`DOTENV_PRIVATE_KEY_${r.toUpperCase()}`:"DOTENV_PRIVATE_KEY",L=y.slice(0,5).join(", "),P=y.length>5?`, \u2026 +${y.length-5} more`:"";console.warn(`[env] warning: skipped ${y.length} encrypted value(s) in ${E} (${R} not set; defaults apply): ${L}${P}`)}let m=0;for(let[R,L]of Object.entries(v)){if(R==="DOTENV_PUBLIC_KEY")continue;let P=process.env[R],D=U(P)&&L!==P;if(t||!f.has(R)||D)process.env[R]=L,a++,m++}if(!o&&!process.env.__ENV_LOADED__)console.error(`[env] loaded ${m}/${Object.keys(v).length} variables from ${E}`),process.env.__ENV_LOADED__="1"}catch(T){u.push(`Failed to load ${l}: ${T instanceof Error?T.message:"Unknown error"}`)}}return{loaded:a,errors:u}}function en(e={}){return{name:"env-plugin",setup(n){le(e)}}}function Bn(e={}){let n=b(e.env)||b("development")||b(process.env.DOTENV_ENV)||b(process.env.APP_ENV)||"development",t=e.cwd||process.cwd();if(W!==n)W=n,F=null,Y=void 0;let r=[],i=(d)=>{if(!r.includes(d)&&V(M(t,d)))r.push(d)};i(".env"),i(".env.local");let s=`.env.${n}`,o=`.env.${n}.local`;return i(s),i(o),le({...e,path:r,env:n})}var Mn=en;import{existsSync as I,readFileSync as A,renameSync as pe,rmSync as ge,writeFileSync as N}from"fs";import{basename as _e,dirname as Te,resolve as O}from"path";function Hn(e,n){if(e)return e;let t=String(n??"").trim();if(!t||t==="development"||t==="dev"||t==="local")return"";if(!/^[\w.-]+$/.test(t))return"";return`.env.${t}`}function ye(e,n){return(!n.key||e.includes(n.key))&&(!n.excludeKey||!e.includes(n.excludeKey))}function nn(e,n){let t=[];for(let r of e.split(`
5
5
  `)){let i=r.trim();if(!i||i.startsWith("#"))continue;if(i.startsWith("DOTENV_PUBLIC_KEY"))continue;let s=i.match(/^([^=]+)=(.*)$/);if(!s||s[1]===void 0)continue;let o=s[1].trim();if(ye(o,n))t.push(o)}return t}function Re(e,n,t,r){let i=["#/-------------------[DOTENV_PUBLIC_KEY]--------------------/","#/ versioned X25519 encryption for .env files /","#/ [how it works](https://stacksjs.com/encryption) /","#/----------------------------------------------------------/",`${t}="${n}"`,""],s=!1;for(let o of e.split(`
6
6
  `)){let d=o.trim();if(d.startsWith("#/"))continue;if(d.startsWith("DOTENV_PUBLIC_KEY"))continue;if(!d&&!s)continue;if(!d||d.startsWith("#")){s=!0,i.push(o);continue}s=!0;let c=d.match(/^([^=]+)=(.*)$/);if(!c||c[1]===void 0||c[2]===void 0){i.push(o);continue}let u=c[1].trim(),a=c[2].trim();if(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))a=a.slice(1,-1);if(ye(u,r)&&!a.startsWith("encrypted:"))a=B(a,n);i.push(`${u}="${a}"`)}return i.join(`
7
- `)}function x(e){let t=((e||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase();return{publicKeyName:t?`DOTENV_PUBLIC_KEY_${t}`:"DOTENV_PUBLIC_KEY",privateKeyName:t?`DOTENV_PRIVATE_KEY_${t}`:"DOTENV_PRIVATE_KEY"}}function me(e,n){let t,r=!1;for(let i of e.split(`
8
- `)){let s=i.trim();if(!s||s.startsWith("#"))continue;let o=s.match(/^([^=]+)=(.*)$/);if(!o?.[1]||o[2]===void 0)continue;let d=o[1].trim(),c=o[2].trim().replace(/^["']|["']$/g,"");if(d===n)t=c;else if(c.startsWith("encrypted:")||c.startsWith("enc:"))r=!0}return t&&r?t:void 0}function jn(e={}){let n=e.cwd||process.cwd(),t=A(n,e.file||".env"),r=A(n,e.keysFile||".env.keys");if(!N(t))return{success:!1,error:`File not found: ${t}`};try{let i,s,o=me(O(t,"utf-8"),x(e.file).publicKeyName);if(o)i=o;else if(N(r)){let u=O(r,"utf-8"),{parsed:a}=I(u),{publicKeyName:f,privateKeyName:p}=x(e.file);if(i=a[f]||"",s=a[p]||"",!i||!s){let E=k();i=E.publicKey,s=E.privateKey;let l=`
7
+ `)}function w(e){let t=((e||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase();return{publicKeyName:t?`DOTENV_PUBLIC_KEY_${t}`:"DOTENV_PUBLIC_KEY",privateKeyName:t?`DOTENV_PRIVATE_KEY_${t}`:"DOTENV_PRIVATE_KEY"}}function me(e,n){let t,r=!1;for(let i of e.split(`
8
+ `)){let s=i.trim();if(!s||s.startsWith("#"))continue;let o=s.match(/^([^=]+)=(.*)$/);if(!o?.[1]||o[2]===void 0)continue;let d=o[1].trim(),c=o[2].trim().replace(/^["']|["']$/g,"");if(d===n)t=c;else if(c.startsWith("encrypted:")||c.startsWith("enc:"))r=!0}return t&&r?t:void 0}function jn(e={}){let n=e.cwd||process.cwd(),t=O(n,e.file||".env"),r=O(n,e.keysFile||".env.keys");if(!I(t))return{success:!1,error:`File not found: ${t}`};try{let i,s,o=me(A(t,"utf-8"),w(e.file).publicKeyName);if(o)i=o;else if(I(r)){let u=A(r,"utf-8"),{parsed:a}=S(u),{publicKeyName:f,privateKeyName:p}=w(e.file);if(i=a[f]||"",s=a[p]||"",!i||!s){let E=k();i=E.publicKey,s=E.privateKey;let l=`
9
9
  ${f}="${i}"
10
10
  ${p}="${s}"
11
- `;h(r,u+l,"utf-8")}}else{let u=k();i=u.publicKey,s=u.privateKey;let{publicKeyName:a,privateKeyName:f}=x(e.file),p=`# .env.keys - Keep this file secure and never commit to source control
11
+ `;N(r,u+l,"utf-8")}}else{let u=k();i=u.publicKey,s=u.privateKey;let{publicKeyName:a,privateKeyName:f}=w(e.file),p=`# .env.keys - Keep this file secure and never commit to source control
12
12
  ${a}="${i}"
13
13
  ${f}="${s}"
14
- `;h(r,p,"utf-8")}let d=O(t,"utf-8"),c=Re(d,i,x(e.file).publicKeyName,e);if(e.stdout)return{success:!0,output:c};return h(t,c,"utf-8"),{success:!0,output:`\u2714 encrypted (${e.file||".env"})
15
- \u2714 key added to ${e.keysFile||".env.keys"}`}}catch(i){return{success:!1,error:`Failed to encrypt: ${i instanceof Error?i.message:"Unknown error"}`}}}function tn(e={}){let n=e.cwd||process.cwd(),t=A(n,e.file||".env"),r=A(n,e.keysFile||".env.keys");if(!N(t))return{success:!1,error:`File not found: ${t}`};if(!N(r))return{success:!1,error:`Keys file not found: ${r}`};try{let i=O(r,"utf-8"),{parsed:s}=I(i),c=((e.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=c?`DOTENV_PRIVATE_KEY_${c}`:"DOTENV_PRIVATE_KEY",a=s[u];if(!a)return{success:!1,error:`Private key not found: ${u}`};let f=[a];if(u!=="DOTENV_PRIVATE_KEY"&&s.DOTENV_PRIVATE_KEY&&s.DOTENV_PRIVATE_KEY!==a)f.push(s.DOTENV_PRIVATE_KEY);let E=O(t,"utf-8").split(`
16
- `),l=[];for(let v of E){let _=v.trim();if(!_||_.startsWith("#")){l.push(v);continue}if(_.startsWith("DOTENV_PUBLIC_KEY"))continue;let y=_.match(/^([^=]+)=(.*)$/);if(!y||y[1]===void 0||y[2]===void 0){l.push(v);continue}let m=y[1].trim(),R=y[2].trim();if(R.startsWith('"')&&R.endsWith('"')||R.startsWith("'")&&R.endsWith("'"))R=R.slice(1,-1);let K=R.startsWith("encrypted:");if(e.key&&!m.includes(e.key))K=!1;if(K){let P,D;for(let De of f)try{P=L(R,De);break}catch(Ce){D=Ce}if(P===void 0)throw D instanceof Error?D:Error(`Unable to decrypt ${m}`);R=P}l.push(`${m}="${R}"`)}let T=l.join(`
17
- `);if(e.stdout)return{success:!0,output:T};return h(t,T,"utf-8"),{success:!0,output:`\u2714 decrypted (${e.file||".env"})`}}catch(i){return{success:!1,error:`Failed to decrypt: ${i instanceof Error?i.message:"Unknown error"}`}}}function Xn(e,n,t={}){let r=t.cwd||process.cwd(),i=A(r,t.file||".env"),s=A(r,t.keysFile||".env.keys");try{let o="";if(N(i))o=O(i,"utf-8");let d=o.split(`
18
- `),c=!1,u,p=((t.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),E=p?`DOTENV_PUBLIC_KEY_${p}`:"DOTENV_PUBLIC_KEY",l=p?`DOTENV_PRIVATE_KEY_${p}`:"DOTENV_PRIVATE_KEY";for(let _ of d){let y=_.trim();if(y.startsWith(`${E}=`)){let m=y.match(/^[^=]+=["']?([^"'\n]+)["']?/);if(m)u=m[1];break}}if(u){let _=!1;if(N(s)){let y=O(s,"utf-8"),{parsed:m}=I(y);_=Boolean(m[l])}if(!_&&!process.env[l]&&!me(o,E))u=void 0}if(!t.plain&&!u){let _=k();u=_.publicKey;let y="";if(N(s))y=O(s,"utf-8");y+=`
14
+ `;N(r,p,"utf-8")}let d=A(t,"utf-8"),c=Re(d,i,w(e.file).publicKeyName,e);if(e.stdout)return{success:!0,output:c};return N(t,c,"utf-8"),{success:!0,output:`\u2714 encrypted (${e.file||".env"})
15
+ \u2714 key added to ${e.keysFile||".env.keys"}`}}catch(i){return{success:!1,error:`Failed to encrypt: ${i instanceof Error?i.message:"Unknown error"}`}}}function tn(e={}){let n=e.cwd||process.cwd(),t=O(n,e.file||".env"),r=O(n,e.keysFile||".env.keys");if(!I(t))return{success:!1,error:`File not found: ${t}`};if(!I(r))return{success:!1,error:`Keys file not found: ${r}`};try{let i=A(r,"utf-8"),{parsed:s}=S(i),c=((e.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=c?`DOTENV_PRIVATE_KEY_${c}`:"DOTENV_PRIVATE_KEY",a=s[u];if(!a)return{success:!1,error:`Private key not found: ${u}`};let f=[a];if(u!=="DOTENV_PRIVATE_KEY"&&s.DOTENV_PRIVATE_KEY&&s.DOTENV_PRIVATE_KEY!==a)f.push(s.DOTENV_PRIVATE_KEY);let E=A(t,"utf-8").split(`
16
+ `),l=[];for(let v of E){let _=v.trim();if(!_||_.startsWith("#")){l.push(v);continue}if(_.startsWith("DOTENV_PUBLIC_KEY"))continue;let y=_.match(/^([^=]+)=(.*)$/);if(!y||y[1]===void 0||y[2]===void 0){l.push(v);continue}let m=y[1].trim(),R=y[2].trim();if(R.startsWith('"')&&R.endsWith('"')||R.startsWith("'")&&R.endsWith("'"))R=R.slice(1,-1);let L=R.startsWith("encrypted:");if(e.key&&!m.includes(e.key))L=!1;if(L){let P,D;for(let De of f)try{P=K(R,De);break}catch(Ce){D=Ce}if(P===void 0)throw D instanceof Error?D:Error(`Unable to decrypt ${m}`);R=P}l.push(`${m}="${R}"`)}let T=l.join(`
17
+ `);if(e.stdout)return{success:!0,output:T};return N(t,T,"utf-8"),{success:!0,output:`\u2714 decrypted (${e.file||".env"})`}}catch(i){return{success:!1,error:`Failed to decrypt: ${i instanceof Error?i.message:"Unknown error"}`}}}function Xn(e,n,t={}){let r=t.cwd||process.cwd(),i=O(r,t.file||".env"),s=O(r,t.keysFile||".env.keys");try{let o="";if(I(i))o=A(i,"utf-8");let d=o.split(`
18
+ `),c=!1,u,p=((t.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),E=p?`DOTENV_PUBLIC_KEY_${p}`:"DOTENV_PUBLIC_KEY",l=p?`DOTENV_PRIVATE_KEY_${p}`:"DOTENV_PRIVATE_KEY";for(let _ of d){let y=_.trim();if(y.startsWith(`${E}=`)){let m=y.match(/^[^=]+=["']?([^"'\n]+)["']?/);if(m)u=m[1];break}}if(u){let _=!1;if(I(s)){let y=A(s,"utf-8"),{parsed:m}=S(y);_=Boolean(m[l])}if(!_&&!process.env[l]&&!me(o,E))u=void 0}if(!t.plain&&!u){let _=k();u=_.publicKey;let y="";if(I(s))y=A(s,"utf-8");y+=`
19
19
  ${E}="${_.publicKey}"
20
20
  ${l}="${_.privateKey}"
21
- `,h(s,y,"utf-8");for(let m=d.length-1;m>=0;m--){let R=d[m];if(R!==void 0&&R.trim().startsWith(`${E}=`))d.splice(m,1)}d.unshift(`${E}="${u}"`)}let T=n;if(!t.plain&&u)T=B(n,u);for(let _=0;_<d.length;_++){let y=d[_];if(y===void 0)continue;if(y.trim().startsWith(`${e}=`)){d[_]=`${e}="${T}"`,c=!0;break}}if(!c)d.push(`${e}="${T}"`);let v=d.join(`
22
- `);return h(i,v,"utf-8"),{success:!0,output:`set ${e}${t.plain?"":" with encryption"} (${t.file||".env"})`}}catch(o){return{success:!1,error:`Failed to set: ${o instanceof Error?o.message:"Unknown error"}`}}}function Qn(e,n={}){let t=n.cwd||process.cwd(),r=A(t,n.file||".env");if(!N(r))return{success:!1,error:`File not found: ${r}`};try{let i,s=A(t,n.keysFile||".env.keys"),c=((n.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=c?`DOTENV_PRIVATE_KEY_${c}`:"DOTENV_PRIVATE_KEY";if(N(s)){let l=O(s,"utf-8"),{parsed:T}=I(l);i=T[u]}if(!i)i=process.env[u];let a=O(r,"utf-8"),{parsed:f}=I(a,{privateKey:i});if(e&&!n.all){let l=f[e];if(l===void 0)return{success:!1,error:`Key not found: ${e}`};return{success:!0,output:l}}let p=n.all?{...process.env,...f}:f,E;switch(n.format){case"shell":E=Object.entries(p).map(([l,T])=>`${l}=${T}`).join(" ");break;case"eval":E=Object.entries(p).map(([l,T])=>`${l}="${T}"`).join(`
23
- `);break;case"json":default:E=n.prettyPrint?JSON.stringify(p,null,2):JSON.stringify(p);break}return{success:!0,output:E}}catch(i){return{success:!1,error:`Failed to get: ${i instanceof Error?i.message:"Unknown error"}`}}}function qn(e,n={}){let t=n.cwd||process.cwd(),r=A(t,n.keysFile||".env.keys");if(!N(r))return{success:!1,error:`Keys file not found: ${r}`};try{let i=O(r,"utf-8"),{parsed:s}=I(i),c=((n.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=c?`DOTENV_PUBLIC_KEY_${c}`:"DOTENV_PUBLIC_KEY",a=c?`DOTENV_PRIVATE_KEY_${c}`:"DOTENV_PRIVATE_KEY";if(e){let E=s[e];if(!E)return{success:!1,error:`Key not found: ${e}`};return{success:!0,output:E}}let f={[u]:s[u],[a]:s[a]};return{success:!0,output:n.format==="shell"?`${u}=${f[u]} ${a}=${f[a]}`:JSON.stringify(f)}}catch(i){return{success:!1,error:`Failed to get keypair: ${i instanceof Error?i.message:"Unknown error"}`}}}function rn(e,n,t,r){let i=e.split(`
21
+ `,N(s,y,"utf-8");for(let m=d.length-1;m>=0;m--){let R=d[m];if(R!==void 0&&R.trim().startsWith(`${E}=`))d.splice(m,1)}d.unshift(`${E}="${u}"`)}let T=n;if(!t.plain&&u)T=B(n,u);for(let _=0;_<d.length;_++){let y=d[_];if(y===void 0)continue;if(y.trim().startsWith(`${e}=`)){d[_]=`${e}="${T}"`,c=!0;break}}if(!c)d.push(`${e}="${T}"`);let v=d.join(`
22
+ `);return N(i,v,"utf-8"),{success:!0,output:`set ${e}${t.plain?"":" with encryption"} (${t.file||".env"})`}}catch(o){return{success:!1,error:`Failed to set: ${o instanceof Error?o.message:"Unknown error"}`}}}function Qn(e,n={}){let t=n.cwd||process.cwd(),r=O(t,n.file||".env");if(!I(r))return{success:!1,error:`File not found: ${r}`};try{let i,s=O(t,n.keysFile||".env.keys"),c=((n.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=c?`DOTENV_PRIVATE_KEY_${c}`:"DOTENV_PRIVATE_KEY";if(I(s)){let l=A(s,"utf-8"),{parsed:T}=S(l);i=T[u]}if(!i)i=process.env[u];let a=A(r,"utf-8"),{parsed:f}=S(a,{privateKey:i});if(e&&!n.all){let l=f[e];if(l===void 0)return{success:!1,error:`Key not found: ${e}`};return{success:!0,output:l}}let p=n.all?{...process.env,...f}:f,E;switch(n.format){case"shell":E=Object.entries(p).map(([l,T])=>`${l}=${T}`).join(" ");break;case"eval":E=Object.entries(p).map(([l,T])=>`${l}="${T}"`).join(`
23
+ `);break;case"json":default:E=n.prettyPrint?JSON.stringify(p,null,2):JSON.stringify(p);break}return{success:!0,output:E}}catch(i){return{success:!1,error:`Failed to get: ${i instanceof Error?i.message:"Unknown error"}`}}}function qn(e,n={}){let t=n.cwd||process.cwd(),r=O(t,n.keysFile||".env.keys");if(!I(r))return{success:!1,error:`Keys file not found: ${r}`};try{let i=A(r,"utf-8"),{parsed:s}=S(i),c=((n.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=c?`DOTENV_PUBLIC_KEY_${c}`:"DOTENV_PUBLIC_KEY",a=c?`DOTENV_PRIVATE_KEY_${c}`:"DOTENV_PRIVATE_KEY";if(e){let E=s[e];if(!E)return{success:!1,error:`Key not found: ${e}`};return{success:!0,output:E}}let f={[u]:s[u],[a]:s[a]};return{success:!0,output:n.format==="shell"?`${u}=${f[u]} ${a}=${f[a]}`:JSON.stringify(f)}}catch(i){return{success:!1,error:`Failed to get keypair: ${i instanceof Error?i.message:"Unknown error"}`}}}function rn(e,n,t,r){let i=e.split(`
24
24
  `),s=!1,o=!1;for(let d=0;d<i.length;d++){let c=i[d];if(c===void 0)continue;if(c.startsWith(`${t}=`))i[d]=`${t}="${n.publicKey}"`,s=!0;else if(c.startsWith(`${r}=`))i[d]=`${r}="${n.privateKey}"`,o=!0}if(!s)i.push(`${t}="${n.publicKey}"`);if(!o)i.push(`${r}="${n.privateKey}"`);return`${i.join(`
25
25
  `).replace(/\n+$/,"")}
26
- `}function zn(e={}){let n=tn({file:e.file,keysFile:e.keysFile,stdout:!0,cwd:e.cwd});if(!n.success)return n;if(n.output===void 0)return{success:!1,error:"Rotation produced no decrypted content"};let t=e.cwd||process.cwd(),r=e.file||".env",i=e.keysFile||".env.keys",s=A(t,r),o=A(t,i),{publicKeyName:d,privateKeyName:c}=x(e.file);if(e.dryRun){let _=nn(n.output,e);return{success:!0,output:["Dry run: nothing was written.",`${r}: ${_.length} value${_.length===1?"":"s"} would be re-encrypted under a new ${d}.`,`${i}: ${d} and ${c} would be replaced.`,`The current ${c} decrypts nothing once that happens, so keep a copy until the rotation is verified.`].join(`
26
+ `}function zn(e={}){let n=tn({file:e.file,keysFile:e.keysFile,stdout:!0,cwd:e.cwd});if(!n.success)return n;if(n.output===void 0)return{success:!1,error:"Rotation produced no decrypted content"};let t=e.cwd||process.cwd(),r=e.file||".env",i=e.keysFile||".env.keys",s=O(t,r),o=O(t,i),{publicKeyName:d,privateKeyName:c}=w(e.file);if(e.dryRun){let _=nn(n.output,e);return{success:!0,output:["Dry run: nothing was written.",`${r}: ${_.length} value${_.length===1?"":"s"} would be re-encrypted under a new ${d}.`,`${i}: ${d} and ${c} would be replaced.`,`The current ${c} decrypts nothing once that happens, so keep a copy until the rotation is verified.`].join(`
27
27
  `)}}let u=k(),a=Re(n.output,u.publicKey,d,e);if(e.stdout)return{success:!0,output:a,notice:[`Nothing was written. To adopt the output above, put this keypair in ${i}:`,"",`${d}="${u.publicKey}"`,`${c}="${u.privateKey}"`,"","Without it that output cannot be decrypted. Run without --stdout to have both applied together."].join(`
28
- `)};let f=O(s),p=O(o),E=rn(p.toString("utf8"),u,d,c),l=`${process.pid}-${Date.now()}`,T=A(Te(s),`.${_e(s)}.${l}.rotate`),v=A(Te(o),`.${_e(o)}.${l}.rotate`);try{h(T,a,{encoding:"utf8",mode:384}),h(v,E,{encoding:"utf8",mode:384}),pe(T,s);try{pe(v,o)}catch(_){throw h(s,f),_}return{success:!0,output:`\u2714 rotated (${r}) to encrypted:v2`}}catch(_){if(!N(o))h(o,p,{mode:384});return{success:!1,error:`Failed to rotate without exposing plaintext: ${_ instanceof Error?_.message:"Unknown error"}`}}finally{ge(T,{force:!0}),ge(v,{force:!0})}}import g from"process";import{platform as sn}from"os";var ve=typeof Bun<"u",Ae=typeof g<"u"&&g.versions?.node!==void 0,on=ve?"bun":Ae?"node":"unknown",nt={name:on,version:ve?Bun.version:Ae?g.version:void 0},ee=sn(),tt=ee==="win32",rt=ee==="darwin",it=ee==="linux",Oe=Boolean(g.stdout?.isTTY),st=typeof globalThis.window<"u",dn=Boolean(g.env.CI||g.env.CONTINUOUS_INTEGRATION||g.env.BUILD_NUMBER||g.env.RUN_ID),ot=Boolean(g.env.DEBUG||g.env.VERBOSE||g.argv.includes("--debug")||g.argv.includes("--verbose")),cn=dn||!Oe,dt=Boolean(!cn&&(Oe||g.env.COLORTERM||g.env.FORCE_COLOR||g.env.TERM&&g.env.TERM!=="dumb")),Z={github:{name:"GitHub Actions",detected:Boolean(g.env.GITHUB_ACTIONS)},gitlab:{name:"GitLab CI",detected:Boolean(g.env.GITLAB_CI)},circle:{name:"CircleCI",detected:Boolean(g.env.CIRCLECI)},travis:{name:"Travis CI",detected:Boolean(g.env.TRAVIS)},jenkins:{name:"Jenkins",detected:Boolean(g.env.JENKINS_URL)},vercel:{name:"Vercel",detected:Boolean(g.env.VERCEL)},netlify:{name:"Netlify",detected:Boolean(g.env.NETLIFY)},heroku:{name:"Heroku",detected:Boolean(g.env.DYNO)},aws:{name:"AWS",detected:Boolean(g.env.AWS_REGION||g.env.AWS_LAMBDA_FUNCTION_NAME)},azure:{name:"Azure",detected:Boolean(g.env.AZURE_HTTP_USER_AGENT)},cloudflare:{name:"Cloudflare",detected:Boolean(g.env.CF_PAGES)},railway:{name:"Railway",detected:Boolean(g.env.RAILWAY_ENVIRONMENT)},render:{name:"Render",detected:Boolean(g.env.RENDER)}},an=Object.keys(Z).find((e)=>{let n=Z[e];return n!==void 0&&n.detected})||"unknown",ct=Z[an]||{name:"Unknown",detected:!1};import gn from"process";import{projectPath as _n}from"@stacksjs/path";import he from"fs";var Ie={APP_ENV:["local","dev","development","staging","prod","production"],DB_CONNECTION:["mysql","sqlite","postgres","singlestore","vitess","dynamodb"],DB_MIGRATE_FRESH:["allow","confirm","disabled"],MAIL_MAILER:["smtp","mailgun","ses","log","sendgrid","mailtrap","capture"],SEARCH_ENGINE_DRIVER:["opensearch","meilisearch","algolia","typesense"],FRONTEND_APP_ENV:["development","staging","production"]};function ut(e){return e}function un(e){return typeof e==="string"&&(e.startsWith("encrypted:")||e.startsWith("enc:"))}var fn=/(?:^|_)(?:PASSWORD|PASSWD|SECRET|TOKEN|APIKEY|API_KEY|CREDENTIAL|CREDENTIALS|PRIVATE|SALT|DSN|CERT|CIPHER|SIGNATURE|WEBHOOK)(?:_|$)|(?:^|_)(?:ACCESS|SECRET)_KEY(?:_|$)|_KEY$/,En=/^DOTENV_(?:PUBLIC|PRIVATE)_KEY/,ln=/^\$\{[^}]+\}$/;function Et(e,n={}){let{placeholders:t={},strict:r=!1}=n,i=[];for(let[s,o]of Object.entries(e)){if(!o||o.trim()==="")continue;if(un(o))continue;if(En.test(s))continue;if(ln.test(o.trim()))continue;let d=fn.test(s),c=Object.prototype.hasOwnProperty.call(t,s)&&t[s]===o;if(d&&!c){i.push({key:s,reason:"plaintext-secret"});continue}if(r)i.push({key:s,reason:"plaintext-value"})}return i}function lt(e){return e.split(`
29
- `).map((n)=>n.trim()).filter(Boolean).filter((n)=>n!==".env.example").filter((n)=>/(?:^|\/)\.env(?:\.|$)/.test(n)).filter((n)=>!n.endsWith(".env.keys"))}function Ne(e){return`${e.replace(/[^a-z0-9]/gi,"").toUpperCase()}_`}function pn(e,n={}){let t=n.self?Ne(n.self):void 0,r=(n.tenants??[]).filter((o)=>typeof o==="string"&&o.trim().length>0).map((o)=>({slug:o,prefix:Ne(o)})).filter(({prefix:o})=>o!==t).sort((o,d)=>d.prefix.length-o.prefix.length),i={},s={};for(let[o,d]of Object.entries(e)){let c=r.find(({prefix:u})=>o.startsWith(u));if(c){(s[c.slug]??={})[o]=d;continue}i[o]=d}return{own:i,foreign:s}}function gt(e,n={}){return pn(e,n).own}function _t(e){return Object.entries(e.foreign).map(([n,t])=>({tenant:n,keys:Object.keys(t).sort()})).sort((n,t)=>n.tenant.localeCompare(t.tenant))}var Se=new Set;function Tn(e){if(Se.has(e))return;Se.add(e);let n=J();console.warn(`[env] warning: "${e}" is encrypted but no usable private key was found for the "${n}" environment; falling back to its default. Set DOTENV_PRIVATE_KEY_${n.toUpperCase()} or ship .env.keys.`)}var yn={get:(e,n)=>{let t=e,r=t[n];if(typeof r==="string"&&(r.startsWith("encrypted:")||r.startsWith("enc:"))){let s=Ee(r);if(s===void 0){Tn(n),delete t[n];return}t[n]=s,r=s}let i=["_PORT","_TIMEOUT","_TTL","_SIZE","_LIMIT","_MAX","_MIN","_INTERVAL","_RETRIES","_CONCURRENCY","_WORKERS","_CONNECTIONS"];if(typeof r==="string"&&/^\d+$/.test(r)&&!r.startsWith("0")&&i.some((s)=>n.endsWith(s)))return Number(r);if(typeof r==="string"){let s=r.toLowerCase();if(s==="true")return!0;if(s==="false")return!1}return r}};function Rn(){return typeof Bun<"u"?Bun.env:gn.env}var Pe=new Proxy(Rn(),yn);function Ot(e,n,t){let r=t?.path||_n(".env"),s=he.readFileSync(r,"utf-8").split(`
30
- `),o=s.findIndex((u)=>u.startsWith(`${e}=`)),c=/[\s"'#$\\]/.test(n)?`"${n.replace(/"/g,"\\\"")}"`:n;if(o!==-1)s[o]=`${e}=${c}`;else s.push(`${e}=${c}`);he.writeFileSync(r,s.join(`
31
- `))}function It(e=Pe){let n=[],t=e;for(let[r,i]of Object.entries(Ie)){let s=t[r];if(s!==void 0&&s!==""&&!i.includes(String(s)))n.push(`${r}="${s}" is not valid. Allowed values: ${i.join(", ")}`)}return n}function Nt(e,n=Pe){let t=[],r=n;for(let i of e){let s=r[i];if(s===void 0||s===""||s===null)t.push(i)}if(t.length>0)throw Error(`[env] Missing required environment variable(s): ${t.join(", ")}. Set them in .env or your process environment before booting.`);return n}export{fn as SECRET_NAME_PATTERN,J as activeEnvName,Ke as aesDecrypt,vn as aesEncrypt,Bn as autoLoadEnv,tn as decryptEnv,Ee as decryptEnvValue,L as decryptValue,ut as defineEnv,jn as encryptEnv,B as encryptValue,Pe as env,Ie as envEnum,x as envKeyNames,en as envPlugin,_t as foreignTenantKeys,k as generateKeypair,Qn as getEnv,qn as getKeypair,q as getPrivateKey,Oe as hasTTY,st as hasWindow,ve as isBun,dn as isCI,dt as isColorSupported,ot as isDebug,un as isEncryptedValue,An as isLegacyEncryptedValue,it as isLinux,rt as isMacOS,cn as isMinimal,Ae as isNode,tt as isWindows,le as loadEnv,bn as loadEnvFiles,On as migrateEncryptedValue,I as parse,In as parseEnvFromKey,pn as partitionTenantEnv,Et as plaintextSecrets,ee as platform,Rn as process,an as provider,ct as providerInfo,Nt as requireEnv,Un as resetPrivateKeyCache,Hn as resolveEnvFile,Ze as resolvePrivateKey,me as reusableEnvPublicKey,zn as rotateKeypair,on as runtime,nt as runtimeInfo,Xn as setEnv,gt as stripForeignTenantEnv,Ne as tenantEnvPrefix,lt as trackedEnvFiles,It as validateEnv,Ot as writeEnv};
28
+ `)};let f=A(s),p=A(o),E=rn(p.toString("utf8"),u,d,c),l=`${process.pid}-${Date.now()}`,T=O(Te(s),`.${_e(s)}.${l}.rotate`),v=O(Te(o),`.${_e(o)}.${l}.rotate`);try{N(T,a,{encoding:"utf8",mode:384}),N(v,E,{encoding:"utf8",mode:384}),pe(T,s);try{pe(v,o)}catch(_){throw N(s,f),_}return{success:!0,output:`\u2714 rotated (${r}) to encrypted:v2`}}catch(_){if(!I(o))N(o,p,{mode:384});return{success:!1,error:`Failed to rotate without exposing plaintext: ${_ instanceof Error?_.message:"Unknown error"}`}}finally{ge(T,{force:!0}),ge(v,{force:!0})}}import g from"process";import{platform as sn}from"os";var ve=typeof Bun<"u",Oe=typeof g<"u"&&g.versions?.node!==void 0,on=ve?"bun":Oe?"node":"unknown",nt={name:on,version:ve?Bun.version:Oe?g.version:void 0},ee=sn(),tt=ee==="win32",rt=ee==="darwin",it=ee==="linux",Ae=Boolean(g.stdout?.isTTY),st=typeof globalThis.window<"u",dn=Boolean(g.env.CI||g.env.CONTINUOUS_INTEGRATION||g.env.BUILD_NUMBER||g.env.RUN_ID),ot=Boolean(g.env.DEBUG||g.env.VERBOSE||g.argv.includes("--debug")||g.argv.includes("--verbose")),cn=dn||!Ae,dt=Boolean(!cn&&(Ae||g.env.COLORTERM||g.env.FORCE_COLOR||g.env.TERM&&g.env.TERM!=="dumb")),Z={github:{name:"GitHub Actions",detected:Boolean(g.env.GITHUB_ACTIONS)},gitlab:{name:"GitLab CI",detected:Boolean(g.env.GITLAB_CI)},circle:{name:"CircleCI",detected:Boolean(g.env.CIRCLECI)},travis:{name:"Travis CI",detected:Boolean(g.env.TRAVIS)},jenkins:{name:"Jenkins",detected:Boolean(g.env.JENKINS_URL)},vercel:{name:"Vercel",detected:Boolean(g.env.VERCEL)},netlify:{name:"Netlify",detected:Boolean(g.env.NETLIFY)},heroku:{name:"Heroku",detected:Boolean(g.env.DYNO)},aws:{name:"AWS",detected:Boolean(g.env.AWS_REGION||g.env.AWS_LAMBDA_FUNCTION_NAME)},azure:{name:"Azure",detected:Boolean(g.env.AZURE_HTTP_USER_AGENT)},cloudflare:{name:"Cloudflare",detected:Boolean(g.env.CF_PAGES)},railway:{name:"Railway",detected:Boolean(g.env.RAILWAY_ENVIRONMENT)},render:{name:"Render",detected:Boolean(g.env.RENDER)}},an=Object.keys(Z).find((e)=>{let n=Z[e];return n!==void 0&&n.detected})||"unknown",ct=Z[an]||{name:"Unknown",detected:!1};import gn from"process";import{projectPath as _n}from"@stacksjs/path";import Ne from"fs";var Se={APP_ENV:["local","dev","development","staging","prod","production"],DB_CONNECTION:["mysql","sqlite","postgres","singlestore","vitess","dynamodb"],DB_MIGRATE_FRESH:["allow","confirm","disabled"],MAIL_MAILER:["smtp","mailgun","ses","log","sendgrid","mailtrap","capture"],SEARCH_ENGINE_DRIVER:["opensearch","meilisearch","algolia","typesense"],FRONTEND_APP_ENV:["development","staging","production"]};function ut(e){return e}function un(e){return typeof e==="string"&&(e.startsWith("encrypted:")||e.startsWith("enc:"))}var fn=/(?:^|_)(?:PASSWORD|PASSWD|SECRET|TOKEN|APIKEY|API_KEY|CREDENTIAL|CREDENTIALS|PRIVATE|SALT|DSN|CERT|CIPHER|SIGNATURE|WEBHOOK)(?:_|$)|(?:^|_)(?:ACCESS|SECRET)_KEY(?:_|$)|_KEY$/,En=/^DOTENV_(?:PUBLIC|PRIVATE)_KEY/,ln=/^\$\{[^}]+\}$/;function Et(e,n={}){let{placeholders:t={},strict:r=!1}=n,i=[];for(let[s,o]of Object.entries(e)){if(!o||o.trim()==="")continue;if(un(o))continue;if(En.test(s))continue;if(ln.test(o.trim()))continue;let d=fn.test(s),c=Object.prototype.hasOwnProperty.call(t,s)&&t[s]===o;if(d&&!c){i.push({key:s,reason:"plaintext-secret"});continue}if(r)i.push({key:s,reason:"plaintext-value"})}return i}function lt(e){return e.split(`
29
+ `).map((n)=>n.trim()).filter(Boolean).filter((n)=>n!==".env.example").filter((n)=>/(?:^|\/)\.env(?:\.|$)/.test(n)).filter((n)=>!n.endsWith(".env.keys"))}function Ie(e){return`${e.replace(/[^a-z0-9]/gi,"").toUpperCase()}_`}function pn(e,n={}){let t=n.self?Ie(n.self):void 0,r=(n.tenants??[]).filter((o)=>typeof o==="string"&&o.trim().length>0).map((o)=>({slug:o,prefix:Ie(o)})).filter(({prefix:o})=>o!==t).sort((o,d)=>d.prefix.length-o.prefix.length),i={},s={};for(let[o,d]of Object.entries(e)){let c=r.find(({prefix:u})=>o.startsWith(u));if(c){(s[c.slug]??={})[o]=d;continue}i[o]=d}return{own:i,foreign:s}}function gt(e,n={}){return pn(e,n).own}function _t(e){return Object.entries(e.foreign).map(([n,t])=>({tenant:n,keys:Object.keys(t).sort()})).sort((n,t)=>n.tenant.localeCompare(t.tenant))}var he=new Set;function Tn(e){if(he.has(e))return;he.add(e);let n=J();console.warn(`[env] warning: "${e}" is encrypted but no usable private key was found for the "${n}" environment; falling back to its default. Set DOTENV_PRIVATE_KEY_${n.toUpperCase()} or ship .env.keys.`)}var yn={get:(e,n)=>{let t=e,r=t[n];if(typeof r==="string"&&(r.startsWith("encrypted:")||r.startsWith("enc:"))){let s=Ee(r);if(s===void 0){Tn(n),delete t[n];return}t[n]=s,r=s}let i=["_PORT","_TIMEOUT","_TTL","_SIZE","_LIMIT","_MAX","_MIN","_INTERVAL","_RETRIES","_CONCURRENCY","_WORKERS","_CONNECTIONS"];if(typeof r==="string"&&/^\d+$/.test(r)&&!r.startsWith("0")&&i.some((s)=>n.endsWith(s)))return Number(r);if(typeof r==="string"){let s=r.toLowerCase();if(s==="true")return!0;if(s==="false")return!1}return r}};function Rn(){return typeof Bun<"u"?Bun.env:gn.env}var Pe=new Proxy(Rn(),yn);function At(e,n,t){let r=t?.path||_n(".env"),s=Ne.readFileSync(r,"utf-8").split(`
30
+ `),o=s.findIndex((u)=>u.startsWith(`${e}=`)),c=/[\s"'#$\\]/.test(n)?`"${n.replace(/"/g,"\\\"")}"`:n;if(o!==-1)s[o]=`${e}=${c}`;else s.push(`${e}=${c}`);Ne.writeFileSync(r,s.join(`
31
+ `))}function St(e=Pe){let n=[],t=e;for(let[r,i]of Object.entries(Se)){let s=t[r];if(s!==void 0&&s!==""&&!i.includes(String(s)))n.push(`${r}="${s}" is not valid. Allowed values: ${i.join(", ")}`)}return n}function It(e,n=Pe){let t=[],r=n;for(let i of e){let s=r[i];if(s===void 0||s===""||s===null)t.push(i)}if(t.length>0)throw Error(`[env] Missing required environment variable(s): ${t.join(", ")}. Set them in .env or your process environment before booting.`);return n}export{fn as SECRET_NAME_PATTERN,J as activeEnvName,Le as aesDecrypt,vn as aesEncrypt,Bn as autoLoadEnv,tn as decryptEnv,Ee as decryptEnvValue,K as decryptValue,ut as defineEnv,jn as encryptEnv,B as encryptValue,Pe as env,Se as envEnum,w as envKeyNames,en as envPlugin,_t as foreignTenantKeys,k as generateKeypair,Qn as getEnv,qn as getKeypair,q as getPrivateKey,Ae as hasTTY,st as hasWindow,ve as isBun,dn as isCI,dt as isColorSupported,ot as isDebug,un as isEncryptedValue,On as isLegacyEncryptedValue,it as isLinux,rt as isMacOS,cn as isMinimal,Oe as isNode,tt as isWindows,le as loadEnv,bn as loadEnvFiles,An as migrateEncryptedValue,S as parse,Sn as parseEnvFromKey,pn as partitionTenantEnv,Et as plaintextSecrets,ee as platform,Rn as process,an as provider,ct as providerInfo,It as requireEnv,xn as resetPrivateKeyCache,Hn as resolveEnvFile,Ze as resolvePrivateKey,me as reusableEnvPublicKey,zn as rotateKeypair,on as runtime,nt as runtimeInfo,Xn as setEnv,gt as stripForeignTenantEnv,Ie as tenantEnvPrefix,lt as trackedEnvFiles,St as validateEnv,At as writeEnv};
package/dist/types.d.ts CHANGED
@@ -48,6 +48,13 @@ export declare interface FrameworkEnv {
48
48
  DEBUG: boolean | undefined
49
49
  FILESYSTEM_DISK: string | undefined
50
50
  HCLOUD_TOKEN: string | undefined
51
+ TS_CLOUD_SSH_HOST: string | undefined
52
+ TS_CLOUD_SSH_USER: string | undefined
53
+ TS_CLOUD_SSH_PORT: string | undefined
54
+ TS_CLOUD_SSH_KEY: string | undefined
55
+ TS_CLOUD_SSH_HOST_KEY: string | undefined
56
+ TS_CLOUD_SSH_PROFILE: string | undefined
57
+ TS_CLOUD_SSH_PUBLISH_DNS: string | undefined
51
58
  HETZNER_API_TOKEN: string | undefined
52
59
  DOTENV_PRIVATE_KEY: string | undefined
53
60
  DOTENV_PUBLIC_KEY: string | undefined
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/env",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.74.3",
5
+ "version": "0.74.5",
6
6
  "description": "Stacks env helper methods.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -56,10 +56,10 @@
56
56
  "prepublishOnly": "bun run build"
57
57
  },
58
58
  "dependencies": {
59
- "@stacksjs/path": "0.74.3"
59
+ "@stacksjs/path": "0.74.5"
60
60
  },
61
61
  "devDependencies": {
62
62
  "better-dx": "^0.2.24",
63
- "@stacksjs/validation": "0.74.3"
63
+ "@stacksjs/validation": "0.74.5"
64
64
  }
65
65
  }