@stacksjs/env 0.70.229 → 0.70.231

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/cli.js CHANGED
@@ -1,24 +1,24 @@
1
1
  // @bun
2
- import{createCipheriv as u,createDecipheriv as K,createHash as C,createPrivateKey as e,createPublicKey as k,diffieHellman as m,generateKeyPairSync as n,hkdfSync as s,randomBytes as F}from"crypto";var b="x25519-public:",S="x25519-private:",V="encrypted:v2:",P="encrypted:",o=Buffer.from("stacks-env:v2","utf8"),i="Environment decryption failed: authentication or format error";function v(f){if(f.length===32)return f;return C("sha256").update(f).digest()}function _f(f,r){let g=F(16),c=u("aes-256-gcm",v(r),g);return{ciphertext:Buffer.concat([c.update(f,"utf8"),c.final()]).toString("hex"),iv:g.toString("hex"),authTag:c.getAuthTag().toString("hex")}}function ff(f,r,g,c){try{let E=K("aes-256-gcm",v(r),Buffer.from(g,"hex"));return E.setAuthTag(Buffer.from(c,"hex")),Buffer.concat([E.update(Buffer.from(f,"hex")),E.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function U(f){return f.toString("base64url")}function z(f,r,g){if(typeof f!=="string"||f.length>0&&!/^[A-Za-z0-9_-]+$/.test(f))throw Error(`${r} is not canonical base64url`);let c=Buffer.from(f,"base64url");if(U(c)!==f)throw Error(`${r} is not canonical base64url`);if(g!==void 0&&c.length!==g)throw Error(`${r} has an invalid length`);return c}function gf(f){if(!f.startsWith(b))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let r=k({key:z(f.slice(b.length),"public key"),format:"der",type:"spki"});if(r.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return r}function rf(f){if(!f.startsWith(S))throw Error("Private key is not a version 2 X25519 key");let r=e({key:z(f.slice(S.length),"private key"),format:"der",type:"pkcs8"});if(r.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return r}function y(f){return Buffer.from(`stacks-env:v2;${f.epk};${f.salt};${f.nonce}`,"utf8")}function q(){let{publicKey:f,privateKey:r}=n("x25519"),g=f.export({format:"der",type:"spki"}),c=r.export({format:"der",type:"pkcs8"});return{publicKey:`${b}${U(g)}`,privateKey:`${S}${U(c)}`}}function L(f,r){let g=gf(r),c=n("x25519"),E=U(c.publicKey.export({format:"der",type:"spki"})),h=F(16),A=F(12),x=m({privateKey:c.privateKey,publicKey:g}),$=Buffer.from(s("sha256",x,h,o,32)),B={epk:E,salt:U(h),nonce:U(A)};try{let w=u("aes-256-gcm",$,A);w.setAAD(y(B));let _=Buffer.concat([w.update(f,"utf8"),w.final()]),X={v:2,...B,ciphertext:U(_),tag:U(w.getAuthTag())};return`${V}${U(Buffer.from(JSON.stringify(X),"utf8"))}`}finally{x.fill(0),$.fill(0)}}function Ef(f){let r=z(f.slice(V.length),"envelope").toString("utf8"),g=JSON.parse(r);if(!g||typeof g!=="object"||Array.isArray(g))throw Error("envelope is not an object");let c=Object.keys(g).sort(),E=["ciphertext","epk","nonce","salt","tag","v"];if(c.length!==E.length||c.some((h,A)=>h!==E[A]))throw Error("envelope fields are invalid");if(g.v!==2)throw Error("envelope version is unsupported");for(let h of["epk","salt","nonce","ciphertext","tag"])if(typeof g[h]!=="string")throw Error(`${h} is invalid`);return g}function cf(f,r){try{let g=Ef(f),c=rf(r),E=k({key:z(g.epk,"ephemeral public key"),format:"der",type:"spki"});if(E.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let h=z(g.salt,"salt",16),A=z(g.nonce,"nonce",12),x=z(g.ciphertext,"ciphertext"),$=z(g.tag,"tag",16),B=m({privateKey:c,publicKey:E}),w=Buffer.from(s("sha256",B,h,o,32));try{let _=K("aes-256-gcm",w,A);return _.setAAD(y(g)),_.setAuthTag($),Buffer.concat([_.update(x),_.final()]).toString("utf8")}finally{B.fill(0),w.fill(0)}}catch{throw Error(i)}}function Bf(f,r){try{if(!/^[0-9a-f]{64}$/.test(r))throw Error("invalid legacy private key");let g=Buffer.from(f.slice(P.length),"base64");if(g.length<32)throw Error("invalid legacy payload");let c=C("sha256").update(Buffer.from(r,"hex")).digest(),E=C("sha256").update(c).digest();return ff(g.subarray(32).toString("hex"),E,g.subarray(0,16).toString("hex"),g.subarray(16,32).toString("hex"))}catch{throw Error(i)}}function If(f){return f.startsWith(P)&&!f.startsWith(V)}function Q(f,r){if(!f.startsWith(P))return f;return f.startsWith(V)?cf(f,r):Bf(f,r)}function Tf(f,r,g){return L(Q(f,r),g)}function Rf(f){let r=f.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return r&&r[1]?r[1].toLowerCase():""}function Df(f=""){return f?process.env[`DOTENV_PRIVATE_KEY_${f.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}function Z(f,r={}){let g={},c=[],E=[],h=f.split(`
3
- `);for(let A of h){let x=A.trim();if(!x||x.startsWith("#"))continue;if(x.startsWith("DOTENV_PUBLIC_KEY=")){let _=x.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(_&&_[1]!==void 0)g.DOTENV_PUBLIC_KEY=_[1];continue}let $=x.match(/^([^=]+)=(.*)$/);if(!$||$[1]===void 0||$[2]===void 0)continue;let B=$[1].trim(),w=$[2].trim();if(w.startsWith('"')&&w.endsWith('"')||w.startsWith("'")&&w.endsWith("'")){if(w=w.slice(1,-1),w.includes("\\n"))w=w.replace(/\\n/g,`
4
- `)}if(w.startsWith("encrypted:")||w.startsWith("enc:")){if(!r.privateKey){E.push(B);continue}try{let _=w.startsWith("enc:")?`encrypted:${w.slice(4)}`:w;w=Q(_,r.privateKey)}catch(_){c.push(`Failed to decrypt ${B}: ${_ instanceof Error?_.message:"Unknown error"}`)}}w=hf(w,{...r.processEnv||process.env,...g}),w=$f(w),g[B]=w}return{parsed:g,errors:c,skippedEncrypted:E}}function hf(f,r){return f.replace(/\$\{([^}]+)\}/g,(g,c)=>{let E=c.match(/^([^:\-+]+)(:-|-)(.+)$/);if(E){let[,A,x,$]=E,B=r[A];if(x===":-")return B||$;else return B!==void 0?B:$}let h=c.match(/^([^:\-+]+)(:?\+)(.+)$/);if(h){let[,A,x,$]=h,B=r[A];if(x===":+")return B?$:"";else return B!==void 0?$:""}return r[c]||""})}var wf=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function $f(f){return f.replace(/\$\(([^)]+)\)/g,(r,g)=>{try{let c=g.trim().split(/\s+/),E=c[0];if(!E||!wf.has(E))return console.warn(`[env] Blocked command substitution for disallowed command: ${E}`),"";let h=Bun.spawnSync(c,{stdout:"pipe",stderr:"pipe"});if(h.exitCode===0)return new TextDecoder().decode(h.stdout).trim();console.warn(`[env] Command substitution failed (exit code ${h.exitCode}): ${E}`)}catch(c){console.warn(`[env] Command substitution error: ${c instanceof Error?c.message:String(c)}`)}return""})}async function Of(f,r={}){let g={},c=[],E=[];for(let h of f)try{let A=Bun.file(h);if(!A.size)continue;let x=await A.text(),{parsed:$,errors:B,skippedEncrypted:w}=Z(x,r);c.push(...B),E.push(...w);for(let[_,X]of Object.entries($)){if(!r.overload&&g[_]!==void 0)continue;g[_]=X}}catch(A){if(A?.code==="ENOENT")continue;c.push(`Failed to read ${h}: ${A instanceof Error?A.message:String(A)}`)}return{parsed:g,errors:c,skippedEncrypted:E}}import{existsSync as G,readFileSync as j,renameSync as d,rmSync as l,writeFileSync as J}from"fs";import{basename as N,dirname as p,resolve as W}from"path";function Jf(f,r){if(f)return f;let g=String(r??"").trim();if(!g||g==="development"||g==="dev"||g==="local")return"";if(!/^[\w.-]+$/.test(g))return"";return`.env.${g}`}function a(f,r,g,c){let E=["#/-------------------[DOTENV_PUBLIC_KEY]--------------------/","#/ versioned X25519 encryption for .env files /","#/ [how it works](https://stacksjs.com/encryption) /","#/----------------------------------------------------------/",`${g}="${r}"`,""];for(let h of f.split(`
5
- `)){let A=h.trim();if(!A||A.startsWith("#")){E.push(h);continue}if(A.startsWith("DOTENV_PUBLIC_KEY"))continue;let x=A.match(/^([^=]+)=(.*)$/);if(!x||x[1]===void 0||x[2]===void 0){E.push(h);continue}let $=x[1].trim(),B=x[2].trim();if(B.startsWith('"')&&B.endsWith('"')||B.startsWith("'")&&B.endsWith("'"))B=B.slice(1,-1);if((!c.key||$.includes(c.key))&&(!c.excludeKey||!$.includes(c.excludeKey))&&!B.startsWith("encrypted:"))B=L(B,r);E.push(`${$}="${B}"`)}return E.join(`
6
- `)}function Uf(f={}){let r=f.cwd||process.cwd(),g=W(r,f.file||".env"),c=W(r,f.keysFile||".env.keys");if(!G(g))return{success:!1,error:`File not found: ${g}`};try{let E,h;if(G(c)){let w=j(c,"utf-8"),{parsed:_}=Z(w),D=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),t=D?`DOTENV_PUBLIC_KEY_${D}`:"DOTENV_PUBLIC_KEY",H=D?`DOTENV_PRIVATE_KEY_${D}`:"DOTENV_PRIVATE_KEY";if(E=_[t]||"",h=_[H]||"",!E||!h){let R=q();E=R.publicKey,h=R.privateKey;let O=`
7
- ${t}="${E}"
8
- ${H}="${h}"
9
- `;J(c,w+O,"utf-8")}}else{let w=q();E=w.publicKey,h=w.privateKey;let I=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),D=I?`DOTENV_PUBLIC_KEY_${I}`:"DOTENV_PUBLIC_KEY",t=I?`DOTENV_PRIVATE_KEY_${I}`:"DOTENV_PRIVATE_KEY",H=`# .env.keys - Keep this file secure and never commit to source control
10
- ${D}="${E}"
11
- ${t}="${h}"
12
- `;J(c,H,"utf-8")}let A=j(g,"utf-8"),x=f.file?f.file.replace(/^\.env\./,"").toUpperCase():"",$=x?`DOTENV_PUBLIC_KEY_${x}`:"DOTENV_PUBLIC_KEY",B=a(A,E,$,f);if(f.stdout)return{success:!0,output:B};return J(g,B,"utf-8"),{success:!0,output:`\u2714 encrypted (${f.file||".env"})
13
- \u2714 key added to ${f.keysFile||".env.keys"}`}}catch(E){return{success:!1,error:`Failed to encrypt: ${E instanceof Error?E.message:"Unknown error"}`}}}function xf(f={}){let r=f.cwd||process.cwd(),g=W(r,f.file||".env"),c=W(r,f.keysFile||".env.keys");if(!G(g))return{success:!1,error:`File not found: ${g}`};if(!G(c))return{success:!1,error:`Keys file not found: ${c}`};try{let E=j(c,"utf-8"),{parsed:h}=Z(E),$=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),B=$?`DOTENV_PRIVATE_KEY_${$}`:"DOTENV_PRIVATE_KEY",w=h[B];if(!w)return{success:!1,error:`Private key not found: ${B}`};let X=j(g,"utf-8").split(`
14
- `),I=[];for(let t of X){let H=t.trim();if(!H||H.startsWith("#")){I.push(t);continue}if(H.startsWith("DOTENV_PUBLIC_KEY"))continue;let R=H.match(/^([^=]+)=(.*)$/);if(!R||R[1]===void 0||R[2]===void 0){I.push(t);continue}let O=R[1].trim(),T=R[2].trim();if(T.startsWith('"')&&T.endsWith('"')||T.startsWith("'")&&T.endsWith("'"))T=T.slice(1,-1);let Y=T.startsWith("encrypted:");if(f.key&&!O.includes(f.key))Y=!1;if(Y)T=Q(T,w);I.push(`${O}="${T}"`)}let D=I.join(`
15
- `);if(f.stdout)return{success:!0,output:D};return J(g,D,"utf-8"),{success:!0,output:`\u2714 decrypted (${f.file||".env"})`}}catch(E){return{success:!1,error:`Failed to decrypt: ${E instanceof Error?E.message:"Unknown error"}`}}}function zf(f,r,g={}){let c=g.cwd||process.cwd(),E=W(c,g.file||".env"),h=W(c,g.keysFile||".env.keys");try{let A="";if(G(E))A=j(E,"utf-8");let x=A.split(`
16
- `),$=!1,B,X=((g.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),I=X?`DOTENV_PUBLIC_KEY_${X}`:"DOTENV_PUBLIC_KEY",D=X?`DOTENV_PRIVATE_KEY_${X}`:"DOTENV_PRIVATE_KEY";for(let R of x){let O=R.trim();if(O.startsWith(`${I}=`)){let T=O.match(/^[^=]+=["']?([^"'\n]+)["']?/);if(T)B=T[1];break}}if(B){let R=!1;if(G(h)){let O=j(h,"utf-8"),{parsed:T}=Z(O);R=Boolean(T[D])}if(!R)B=void 0}if(!g.plain&&!B){let R=q();B=R.publicKey;let O="";if(G(h))O=j(h,"utf-8");O+=`
17
- ${I}="${R.publicKey}"
18
- ${D}="${R.privateKey}"
19
- `,J(h,O,"utf-8");for(let T=x.length-1;T>=0;T--){let Y=x[T];if(Y!==void 0&&Y.trim().startsWith(`${I}=`))x.splice(T,1)}x.unshift(`${I}="${B}"`)}let t=r;if(!g.plain&&B)t=L(r,B);for(let R=0;R<x.length;R++){let O=x[R];if(O===void 0)continue;if(O.trim().startsWith(`${f}=`)){x[R]=`${f}="${t}"`,$=!0;break}}if(!$)x.push(`${f}="${t}"`);let H=x.join(`
20
- `);return J(E,H,"utf-8"),{success:!0,output:`set ${f}${g.plain?"":" with encryption"} (${g.file||".env"})`}}catch(A){return{success:!1,error:`Failed to set: ${A instanceof Error?A.message:"Unknown error"}`}}}function Zf(f,r={}){let g=r.cwd||process.cwd(),c=W(g,r.file||".env");if(!G(c))return{success:!1,error:`File not found: ${c}`};try{let E,h=W(g,r.keysFile||".env.keys"),$=((r.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),B=$?`DOTENV_PRIVATE_KEY_${$}`:"DOTENV_PRIVATE_KEY";if(G(h)){let D=j(h,"utf-8"),{parsed:t}=Z(D);E=t[B]}if(!E)E=process.env[B];let w=j(c,"utf-8"),{parsed:_}=Z(w,{privateKey:E});if(f&&!r.all){let D=_[f];if(D===void 0)return{success:!1,error:`Key not found: ${f}`};return{success:!0,output:D}}let X=r.all?{...process.env,..._}:_,I;switch(r.format){case"shell":I=Object.entries(X).map(([D,t])=>`${D}=${t}`).join(" ");break;case"eval":I=Object.entries(X).map(([D,t])=>`${D}="${t}"`).join(`
21
- `);break;case"json":default:I=r.prettyPrint?JSON.stringify(X,null,2):JSON.stringify(X);break}return{success:!0,output:I}}catch(E){return{success:!1,error:`Failed to get: ${E instanceof Error?E.message:"Unknown error"}`}}}function qf(f,r={}){let g=r.cwd||process.cwd(),c=W(g,r.keysFile||".env.keys");if(!G(c))return{success:!1,error:`Keys file not found: ${c}`};try{let E=j(c,"utf-8"),{parsed:h}=Z(E),$=((r.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),B=$?`DOTENV_PUBLIC_KEY_${$}`:"DOTENV_PUBLIC_KEY",w=$?`DOTENV_PRIVATE_KEY_${$}`:"DOTENV_PRIVATE_KEY";if(f){let I=h[f];if(!I)return{success:!1,error:`Key not found: ${f}`};return{success:!0,output:I}}let _={[B]:h[B],[w]:h[w]};return{success:!0,output:r.format==="shell"?`${B}=${_[B]} ${w}=${_[w]}`:JSON.stringify(_)}}catch(E){return{success:!1,error:`Failed to get keypair: ${E instanceof Error?E.message:"Unknown error"}`}}}function Qf(f={}){let r=xf({file:f.file,keysFile:f.keysFile,stdout:!0,cwd:f.cwd});if(!r.success)return r;let g=f.cwd||process.cwd(),c=W(g,f.file||".env"),E=W(g,f.keysFile||".env.keys");if(r.output===void 0)return{success:!1,error:"Rotation produced no decrypted content"};let h=q(),A=j(c),x=j(E),$=x.toString("utf8").split(`
22
- `),B=f.file||".env",w=N(B).replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),_=w?`DOTENV_PUBLIC_KEY_${w}`:"DOTENV_PUBLIC_KEY",X=w?`DOTENV_PRIVATE_KEY_${w}`:"DOTENV_PRIVATE_KEY",I=!1,D=!1;for(let Y=0;Y<$.length;Y++){let M=$[Y];if(M===void 0)continue;if(M.startsWith(`${_}=`))$[Y]=`${_}="${h.publicKey}"`,I=!0;else if(M.startsWith(`${X}=`))$[Y]=`${X}="${h.privateKey}"`,D=!0}if(!I)$.push(`${_}="${h.publicKey}"`);if(!D)$.push(`${X}="${h.privateKey}"`);let t=`${$.join(`
2
+ import{createCipheriv as d,createDecipheriv as k,createHash as F,createPrivateKey as ff,createPublicKey as u,diffieHellman as m,generateKeyPairSync as n,hkdfSync as i,randomBytes as S}from"crypto";var b="x25519-public:",P="x25519-private:",r="encrypted:v2:",N="encrypted:",o=Buffer.from("stacks-env:v2","utf8"),v="Environment decryption failed: authentication or format error";function s(f){if(f.length===32)return f;return F("sha256").update(f).digest()}function zf(f,E){let g=S(16),$=d("aes-256-gcm",s(E),g);return{ciphertext:Buffer.concat([$.update(f,"utf8"),$.final()]).toString("hex"),iv:g.toString("hex"),authTag:$.getAuthTag().toString("hex")}}function gf(f,E,g,$){try{let B=k("aes-256-gcm",s(E),Buffer.from(g,"hex"));return B.setAuthTag(Buffer.from($,"hex")),Buffer.concat([B.update(Buffer.from(f,"hex")),B.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function Q(f){return f.toString("base64url")}function V(f,E,g){if(typeof f!=="string"||f.length>0&&!/^[A-Za-z0-9_-]+$/.test(f))throw Error(`${E} is not canonical base64url`);let $=Buffer.from(f,"base64url");if(Q($)!==f)throw Error(`${E} is not canonical base64url`);if(g!==void 0&&$.length!==g)throw Error(`${E} has an invalid length`);return $}function Ef(f){if(!f.startsWith(b))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let E=u({key:V(f.slice(b.length),"public key"),format:"der",type:"spki"});if(E.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return E}function Bf(f){if(!f.startsWith(P))throw Error("Private key is not a version 2 X25519 key");let E=ff({key:V(f.slice(P.length),"private key"),format:"der",type:"pkcs8"});if(E.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return E}function y(f){return Buffer.from(`stacks-env:v2;${f.epk};${f.salt};${f.nonce}`,"utf8")}function q(){let{publicKey:f,privateKey:E}=n("x25519"),g=f.export({format:"der",type:"spki"}),$=E.export({format:"der",type:"pkcs8"});return{publicKey:`${b}${Q(g)}`,privateKey:`${P}${Q($)}`}}function C(f,E){let g=Ef(E),$=n("x25519"),B=Q($.publicKey.export({format:"der",type:"spki"})),w=S(16),D=S(12),I=m({privateKey:$.privateKey,publicKey:g}),T=Buffer.from(i("sha256",I,w,o,32)),A={epk:B,salt:Q(w),nonce:Q(D)};try{let _=d("aes-256-gcm",T,D);_.setAAD(y(A));let X=Buffer.concat([_.update(f,"utf8"),_.final()]),H={v:2,...A,ciphertext:Q(X),tag:Q(_.getAuthTag())};return`${r}${Q(Buffer.from(JSON.stringify(H),"utf8"))}`}finally{I.fill(0),T.fill(0)}}function $f(f){let E=V(f.slice(r.length),"envelope").toString("utf8"),g=JSON.parse(E);if(!g||typeof g!=="object"||Array.isArray(g))throw Error("envelope is not an object");let $=Object.keys(g).sort(),B=["ciphertext","epk","nonce","salt","tag","v"];if($.length!==B.length||$.some((w,D)=>w!==B[D]))throw Error("envelope fields are invalid");if(g.v!==2)throw Error("envelope version is unsupported");for(let w of["epk","salt","nonce","ciphertext","tag"])if(typeof g[w]!=="string")throw Error(`${w} is invalid`);return g}function wf(f,E){try{let g=$f(f),$=Bf(E),B=u({key:V(g.epk,"ephemeral public key"),format:"der",type:"spki"});if(B.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let w=V(g.salt,"salt",16),D=V(g.nonce,"nonce",12),I=V(g.ciphertext,"ciphertext"),T=V(g.tag,"tag",16),A=m({privateKey:$,publicKey:B}),_=Buffer.from(i("sha256",A,w,o,32));try{let X=k("aes-256-gcm",_,D);return X.setAAD(y(g)),X.setAuthTag(T),Buffer.concat([X.update(I),X.final()]).toString("utf8")}finally{A.fill(0),_.fill(0)}}catch{throw Error(v)}}function Af(f,E){try{if(!/^[0-9a-f]{64}$/.test(E))throw Error("invalid legacy private key");let g=Buffer.from(f.slice(N.length),"base64");if(g.length<32)throw Error("invalid legacy payload");let $=F("sha256").update(Buffer.from(E,"hex")).digest(),B=F("sha256").update($).digest();return gf(g.subarray(32).toString("hex"),B,g.subarray(0,16).toString("hex"),g.subarray(16,32).toString("hex"))}catch{throw Error(v)}}function Zf(f){return f.startsWith(N)&&!f.startsWith(r)}function M(f,E){if(!f.startsWith(N))return f;return f.startsWith(r)?wf(f,E):Af(f,E)}function Qf(f,E,g){return C(M(f,E),g)}function Vf(f){let E=f.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return E&&E[1]?E[1].toLowerCase():""}function Lf(f=""){return f?process.env[`DOTENV_PRIVATE_KEY_${f.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}import{spawnSync as _f}from"child_process";import{readFileSync as Tf}from"fs";import{arch as If,hostname as Df,platform as p,release as Xf,userInfo as Of}from"os";import{basename as Rf,dirname as Yf,resolve as xf}from"path";function L(f,E={}){let g={},$=[],B=[],w=f.split(`
3
+ `);for(let D of w){let I=D.trim();if(!I||I.startsWith("#"))continue;if(I.startsWith("DOTENV_PUBLIC_KEY=")){let X=I.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(X&&X[1]!==void 0)g.DOTENV_PUBLIC_KEY=X[1];continue}let T=I.match(/^([^=]+)=(.*)$/);if(!T||T[1]===void 0||T[2]===void 0)continue;let A=T[1].trim(),_=T[2].trim();if(_.startsWith('"')&&_.endsWith('"')||_.startsWith("'")&&_.endsWith("'")){if(_=_.slice(1,-1),_.includes("\\n"))_=_.replace(/\\n/g,`
4
+ `)}if(_.startsWith("encrypted:")||_.startsWith("enc:")){if(!E.privateKey){B.push(A);continue}try{let X=_.startsWith("enc:")?`encrypted:${_.slice(4)}`:_;_=M(X,E.privateKey)}catch(X){$.push(`Failed to decrypt ${A}: ${X instanceof Error?X.message:"Unknown error"}`)}}_=Hf(_,{...E.processEnv||process.env,...g}),_=Gf(_),g[A]=_}return{parsed:g,errors:$,skippedEncrypted:B}}function Hf(f,E){return f.replace(/\$\{([^}]+)\}/g,(g,$)=>{let B=$.match(/^([^:\-+]+)(:-|-)(.+)$/);if(B){let[,D,I,T]=B,A=E[D];if(I===":-")return A||T;else return A!==void 0?A:T}let w=$.match(/^([^:\-+]+)(:?\+)(.+)$/);if(w){let[,D,I,T]=w,A=E[D];if(I===":+")return A?T:"";else return A!==void 0?T:""}return E[$]||""})}var Wf=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function hf(f){let E=[],g="",$=null,B=!1;for(let w of f.trim()){if(B){g+=w,B=!1;continue}if(w==="\\"&&$!=="'"){B=!0;continue}if($){if(w===$)$=null;else g+=w;continue}if(w==='"'||w==="'"){$=w;continue}if(/\s/.test(w)){if(g)E.push(g),g="";continue}g+=w}if(B||$)throw Error("Command substitution contains an unterminated escape or quote");if(g)E.push(g);return E}function jf(f){let[E,...g]=f,$=g.some((B)=>B.startsWith("-"));if(E==="echo"&&!$)return g.join(" ");if(E==="printf"&&g.length===1&&!g[0]?.includes("%"))return g[0];if(E==="hostname"&&g.length===0)return Df();if(E==="whoami"&&g.length===0)return Of().username;if(E==="pwd"&&g.length===0)return process.cwd();if(E==="basename"&&g.length===1)return Rf(g[0]??"");if(E==="dirname"&&g.length===1)return Yf(g[0]??"");if(E==="cat"&&g.length>0&&!$)return g.map((B)=>Tf(xf(process.cwd(),B),"utf8")).join("");if(E==="uname"){let B=g[0]??"-s";if(g.length<=1&&B==="-m")return If();if(g.length<=1&&B==="-r")return Xf();if(g.length<=1&&B==="-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"}[p()]??p()}return}function Gf(f){return f.replace(/\$\(([^)]+)\)/g,(E,g)=>{try{let $=hf(g),B=$[0];if(!B||!Wf.has(B))return console.warn(`[env] Blocked command substitution for disallowed command: ${B}`),"";let w=jf($);if(w!==void 0)return w.trim();let D=_f(B,$.slice(1),{encoding:"utf8",env:process.env});if(D.status===0)return D.stdout.trim();let I=D.stderr.trim();console.warn(`[env] Command substitution failed (exit code ${D.status??"unknown"}): ${B}${I?`: ${I}`:""}`)}catch($){console.warn(`[env] Command substitution error: ${$ instanceof Error?$.message:String($)}`)}return""})}async function Sf(f,E={}){let g={},$=[],B=[];for(let w of f)try{let D=Bun.file(w);if(!D.size)continue;let I=await D.text(),{parsed:T,errors:A,skippedEncrypted:_}=L(I,E);$.push(...A),B.push(..._);for(let[X,H]of Object.entries(T)){if(!E.overload&&g[X]!==void 0)continue;g[X]=H}}catch(D){if(D?.code==="ENOENT")continue;$.push(`Failed to read ${w}: ${D instanceof Error?D.message:String(D)}`)}return{parsed:g,errors:$,skippedEncrypted:B}}import{existsSync as z,readFileSync as U,renameSync as K,rmSync as l,writeFileSync as Z}from"fs";import{basename as t,dirname as a,resolve as J}from"path";function df(f,E){if(f)return f;let g=String(E??"").trim();if(!g||g==="development"||g==="dev"||g==="local")return"";if(!/^[\w.-]+$/.test(g))return"";return`.env.${g}`}function e(f,E,g,$){let B=["#/-------------------[DOTENV_PUBLIC_KEY]--------------------/","#/ versioned X25519 encryption for .env files /","#/ [how it works](https://stacksjs.com/encryption) /","#/----------------------------------------------------------/",`${g}="${E}"`,""];for(let w of f.split(`
5
+ `)){let D=w.trim();if(!D||D.startsWith("#")){B.push(w);continue}if(D.startsWith("DOTENV_PUBLIC_KEY"))continue;let I=D.match(/^([^=]+)=(.*)$/);if(!I||I[1]===void 0||I[2]===void 0){B.push(w);continue}let T=I[1].trim(),A=I[2].trim();if(A.startsWith('"')&&A.endsWith('"')||A.startsWith("'")&&A.endsWith("'"))A=A.slice(1,-1);if((!$.key||T.includes($.key))&&(!$.excludeKey||!T.includes($.excludeKey))&&!A.startsWith("encrypted:"))A=C(A,E);B.push(`${T}="${A}"`)}return B.join(`
6
+ `)}function kf(f={}){let E=f.cwd||process.cwd(),g=J(E,f.file||".env"),$=J(E,f.keysFile||".env.keys");if(!z(g))return{success:!1,error:`File not found: ${g}`};try{let B,w;if(z($)){let _=U($,"utf-8"),{parsed:X}=L(_),x=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),W=x?`DOTENV_PUBLIC_KEY_${x}`:"DOTENV_PUBLIC_KEY",G=x?`DOTENV_PRIVATE_KEY_${x}`:"DOTENV_PRIVATE_KEY";if(B=X[W]||"",w=X[G]||"",!B||!w){let Y=q();B=Y.publicKey,w=Y.privateKey;let h=`
7
+ ${W}="${B}"
8
+ ${G}="${w}"
9
+ `;Z($,_+h,"utf-8")}}else{let _=q();B=_.publicKey,w=_.privateKey;let O=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),x=O?`DOTENV_PUBLIC_KEY_${O}`:"DOTENV_PUBLIC_KEY",W=O?`DOTENV_PRIVATE_KEY_${O}`:"DOTENV_PRIVATE_KEY",G=`# .env.keys - Keep this file secure and never commit to source control
10
+ ${x}="${B}"
11
+ ${W}="${w}"
12
+ `;Z($,G,"utf-8")}let D=U(g,"utf-8"),I=f.file?f.file.replace(/^\.env\./,"").toUpperCase():"",T=I?`DOTENV_PUBLIC_KEY_${I}`:"DOTENV_PUBLIC_KEY",A=e(D,B,T,f);if(f.stdout)return{success:!0,output:A};return Z(g,A,"utf-8"),{success:!0,output:`\u2714 encrypted (${f.file||".env"})
13
+ \u2714 key added to ${f.keysFile||".env.keys"}`}}catch(B){return{success:!1,error:`Failed to encrypt: ${B instanceof Error?B.message:"Unknown error"}`}}}function Jf(f={}){let E=f.cwd||process.cwd(),g=J(E,f.file||".env"),$=J(E,f.keysFile||".env.keys");if(!z(g))return{success:!1,error:`File not found: ${g}`};if(!z($))return{success:!1,error:`Keys file not found: ${$}`};try{let B=U($,"utf-8"),{parsed:w}=L(B),T=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),A=T?`DOTENV_PRIVATE_KEY_${T}`:"DOTENV_PRIVATE_KEY",_=w[A];if(!_)return{success:!1,error:`Private key not found: ${A}`};let H=U(g,"utf-8").split(`
14
+ `),O=[];for(let W of H){let G=W.trim();if(!G||G.startsWith("#")){O.push(W);continue}if(G.startsWith("DOTENV_PUBLIC_KEY"))continue;let Y=G.match(/^([^=]+)=(.*)$/);if(!Y||Y[1]===void 0||Y[2]===void 0){O.push(W);continue}let h=Y[1].trim(),R=Y[2].trim();if(R.startsWith('"')&&R.endsWith('"')||R.startsWith("'")&&R.endsWith("'"))R=R.slice(1,-1);let j=R.startsWith("encrypted:");if(f.key&&!h.includes(f.key))j=!1;if(j)R=M(R,_);O.push(`${h}="${R}"`)}let x=O.join(`
15
+ `);if(f.stdout)return{success:!0,output:x};return Z(g,x,"utf-8"),{success:!0,output:`\u2714 decrypted (${f.file||".env"})`}}catch(B){return{success:!1,error:`Failed to decrypt: ${B instanceof Error?B.message:"Unknown error"}`}}}function uf(f,E,g={}){let $=g.cwd||process.cwd(),B=J($,g.file||".env"),w=J($,g.keysFile||".env.keys");try{let D="";if(z(B))D=U(B,"utf-8");let I=D.split(`
16
+ `),T=!1,A,H=((g.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),O=H?`DOTENV_PUBLIC_KEY_${H}`:"DOTENV_PUBLIC_KEY",x=H?`DOTENV_PRIVATE_KEY_${H}`:"DOTENV_PRIVATE_KEY";for(let Y of I){let h=Y.trim();if(h.startsWith(`${O}=`)){let R=h.match(/^[^=]+=["']?([^"'\n]+)["']?/);if(R)A=R[1];break}}if(A){let Y=!1;if(z(w)){let h=U(w,"utf-8"),{parsed:R}=L(h);Y=Boolean(R[x])}if(!Y)A=void 0}if(!g.plain&&!A){let Y=q();A=Y.publicKey;let h="";if(z(w))h=U(w,"utf-8");h+=`
17
+ ${O}="${Y.publicKey}"
18
+ ${x}="${Y.privateKey}"
19
+ `,Z(w,h,"utf-8");for(let R=I.length-1;R>=0;R--){let j=I[R];if(j!==void 0&&j.trim().startsWith(`${O}=`))I.splice(R,1)}I.unshift(`${O}="${A}"`)}let W=E;if(!g.plain&&A)W=C(E,A);for(let Y=0;Y<I.length;Y++){let h=I[Y];if(h===void 0)continue;if(h.trim().startsWith(`${f}=`)){I[Y]=`${f}="${W}"`,T=!0;break}}if(!T)I.push(`${f}="${W}"`);let G=I.join(`
20
+ `);return Z(B,G,"utf-8"),{success:!0,output:`set ${f}${g.plain?"":" with encryption"} (${g.file||".env"})`}}catch(D){return{success:!1,error:`Failed to set: ${D instanceof Error?D.message:"Unknown error"}`}}}function mf(f,E={}){let g=E.cwd||process.cwd(),$=J(g,E.file||".env");if(!z($))return{success:!1,error:`File not found: ${$}`};try{let B,w=J(g,E.keysFile||".env.keys"),T=((E.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),A=T?`DOTENV_PRIVATE_KEY_${T}`:"DOTENV_PRIVATE_KEY";if(z(w)){let x=U(w,"utf-8"),{parsed:W}=L(x);B=W[A]}if(!B)B=process.env[A];let _=U($,"utf-8"),{parsed:X}=L(_,{privateKey:B});if(f&&!E.all){let x=X[f];if(x===void 0)return{success:!1,error:`Key not found: ${f}`};return{success:!0,output:x}}let H=E.all?{...process.env,...X}:X,O;switch(E.format){case"shell":O=Object.entries(H).map(([x,W])=>`${x}=${W}`).join(" ");break;case"eval":O=Object.entries(H).map(([x,W])=>`${x}="${W}"`).join(`
21
+ `);break;case"json":default:O=E.prettyPrint?JSON.stringify(H,null,2):JSON.stringify(H);break}return{success:!0,output:O}}catch(B){return{success:!1,error:`Failed to get: ${B instanceof Error?B.message:"Unknown error"}`}}}function nf(f,E={}){let g=E.cwd||process.cwd(),$=J(g,E.keysFile||".env.keys");if(!z($))return{success:!1,error:`Keys file not found: ${$}`};try{let B=U($,"utf-8"),{parsed:w}=L(B),T=((E.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),A=T?`DOTENV_PUBLIC_KEY_${T}`:"DOTENV_PUBLIC_KEY",_=T?`DOTENV_PRIVATE_KEY_${T}`:"DOTENV_PRIVATE_KEY";if(f){let O=w[f];if(!O)return{success:!1,error:`Key not found: ${f}`};return{success:!0,output:O}}let X={[A]:w[A],[_]:w[_]};return{success:!0,output:E.format==="shell"?`${A}=${X[A]} ${_}=${X[_]}`:JSON.stringify(X)}}catch(B){return{success:!1,error:`Failed to get keypair: ${B instanceof Error?B.message:"Unknown error"}`}}}function of(f={}){let E=Jf({file:f.file,keysFile:f.keysFile,stdout:!0,cwd:f.cwd});if(!E.success)return E;let g=f.cwd||process.cwd(),$=J(g,f.file||".env"),B=J(g,f.keysFile||".env.keys");if(E.output===void 0)return{success:!1,error:"Rotation produced no decrypted content"};let w=q(),D=U($),I=U(B),T=I.toString("utf8").split(`
22
+ `),A=f.file||".env",_=t(A).replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),X=_?`DOTENV_PUBLIC_KEY_${_}`:"DOTENV_PUBLIC_KEY",H=_?`DOTENV_PRIVATE_KEY_${_}`:"DOTENV_PRIVATE_KEY",O=!1,x=!1;for(let j=0;j<T.length;j++){let c=T[j];if(c===void 0)continue;if(c.startsWith(`${X}=`))T[j]=`${X}="${w.publicKey}"`,O=!0;else if(c.startsWith(`${H}=`))T[j]=`${H}="${w.privateKey}"`,x=!0}if(!O)T.push(`${X}="${w.publicKey}"`);if(!x)T.push(`${H}="${w.privateKey}"`);let W=`${T.join(`
23
23
  `).replace(/\n+$/,"")}
24
- `,H=a(r.output,h.publicKey,_,f),R=`${process.pid}-${Date.now()}`,O=W(p(c),`.${N(c)}.${R}.rotate`),T=W(p(E),`.${N(E)}.${R}.rotate`);try{if(J(O,H,{encoding:"utf8",mode:384}),J(T,t,{encoding:"utf8",mode:384}),f.stdout)return d(T,E),{success:!0,output:H};d(O,c);try{d(T,E)}catch(Y){throw J(c,A),Y}return{success:!0,output:`\u2714 rotated (${f.file||".env"}) to encrypted:v2`}}catch(Y){if(!G(E))J(E,x,{mode:384});return{success:!1,error:`Failed to rotate without exposing plaintext: ${Y instanceof Error?Y.message:"Unknown error"}`}}finally{l(O,{force:!0}),l(T,{force:!0})}}export{zf as setEnv,Qf as rotateKeypair,Jf as resolveEnvFile,qf as getKeypair,Zf as getEnv,Uf as encryptEnv,xf as decryptEnv};
24
+ `,G=e(E.output,w.publicKey,X,f),Y=`${process.pid}-${Date.now()}`,h=J(a($),`.${t($)}.${Y}.rotate`),R=J(a(B),`.${t(B)}.${Y}.rotate`);try{if(Z(h,G,{encoding:"utf8",mode:384}),Z(R,W,{encoding:"utf8",mode:384}),f.stdout)return K(R,B),{success:!0,output:G};K(h,$);try{K(R,B)}catch(j){throw Z($,D),j}return{success:!0,output:`\u2714 rotated (${f.file||".env"}) to encrypted:v2`}}catch(j){if(!z(B))Z(B,I,{mode:384});return{success:!1,error:`Failed to rotate without exposing plaintext: ${j instanceof Error?j.message:"Unknown error"}`}}finally{l(h,{force:!0}),l(R,{force:!0})}}export{uf as setEnv,of as rotateKeypair,df as resolveEnvFile,nf as getKeypair,mf as getEnv,kf as encryptEnv,Jf as decryptEnv};
package/dist/index.js CHANGED
@@ -1,26 +1,26 @@
1
1
  // @bun
2
- import{createCipheriv as gf,createDecipheriv as Bf,createHash as r,createPrivateKey as xf,createPublicKey as $f,diffieHellman as Af,generateKeyPairSync as _f,hkdfSync as Xf,randomBytes as t}from"crypto";var y="x25519-public:",n="x25519-private:",P="encrypted:v2:",v="encrypted:",Df=Buffer.from("stacks-env:v2","utf8"),Hf="Environment decryption failed: authentication or format error";function Of(f){if(f.length===32)return f;return r("sha256").update(f).digest()}function sf(f,g){let B=t(16),A=gf("aes-256-gcm",Of(g),B);return{ciphertext:Buffer.concat([A.update(f,"utf8"),A.final()]).toString("hex"),iv:B.toString("hex"),authTag:A.getAuthTag().toString("hex")}}function Mf(f,g,B,A){try{let $=Bf("aes-256-gcm",Of(g),Buffer.from(B,"hex"));return $.setAuthTag(Buffer.from(A,"hex")),Buffer.concat([$.update(Buffer.from(f,"hex")),$.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function z(f){return f.toString("base64url")}function C(f,g,B){if(typeof f!=="string"||f.length>0&&!/^[A-Za-z0-9_-]+$/.test(f))throw Error(`${g} is not canonical base64url`);let A=Buffer.from(f,"base64url");if(z(A)!==f)throw Error(`${g} is not canonical base64url`);if(B!==void 0&&A.length!==B)throw Error(`${g} has an invalid length`);return A}function Ef(f){if(!f.startsWith(y))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let g=$f({key:C(f.slice(y.length),"public key"),format:"der",type:"spki"});if(g.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return g}function zf(f){if(!f.startsWith(n))throw Error("Private key is not a version 2 X25519 key");let g=xf({key:C(f.slice(n.length),"private key"),format:"der",type:"pkcs8"});if(g.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return g}function Rf(f){return Buffer.from(`stacks-env:v2;${f.epk};${f.salt};${f.nonce}`,"utf8")}function F(){let{publicKey:f,privateKey:g}=_f("x25519"),B=f.export({format:"der",type:"spki"}),A=g.export({format:"der",type:"pkcs8"});return{publicKey:`${y}${z(B)}`,privateKey:`${n}${z(A)}`}}function c(f,g){let B=Ef(g),A=_f("x25519"),$=z(A.publicKey.export({format:"der",type:"spki"})),_=t(16),D=t(12),O=Af({privateKey:A.privateKey,publicKey:B}),R=Buffer.from(Xf("sha256",O,_,Df,32)),X={epk:$,salt:z(_),nonce:z(D)};try{let H=gf("aes-256-gcm",R,D);H.setAAD(Rf(X));let W=Buffer.concat([H.update(f,"utf8"),H.final()]),G={v:2,...X,ciphertext:z(W),tag:z(H.getAuthTag())};return`${P}${z(Buffer.from(JSON.stringify(G),"utf8"))}`}finally{O.fill(0),R.fill(0)}}function Vf(f){let g=C(f.slice(P.length),"envelope").toString("utf8"),B=JSON.parse(g);if(!B||typeof B!=="object"||Array.isArray(B))throw Error("envelope is not an object");let A=Object.keys(B).sort(),$=["ciphertext","epk","nonce","salt","tag","v"];if(A.length!==$.length||A.some((_,D)=>_!==$[D]))throw Error("envelope fields are invalid");if(B.v!==2)throw Error("envelope version is unsupported");for(let _ of["epk","salt","nonce","ciphertext","tag"])if(typeof B[_]!=="string")throw Error(`${_} is invalid`);return B}function Cf(f,g){try{let B=Vf(f),A=zf(g),$=$f({key:C(B.epk,"ephemeral public key"),format:"der",type:"spki"});if($.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let _=C(B.salt,"salt",16),D=C(B.nonce,"nonce",12),O=C(B.ciphertext,"ciphertext"),R=C(B.tag,"tag",16),X=Af({privateKey:A,publicKey:$}),H=Buffer.from(Xf("sha256",X,_,Df,32));try{let W=Bf("aes-256-gcm",H,D);return W.setAAD(Rf(B)),W.setAuthTag(R),Buffer.concat([W.update(O),W.final()]).toString("utf8")}finally{X.fill(0),H.fill(0)}}catch{throw Error(Hf)}}function bf(f,g){try{if(!/^[0-9a-f]{64}$/.test(g))throw Error("invalid legacy private key");let B=Buffer.from(f.slice(v.length),"base64");if(B.length<32)throw Error("invalid legacy payload");let A=r("sha256").update(Buffer.from(g,"hex")).digest(),$=r("sha256").update(A).digest();return Mf(B.subarray(32).toString("hex"),$,B.subarray(0,16).toString("hex"),B.subarray(16,32).toString("hex"))}catch{throw Error(Hf)}}function af(f){return f.startsWith(v)&&!f.startsWith(P)}function h(f,g){if(!f.startsWith(v))return f;return f.startsWith(P)?Cf(f,g):bf(f,g)}function ef(f,g,B){return c(h(f,g),B)}function fg(f){let g=f.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return g&&g[1]?g[1].toLowerCase():""}function i(f=""){return f?process.env[`DOTENV_PRIVATE_KEY_${f.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}function L(f,g={}){let B={},A=[],$=[],_=f.split(`
3
- `);for(let D of _){let O=D.trim();if(!O||O.startsWith("#"))continue;if(O.startsWith("DOTENV_PUBLIC_KEY=")){let W=O.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(W&&W[1]!==void 0)B.DOTENV_PUBLIC_KEY=W[1];continue}let R=O.match(/^([^=]+)=(.*)$/);if(!R||R[1]===void 0||R[2]===void 0)continue;let X=R[1].trim(),H=R[2].trim();if(H.startsWith('"')&&H.endsWith('"')||H.startsWith("'")&&H.endsWith("'")){if(H=H.slice(1,-1),H.includes("\\n"))H=H.replace(/\\n/g,`
4
- `)}if(H.startsWith("encrypted:")||H.startsWith("enc:")){if(!g.privateKey){$.push(X);continue}try{let W=H.startsWith("enc:")?`encrypted:${H.slice(4)}`:H;H=h(W,g.privateKey)}catch(W){A.push(`Failed to decrypt ${X}: ${W instanceof Error?W.message:"Unknown error"}`)}}H=hf(H,{...g.processEnv||process.env,...B}),H=Sf(H),B[X]=H}return{parsed:B,errors:A,skippedEncrypted:$}}function hf(f,g){return f.replace(/\$\{([^}]+)\}/g,(B,A)=>{let $=A.match(/^([^:\-+]+)(:-|-)(.+)$/);if($){let[,D,O,R]=$,X=g[D];if(O===":-")return X||R;else return X!==void 0?X:R}let _=A.match(/^([^:\-+]+)(:?\+)(.+)$/);if(_){let[,D,O,R]=_,X=g[D];if(O===":+")return X?R:"";else return X!==void 0?R:""}return g[A]||""})}var Ff=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function Sf(f){return f.replace(/\$\(([^)]+)\)/g,(g,B)=>{try{let A=B.trim().split(/\s+/),$=A[0];if(!$||!Ff.has($))return console.warn(`[env] Blocked command substitution for disallowed command: ${$}`),"";let _=Bun.spawnSync(A,{stdout:"pipe",stderr:"pipe"});if(_.exitCode===0)return new TextDecoder().decode(_.stdout).trim();console.warn(`[env] Command substitution failed (exit code ${_.exitCode}): ${$}`)}catch(A){console.warn(`[env] Command substitution error: ${A instanceof Error?A.message:String(A)}`)}return""})}async function $g(f,g={}){let B={},A=[],$=[];for(let _ of f)try{let D=Bun.file(_);if(!D.size)continue;let O=await D.text(),{parsed:R,errors:X,skippedEncrypted:H}=L(O,g);A.push(...X),$.push(...H);for(let[W,G]of Object.entries(R)){if(!g.overload&&B[W]!==void 0)continue;B[W]=G}}catch(D){if(D?.code==="ENOENT")continue;A.push(`Failed to read ${_}: ${D instanceof Error?D.message:String(D)}`)}return{parsed:B,errors:A,skippedEncrypted:$}}import{existsSync as m}from"fs";import{readFileSync as o}from"fs";import{resolve as k}from"path";function S(f){return typeof f==="string"&&(f.startsWith("encrypted:")||f.startsWith("enc:"))}function b(f){if(!f||S(f))return;let g=f.trim().toLowerCase();if(!/^[a-z0-9_-]+$/.test(g))return;if(g==="prod")return"production";if(g==="stage")return"staging";if(g==="dev")return"development";return g}var d=null,u,p;function Kf(f,g,B=".env.keys"){let A=k(g,B);if(!m(A))return;try{let{parsed:$}=L(o(A,"utf-8"));if(f){let _=$[`DOTENV_PRIVATE_KEY_${f.toUpperCase()}`];if(_)return _}return $.DOTENV_PRIVATE_KEY}catch{return}}function l(f={}){return b(f.env)||p||b("development")||b(process.env.DOTENV_ENV)||b(process.env.APP_ENV)||"development"}function Nf(f={}){let g=l(f),B=f.cwd||process.cwd();if(d===g)return u;let A=i(g);if(!A)A=process.env.DOTENV_PRIVATE_KEY;if(!A)A=Kf(g,B);return d=g,u=A,A}function Wg(){d=null,u=void 0}function Wf(f,g={}){if(!S(f))return f;let B=Nf(g);if(!B)return;try{let A=f.startsWith("enc:")?`encrypted:${f.slice(4)}`:f;return h(A,B)}catch{return}}function Tf(f={}){let{path:g=[".env"],overload:B=!1,env:A,privateKey:$,keysFile:_=".env.keys",quiet:D=!1,cwd:O=process.cwd()}=f,R=Array.isArray(g)?g:[g],X=[],H=0,W=new Set(Object.entries(process.env).filter(([,T])=>T!==void 0&&!S(T)).map(([T])=>T)),G=$;if(!G&&_){let T=k(O,_);if(m(T))try{let Y=o(T,"utf-8"),{parsed:Z}=L(Y);if(A){let U=`DOTENV_PRIVATE_KEY_${A.toUpperCase()}`;G=Z[U]}else G=Z.DOTENV_PRIVATE_KEY}catch(Y){X.push(`Failed to load keys file: ${Y instanceof Error?Y.message:"Unknown error"}`)}}if(!G)G=i(A||"");for(let T of R){let Y=k(O,T);if(!m(Y)){if(!D)X.push(`File not found: ${Y}`);continue}try{let Z=o(Y,"utf-8"),{parsed:U,errors:I,skippedEncrypted:Q}=L(Z,{privateKey:G,processEnv:process.env});if(X.push(...I),Q.length>0){for(let N of Q)if(S(process.env[N]))delete process.env[N];let w=A?`DOTENV_PRIVATE_KEY_${A.toUpperCase()}`:"DOTENV_PRIVATE_KEY",V=Q.slice(0,5).join(", "),K=Q.length>5?`, \u2026 +${Q.length-5} more`:"";console.warn(`[env] warning: skipped ${Q.length} encrypted value(s) in ${T} (${w} not set; defaults apply): ${V}${K}`)}let J=0;for(let[w,V]of Object.entries(U)){if(w==="DOTENV_PUBLIC_KEY")continue;let K=process.env[w],N=S(K)&&V!==K;if(B||!W.has(w)||N)process.env[w]=V,H++,J++}if(!D&&!process.env.__ENV_LOADED__)console.error(`[env] loaded ${J}/${Object.keys(U).length} variables from ${T}`),process.env.__ENV_LOADED__="1"}catch(Z){X.push(`Failed to load ${Y}: ${Z instanceof Error?Z.message:"Unknown error"}`)}}return{loaded:H,errors:X}}function Pf(f={}){return{name:"env-plugin",setup(g){Tf(f)}}}function Tg(f={}){let g=b(f.env)||b("development")||b(process.env.DOTENV_ENV)||b(process.env.APP_ENV)||"development",B=f.cwd||process.cwd();if(p!==g)p=g,d=null,u=void 0;let A=[],$=(O)=>{if(!A.includes(O)&&m(k(B,O)))A.push(O)};$(".env"),$(".env.local");let _=`.env.${g}`,D=`.env.${g}.local`;return $(_),$(D),Tf({...f,path:A,env:g})}var jg=Pf;import{existsSync as M,readFileSync as x,renameSync as s,rmSync as Yf,writeFileSync as E}from"fs";import{basename as a,dirname as jf,resolve as q}from"path";function Qg(f,g){if(f)return f;let B=String(g??"").trim();if(!B||B==="development"||B==="dev"||B==="local")return"";if(!/^[\w.-]+$/.test(B))return"";return`.env.${B}`}function Gf(f,g,B,A){let $=["#/-------------------[DOTENV_PUBLIC_KEY]--------------------/","#/ versioned X25519 encryption for .env files /","#/ [how it works](https://stacksjs.com/encryption) /","#/----------------------------------------------------------/",`${B}="${g}"`,""];for(let _ of f.split(`
5
- `)){let D=_.trim();if(!D||D.startsWith("#")){$.push(_);continue}if(D.startsWith("DOTENV_PUBLIC_KEY"))continue;let O=D.match(/^([^=]+)=(.*)$/);if(!O||O[1]===void 0||O[2]===void 0){$.push(_);continue}let R=O[1].trim(),X=O[2].trim();if(X.startsWith('"')&&X.endsWith('"')||X.startsWith("'")&&X.endsWith("'"))X=X.slice(1,-1);if((!A.key||R.includes(A.key))&&(!A.excludeKey||!R.includes(A.excludeKey))&&!X.startsWith("encrypted:"))X=c(X,g);$.push(`${R}="${X}"`)}return $.join(`
6
- `)}function wg(f={}){let g=f.cwd||process.cwd(),B=q(g,f.file||".env"),A=q(g,f.keysFile||".env.keys");if(!M(B))return{success:!1,error:`File not found: ${B}`};try{let $,_;if(M(A)){let H=x(A,"utf-8"),{parsed:W}=L(H),Y=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),Z=Y?`DOTENV_PUBLIC_KEY_${Y}`:"DOTENV_PUBLIC_KEY",U=Y?`DOTENV_PRIVATE_KEY_${Y}`:"DOTENV_PRIVATE_KEY";if($=W[Z]||"",_=W[U]||"",!$||!_){let I=F();$=I.publicKey,_=I.privateKey;let Q=`
2
+ import{createCipheriv as gf,createDecipheriv as Bf,createHash as r,createPrivateKey as qf,createPublicKey as $f,diffieHellman as Af,generateKeyPairSync as _f,hkdfSync as Xf,randomBytes as t}from"crypto";var y="x25519-public:",v="x25519-private:",P="encrypted:v2:",i="encrypted:",Df=Buffer.from("stacks-env:v2","utf8"),Hf="Environment decryption failed: authentication or format error";function Of(f){if(f.length===32)return f;return r("sha256").update(f).digest()}function O2(f,g){let B=t(16),A=gf("aes-256-gcm",Of(g),B);return{ciphertext:Buffer.concat([A.update(f,"utf8"),A.final()]).toString("hex"),iv:B.toString("hex"),authTag:A.getAuthTag().toString("hex")}}function zf(f,g,B,A){try{let $=Bf("aes-256-gcm",Of(g),Buffer.from(B,"hex"));return $.setAuthTag(Buffer.from(A,"hex")),Buffer.concat([$.update(Buffer.from(f,"hex")),$.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function V(f){return f.toString("base64url")}function C(f,g,B){if(typeof f!=="string"||f.length>0&&!/^[A-Za-z0-9_-]+$/.test(f))throw Error(`${g} is not canonical base64url`);let A=Buffer.from(f,"base64url");if(V(A)!==f)throw Error(`${g} is not canonical base64url`);if(B!==void 0&&A.length!==B)throw Error(`${g} has an invalid length`);return A}function Vf(f){if(!f.startsWith(y))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let g=$f({key:C(f.slice(y.length),"public key"),format:"der",type:"spki"});if(g.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return g}function xf(f){if(!f.startsWith(v))throw Error("Private key is not a version 2 X25519 key");let g=qf({key:C(f.slice(v.length),"private key"),format:"der",type:"pkcs8"});if(g.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return g}function Wf(f){return Buffer.from(`stacks-env:v2;${f.epk};${f.salt};${f.nonce}`,"utf8")}function S(){let{publicKey:f,privateKey:g}=_f("x25519"),B=f.export({format:"der",type:"spki"}),A=g.export({format:"der",type:"pkcs8"});return{publicKey:`${y}${V(B)}`,privateKey:`${v}${V(A)}`}}function c(f,g){let B=Vf(g),A=_f("x25519"),$=V(A.publicKey.export({format:"der",type:"spki"})),_=t(16),X=t(12),H=Af({privateKey:A.privateKey,publicKey:B}),W=Buffer.from(Xf("sha256",H,_,Df,32)),D={epk:$,salt:V(_),nonce:V(X)};try{let O=gf("aes-256-gcm",W,X);O.setAAD(Wf(D));let R=Buffer.concat([O.update(f,"utf8"),O.final()]),G={v:2,...D,ciphertext:V(R),tag:V(O.getAuthTag())};return`${P}${V(Buffer.from(JSON.stringify(G),"utf8"))}`}finally{H.fill(0),W.fill(0)}}function Cf(f){let g=C(f.slice(P.length),"envelope").toString("utf8"),B=JSON.parse(g);if(!B||typeof B!=="object"||Array.isArray(B))throw Error("envelope is not an object");let A=Object.keys(B).sort(),$=["ciphertext","epk","nonce","salt","tag","v"];if(A.length!==$.length||A.some((_,X)=>_!==$[X]))throw Error("envelope fields are invalid");if(B.v!==2)throw Error("envelope version is unsupported");for(let _ of["epk","salt","nonce","ciphertext","tag"])if(typeof B[_]!=="string")throw Error(`${_} is invalid`);return B}function Ff(f,g){try{let B=Cf(f),A=xf(g),$=$f({key:C(B.epk,"ephemeral public key"),format:"der",type:"spki"});if($.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let _=C(B.salt,"salt",16),X=C(B.nonce,"nonce",12),H=C(B.ciphertext,"ciphertext"),W=C(B.tag,"tag",16),D=Af({privateKey:A,publicKey:$}),O=Buffer.from(Xf("sha256",D,_,Df,32));try{let R=Bf("aes-256-gcm",O,X);return R.setAAD(Wf(B)),R.setAuthTag(W),Buffer.concat([R.update(H),R.final()]).toString("utf8")}finally{D.fill(0),O.fill(0)}}catch{throw Error(Hf)}}function bf(f,g){try{if(!/^[0-9a-f]{64}$/.test(g))throw Error("invalid legacy private key");let B=Buffer.from(f.slice(i.length),"base64");if(B.length<32)throw Error("invalid legacy payload");let A=r("sha256").update(Buffer.from(g,"hex")).digest(),$=r("sha256").update(A).digest();return zf(B.subarray(32).toString("hex"),$,B.subarray(0,16).toString("hex"),B.subarray(16,32).toString("hex"))}catch{throw Error(Hf)}}function W2(f){return f.startsWith(i)&&!f.startsWith(P)}function b(f,g){if(!f.startsWith(i))return f;return f.startsWith(P)?Ff(f,g):bf(f,g)}function R2(f,g,B){return c(b(f,g),B)}function T2(f){let g=f.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return g&&g[1]?g[1].toLowerCase():""}function n(f=""){return f?process.env[`DOTENV_PRIVATE_KEY_${f.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}import{spawnSync as Sf}from"child_process";import{readFileSync as hf}from"fs";import{arch as Kf,hostname as Nf,platform as Rf,release as Pf,userInfo as cf}from"os";import{basename as kf,dirname as mf,resolve as df}from"path";function M(f,g={}){let B={},A=[],$=[],_=f.split(`
3
+ `);for(let X of _){let H=X.trim();if(!H||H.startsWith("#"))continue;if(H.startsWith("DOTENV_PUBLIC_KEY=")){let R=H.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(R&&R[1]!==void 0)B.DOTENV_PUBLIC_KEY=R[1];continue}let W=H.match(/^([^=]+)=(.*)$/);if(!W||W[1]===void 0||W[2]===void 0)continue;let D=W[1].trim(),O=W[2].trim();if(O.startsWith('"')&&O.endsWith('"')||O.startsWith("'")&&O.endsWith("'")){if(O=O.slice(1,-1),O.includes("\\n"))O=O.replace(/\\n/g,`
4
+ `)}if(O.startsWith("encrypted:")||O.startsWith("enc:")){if(!g.privateKey){$.push(D);continue}try{let R=O.startsWith("enc:")?`encrypted:${O.slice(4)}`:O;O=b(R,g.privateKey)}catch(R){A.push(`Failed to decrypt ${D}: ${R instanceof Error?R.message:"Unknown error"}`)}}O=uf(O,{...g.processEnv||process.env,...B}),O=vf(O),B[D]=O}return{parsed:B,errors:A,skippedEncrypted:$}}function uf(f,g){return f.replace(/\$\{([^}]+)\}/g,(B,A)=>{let $=A.match(/^([^:\-+]+)(:-|-)(.+)$/);if($){let[,X,H,W]=$,D=g[X];if(H===":-")return D||W;else return D!==void 0?D:W}let _=A.match(/^([^:\-+]+)(:?\+)(.+)$/);if(_){let[,X,H,W]=_,D=g[X];if(H===":+")return D?W:"";else return D!==void 0?W:""}return g[A]||""})}var rf=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function tf(f){let g=[],B="",A=null,$=!1;for(let _ of f.trim()){if($){B+=_,$=!1;continue}if(_==="\\"&&A!=="'"){$=!0;continue}if(A){if(_===A)A=null;else B+=_;continue}if(_==='"'||_==="'"){A=_;continue}if(/\s/.test(_)){if(B)g.push(B),B="";continue}B+=_}if($||A)throw Error("Command substitution contains an unterminated escape or quote");if(B)g.push(B);return g}function yf(f){let[g,...B]=f,A=B.some(($)=>$.startsWith("-"));if(g==="echo"&&!A)return B.join(" ");if(g==="printf"&&B.length===1&&!B[0]?.includes("%"))return B[0];if(g==="hostname"&&B.length===0)return Nf();if(g==="whoami"&&B.length===0)return cf().username;if(g==="pwd"&&B.length===0)return process.cwd();if(g==="basename"&&B.length===1)return kf(B[0]??"");if(g==="dirname"&&B.length===1)return mf(B[0]??"");if(g==="cat"&&B.length>0&&!A)return B.map(($)=>hf(df(process.cwd(),$),"utf8")).join("");if(g==="uname"){let $=B[0]??"-s";if(B.length<=1&&$==="-m")return Kf();if(B.length<=1&&$==="-r")return Pf();if(B.length<=1&&$==="-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"}[Rf()]??Rf()}return}function vf(f){return f.replace(/\$\(([^)]+)\)/g,(g,B)=>{try{let A=tf(B),$=A[0];if(!$||!rf.has($))return console.warn(`[env] Blocked command substitution for disallowed command: ${$}`),"";let _=yf(A);if(_!==void 0)return _.trim();let X=Sf($,A.slice(1),{encoding:"utf8",env:process.env});if(X.status===0)return X.stdout.trim();let H=X.stderr.trim();console.warn(`[env] Command substitution failed (exit code ${X.status??"unknown"}): ${$}${H?`: ${H}`:""}`)}catch(A){console.warn(`[env] Command substitution error: ${A instanceof Error?A.message:String(A)}`)}return""})}async function I2(f,g={}){let B={},A=[],$=[];for(let _ of f)try{let X=Bun.file(_);if(!X.size)continue;let H=await X.text(),{parsed:W,errors:D,skippedEncrypted:O}=M(H,g);A.push(...D),$.push(...O);for(let[R,G]of Object.entries(W)){if(!g.overload&&B[R]!==void 0)continue;B[R]=G}}catch(X){if(X?.code==="ENOENT")continue;A.push(`Failed to read ${_}: ${X instanceof Error?X.message:String(X)}`)}return{parsed:B,errors:A,skippedEncrypted:$}}import{existsSync as k}from"fs";import{readFileSync as o}from"fs";import{resolve as m}from"path";function h(f){return typeof f==="string"&&(f.startsWith("encrypted:")||f.startsWith("enc:"))}function F(f){if(!f||h(f))return;let g=f.trim().toLowerCase();if(!/^[a-z0-9_-]+$/.test(g))return;if(g==="prod")return"production";if(g==="stage")return"staging";if(g==="dev")return"development";return g}var d=null,u,p;function nf(f,g,B=".env.keys"){let A=m(g,B);if(!k(A))return;try{let{parsed:$}=M(o(A,"utf-8"));if(f){let _=$[`DOTENV_PRIVATE_KEY_${f.toUpperCase()}`];if(_)return _}return $.DOTENV_PRIVATE_KEY}catch{return}}function l(f={}){return F(f.env)||p||F("development")||F(process.env.DOTENV_ENV)||F(process.env.APP_ENV)||"development"}function of(f={}){let g=l(f),B=f.cwd||process.cwd();if(d===g)return u;let A=n(g);if(!A)A=process.env.DOTENV_PRIVATE_KEY;if(!A)A=nf(g,B);return d=g,u=A,A}function V2(){d=null,u=void 0}function Tf(f,g={}){if(!h(f))return f;let B=of(g);if(!B)return;try{let A=f.startsWith("enc:")?`encrypted:${f.slice(4)}`:f;return b(A,B)}catch{return}}function Yf(f={}){let{path:g=[".env"],overload:B=!1,env:A,privateKey:$,keysFile:_=".env.keys",quiet:X=!1,cwd:H=process.cwd()}=f,W=Array.isArray(g)?g:[g],D=[],O=0,R=new Set(Object.entries(process.env).filter(([,T])=>T!==void 0&&!h(T)).map(([T])=>T)),G=$;if(!G&&_){let T=m(H,_);if(k(T))try{let Y=o(T,"utf-8"),{parsed:Z}=M(Y);if(A){let U=`DOTENV_PRIVATE_KEY_${A.toUpperCase()}`;G=Z[U]}else G=Z.DOTENV_PRIVATE_KEY}catch(Y){D.push(`Failed to load keys file: ${Y instanceof Error?Y.message:"Unknown error"}`)}}if(!G)G=n(A||"");for(let T of W){let Y=m(H,T);if(!k(Y)){if(!X)D.push(`File not found: ${Y}`);continue}try{let Z=o(Y,"utf-8"),{parsed:U,errors:Q,skippedEncrypted:I}=M(Z,{privateKey:G,processEnv:process.env});if(D.push(...Q),I.length>0){for(let N of I)if(h(process.env[N]))delete process.env[N];let w=A?`DOTENV_PRIVATE_KEY_${A.toUpperCase()}`:"DOTENV_PRIVATE_KEY",x=I.slice(0,5).join(", "),K=I.length>5?`, \u2026 +${I.length-5} more`:"";console.warn(`[env] warning: skipped ${I.length} encrypted value(s) in ${T} (${w} not set; defaults apply): ${x}${K}`)}let J=0;for(let[w,x]of Object.entries(U)){if(w==="DOTENV_PUBLIC_KEY")continue;let K=process.env[w],N=h(K)&&x!==K;if(B||!R.has(w)||N)process.env[w]=x,O++,J++}if(!X&&!process.env.__ENV_LOADED__)console.error(`[env] loaded ${J}/${Object.keys(U).length} variables from ${T}`),process.env.__ENV_LOADED__="1"}catch(Z){D.push(`Failed to load ${Y}: ${Z instanceof Error?Z.message:"Unknown error"}`)}}return{loaded:O,errors:D}}function pf(f={}){return{name:"env-plugin",setup(g){Yf(f)}}}function x2(f={}){let g=F(f.env)||F("development")||F(process.env.DOTENV_ENV)||F(process.env.APP_ENV)||"development",B=f.cwd||process.cwd();if(p!==g)p=g,d=null,u=void 0;let A=[],$=(H)=>{if(!A.includes(H)&&k(m(B,H)))A.push(H)};$(".env"),$(".env.local");let _=`.env.${g}`,X=`.env.${g}.local`;return $(_),$(X),Yf({...f,path:A,env:g})}var F2=pf;import{existsSync as q,readFileSync as E,renameSync as s,rmSync as jf,writeFileSync as z}from"fs";import{basename as a,dirname as Gf,resolve as L}from"path";function N2(f,g){if(f)return f;let B=String(g??"").trim();if(!B||B==="development"||B==="dev"||B==="local")return"";if(!/^[\w.-]+$/.test(B))return"";return`.env.${B}`}function Jf(f,g,B,A){let $=["#/-------------------[DOTENV_PUBLIC_KEY]--------------------/","#/ versioned X25519 encryption for .env files /","#/ [how it works](https://stacksjs.com/encryption) /","#/----------------------------------------------------------/",`${B}="${g}"`,""];for(let _ of f.split(`
5
+ `)){let X=_.trim();if(!X||X.startsWith("#")){$.push(_);continue}if(X.startsWith("DOTENV_PUBLIC_KEY"))continue;let H=X.match(/^([^=]+)=(.*)$/);if(!H||H[1]===void 0||H[2]===void 0){$.push(_);continue}let W=H[1].trim(),D=H[2].trim();if(D.startsWith('"')&&D.endsWith('"')||D.startsWith("'")&&D.endsWith("'"))D=D.slice(1,-1);if((!A.key||W.includes(A.key))&&(!A.excludeKey||!W.includes(A.excludeKey))&&!D.startsWith("encrypted:"))D=c(D,g);$.push(`${W}="${D}"`)}return $.join(`
6
+ `)}function P2(f={}){let g=f.cwd||process.cwd(),B=L(g,f.file||".env"),A=L(g,f.keysFile||".env.keys");if(!q(B))return{success:!1,error:`File not found: ${B}`};try{let $,_;if(q(A)){let O=E(A,"utf-8"),{parsed:R}=M(O),Y=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),Z=Y?`DOTENV_PUBLIC_KEY_${Y}`:"DOTENV_PUBLIC_KEY",U=Y?`DOTENV_PRIVATE_KEY_${Y}`:"DOTENV_PRIVATE_KEY";if($=R[Z]||"",_=R[U]||"",!$||!_){let Q=S();$=Q.publicKey,_=Q.privateKey;let I=`
7
7
  ${Z}="${$}"
8
8
  ${U}="${_}"
9
- `;E(A,H+Q,"utf-8")}}else{let H=F();$=H.publicKey,_=H.privateKey;let T=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),Y=T?`DOTENV_PUBLIC_KEY_${T}`:"DOTENV_PUBLIC_KEY",Z=T?`DOTENV_PRIVATE_KEY_${T}`:"DOTENV_PRIVATE_KEY",U=`# .env.keys - Keep this file secure and never commit to source control
9
+ `;z(A,O+I,"utf-8")}}else{let O=S();$=O.publicKey,_=O.privateKey;let T=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),Y=T?`DOTENV_PUBLIC_KEY_${T}`:"DOTENV_PUBLIC_KEY",Z=T?`DOTENV_PRIVATE_KEY_${T}`:"DOTENV_PRIVATE_KEY",U=`# .env.keys - Keep this file secure and never commit to source control
10
10
  ${Y}="${$}"
11
11
  ${Z}="${_}"
12
- `;E(A,U,"utf-8")}let D=x(B,"utf-8"),O=f.file?f.file.replace(/^\.env\./,"").toUpperCase():"",R=O?`DOTENV_PUBLIC_KEY_${O}`:"DOTENV_PUBLIC_KEY",X=Gf(D,$,R,f);if(f.stdout)return{success:!0,output:X};return E(B,X,"utf-8"),{success:!0,output:`\u2714 encrypted (${f.file||".env"})
13
- \u2714 key added to ${f.keysFile||".env.keys"}`}}catch($){return{success:!1,error:`Failed to encrypt: ${$ instanceof Error?$.message:"Unknown error"}`}}}function cf(f={}){let g=f.cwd||process.cwd(),B=q(g,f.file||".env"),A=q(g,f.keysFile||".env.keys");if(!M(B))return{success:!1,error:`File not found: ${B}`};if(!M(A))return{success:!1,error:`Keys file not found: ${A}`};try{let $=x(A,"utf-8"),{parsed:_}=L($),R=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),X=R?`DOTENV_PRIVATE_KEY_${R}`:"DOTENV_PRIVATE_KEY",H=_[X];if(!H)return{success:!1,error:`Private key not found: ${X}`};let G=x(B,"utf-8").split(`
14
- `),T=[];for(let Z of G){let U=Z.trim();if(!U||U.startsWith("#")){T.push(Z);continue}if(U.startsWith("DOTENV_PUBLIC_KEY"))continue;let I=U.match(/^([^=]+)=(.*)$/);if(!I||I[1]===void 0||I[2]===void 0){T.push(Z);continue}let Q=I[1].trim(),J=I[2].trim();if(J.startsWith('"')&&J.endsWith('"')||J.startsWith("'")&&J.endsWith("'"))J=J.slice(1,-1);let w=J.startsWith("encrypted:");if(f.key&&!Q.includes(f.key))w=!1;if(w)J=h(J,H);T.push(`${Q}="${J}"`)}let Y=T.join(`
15
- `);if(f.stdout)return{success:!0,output:Y};return E(B,Y,"utf-8"),{success:!0,output:`\u2714 decrypted (${f.file||".env"})`}}catch($){return{success:!1,error:`Failed to decrypt: ${$ instanceof Error?$.message:"Unknown error"}`}}}function Ug(f,g,B={}){let A=B.cwd||process.cwd(),$=q(A,B.file||".env"),_=q(A,B.keysFile||".env.keys");try{let D="";if(M($))D=x($,"utf-8");let O=D.split(`
16
- `),R=!1,X,G=((B.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),T=G?`DOTENV_PUBLIC_KEY_${G}`:"DOTENV_PUBLIC_KEY",Y=G?`DOTENV_PRIVATE_KEY_${G}`:"DOTENV_PRIVATE_KEY";for(let I of O){let Q=I.trim();if(Q.startsWith(`${T}=`)){let J=Q.match(/^[^=]+=["']?([^"'\n]+)["']?/);if(J)X=J[1];break}}if(X){let I=!1;if(M(_)){let Q=x(_,"utf-8"),{parsed:J}=L(Q);I=Boolean(J[Y])}if(!I)X=void 0}if(!B.plain&&!X){let I=F();X=I.publicKey;let Q="";if(M(_))Q=x(_,"utf-8");Q+=`
17
- ${T}="${I.publicKey}"
18
- ${Y}="${I.privateKey}"
19
- `,E(_,Q,"utf-8");for(let J=O.length-1;J>=0;J--){let w=O[J];if(w!==void 0&&w.trim().startsWith(`${T}=`))O.splice(J,1)}O.unshift(`${T}="${X}"`)}let Z=g;if(!B.plain&&X)Z=c(g,X);for(let I=0;I<O.length;I++){let Q=O[I];if(Q===void 0)continue;if(Q.trim().startsWith(`${f}=`)){O[I]=`${f}="${Z}"`,R=!0;break}}if(!R)O.push(`${f}="${Z}"`);let U=O.join(`
20
- `);return E($,U,"utf-8"),{success:!0,output:`set ${f}${B.plain?"":" with encryption"} (${B.file||".env"})`}}catch(D){return{success:!1,error:`Failed to set: ${D instanceof Error?D.message:"Unknown error"}`}}}function qg(f,g={}){let B=g.cwd||process.cwd(),A=q(B,g.file||".env");if(!M(A))return{success:!1,error:`File not found: ${A}`};try{let $,_=q(B,g.keysFile||".env.keys"),R=((g.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),X=R?`DOTENV_PRIVATE_KEY_${R}`:"DOTENV_PRIVATE_KEY";if(M(_)){let Y=x(_,"utf-8"),{parsed:Z}=L(Y);$=Z[X]}if(!$)$=process.env[X];let H=x(A,"utf-8"),{parsed:W}=L(H,{privateKey:$});if(f&&!g.all){let Y=W[f];if(Y===void 0)return{success:!1,error:`Key not found: ${f}`};return{success:!0,output:Y}}let G=g.all?{...process.env,...W}:W,T;switch(g.format){case"shell":T=Object.entries(G).map(([Y,Z])=>`${Y}=${Z}`).join(" ");break;case"eval":T=Object.entries(G).map(([Y,Z])=>`${Y}="${Z}"`).join(`
21
- `);break;case"json":default:T=g.prettyPrint?JSON.stringify(G,null,2):JSON.stringify(G);break}return{success:!0,output:T}}catch($){return{success:!1,error:`Failed to get: ${$ instanceof Error?$.message:"Unknown error"}`}}}function Lg(f,g={}){let B=g.cwd||process.cwd(),A=q(B,g.keysFile||".env.keys");if(!M(A))return{success:!1,error:`Keys file not found: ${A}`};try{let $=x(A,"utf-8"),{parsed:_}=L($),R=((g.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),X=R?`DOTENV_PUBLIC_KEY_${R}`:"DOTENV_PUBLIC_KEY",H=R?`DOTENV_PRIVATE_KEY_${R}`:"DOTENV_PRIVATE_KEY";if(f){let T=_[f];if(!T)return{success:!1,error:`Key not found: ${f}`};return{success:!0,output:T}}let W={[X]:_[X],[H]:_[H]};return{success:!0,output:g.format==="shell"?`${X}=${W[X]} ${H}=${W[H]}`:JSON.stringify(W)}}catch($){return{success:!1,error:`Failed to get keypair: ${$ instanceof Error?$.message:"Unknown error"}`}}}function xg(f={}){let g=cf({file:f.file,keysFile:f.keysFile,stdout:!0,cwd:f.cwd});if(!g.success)return g;let B=f.cwd||process.cwd(),A=q(B,f.file||".env"),$=q(B,f.keysFile||".env.keys");if(g.output===void 0)return{success:!1,error:"Rotation produced no decrypted content"};let _=F(),D=x(A),O=x($),R=O.toString("utf8").split(`
22
- `),X=f.file||".env",H=a(X).replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),W=H?`DOTENV_PUBLIC_KEY_${H}`:"DOTENV_PUBLIC_KEY",G=H?`DOTENV_PRIVATE_KEY_${H}`:"DOTENV_PRIVATE_KEY",T=!1,Y=!1;for(let w=0;w<R.length;w++){let V=R[w];if(V===void 0)continue;if(V.startsWith(`${W}=`))R[w]=`${W}="${_.publicKey}"`,T=!0;else if(V.startsWith(`${G}=`))R[w]=`${G}="${_.privateKey}"`,Y=!0}if(!T)R.push(`${W}="${_.publicKey}"`);if(!Y)R.push(`${G}="${_.privateKey}"`);let Z=`${R.join(`
12
+ `;z(A,U,"utf-8")}let X=E(B,"utf-8"),H=f.file?f.file.replace(/^\.env\./,"").toUpperCase():"",W=H?`DOTENV_PUBLIC_KEY_${H}`:"DOTENV_PUBLIC_KEY",D=Jf(X,$,W,f);if(f.stdout)return{success:!0,output:D};return z(B,D,"utf-8"),{success:!0,output:`\u2714 encrypted (${f.file||".env"})
13
+ \u2714 key added to ${f.keysFile||".env.keys"}`}}catch($){return{success:!1,error:`Failed to encrypt: ${$ instanceof Error?$.message:"Unknown error"}`}}}function lf(f={}){let g=f.cwd||process.cwd(),B=L(g,f.file||".env"),A=L(g,f.keysFile||".env.keys");if(!q(B))return{success:!1,error:`File not found: ${B}`};if(!q(A))return{success:!1,error:`Keys file not found: ${A}`};try{let $=E(A,"utf-8"),{parsed:_}=M($),W=((f.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),D=W?`DOTENV_PRIVATE_KEY_${W}`:"DOTENV_PRIVATE_KEY",O=_[D];if(!O)return{success:!1,error:`Private key not found: ${D}`};let G=E(B,"utf-8").split(`
14
+ `),T=[];for(let Z of G){let U=Z.trim();if(!U||U.startsWith("#")){T.push(Z);continue}if(U.startsWith("DOTENV_PUBLIC_KEY"))continue;let Q=U.match(/^([^=]+)=(.*)$/);if(!Q||Q[1]===void 0||Q[2]===void 0){T.push(Z);continue}let I=Q[1].trim(),J=Q[2].trim();if(J.startsWith('"')&&J.endsWith('"')||J.startsWith("'")&&J.endsWith("'"))J=J.slice(1,-1);let w=J.startsWith("encrypted:");if(f.key&&!I.includes(f.key))w=!1;if(w)J=b(J,O);T.push(`${I}="${J}"`)}let Y=T.join(`
15
+ `);if(f.stdout)return{success:!0,output:Y};return z(B,Y,"utf-8"),{success:!0,output:`\u2714 decrypted (${f.file||".env"})`}}catch($){return{success:!1,error:`Failed to decrypt: ${$ instanceof Error?$.message:"Unknown error"}`}}}function c2(f,g,B={}){let A=B.cwd||process.cwd(),$=L(A,B.file||".env"),_=L(A,B.keysFile||".env.keys");try{let X="";if(q($))X=E($,"utf-8");let H=X.split(`
16
+ `),W=!1,D,G=((B.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),T=G?`DOTENV_PUBLIC_KEY_${G}`:"DOTENV_PUBLIC_KEY",Y=G?`DOTENV_PRIVATE_KEY_${G}`:"DOTENV_PRIVATE_KEY";for(let Q of H){let I=Q.trim();if(I.startsWith(`${T}=`)){let J=I.match(/^[^=]+=["']?([^"'\n]+)["']?/);if(J)D=J[1];break}}if(D){let Q=!1;if(q(_)){let I=E(_,"utf-8"),{parsed:J}=M(I);Q=Boolean(J[Y])}if(!Q)D=void 0}if(!B.plain&&!D){let Q=S();D=Q.publicKey;let I="";if(q(_))I=E(_,"utf-8");I+=`
17
+ ${T}="${Q.publicKey}"
18
+ ${Y}="${Q.privateKey}"
19
+ `,z(_,I,"utf-8");for(let J=H.length-1;J>=0;J--){let w=H[J];if(w!==void 0&&w.trim().startsWith(`${T}=`))H.splice(J,1)}H.unshift(`${T}="${D}"`)}let Z=g;if(!B.plain&&D)Z=c(g,D);for(let Q=0;Q<H.length;Q++){let I=H[Q];if(I===void 0)continue;if(I.trim().startsWith(`${f}=`)){H[Q]=`${f}="${Z}"`,W=!0;break}}if(!W)H.push(`${f}="${Z}"`);let U=H.join(`
20
+ `);return z($,U,"utf-8"),{success:!0,output:`set ${f}${B.plain?"":" with encryption"} (${B.file||".env"})`}}catch(X){return{success:!1,error:`Failed to set: ${X instanceof Error?X.message:"Unknown error"}`}}}function k2(f,g={}){let B=g.cwd||process.cwd(),A=L(B,g.file||".env");if(!q(A))return{success:!1,error:`File not found: ${A}`};try{let $,_=L(B,g.keysFile||".env.keys"),W=((g.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),D=W?`DOTENV_PRIVATE_KEY_${W}`:"DOTENV_PRIVATE_KEY";if(q(_)){let Y=E(_,"utf-8"),{parsed:Z}=M(Y);$=Z[D]}if(!$)$=process.env[D];let O=E(A,"utf-8"),{parsed:R}=M(O,{privateKey:$});if(f&&!g.all){let Y=R[f];if(Y===void 0)return{success:!1,error:`Key not found: ${f}`};return{success:!0,output:Y}}let G=g.all?{...process.env,...R}:R,T;switch(g.format){case"shell":T=Object.entries(G).map(([Y,Z])=>`${Y}=${Z}`).join(" ");break;case"eval":T=Object.entries(G).map(([Y,Z])=>`${Y}="${Z}"`).join(`
21
+ `);break;case"json":default:T=g.prettyPrint?JSON.stringify(G,null,2):JSON.stringify(G);break}return{success:!0,output:T}}catch($){return{success:!1,error:`Failed to get: ${$ instanceof Error?$.message:"Unknown error"}`}}}function m2(f,g={}){let B=g.cwd||process.cwd(),A=L(B,g.keysFile||".env.keys");if(!q(A))return{success:!1,error:`Keys file not found: ${A}`};try{let $=E(A,"utf-8"),{parsed:_}=M($),W=((g.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),D=W?`DOTENV_PUBLIC_KEY_${W}`:"DOTENV_PUBLIC_KEY",O=W?`DOTENV_PRIVATE_KEY_${W}`:"DOTENV_PRIVATE_KEY";if(f){let T=_[f];if(!T)return{success:!1,error:`Key not found: ${f}`};return{success:!0,output:T}}let R={[D]:_[D],[O]:_[O]};return{success:!0,output:g.format==="shell"?`${D}=${R[D]} ${O}=${R[O]}`:JSON.stringify(R)}}catch($){return{success:!1,error:`Failed to get keypair: ${$ instanceof Error?$.message:"Unknown error"}`}}}function d2(f={}){let g=lf({file:f.file,keysFile:f.keysFile,stdout:!0,cwd:f.cwd});if(!g.success)return g;let B=f.cwd||process.cwd(),A=L(B,f.file||".env"),$=L(B,f.keysFile||".env.keys");if(g.output===void 0)return{success:!1,error:"Rotation produced no decrypted content"};let _=S(),X=E(A),H=E($),W=H.toString("utf8").split(`
22
+ `),D=f.file||".env",O=a(D).replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),R=O?`DOTENV_PUBLIC_KEY_${O}`:"DOTENV_PUBLIC_KEY",G=O?`DOTENV_PRIVATE_KEY_${O}`:"DOTENV_PRIVATE_KEY",T=!1,Y=!1;for(let w=0;w<W.length;w++){let x=W[w];if(x===void 0)continue;if(x.startsWith(`${R}=`))W[w]=`${R}="${_.publicKey}"`,T=!0;else if(x.startsWith(`${G}=`))W[w]=`${G}="${_.privateKey}"`,Y=!0}if(!T)W.push(`${R}="${_.publicKey}"`);if(!Y)W.push(`${G}="${_.privateKey}"`);let Z=`${W.join(`
23
23
  `).replace(/\n+$/,"")}
24
- `,U=Gf(g.output,_.publicKey,W,f),I=`${process.pid}-${Date.now()}`,Q=q(jf(A),`.${a(A)}.${I}.rotate`),J=q(jf($),`.${a($)}.${I}.rotate`);try{if(E(Q,U,{encoding:"utf8",mode:384}),E(J,Z,{encoding:"utf8",mode:384}),f.stdout)return s(J,$),{success:!0,output:U};s(Q,A);try{s(J,$)}catch(w){throw E(A,D),w}return{success:!0,output:`\u2714 rotated (${f.file||".env"}) to encrypted:v2`}}catch(w){if(!M($))E($,O,{mode:384});return{success:!1,error:`Failed to rotate without exposing plaintext: ${w instanceof Error?w.message:"Unknown error"}`}}finally{Yf(Q,{force:!0}),Yf(J,{force:!0})}}import j from"process";import{platform as mf}from"os";var Jf=typeof Bun<"u",Zf=typeof j<"u"&&j.versions?.node!==void 0,kf=Jf?"bun":Zf?"node":"unknown",Vg={name:kf,version:Jf?Bun.version:Zf?j.version:void 0},ff=mf(),Cg=ff==="win32",bg=ff==="darwin",hg=ff==="linux",If=Boolean(j.stdout?.isTTY),Fg=typeof globalThis.window<"u",df=Boolean(j.env.CI||j.env.CONTINUOUS_INTEGRATION||j.env.BUILD_NUMBER||j.env.RUN_ID),Sg=Boolean(j.env.DEBUG||j.env.VERBOSE||j.argv.includes("--debug")||j.argv.includes("--verbose")),uf=df||!If,Kg=Boolean(!uf&&(If||j.env.COLORTERM||j.env.FORCE_COLOR||j.env.TERM&&j.env.TERM!=="dumb")),e={github:{name:"GitHub Actions",detected:Boolean(j.env.GITHUB_ACTIONS)},gitlab:{name:"GitLab CI",detected:Boolean(j.env.GITLAB_CI)},circle:{name:"CircleCI",detected:Boolean(j.env.CIRCLECI)},travis:{name:"Travis CI",detected:Boolean(j.env.TRAVIS)},jenkins:{name:"Jenkins",detected:Boolean(j.env.JENKINS_URL)},vercel:{name:"Vercel",detected:Boolean(j.env.VERCEL)},netlify:{name:"Netlify",detected:Boolean(j.env.NETLIFY)},heroku:{name:"Heroku",detected:Boolean(j.env.DYNO)},aws:{name:"AWS",detected:Boolean(j.env.AWS_REGION||j.env.AWS_LAMBDA_FUNCTION_NAME)},azure:{name:"Azure",detected:Boolean(j.env.AZURE_HTTP_USER_AGENT)},cloudflare:{name:"Cloudflare",detected:Boolean(j.env.CF_PAGES)},railway:{name:"Railway",detected:Boolean(j.env.RAILWAY_ENVIRONMENT)},render:{name:"Render",detected:Boolean(j.env.RENDER)}},rf=Object.keys(e).find((f)=>{let g=e[f];return g!==void 0&&g.detected})||"unknown",Ng=e[rf]||{name:"Unknown",detected:!1};import yf from"process";import{projectPath as nf}from"@stacksjs/path";import Uf from"fs";var Qf={APP_ENV:["local","dev","development","staging","prod","production"],DB_CONNECTION:["mysql","sqlite","postgres","dynamodb"],DB_MIGRATE_FRESH:["allow","confirm","disabled"],MAIL_MAILER:["smtp","mailgun","ses","log","sendgrid","mailtrap"],SEARCH_ENGINE_DRIVER:["opensearch","meilisearch","algolia","typesense"],FRONTEND_APP_ENV:["development","staging","production"]};function wf(f){return`${f.replace(/[^a-z0-9]/gi,"").toUpperCase()}_`}function tf(f,g={}){let B=g.self?wf(g.self):void 0,A=(g.tenants??[]).filter((D)=>typeof D==="string"&&D.trim().length>0).map((D)=>({slug:D,prefix:wf(D)})).filter(({prefix:D})=>D!==B).sort((D,O)=>O.prefix.length-D.prefix.length),$={},_={};for(let[D,O]of Object.entries(f)){let R=A.find(({prefix:X})=>D.startsWith(X));if(R){(_[R.slug]??={})[D]=O;continue}$[D]=O}return{own:$,foreign:_}}function mg(f,g={}){return tf(f,g).own}function kg(f){return Object.entries(f.foreign).map(([g,B])=>({tenant:g,keys:Object.keys(B).sort()})).sort((g,B)=>g.tenant.localeCompare(B.tenant))}var qf=new Set;function vf(f){if(qf.has(f))return;qf.add(f);let g=l();console.warn(`[env] warning: "${f}" is encrypted but no usable private key was found for the "${g}" environment; falling back to its default. Set DOTENV_PRIVATE_KEY_${g.toUpperCase()} or ship .env.keys.`)}var of={get:(f,g)=>{let B=f[g];if(typeof B==="string"&&(B.startsWith("encrypted:")||B.startsWith("enc:"))){let $=Wf(B);if($===void 0){vf(g),delete f[g];return}f[g]=$,B=$}let A=["_PORT","_TIMEOUT","_TTL","_SIZE","_LIMIT","_MAX","_MIN","_INTERVAL","_RETRIES","_CONCURRENCY","_WORKERS","_CONNECTIONS"];if(typeof B==="string"&&/^\d+$/.test(B)&&!B.startsWith("0")&&A.some(($)=>g.endsWith($)))return Number(B);if(typeof B==="string"){let $=B.toLowerCase();if($==="true")return!0;if($==="false")return!1}return B}};function pf(){return typeof Bun<"u"?Bun.env:yf.env}var Lf=new Proxy(pf(),of);function vg(f,g,B){let A=B?.path||nf(".env"),_=Uf.readFileSync(A,"utf-8").split(`
25
- `),D=_.findIndex((X)=>X.startsWith(`${f}=`)),R=/[\s"'#$\\]/.test(g)?`"${g.replace(/"/g,"\\\"")}"`:g;if(D!==-1)_[D]=`${f}=${R}`;else _.push(`${f}=${R}`);Uf.writeFileSync(A,_.join(`
26
- `))}function ig(f=Lf){let g=[];for(let[B,A]of Object.entries(Qf)){let $=f[B];if($!==void 0&&$!==""&&!A.includes(String($)))g.push(`${B}="${$}" is not valid. Allowed values: ${A.join(", ")}`)}return g}function og(f,g=Lf){let B=[];for(let A of f){let $=g[A];if($===void 0||$===""||$===null)B.push(A)}if(B.length>0)throw Error(`[env] Missing required environment variable(s): ${B.join(", ")}. Set them in .env or your process environment before booting.`);return g}export{vg as writeEnv,ig as validateEnv,wf as tenantEnvPrefix,mg as stripForeignTenantEnv,Ug as setEnv,Vg as runtimeInfo,kf as runtime,xg as rotateKeypair,Nf as resolvePrivateKey,Qg as resolveEnvFile,Wg as resetPrivateKeyCache,og as requireEnv,Ng as providerInfo,rf as provider,pf as process,ff as platform,tf as partitionTenantEnv,fg as parseEnvFromKey,L as parse,ef as migrateEncryptedValue,$g as loadEnvFiles,Tf as loadEnv,Cg as isWindows,Zf as isNode,uf as isMinimal,bg as isMacOS,hg as isLinux,af as isLegacyEncryptedValue,Sg as isDebug,Kg as isColorSupported,df as isCI,Jf as isBun,Fg as hasWindow,If as hasTTY,i as getPrivateKey,Lg as getKeypair,qg as getEnv,F as generateKeypair,kg as foreignTenantKeys,Pf as envPlugin,Qf as envEnum,Lf as env,c as encryptValue,wg as encryptEnv,h as decryptValue,Wf as decryptEnvValue,cf as decryptEnv,Tg as autoLoadEnv,sf as aesEncrypt,Mf as aesDecrypt,l as activeEnvName};
24
+ `,U=Jf(g.output,_.publicKey,R,f),Q=`${process.pid}-${Date.now()}`,I=L(Gf(A),`.${a(A)}.${Q}.rotate`),J=L(Gf($),`.${a($)}.${Q}.rotate`);try{if(z(I,U,{encoding:"utf8",mode:384}),z(J,Z,{encoding:"utf8",mode:384}),f.stdout)return s(J,$),{success:!0,output:U};s(I,A);try{s(J,$)}catch(w){throw z(A,X),w}return{success:!0,output:`\u2714 rotated (${f.file||".env"}) to encrypted:v2`}}catch(w){if(!q($))z($,H,{mode:384});return{success:!1,error:`Failed to rotate without exposing plaintext: ${w instanceof Error?w.message:"Unknown error"}`}}finally{jf(I,{force:!0}),jf(J,{force:!0})}}import j from"process";import{platform as sf}from"os";var Zf=typeof Bun<"u",Qf=typeof j<"u"&&j.versions?.node!==void 0,af=Zf?"bun":Qf?"node":"unknown",y2={name:af,version:Zf?Bun.version:Qf?j.version:void 0},ff=sf(),v2=ff==="win32",i2=ff==="darwin",n2=ff==="linux",If=Boolean(j.stdout?.isTTY),o2=typeof globalThis.window<"u",ef=Boolean(j.env.CI||j.env.CONTINUOUS_INTEGRATION||j.env.BUILD_NUMBER||j.env.RUN_ID),p2=Boolean(j.env.DEBUG||j.env.VERBOSE||j.argv.includes("--debug")||j.argv.includes("--verbose")),f2=ef||!If,l2=Boolean(!f2&&(If||j.env.COLORTERM||j.env.FORCE_COLOR||j.env.TERM&&j.env.TERM!=="dumb")),e={github:{name:"GitHub Actions",detected:Boolean(j.env.GITHUB_ACTIONS)},gitlab:{name:"GitLab CI",detected:Boolean(j.env.GITLAB_CI)},circle:{name:"CircleCI",detected:Boolean(j.env.CIRCLECI)},travis:{name:"Travis CI",detected:Boolean(j.env.TRAVIS)},jenkins:{name:"Jenkins",detected:Boolean(j.env.JENKINS_URL)},vercel:{name:"Vercel",detected:Boolean(j.env.VERCEL)},netlify:{name:"Netlify",detected:Boolean(j.env.NETLIFY)},heroku:{name:"Heroku",detected:Boolean(j.env.DYNO)},aws:{name:"AWS",detected:Boolean(j.env.AWS_REGION||j.env.AWS_LAMBDA_FUNCTION_NAME)},azure:{name:"Azure",detected:Boolean(j.env.AZURE_HTTP_USER_AGENT)},cloudflare:{name:"Cloudflare",detected:Boolean(j.env.CF_PAGES)},railway:{name:"Railway",detected:Boolean(j.env.RAILWAY_ENVIRONMENT)},render:{name:"Render",detected:Boolean(j.env.RENDER)}},g2=Object.keys(e).find((f)=>{let g=e[f];return g!==void 0&&g.detected})||"unknown",s2=e[g2]||{name:"Unknown",detected:!1};import $2 from"process";import{projectPath as A2}from"@stacksjs/path";import Lf from"fs";var wf={APP_ENV:["local","dev","development","staging","prod","production"],DB_CONNECTION:["mysql","sqlite","postgres","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 Uf(f){return`${f.replace(/[^a-z0-9]/gi,"").toUpperCase()}_`}function B2(f,g={}){let B=g.self?Uf(g.self):void 0,A=(g.tenants??[]).filter((X)=>typeof X==="string"&&X.trim().length>0).map((X)=>({slug:X,prefix:Uf(X)})).filter(({prefix:X})=>X!==B).sort((X,H)=>H.prefix.length-X.prefix.length),$={},_={};for(let[X,H]of Object.entries(f)){let W=A.find(({prefix:D})=>X.startsWith(D));if(W){(_[W.slug]??={})[X]=H;continue}$[X]=H}return{own:$,foreign:_}}function f5(f,g={}){return B2(f,g).own}function g5(f){return Object.entries(f.foreign).map(([g,B])=>({tenant:g,keys:Object.keys(B).sort()})).sort((g,B)=>g.tenant.localeCompare(B.tenant))}var Mf=new Set;function _2(f){if(Mf.has(f))return;Mf.add(f);let g=l();console.warn(`[env] warning: "${f}" is encrypted but no usable private key was found for the "${g}" environment; falling back to its default. Set DOTENV_PRIVATE_KEY_${g.toUpperCase()} or ship .env.keys.`)}var X2={get:(f,g)=>{let B=f[g];if(typeof B==="string"&&(B.startsWith("encrypted:")||B.startsWith("enc:"))){let $=Tf(B);if($===void 0){_2(g),delete f[g];return}f[g]=$,B=$}let A=["_PORT","_TIMEOUT","_TTL","_SIZE","_LIMIT","_MAX","_MIN","_INTERVAL","_RETRIES","_CONCURRENCY","_WORKERS","_CONNECTIONS"];if(typeof B==="string"&&/^\d+$/.test(B)&&!B.startsWith("0")&&A.some(($)=>g.endsWith($)))return Number(B);if(typeof B==="string"){let $=B.toLowerCase();if($==="true")return!0;if($==="false")return!1}return B}};function D2(){return typeof Bun<"u"?Bun.env:$2.env}var Ef=new Proxy(D2(),X2);function H5(f,g,B){let A=B?.path||A2(".env"),_=Lf.readFileSync(A,"utf-8").split(`
25
+ `),X=_.findIndex((D)=>D.startsWith(`${f}=`)),W=/[\s"'#$\\]/.test(g)?`"${g.replace(/"/g,"\\\"")}"`:g;if(X!==-1)_[X]=`${f}=${W}`;else _.push(`${f}=${W}`);Lf.writeFileSync(A,_.join(`
26
+ `))}function O5(f=Ef){let g=[];for(let[B,A]of Object.entries(wf)){let $=f[B];if($!==void 0&&$!==""&&!A.includes(String($)))g.push(`${B}="${$}" is not valid. Allowed values: ${A.join(", ")}`)}return g}function W5(f,g=Ef){let B=[];for(let A of f){let $=g[A];if($===void 0||$===""||$===null)B.push(A)}if(B.length>0)throw Error(`[env] Missing required environment variable(s): ${B.join(", ")}. Set them in .env or your process environment before booting.`);return g}export{H5 as writeEnv,O5 as validateEnv,Uf as tenantEnvPrefix,f5 as stripForeignTenantEnv,c2 as setEnv,y2 as runtimeInfo,af as runtime,d2 as rotateKeypair,of as resolvePrivateKey,N2 as resolveEnvFile,V2 as resetPrivateKeyCache,W5 as requireEnv,s2 as providerInfo,g2 as provider,D2 as process,ff as platform,B2 as partitionTenantEnv,T2 as parseEnvFromKey,M as parse,R2 as migrateEncryptedValue,I2 as loadEnvFiles,Yf as loadEnv,v2 as isWindows,Qf as isNode,f2 as isMinimal,i2 as isMacOS,n2 as isLinux,W2 as isLegacyEncryptedValue,p2 as isDebug,l2 as isColorSupported,ef as isCI,Zf as isBun,o2 as hasWindow,If as hasTTY,n as getPrivateKey,m2 as getKeypair,k2 as getEnv,S as generateKeypair,g5 as foreignTenantKeys,pf as envPlugin,wf as envEnum,Ef as env,c as encryptValue,P2 as encryptEnv,b as decryptValue,Tf as decryptEnvValue,lf as decryptEnv,x2 as autoLoadEnv,O2 as aesEncrypt,zf as aesDecrypt,l as activeEnvName};
package/dist/parser.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{createCipheriv as b,createDecipheriv as B,createHash as d,createPrivateKey as I,createPublicKey as P,diffieHellman as T,generateKeyPairSync as $,hkdfSync as A,randomBytes as w}from"crypto";var m="x25519-public:",x="x25519-private:",u="encrypted:v2:",K="encrypted:",R=Buffer.from("stacks-env:v2","utf8"),_="Environment decryption failed: authentication or format error";function S(t){if(t.length===32)return t;return d("sha256").update(t).digest()}function V(t,r){let e=w(16),n=b("aes-256-gcm",S(r),e);return{ciphertext:Buffer.concat([n.update(t,"utf8"),n.final()]).toString("hex"),iv:e.toString("hex"),authTag:n.getAuthTag().toString("hex")}}function F(t,r,e,n){try{let o=B("aes-256-gcm",S(r),Buffer.from(e,"hex"));return o.setAuthTag(Buffer.from(n,"hex")),Buffer.concat([o.update(Buffer.from(t,"hex")),o.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function y(t){return t.toString("base64url")}function a(t,r,e){if(typeof t!=="string"||t.length>0&&!/^[A-Za-z0-9_-]+$/.test(t))throw Error(`${r} is not canonical base64url`);let n=Buffer.from(t,"base64url");if(y(n)!==t)throw Error(`${r} is not canonical base64url`);if(e!==void 0&&n.length!==e)throw Error(`${r} has an invalid length`);return n}function X(t){if(!t.startsWith(m))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let r=P({key:a(t.slice(m.length),"public key"),format:"der",type:"spki"});if(r.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return r}function O(t){if(!t.startsWith(x))throw Error("Private key is not a version 2 X25519 key");let r=I({key:a(t.slice(x.length),"private key"),format:"der",type:"pkcs8"});if(r.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return r}function D(t){return Buffer.from(`stacks-env:v2;${t.epk};${t.salt};${t.nonce}`,"utf8")}function G(){let{publicKey:t,privateKey:r}=$("x25519"),e=t.export({format:"der",type:"spki"}),n=r.export({format:"der",type:"pkcs8"});return{publicKey:`${m}${y(e)}`,privateKey:`${x}${y(n)}`}}function v(t,r){let e=X(r),n=$("x25519"),o=y(n.publicKey.export({format:"der",type:"spki"})),c=w(16),s=w(12),h=T({privateKey:n.privateKey,publicKey:e}),f=Buffer.from(A("sha256",h,c,R,32)),g={epk:o,salt:y(c),nonce:y(s)};try{let i=b("aes-256-gcm",f,s);i.setAAD(D(g));let p=Buffer.concat([i.update(t,"utf8"),i.final()]),E={v:2,...g,ciphertext:y(p),tag:y(i.getAuthTag())};return`${u}${y(Buffer.from(JSON.stringify(E),"utf8"))}`}finally{h.fill(0),f.fill(0)}}function Y(t){let r=a(t.slice(u.length),"envelope").toString("utf8"),e=JSON.parse(r);if(!e||typeof e!=="object"||Array.isArray(e))throw Error("envelope is not an object");let n=Object.keys(e).sort(),o=["ciphertext","epk","nonce","salt","tag","v"];if(n.length!==o.length||n.some((c,s)=>c!==o[s]))throw Error("envelope fields are invalid");if(e.v!==2)throw Error("envelope version is unsupported");for(let c of["epk","salt","nonce","ciphertext","tag"])if(typeof e[c]!=="string")throw Error(`${c} is invalid`);return e}function C(t,r){try{let e=Y(t),n=O(r),o=P({key:a(e.epk,"ephemeral public key"),format:"der",type:"spki"});if(o.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let c=a(e.salt,"salt",16),s=a(e.nonce,"nonce",12),h=a(e.ciphertext,"ciphertext"),f=a(e.tag,"tag",16),g=T({privateKey:n,publicKey:o}),i=Buffer.from(A("sha256",g,c,R,32));try{let p=B("aes-256-gcm",i,s);return p.setAAD(D(e)),p.setAuthTag(f),Buffer.concat([p.update(h),p.final()]).toString("utf8")}finally{g.fill(0),i.fill(0)}}catch{throw Error(_)}}function H(t,r){try{if(!/^[0-9a-f]{64}$/.test(r))throw Error("invalid legacy private key");let e=Buffer.from(t.slice(K.length),"base64");if(e.length<32)throw Error("invalid legacy payload");let n=d("sha256").update(Buffer.from(r,"hex")).digest(),o=d("sha256").update(n).digest();return F(e.subarray(32).toString("hex"),o,e.subarray(0,16).toString("hex"),e.subarray(16,32).toString("hex"))}catch{throw Error(_)}}function J(t){return t.startsWith(K)&&!t.startsWith(u)}function k(t,r){if(!t.startsWith(K))return t;return t.startsWith(u)?C(t,r):H(t,r)}function U(t,r,e){return v(k(t,r),e)}function z(t){let r=t.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return r&&r[1]?r[1].toLowerCase():""}function Z(t=""){return t?process.env[`DOTENV_PRIVATE_KEY_${t.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}function N(t,r={}){let e={},n=[],o=[],c=t.split(`
3
- `);for(let s of c){let h=s.trim();if(!h||h.startsWith("#"))continue;if(h.startsWith("DOTENV_PUBLIC_KEY=")){let p=h.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(p&&p[1]!==void 0)e.DOTENV_PUBLIC_KEY=p[1];continue}let f=h.match(/^([^=]+)=(.*)$/);if(!f||f[1]===void 0||f[2]===void 0)continue;let g=f[1].trim(),i=f[2].trim();if(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'")){if(i=i.slice(1,-1),i.includes("\\n"))i=i.replace(/\\n/g,`
4
- `)}if(i.startsWith("encrypted:")||i.startsWith("enc:")){if(!r.privateKey){o.push(g);continue}try{let p=i.startsWith("enc:")?`encrypted:${i.slice(4)}`:i;i=k(p,r.privateKey)}catch(p){n.push(`Failed to decrypt ${g}: ${p instanceof Error?p.message:"Unknown error"}`)}}i=W(i,{...r.processEnv||process.env,...e}),i=l(i),e[g]=i}return{parsed:e,errors:n,skippedEncrypted:o}}function W(t,r){return t.replace(/\$\{([^}]+)\}/g,(e,n)=>{let o=n.match(/^([^:\-+]+)(:-|-)(.+)$/);if(o){let[,s,h,f]=o,g=r[s];if(h===":-")return g||f;else return g!==void 0?g:f}let c=n.match(/^([^:\-+]+)(:?\+)(.+)$/);if(c){let[,s,h,f]=c,g=r[s];if(h===":+")return g?f:"";else return g!==void 0?f:""}return r[n]||""})}var j=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function l(t){return t.replace(/\$\(([^)]+)\)/g,(r,e)=>{try{let n=e.trim().split(/\s+/),o=n[0];if(!o||!j.has(o))return console.warn(`[env] Blocked command substitution for disallowed command: ${o}`),"";let c=Bun.spawnSync(n,{stdout:"pipe",stderr:"pipe"});if(c.exitCode===0)return new TextDecoder().decode(c.stdout).trim();console.warn(`[env] Command substitution failed (exit code ${c.exitCode}): ${o}`)}catch(n){console.warn(`[env] Command substitution error: ${n instanceof Error?n.message:String(n)}`)}return""})}async function M(t,r={}){let e={},n=[],o=[];for(let c of t)try{let s=Bun.file(c);if(!s.size)continue;let h=await s.text(),{parsed:f,errors:g,skippedEncrypted:i}=N(h,r);n.push(...g),o.push(...i);for(let[p,E]of Object.entries(f)){if(!r.overload&&e[p]!==void 0)continue;e[p]=E}}catch(s){if(s?.code==="ENOENT")continue;n.push(`Failed to read ${c}: ${s instanceof Error?s.message:String(s)}`)}return{parsed:e,errors:n,skippedEncrypted:o}}export{N as parse,M as loadEnvFiles};
2
+ import{createCipheriv as T,createDecipheriv as $,createHash as K,createPrivateKey as O,createPublicKey as m,diffieHellman as A,generateKeyPairSync as _,hkdfSync as R,randomBytes as k}from"crypto";var B="x25519-public:",d="x25519-private:",w="encrypted:v2:",x="encrypted:",b=Buffer.from("stacks-env:v2","utf8"),D="Environment decryption failed: authentication or format error";function I(n){if(n.length===32)return n;return K("sha256").update(n).digest()}function it(n,r){let t=k(16),i=T("aes-256-gcm",I(r),t);return{ciphertext:Buffer.concat([i.update(n,"utf8"),i.final()]).toString("hex"),iv:t.toString("hex"),authTag:i.getAuthTag().toString("hex")}}function Y(n,r,t,i){try{let e=$("aes-256-gcm",I(r),Buffer.from(t,"hex"));return e.setAuthTag(Buffer.from(i,"hex")),Buffer.concat([e.update(Buffer.from(n,"hex")),e.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function p(n){return n.toString("base64url")}function E(n,r,t){if(typeof n!=="string"||n.length>0&&!/^[A-Za-z0-9_-]+$/.test(n))throw Error(`${r} is not canonical base64url`);let i=Buffer.from(n,"base64url");if(p(i)!==n)throw Error(`${r} is not canonical base64url`);if(t!==void 0&&i.length!==t)throw Error(`${r} has an invalid length`);return i}function v(n){if(!n.startsWith(B))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let r=m({key:E(n.slice(B.length),"public key"),format:"der",type:"spki"});if(r.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return r}function F(n){if(!n.startsWith(d))throw Error("Private key is not a version 2 X25519 key");let r=O({key:E(n.slice(d.length),"private key"),format:"der",type:"pkcs8"});if(r.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return r}function S(n){return Buffer.from(`stacks-env:v2;${n.epk};${n.salt};${n.nonce}`,"utf8")}function et(){let{publicKey:n,privateKey:r}=_("x25519"),t=n.export({format:"der",type:"spki"}),i=r.export({format:"der",type:"pkcs8"});return{publicKey:`${B}${p(t)}`,privateKey:`${d}${p(i)}`}}function H(n,r){let t=v(r),i=_("x25519"),e=p(i.publicKey.export({format:"der",type:"spki"})),o=k(16),c=k(12),s=A({privateKey:i.privateKey,publicKey:t}),y=Buffer.from(R("sha256",s,o,b,32)),g={epk:e,salt:p(o),nonce:p(c)};try{let f=T("aes-256-gcm",y,c);f.setAAD(S(g));let h=Buffer.concat([f.update(n,"utf8"),f.final()]),u={v:2,...g,ciphertext:p(h),tag:p(f.getAuthTag())};return`${w}${p(Buffer.from(JSON.stringify(u),"utf8"))}`}finally{s.fill(0),y.fill(0)}}function N(n){let r=E(n.slice(w.length),"envelope").toString("utf8"),t=JSON.parse(r);if(!t||typeof t!=="object"||Array.isArray(t))throw Error("envelope is not an object");let i=Object.keys(t).sort(),e=["ciphertext","epk","nonce","salt","tag","v"];if(i.length!==e.length||i.some((o,c)=>o!==e[c]))throw Error("envelope fields are invalid");if(t.v!==2)throw Error("envelope version is unsupported");for(let o of["epk","salt","nonce","ciphertext","tag"])if(typeof t[o]!=="string")throw Error(`${o} is invalid`);return t}function W(n,r){try{let t=N(n),i=F(r),e=m({key:E(t.epk,"ephemeral public key"),format:"der",type:"spki"});if(e.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let o=E(t.salt,"salt",16),c=E(t.nonce,"nonce",12),s=E(t.ciphertext,"ciphertext"),y=E(t.tag,"tag",16),g=A({privateKey:i,publicKey:e}),f=Buffer.from(R("sha256",g,o,b,32));try{let h=$("aes-256-gcm",f,c);return h.setAAD(S(t)),h.setAuthTag(y),Buffer.concat([h.update(s),h.final()]).toString("utf8")}finally{g.fill(0),f.fill(0)}}catch{throw Error(D)}}function j(n,r){try{if(!/^[0-9a-f]{64}$/.test(r))throw Error("invalid legacy private key");let t=Buffer.from(n.slice(x.length),"base64");if(t.length<32)throw Error("invalid legacy payload");let i=K("sha256").update(Buffer.from(r,"hex")).digest(),e=K("sha256").update(i).digest();return Y(t.subarray(32).toString("hex"),e,t.subarray(0,16).toString("hex"),t.subarray(16,32).toString("hex"))}catch{throw Error(D)}}function ot(n){return n.startsWith(x)&&!n.startsWith(w)}function P(n,r){if(!n.startsWith(x))return n;return n.startsWith(w)?W(n,r):j(n,r)}function ft(n,r,t){return H(P(n,r),t)}function ct(n){let r=n.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return r&&r[1]?r[1].toLowerCase():""}function st(n=""){return n?process.env[`DOTENV_PRIVATE_KEY_${n.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}import{spawnSync as C}from"child_process";import{readFileSync as L}from"fs";import{arch as V,hostname as G,platform as X,release as J,userInfo as U}from"os";import{basename as z,dirname as Z,resolve as Q}from"path";function M(n,r={}){let t={},i=[],e=[],o=n.split(`
3
+ `);for(let c of o){let s=c.trim();if(!s||s.startsWith("#"))continue;if(s.startsWith("DOTENV_PUBLIC_KEY=")){let h=s.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(h&&h[1]!==void 0)t.DOTENV_PUBLIC_KEY=h[1];continue}let y=s.match(/^([^=]+)=(.*)$/);if(!y||y[1]===void 0||y[2]===void 0)continue;let g=y[1].trim(),f=y[2].trim();if(f.startsWith('"')&&f.endsWith('"')||f.startsWith("'")&&f.endsWith("'")){if(f=f.slice(1,-1),f.includes("\\n"))f=f.replace(/\\n/g,`
4
+ `)}if(f.startsWith("encrypted:")||f.startsWith("enc:")){if(!r.privateKey){e.push(g);continue}try{let h=f.startsWith("enc:")?`encrypted:${f.slice(4)}`:f;f=P(h,r.privateKey)}catch(h){i.push(`Failed to decrypt ${g}: ${h instanceof Error?h.message:"Unknown error"}`)}}f=q(f,{...r.processEnv||process.env,...t}),f=nt(f),t[g]=f}return{parsed:t,errors:i,skippedEncrypted:e}}function q(n,r){return n.replace(/\$\{([^}]+)\}/g,(t,i)=>{let e=i.match(/^([^:\-+]+)(:-|-)(.+)$/);if(e){let[,c,s,y]=e,g=r[c];if(s===":-")return g||y;else return g!==void 0?g:y}let o=i.match(/^([^:\-+]+)(:?\+)(.+)$/);if(o){let[,c,s,y]=o,g=r[c];if(s===":+")return g?y:"";else return g!==void 0?y:""}return r[i]||""})}var a=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function l(n){let r=[],t="",i=null,e=!1;for(let o of n.trim()){if(e){t+=o,e=!1;continue}if(o==="\\"&&i!=="'"){e=!0;continue}if(i){if(o===i)i=null;else t+=o;continue}if(o==='"'||o==="'"){i=o;continue}if(/\s/.test(o)){if(t)r.push(t),t="";continue}t+=o}if(e||i)throw Error("Command substitution contains an unterminated escape or quote");if(t)r.push(t);return r}function tt(n){let[r,...t]=n,i=t.some((e)=>e.startsWith("-"));if(r==="echo"&&!i)return t.join(" ");if(r==="printf"&&t.length===1&&!t[0]?.includes("%"))return t[0];if(r==="hostname"&&t.length===0)return G();if(r==="whoami"&&t.length===0)return U().username;if(r==="pwd"&&t.length===0)return process.cwd();if(r==="basename"&&t.length===1)return z(t[0]??"");if(r==="dirname"&&t.length===1)return Z(t[0]??"");if(r==="cat"&&t.length>0&&!i)return t.map((e)=>L(Q(process.cwd(),e),"utf8")).join("");if(r==="uname"){let e=t[0]??"-s";if(t.length<=1&&e==="-m")return V();if(t.length<=1&&e==="-r")return J();if(t.length<=1&&e==="-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"}[X()]??X()}return}function nt(n){return n.replace(/\$\(([^)]+)\)/g,(r,t)=>{try{let i=l(t),e=i[0];if(!e||!a.has(e))return console.warn(`[env] Blocked command substitution for disallowed command: ${e}`),"";let o=tt(i);if(o!==void 0)return o.trim();let c=C(e,i.slice(1),{encoding:"utf8",env:process.env});if(c.status===0)return c.stdout.trim();let s=c.stderr.trim();console.warn(`[env] Command substitution failed (exit code ${c.status??"unknown"}): ${e}${s?`: ${s}`:""}`)}catch(i){console.warn(`[env] Command substitution error: ${i instanceof Error?i.message:String(i)}`)}return""})}async function ut(n,r={}){let t={},i=[],e=[];for(let o of n)try{let c=Bun.file(o);if(!c.size)continue;let s=await c.text(),{parsed:y,errors:g,skippedEncrypted:f}=M(s,r);i.push(...g),e.push(...f);for(let[h,u]of Object.entries(y)){if(!r.overload&&t[h]!==void 0)continue;t[h]=u}}catch(c){if(c?.code==="ENOENT")continue;i.push(`Failed to read ${o}: ${c instanceof Error?c.message:String(c)}`)}return{parsed:t,errors:i,skippedEncrypted:e}}export{M as parse,ut as loadEnvFiles};
package/dist/plugin.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{createCipheriv as V,createDecipheriv as M,createHash as S,createPrivateKey as tt,createPublicKey as k,diffieHellman as P,generateKeyPairSync as m,hkdfSync as z,randomBytes as G}from"crypto";var J="x25519-public:",L="x25519-private:",Y="encrypted:v2:",U="encrypted:",N=Buffer.from("stacks-env:v2","utf8"),e="Environment decryption failed: authentication or format error";function d(t){if(t.length===32)return t;return S("sha256").update(t).digest()}function $t(t,r){let c=G(16),n=V("aes-256-gcm",d(r),c);return{ciphertext:Buffer.concat([n.update(t,"utf8"),n.final()]).toString("hex"),iv:c.toString("hex"),authTag:n.getAuthTag().toString("hex")}}function rt(t,r,c,n){try{let f=M("aes-256-gcm",d(r),Buffer.from(c,"hex"));return f.setAuthTag(Buffer.from(n,"hex")),Buffer.concat([f.update(Buffer.from(t,"hex")),f.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function T(t){return t.toString("base64url")}function $(t,r,c){if(typeof t!=="string"||t.length>0&&!/^[A-Za-z0-9_-]+$/.test(t))throw Error(`${r} is not canonical base64url`);let n=Buffer.from(t,"base64url");if(T(n)!==t)throw Error(`${r} is not canonical base64url`);if(c!==void 0&&n.length!==c)throw Error(`${r} has an invalid length`);return n}function nt(t){if(!t.startsWith(J))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let r=k({key:$(t.slice(J.length),"public key"),format:"der",type:"spki"});if(r.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return r}function ct(t){if(!t.startsWith(L))throw Error("Private key is not a version 2 X25519 key");let r=tt({key:$(t.slice(L.length),"private key"),format:"der",type:"pkcs8"});if(r.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return r}function a(t){return Buffer.from(`stacks-env:v2;${t.epk};${t.salt};${t.nonce}`,"utf8")}function At(){let{publicKey:t,privateKey:r}=m("x25519"),c=t.export({format:"der",type:"spki"}),n=r.export({format:"der",type:"pkcs8"});return{publicKey:`${J}${T(c)}`,privateKey:`${L}${T(n)}`}}function ft(t,r){let c=nt(r),n=m("x25519"),f=T(n.publicKey.export({format:"der",type:"spki"})),g=G(16),o=G(12),h=P({privateKey:n.privateKey,publicKey:c}),w=Buffer.from(z("sha256",h,g,N,32)),s={epk:f,salt:T(g),nonce:T(o)};try{let i=V("aes-256-gcm",w,o);i.setAAD(a(s));let b=Buffer.concat([i.update(t,"utf8"),i.final()]),u={v:2,...s,ciphertext:T(b),tag:T(i.getAuthTag())};return`${Y}${T(Buffer.from(JSON.stringify(u),"utf8"))}`}finally{h.fill(0),w.fill(0)}}function it(t){let r=$(t.slice(Y.length),"envelope").toString("utf8"),c=JSON.parse(r);if(!c||typeof c!=="object"||Array.isArray(c))throw Error("envelope is not an object");let n=Object.keys(c).sort(),f=["ciphertext","epk","nonce","salt","tag","v"];if(n.length!==f.length||n.some((g,o)=>g!==f[o]))throw Error("envelope fields are invalid");if(c.v!==2)throw Error("envelope version is unsupported");for(let g of["epk","salt","nonce","ciphertext","tag"])if(typeof c[g]!=="string")throw Error(`${g} is invalid`);return c}function gt(t,r){try{let c=it(t),n=ct(r),f=k({key:$(c.epk,"ephemeral public key"),format:"der",type:"spki"});if(f.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let g=$(c.salt,"salt",16),o=$(c.nonce,"nonce",12),h=$(c.ciphertext,"ciphertext"),w=$(c.tag,"tag",16),s=P({privateKey:n,publicKey:f}),i=Buffer.from(z("sha256",s,g,N,32));try{let b=M("aes-256-gcm",i,o);return b.setAAD(a(c)),b.setAuthTag(w),Buffer.concat([b.update(h),b.final()]).toString("utf8")}finally{s.fill(0),i.fill(0)}}catch{throw Error(e)}}function ot(t,r){try{if(!/^[0-9a-f]{64}$/.test(r))throw Error("invalid legacy private key");let c=Buffer.from(t.slice(U.length),"base64");if(c.length<32)throw Error("invalid legacy payload");let n=S("sha256").update(Buffer.from(r,"hex")).digest(),f=S("sha256").update(n).digest();return rt(c.subarray(32).toString("hex"),f,c.subarray(0,16).toString("hex"),c.subarray(16,32).toString("hex"))}catch{throw Error(e)}}function yt(t){return t.startsWith(U)&&!t.startsWith(Y)}function E(t,r){if(!t.startsWith(U))return t;return t.startsWith(Y)?gt(t,r):ot(t,r)}function Rt(t,r,c){return ft(E(t,r),c)}function _t(t){let r=t.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return r&&r[1]?r[1].toLowerCase():""}function Z(t=""){return t?process.env[`DOTENV_PRIVATE_KEY_${t.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}function p(t,r={}){let c={},n=[],f=[],g=t.split(`
3
- `);for(let o of g){let h=o.trim();if(!h||h.startsWith("#"))continue;if(h.startsWith("DOTENV_PUBLIC_KEY=")){let b=h.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(b&&b[1]!==void 0)c.DOTENV_PUBLIC_KEY=b[1];continue}let w=h.match(/^([^=]+)=(.*)$/);if(!w||w[1]===void 0||w[2]===void 0)continue;let s=w[1].trim(),i=w[2].trim();if(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'")){if(i=i.slice(1,-1),i.includes("\\n"))i=i.replace(/\\n/g,`
4
- `)}if(i.startsWith("encrypted:")||i.startsWith("enc:")){if(!r.privateKey){f.push(s);continue}try{let b=i.startsWith("enc:")?`encrypted:${i.slice(4)}`:i;i=E(b,r.privateKey)}catch(b){n.push(`Failed to decrypt ${s}: ${b instanceof Error?b.message:"Unknown error"}`)}}i=st(i,{...r.processEnv||process.env,...c}),i=wt(i),c[s]=i}return{parsed:c,errors:n,skippedEncrypted:f}}function st(t,r){return t.replace(/\$\{([^}]+)\}/g,(c,n)=>{let f=n.match(/^([^:\-+]+)(:-|-)(.+)$/);if(f){let[,o,h,w]=f,s=r[o];if(h===":-")return s||w;else return s!==void 0?s:w}let g=n.match(/^([^:\-+]+)(:?\+)(.+)$/);if(g){let[,o,h,w]=g,s=r[o];if(h===":+")return s?w:"";else return s!==void 0?w:""}return r[n]||""})}var ht=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function wt(t){return t.replace(/\$\(([^)]+)\)/g,(r,c)=>{try{let n=c.trim().split(/\s+/),f=n[0];if(!f||!ht.has(f))return console.warn(`[env] Blocked command substitution for disallowed command: ${f}`),"";let g=Bun.spawnSync(n,{stdout:"pipe",stderr:"pipe"});if(g.exitCode===0)return new TextDecoder().decode(g.stdout).trim();console.warn(`[env] Command substitution failed (exit code ${g.exitCode}): ${f}`)}catch(n){console.warn(`[env] Command substitution error: ${n instanceof Error?n.message:String(n)}`)}return""})}async function Kt(t,r={}){let c={},n=[],f=[];for(let g of t)try{let o=Bun.file(g);if(!o.size)continue;let h=await o.text(),{parsed:w,errors:s,skippedEncrypted:i}=p(h,r);n.push(...s),f.push(...i);for(let[b,u]of Object.entries(w)){if(!r.overload&&c[b]!==void 0)continue;c[b]=u}}catch(o){if(o?.code==="ENOENT")continue;n.push(`Failed to read ${g}: ${o instanceof Error?o.message:String(o)}`)}return{parsed:c,errors:n,skippedEncrypted:f}}import{existsSync as H}from"fs";import{readFileSync as Q}from"fs";import{resolve as W}from"path";function K(t){return typeof t==="string"&&(t.startsWith("encrypted:")||t.startsWith("enc:"))}function A(t){if(!t||K(t))return;let r=t.trim().toLowerCase();if(!/^[a-z0-9_-]+$/.test(r))return;if(r==="prod")return"production";if(r==="stage")return"staging";if(r==="dev")return"development";return r}var j=null,C,q;function bt(t,r,c=".env.keys"){let n=W(r,c);if(!H(n))return;try{let{parsed:f}=p(Q(n,"utf-8"));if(t){let g=f[`DOTENV_PRIVATE_KEY_${t.toUpperCase()}`];if(g)return g}return f.DOTENV_PRIVATE_KEY}catch{return}}function Bt(t={}){return A(t.env)||q||A("development")||A(process.env.DOTENV_ENV)||A(process.env.APP_ENV)||"development"}function ut(t={}){let r=Bt(t),c=t.cwd||process.cwd();if(j===r)return C;let n=Z(r);if(!n)n=process.env.DOTENV_PRIVATE_KEY;if(!n)n=bt(r,c);return j=r,C=n,n}function jt(){j=null,C=void 0}function Ct(t,r={}){if(!K(t))return t;let c=ut(r);if(!c)return;try{let n=t.startsWith("enc:")?`encrypted:${t.slice(4)}`:t;return E(n,c)}catch{return}}function l(t={}){let{path:r=[".env"],overload:c=!1,env:n,privateKey:f,keysFile:g=".env.keys",quiet:o=!1,cwd:h=process.cwd()}=t,w=Array.isArray(r)?r:[r],s=[],i=0,b=new Set(Object.entries(process.env).filter(([,B])=>B!==void 0&&!K(B)).map(([B])=>B)),u=f;if(!u&&g){let B=W(h,g);if(H(B))try{let x=Q(B,"utf-8"),{parsed:y}=p(x);if(n){let D=`DOTENV_PRIVATE_KEY_${n.toUpperCase()}`;u=y[D]}else u=y.DOTENV_PRIVATE_KEY}catch(x){s.push(`Failed to load keys file: ${x instanceof Error?x.message:"Unknown error"}`)}}if(!u)u=Z(n||"");for(let B of w){let x=W(h,B);if(!H(x)){if(!o)s.push(`File not found: ${x}`);continue}try{let y=Q(x,"utf-8"),{parsed:D,errors:v,skippedEncrypted:R}=p(y,{privateKey:u,processEnv:process.env});if(s.push(...v),R.length>0){for(let O of R)if(K(process.env[O]))delete process.env[O];let _=n?`DOTENV_PRIVATE_KEY_${n.toUpperCase()}`:"DOTENV_PRIVATE_KEY",X=R.slice(0,5).join(", "),I=R.length>5?`, \u2026 +${R.length-5} more`:"";console.warn(`[env] warning: skipped ${R.length} encrypted value(s) in ${B} (${_} not set; defaults apply): ${X}${I}`)}let F=0;for(let[_,X]of Object.entries(D)){if(_==="DOTENV_PUBLIC_KEY")continue;let I=process.env[_],O=K(I)&&X!==I;if(c||!b.has(_)||O)process.env[_]=X,i++,F++}if(!o&&!process.env.__ENV_LOADED__)console.error(`[env] loaded ${F}/${Object.keys(D).length} variables from ${B}`),process.env.__ENV_LOADED__="1"}catch(y){s.push(`Failed to load ${x}: ${y instanceof Error?y.message:"Unknown error"}`)}}return{loaded:i,errors:s}}function xt(t={}){return{name:"env-plugin",setup(r){l(t)}}}function St(t={}){let r=A(t.env)||A("development")||A(process.env.DOTENV_ENV)||A(process.env.APP_ENV)||"development",c=t.cwd||process.cwd();if(q!==r)q=r,j=null,C=void 0;let n=[],f=(h)=>{if(!n.includes(h)&&H(W(c,h)))n.push(h)};f(".env"),f(".env.local");let g=`.env.${r}`,o=`.env.${r}.local`;return f(g),f(o),l({...t,path:n,env:r})}var Jt=xt;export{ut as resolvePrivateKey,jt as resetPrivateKeyCache,l as loadEnv,xt as envPlugin,Jt as default,Ct as decryptEnvValue,St as autoLoadEnv,Bt as activeEnvName};
2
+ import{createCipheriv as q,createDecipheriv as u,createHash as L,createPrivateKey as nt,createPublicKey as P,diffieHellman as p,generateKeyPairSync as z,hkdfSync as N,randomBytes as S}from"crypto";var U="x25519-public:",Z="x25519-private:",W="encrypted:v2:",Q="encrypted:",m=Buffer.from("stacks-env:v2","utf8"),d="Environment decryption failed: authentication or format error";function v(t){if(t.length===32)return t;return L("sha256").update(t).digest()}function Wt(t,n){let f=S(16),i=q("aes-256-gcm",v(n),f);return{ciphertext:Buffer.concat([i.update(t,"utf8"),i.final()]).toString("hex"),iv:f.toString("hex"),authTag:i.getAuthTag().toString("hex")}}function ft(t,n,f,i){try{let r=u("aes-256-gcm",v(n),Buffer.from(f,"hex"));return r.setAuthTag(Buffer.from(i,"hex")),Buffer.concat([r.update(Buffer.from(t,"hex")),r.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function _(t){return t.toString("base64url")}function y(t,n,f){if(typeof t!=="string"||t.length>0&&!/^[A-Za-z0-9_-]+$/.test(t))throw Error(`${n} is not canonical base64url`);let i=Buffer.from(t,"base64url");if(_(i)!==t)throw Error(`${n} is not canonical base64url`);if(f!==void 0&&i.length!==f)throw Error(`${n} has an invalid length`);return i}function it(t){if(!t.startsWith(U))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let n=P({key:y(t.slice(U.length),"public key"),format:"der",type:"spki"});if(n.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return n}function rt(t){if(!t.startsWith(Z))throw Error("Private key is not a version 2 X25519 key");let n=nt({key:y(t.slice(Z.length),"private key"),format:"der",type:"pkcs8"});if(n.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return n}function e(t){return Buffer.from(`stacks-env:v2;${t.epk};${t.salt};${t.nonce}`,"utf8")}function jt(){let{publicKey:t,privateKey:n}=z("x25519"),f=t.export({format:"der",type:"spki"}),i=n.export({format:"der",type:"pkcs8"});return{publicKey:`${U}${_(f)}`,privateKey:`${Z}${_(i)}`}}function gt(t,n){let f=it(n),i=z("x25519"),r=_(i.publicKey.export({format:"der",type:"spki"})),g=S(16),o=S(12),h=p({privateKey:i.privateKey,publicKey:f}),B=Buffer.from(N("sha256",h,g,m,32)),w={epk:r,salt:_(g),nonce:_(o)};try{let c=q("aes-256-gcm",B,o);c.setAAD(e(w));let s=Buffer.concat([c.update(t,"utf8"),c.final()]),$={v:2,...w,ciphertext:_(s),tag:_(c.getAuthTag())};return`${W}${_(Buffer.from(JSON.stringify($),"utf8"))}`}finally{h.fill(0),B.fill(0)}}function ct(t){let n=y(t.slice(W.length),"envelope").toString("utf8"),f=JSON.parse(n);if(!f||typeof f!=="object"||Array.isArray(f))throw Error("envelope is not an object");let i=Object.keys(f).sort(),r=["ciphertext","epk","nonce","salt","tag","v"];if(i.length!==r.length||i.some((g,o)=>g!==r[o]))throw Error("envelope fields are invalid");if(f.v!==2)throw Error("envelope version is unsupported");for(let g of["epk","salt","nonce","ciphertext","tag"])if(typeof f[g]!=="string")throw Error(`${g} is invalid`);return f}function ot(t,n){try{let f=ct(t),i=rt(n),r=P({key:y(f.epk,"ephemeral public key"),format:"der",type:"spki"});if(r.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let g=y(f.salt,"salt",16),o=y(f.nonce,"nonce",12),h=y(f.ciphertext,"ciphertext"),B=y(f.tag,"tag",16),w=p({privateKey:i,publicKey:r}),c=Buffer.from(N("sha256",w,g,m,32));try{let s=u("aes-256-gcm",c,o);return s.setAAD(e(f)),s.setAuthTag(B),Buffer.concat([s.update(h),s.final()]).toString("utf8")}finally{w.fill(0),c.fill(0)}}catch{throw Error(d)}}function ht(t,n){try{if(!/^[0-9a-f]{64}$/.test(n))throw Error("invalid legacy private key");let f=Buffer.from(t.slice(Q.length),"base64");if(f.length<32)throw Error("invalid legacy payload");let i=L("sha256").update(Buffer.from(n,"hex")).digest(),r=L("sha256").update(i).digest();return ft(f.subarray(32).toString("hex"),r,f.subarray(0,16).toString("hex"),f.subarray(16,32).toString("hex"))}catch{throw Error(d)}}function Ct(t){return t.startsWith(Q)&&!t.startsWith(W)}function K(t,n){if(!t.startsWith(Q))return t;return t.startsWith(W)?ot(t,n):ht(t,n)}function Gt(t,n,f){return gt(K(t,n),f)}function Jt(t){let n=t.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return n&&n[1]?n[1].toLowerCase():""}function V(t=""){return t?process.env[`DOTENV_PRIVATE_KEY_${t.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}import{spawnSync as wt}from"child_process";import{readFileSync as Bt}from"fs";import{arch as st,hostname as Tt,platform as l,release as $t,userInfo as At}from"os";import{basename as _t,dirname as yt,resolve as Et}from"path";function D(t,n={}){let f={},i=[],r=[],g=t.split(`
3
+ `);for(let o of g){let h=o.trim();if(!h||h.startsWith("#"))continue;if(h.startsWith("DOTENV_PUBLIC_KEY=")){let s=h.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(s&&s[1]!==void 0)f.DOTENV_PUBLIC_KEY=s[1];continue}let B=h.match(/^([^=]+)=(.*)$/);if(!B||B[1]===void 0||B[2]===void 0)continue;let w=B[1].trim(),c=B[2].trim();if(c.startsWith('"')&&c.endsWith('"')||c.startsWith("'")&&c.endsWith("'")){if(c=c.slice(1,-1),c.includes("\\n"))c=c.replace(/\\n/g,`
4
+ `)}if(c.startsWith("encrypted:")||c.startsWith("enc:")){if(!n.privateKey){r.push(w);continue}try{let s=c.startsWith("enc:")?`encrypted:${c.slice(4)}`:c;c=K(s,n.privateKey)}catch(s){i.push(`Failed to decrypt ${w}: ${s instanceof Error?s.message:"Unknown error"}`)}}c=Rt(c,{...n.processEnv||process.env,...f}),c=Dt(c),f[w]=c}return{parsed:f,errors:i,skippedEncrypted:r}}function Rt(t,n){return t.replace(/\$\{([^}]+)\}/g,(f,i)=>{let r=i.match(/^([^:\-+]+)(:-|-)(.+)$/);if(r){let[,o,h,B]=r,w=n[o];if(h===":-")return w||B;else return w!==void 0?w:B}let g=i.match(/^([^:\-+]+)(:?\+)(.+)$/);if(g){let[,o,h,B]=g,w=n[o];if(h===":+")return w?B:"";else return w!==void 0?B:""}return n[i]||""})}var bt=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function xt(t){let n=[],f="",i=null,r=!1;for(let g of t.trim()){if(r){f+=g,r=!1;continue}if(g==="\\"&&i!=="'"){r=!0;continue}if(i){if(g===i)i=null;else f+=g;continue}if(g==='"'||g==="'"){i=g;continue}if(/\s/.test(g)){if(f)n.push(f),f="";continue}f+=g}if(r||i)throw Error("Command substitution contains an unterminated escape or quote");if(f)n.push(f);return n}function Kt(t){let[n,...f]=t,i=f.some((r)=>r.startsWith("-"));if(n==="echo"&&!i)return f.join(" ");if(n==="printf"&&f.length===1&&!f[0]?.includes("%"))return f[0];if(n==="hostname"&&f.length===0)return Tt();if(n==="whoami"&&f.length===0)return At().username;if(n==="pwd"&&f.length===0)return process.cwd();if(n==="basename"&&f.length===1)return _t(f[0]??"");if(n==="dirname"&&f.length===1)return yt(f[0]??"");if(n==="cat"&&f.length>0&&!i)return f.map((r)=>Bt(Et(process.cwd(),r),"utf8")).join("");if(n==="uname"){let r=f[0]??"-s";if(f.length<=1&&r==="-m")return st();if(f.length<=1&&r==="-r")return $t();if(f.length<=1&&r==="-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"}[l()]??l()}return}function Dt(t){return t.replace(/\$\(([^)]+)\)/g,(n,f)=>{try{let i=xt(f),r=i[0];if(!r||!bt.has(r))return console.warn(`[env] Blocked command substitution for disallowed command: ${r}`),"";let g=Kt(i);if(g!==void 0)return g.trim();let o=wt(r,i.slice(1),{encoding:"utf8",env:process.env});if(o.status===0)return o.stdout.trim();let h=o.stderr.trim();console.warn(`[env] Command substitution failed (exit code ${o.status??"unknown"}): ${r}${h?`: ${h}`:""}`)}catch(i){console.warn(`[env] Command substitution error: ${i instanceof Error?i.message:String(i)}`)}return""})}async function Ft(t,n={}){let f={},i=[],r=[];for(let g of t)try{let o=Bun.file(g);if(!o.size)continue;let h=await o.text(),{parsed:B,errors:w,skippedEncrypted:c}=D(h,n);i.push(...w),r.push(...c);for(let[s,$]of Object.entries(B)){if(!n.overload&&f[s]!==void 0)continue;f[s]=$}}catch(o){if(o?.code==="ENOENT")continue;i.push(`Failed to read ${g}: ${o instanceof Error?o.message:String(o)}`)}return{parsed:f,errors:i,skippedEncrypted:r}}import{existsSync as j}from"fs";import{readFileSync as F}from"fs";import{resolve as C}from"path";function X(t){return typeof t==="string"&&(t.startsWith("encrypted:")||t.startsWith("enc:"))}function E(t){if(!t||X(t))return;let n=t.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 G=null,J,M;function Xt(t,n,f=".env.keys"){let i=C(n,f);if(!j(i))return;try{let{parsed:r}=D(F(i,"utf-8"));if(t){let g=r[`DOTENV_PRIVATE_KEY_${t.toUpperCase()}`];if(g)return g}return r.DOTENV_PRIVATE_KEY}catch{return}}function Ot(t={}){return E(t.env)||M||E("development")||E(process.env.DOTENV_ENV)||E(process.env.APP_ENV)||"development"}function Yt(t={}){let n=Ot(t),f=t.cwd||process.cwd();if(G===n)return J;let i=V(n);if(!i)i=process.env.DOTENV_PRIVATE_KEY;if(!i)i=Xt(n,f);return G=n,J=i,i}function Nt(){G=null,J=void 0}function mt(t,n={}){if(!X(t))return t;let f=Yt(n);if(!f)return;try{let i=t.startsWith("enc:")?`encrypted:${t.slice(4)}`:t;return K(i,f)}catch{return}}function a(t={}){let{path:n=[".env"],overload:f=!1,env:i,privateKey:r,keysFile:g=".env.keys",quiet:o=!1,cwd:h=process.cwd()}=t,B=Array.isArray(n)?n:[n],w=[],c=0,s=new Set(Object.entries(process.env).filter(([,T])=>T!==void 0&&!X(T)).map(([T])=>T)),$=r;if(!$&&g){let T=C(h,g);if(j(T))try{let A=F(T,"utf-8"),{parsed:R}=D(A);if(i){let O=`DOTENV_PRIVATE_KEY_${i.toUpperCase()}`;$=R[O]}else $=R.DOTENV_PRIVATE_KEY}catch(A){w.push(`Failed to load keys file: ${A instanceof Error?A.message:"Unknown error"}`)}}if(!$)$=V(i||"");for(let T of B){let A=C(h,T);if(!j(A)){if(!o)w.push(`File not found: ${A}`);continue}try{let R=F(A,"utf-8"),{parsed:O,errors:tt,skippedEncrypted:b}=D(R,{privateKey:$,processEnv:process.env});if(w.push(...tt),b.length>0){for(let I of b)if(X(process.env[I]))delete process.env[I];let x=i?`DOTENV_PRIVATE_KEY_${i.toUpperCase()}`:"DOTENV_PRIVATE_KEY",Y=b.slice(0,5).join(", "),H=b.length>5?`, \u2026 +${b.length-5} more`:"";console.warn(`[env] warning: skipped ${b.length} encrypted value(s) in ${T} (${x} not set; defaults apply): ${Y}${H}`)}let k=0;for(let[x,Y]of Object.entries(O)){if(x==="DOTENV_PUBLIC_KEY")continue;let H=process.env[x],I=X(H)&&Y!==H;if(f||!s.has(x)||I)process.env[x]=Y,c++,k++}if(!o&&!process.env.__ENV_LOADED__)console.error(`[env] loaded ${k}/${Object.keys(O).length} variables from ${T}`),process.env.__ENV_LOADED__="1"}catch(R){w.push(`Failed to load ${A}: ${R instanceof Error?R.message:"Unknown error"}`)}}return{loaded:c,errors:w}}function Ht(t={}){return{name:"env-plugin",setup(n){a(t)}}}function dt(t={}){let n=E(t.env)||E("development")||E(process.env.DOTENV_ENV)||E(process.env.APP_ENV)||"development",f=t.cwd||process.cwd();if(M!==n)M=n,G=null,J=void 0;let i=[],r=(h)=>{if(!i.includes(h)&&j(C(f,h)))i.push(h)};r(".env"),r(".env.local");let g=`.env.${n}`,o=`.env.${n}.local`;return r(g),r(o),a({...t,path:i,env:n})}var et=Ht;export{Yt as resolvePrivateKey,Nt as resetPrivateKeyCache,a as loadEnv,Ht as envPlugin,et as default,mt as decryptEnvValue,dt as autoLoadEnv,Ot as activeEnvName};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/env",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.229",
5
+ "version": "0.70.231",
6
6
  "description": "Stacks env helper methods.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "devDependencies": {
53
53
  "better-dx": "^0.2.17",
54
- "@stacksjs/path": "0.70.229",
55
- "@stacksjs/validation": "0.70.229"
54
+ "@stacksjs/path": "0.70.231",
55
+ "@stacksjs/validation": "0.70.231"
56
56
  }
57
57
  }