@stacksjs/env 0.72.79 → 0.72.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -2
- package/dist/index.js +21 -21
- package/dist/types.d.ts +94 -11
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { EnvKey } from '
|
|
2
|
-
import type { StacksEnv } from './types';
|
|
1
|
+
import type { EnvKey, StacksEnv } from './types';
|
|
3
2
|
export declare function process(): StacksEnv;
|
|
4
3
|
// eslint-disable-next-line pickier/no-unused-vars
|
|
5
4
|
export declare function writeEnv(key: EnvKey, value: string, options?: { path: string }): void;
|
package/dist/index.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{createCipheriv as re,createDecipheriv as ie,createHash as G,createPrivateKey as Ce,createPublicKey as se,diffieHellman as oe,generateKeyPairSync as de,hkdfSync as
|
|
3
|
-
`);for(let o of s){let
|
|
4
|
-
`)}if(d.startsWith("encrypted:")||d.startsWith("enc:")){if(!n.privateKey){i.push(u);continue}try{let f=d.startsWith("enc:")?`encrypted:${d.slice(4)}`:d;d=
|
|
5
|
-
`)){let
|
|
6
|
-
`)}function W(e){let t=((e||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase();return{publicKeyName:t?`DOTENV_PUBLIC_KEY_${t}`:"DOTENV_PUBLIC_KEY",privateKeyName:t?`DOTENV_PRIVATE_KEY_${t}`:"DOTENV_PRIVATE_KEY"}}function
|
|
7
|
-
`)){let s=i.trim();if(!s||s.startsWith("#"))continue;let o=s.match(/^([^=]+)=(.*)$/);if(!o?.[1]||o[2]===void 0)continue;let
|
|
2
|
+
import{createCipheriv as re,createDecipheriv as ie,createHash as G,createPrivateKey as Ce,createPublicKey as se,diffieHellman as oe,generateKeyPairSync as de,hkdfSync as ae,randomBytes as H}from"crypto";var X="x25519-public:",j="x25519-private:",x="encrypted:v2:",Q="encrypted:",ce=Buffer.from("stacks-env:v2","utf8"),ue="Environment decryption failed: authentication or format error";function fe(e){if(e.length===32)return e;return G("sha256").update(e).digest()}function yn(e,n){let t=H(16),r=re("aes-256-gcm",fe(n),t);return{ciphertext:Buffer.concat([r.update(e,"utf8"),r.final()]).toString("hex"),iv:t.toString("hex"),authTag:r.getAuthTag().toString("hex")}}function be(e,n,t,r){try{let i=ie("aes-256-gcm",fe(n),Buffer.from(t,"hex"));return i.setAuthTag(Buffer.from(r,"hex")),Buffer.concat([i.update(Buffer.from(e,"hex")),i.final()]).toString("utf8")}catch{throw Error("Decryption failed: authentication or format error")}}function P(e){return e.toString("base64url")}function b(e,n,t){if(typeof e!=="string"||e.length>0&&!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`${n} is not canonical base64url`);let r=Buffer.from(e,"base64url");if(P(r)!==e)throw Error(`${n} is not canonical base64url`);if(t!==void 0&&r.length!==t)throw Error(`${n} has an invalid length`);return r}function Ke(e){if(!e.startsWith(X))throw Error("Legacy or invalid public key. Run buddy env:rotate before creating new ciphertext.");let n=se({key:b(e.slice(X.length),"public key"),format:"der",type:"spki"});if(n.asymmetricKeyType!=="x25519")throw Error("Public key is not X25519");return n}function Le(e){if(!e.startsWith(j))throw Error("Private key is not a version 2 X25519 key");let n=Ce({key:b(e.slice(j.length),"private key"),format:"der",type:"pkcs8"});if(n.asymmetricKeyType!=="x25519")throw Error("Private key is not X25519");return n}function Ee(e){return Buffer.from(`stacks-env:v2;${e.epk};${e.salt};${e.nonce}`,"utf8")}function k(){let{publicKey:e,privateKey:n}=de("x25519"),t=e.export({format:"der",type:"spki"}),r=n.export({format:"der",type:"pkcs8"});return{publicKey:`${X}${P(t)}`,privateKey:`${j}${P(r)}`}}function w(e,n){let t=Ke(n),r=de("x25519"),i=P(r.publicKey.export({format:"der",type:"spki"})),s=H(16),o=H(12),c=oe({privateKey:r.privateKey,publicKey:t}),a=Buffer.from(ae("sha256",c,s,ce,32)),u={epk:i,salt:P(s),nonce:P(o)};try{let d=re("aes-256-gcm",a,o);d.setAAD(Ee(u));let f=Buffer.concat([d.update(e,"utf8"),d.final()]),p={v:2,...u,ciphertext:P(f),tag:P(d.getAuthTag())};return`${x}${P(Buffer.from(JSON.stringify(p),"utf8"))}`}finally{c.fill(0),a.fill(0)}}function ke(e){let n=b(e.slice(x.length),"envelope").toString("utf8"),t=JSON.parse(n);if(!t||typeof t!=="object"||Array.isArray(t))throw Error("envelope is not an object");let r=Object.keys(t).sort(),i=["ciphertext","epk","nonce","salt","tag","v"];if(r.length!==i.length||r.some((s,o)=>s!==i[o]))throw Error("envelope fields are invalid");if(t.v!==2)throw Error("envelope version is unsupported");for(let s of["epk","salt","nonce","ciphertext","tag"])if(typeof t[s]!=="string")throw Error(`${s} is invalid`);return t}function Ue(e,n){try{let t=ke(e),r=Le(n),i=se({key:b(t.epk,"ephemeral public key"),format:"der",type:"spki"});if(i.asymmetricKeyType!=="x25519")throw Error("ephemeral key is not X25519");let s=b(t.salt,"salt",16),o=b(t.nonce,"nonce",12),c=b(t.ciphertext,"ciphertext"),a=b(t.tag,"tag",16),u=oe({privateKey:r,publicKey:i}),d=Buffer.from(ae("sha256",u,s,ce,32));try{let f=ie("aes-256-gcm",d,o);return f.setAAD(Ee(t)),f.setAuthTag(a),Buffer.concat([f.update(c),f.final()]).toString("utf8")}finally{u.fill(0),d.fill(0)}}catch{throw Error(ue)}}function xe(e,n){try{if(!/^[0-9a-f]{64}$/.test(n))throw Error("invalid legacy private key");let t=Buffer.from(e.slice(Q.length),"base64");if(t.length<32)throw Error("invalid legacy payload");let r=G("sha256").update(Buffer.from(n,"hex")).digest(),i=G("sha256").update(r).digest();return be(t.subarray(32).toString("hex"),i,t.subarray(0,16).toString("hex"),t.subarray(16,32).toString("hex"))}catch{throw Error(ue)}}function mn(e){return e.startsWith(Q)&&!e.startsWith(x)}function L(e,n){if(!e.startsWith(Q))return e;return e.startsWith(x)?Ue(e,n):xe(e,n)}function Rn(e,n,t){return w(L(e,n),t)}function vn(e){let n=e.match(/^DOTENV_PRIVATE_KEY_(.+)$/);return n&&n[1]?n[1].toLowerCase():""}function q(e=""){return e?process.env[`DOTENV_PRIVATE_KEY_${e.toUpperCase()}`]:process.env.DOTENV_PRIVATE_KEY}import{spawnSync as $e}from"child_process";import{readFileSync as we}from"fs";import{arch as Be,hostname as Ve,platform as le,release as Me,userInfo as Fe}from"os";import{basename as Ye,dirname as We,resolve as Ge}from"path";function I(e,n={}){let t={},r=[],i=[],s=e.split(`
|
|
3
|
+
`);for(let o of s){let c=o.trim();if(!c||c.startsWith("#"))continue;if(c.startsWith("DOTENV_PUBLIC_KEY=")){let f=c.match(/^DOTENV_PUBLIC_KEY=["']?([^"'\n]+)["']?/);if(f&&f[1]!==void 0)t.DOTENV_PUBLIC_KEY=f[1];continue}let a=c.match(/^([^=]+)=(.*)$/);if(!a||a[1]===void 0||a[2]===void 0)continue;let u=a[1].trim(),d=a[2].trim();if(d.startsWith('"')&&d.endsWith('"')||d.startsWith("'")&&d.endsWith("'")){if(d=d.slice(1,-1),d.includes("\\n"))d=d.replace(/\\n/g,`
|
|
4
|
+
`)}if(d.startsWith("encrypted:")||d.startsWith("enc:")){if(!n.privateKey){i.push(u);continue}try{let f=d.startsWith("enc:")?`encrypted:${d.slice(4)}`:d;d=L(f,n.privateKey)}catch(f){r.push(`Failed to decrypt ${u}: ${f instanceof Error?f.message:"Unknown error"}`)}}d=He(d,{...n.processEnv||process.env,...t}),d=qe(d),t[u]=d}return{parsed:t,errors:r,skippedEncrypted:i}}function He(e,n){return e.replace(/\$\{([^}]+)\}/g,(t,r)=>{let i=r.match(/^([^:\-+]+)(:-|-)(.+)$/);if(i){let[,o,c,a]=i,u=n[o];if(c===":-")return u||a;else return u!==void 0?u:a}let s=r.match(/^([^:\-+]+)(:?\+)(.+)$/);if(s){let[,o,c,a]=s,u=n[o];if(c===":+")return u?a:"";else return u!==void 0?a:""}return n[r]||""})}var Xe=new Set(["date","hostname","whoami","uname","pwd","echo","printf","cat","basename","dirname"]);function je(e){let n=[],t="",r=null,i=!1;for(let s of e.trim()){if(i){t+=s,i=!1;continue}if(s==="\\"&&r!=="'"){i=!0;continue}if(r){if(s===r)r=null;else t+=s;continue}if(s==='"'||s==="'"){r=s;continue}if(/\s/.test(s)){if(t)n.push(t),t="";continue}t+=s}if(i||r)throw Error("Command substitution contains an unterminated escape or quote");if(t)n.push(t);return n}function Qe(e){let[n,...t]=e,r=t.some((i)=>i.startsWith("-"));if(n==="echo"&&!r)return t.join(" ");if(n==="printf"&&t.length===1&&!t[0]?.includes("%"))return t[0];if(n==="hostname"&&t.length===0)return Ve();if(n==="whoami"&&t.length===0)return Fe().username;if(n==="pwd"&&t.length===0)return process.cwd();if(n==="basename"&&t.length===1)return Ye(t[0]??"");if(n==="dirname"&&t.length===1)return We(t[0]??"");if(n==="cat"&&t.length>0&&!r)return t.map((i)=>we(Ge(process.cwd(),i),"utf8")).join("");if(n==="uname"){let i=t[0]??"-s";if(t.length<=1&&i==="-m")return Be();if(t.length<=1&&i==="-r")return Me();if(t.length<=1&&i==="-s")return{aix:"AIX",android:"Android",cygwin:"CYGWIN",darwin:"Darwin",freebsd:"FreeBSD",haiku:"Haiku",linux:"Linux",netbsd:"NetBSD",openbsd:"OpenBSD",sunos:"SunOS",win32:"Windows_NT"}[le()]??le()}return}function qe(e){return e.replace(/\$\(([^)]+)\)/g,(n,t)=>{try{let r=je(t),i=r[0];if(!i||!Xe.has(i))return console.warn(`[env] Blocked command substitution for disallowed command: ${i}`),"";let s=Qe(r);if(s!==void 0)return s.trim();let o=$e(i,r.slice(1),{encoding:"utf8",env:process.env});if(o.status===0)return o.stdout.trim();let c=o.stderr.trim();console.warn(`[env] Command substitution failed (exit code ${o.status??"unknown"}): ${i}${c?`: ${c}`:""}`)}catch(r){console.warn(`[env] Command substitution error: ${r instanceof Error?r.message:String(r)}`)}return""})}async function Pn(e,n={}){let t={},r=[],i=[];for(let s of e)try{let o=Bun.file(s);if(!o.size)continue;let c=await o.text(),{parsed:a,errors:u,skippedEncrypted:d}=I(c,n);r.push(...u),i.push(...d);for(let[f,p]of Object.entries(a)){if(!n.overload&&t[f]!==void 0)continue;t[f]=p}}catch(o){if(o?.code==="ENOENT")continue;r.push(`Failed to read ${s}: ${o instanceof Error?o.message:String(o)}`)}return{parsed:t,errors:r,skippedEncrypted:i}}import{existsSync as B}from"fs";import{readFileSync as z}from"fs";import{resolve as V}from"path";function U(e){return typeof e==="string"&&(e.startsWith("encrypted:")||e.startsWith("enc:"))}function K(e){if(!e||U(e))return;let n=e.trim().toLowerCase();if(!/^[a-z0-9_-]+$/.test(n))return;if(n==="prod")return"production";if(n==="stage")return"staging";if(n==="dev")return"development";return n}var M=null,F,Y;function ze(e,n,t=".env.keys"){let r=V(n,t);if(!B(r))return;try{let{parsed:i}=I(z(r,"utf-8"));if(e){let s=i[`DOTENV_PRIVATE_KEY_${e.toUpperCase()}`];if(s)return s}return i.DOTENV_PRIVATE_KEY}catch{return}}function J(e={}){return K(e.env)||Y||K("development")||K(process.env.DOTENV_ENV)||K(process.env.APP_ENV)||"development"}function Je(e={}){let n=J(e),t=e.cwd||process.cwd();if(M===n)return F;let r=q(n);if(!r)r=process.env.DOTENV_PRIVATE_KEY;if(!r)r=ze(n,t);return M=n,F=r,r}function Un(){M=null,F=void 0,Y=void 0}function pe(e,n={}){if(!U(e))return e;let t=Je(n);if(!t)return;try{let r=e.startsWith("enc:")?`encrypted:${e.slice(4)}`:e;return L(r,t)}catch{return}}function ge(e={}){let{path:n=[".env"],overload:t=!1,env:r,privateKey:i,keysFile:s=".env.keys",quiet:o=!1,cwd:c=process.cwd()}=e,a=Array.isArray(n)?n:[n],u=[],d=0,f=new Set(Object.entries(process.env).filter(([,E])=>E!==void 0&&!U(E)).map(([E])=>E)),p=i;if(!p&&s){let E=V(c,s);if(B(E))try{let l=z(E,"utf-8"),{parsed:m}=I(l);if(r){let v=`DOTENV_PRIVATE_KEY_${r.toUpperCase()}`;p=m[v]}else p=m.DOTENV_PRIVATE_KEY}catch(l){u.push(`Failed to load keys file: ${l instanceof Error?l.message:"Unknown error"}`)}}if(!p)p=q(r||"");for(let E of a){let l=V(c,E);if(!B(l)){if(!o)u.push(`File not found: ${l}`);continue}try{let m=z(l,"utf-8"),{parsed:v,errors:y,skippedEncrypted:T}=I(m,{privateKey:p,processEnv:process.env});if(u.push(...y),T.length>0){for(let C of T)if(U(process.env[C]))delete process.env[C];let g=r?`DOTENV_PRIVATE_KEY_${r.toUpperCase()}`:"DOTENV_PRIVATE_KEY",N=T.slice(0,5).join(", "),D=T.length>5?`, \u2026 +${T.length-5} more`:"";console.warn(`[env] warning: skipped ${T.length} encrypted value(s) in ${E} (${g} not set; defaults apply): ${N}${D}`)}let R=0;for(let[g,N]of Object.entries(v)){if(g==="DOTENV_PUBLIC_KEY")continue;let D=process.env[g],C=U(D)&&N!==D;if(t||!f.has(g)||C)process.env[g]=N,d++,R++}if(!o&&!process.env.__ENV_LOADED__)console.error(`[env] loaded ${R}/${Object.keys(v).length} variables from ${E}`),process.env.__ENV_LOADED__="1"}catch(m){u.push(`Failed to load ${l}: ${m instanceof Error?m.message:"Unknown error"}`)}}return{loaded:d,errors:u}}function Ze(e={}){return{name:"env-plugin",setup(n){ge(e)}}}function xn(e={}){let n=K(e.env)||K("development")||K(process.env.DOTENV_ENV)||K(process.env.APP_ENV)||"development",t=e.cwd||process.cwd();if(Y!==n)Y=n,M=null,F=void 0;let r=[],i=(c)=>{if(!r.includes(c)&&B(V(t,c)))r.push(c)};i(".env"),i(".env.local");let s=`.env.${n}`,o=`.env.${n}.local`;return i(s),i(o),ge({...e,path:r,env:n})}var wn=Ze;import{existsSync as S,readFileSync as O,renameSync as Z,rmSync as _e,writeFileSync as h}from"fs";import{basename as ee,dirname as Te,resolve as A}from"path";function Yn(e,n){if(e)return e;let t=String(n??"").trim();if(!t||t==="development"||t==="dev"||t==="local")return"";if(!/^[\w.-]+$/.test(t))return"";return`.env.${t}`}function ye(e,n,t,r){let i=["#/-------------------[DOTENV_PUBLIC_KEY]--------------------/","#/ versioned X25519 encryption for .env files /","#/ [how it works](https://stacksjs.com/encryption) /","#/----------------------------------------------------------/",`${t}="${n}"`,""],s=!1;for(let o of e.split(`
|
|
5
|
+
`)){let c=o.trim();if(c.startsWith("#/"))continue;if(c.startsWith("DOTENV_PUBLIC_KEY"))continue;if(!c&&!s)continue;if(!c||c.startsWith("#")){s=!0,i.push(o);continue}s=!0;let a=c.match(/^([^=]+)=(.*)$/);if(!a||a[1]===void 0||a[2]===void 0){i.push(o);continue}let u=a[1].trim(),d=a[2].trim();if(d.startsWith('"')&&d.endsWith('"')||d.startsWith("'")&&d.endsWith("'"))d=d.slice(1,-1);if((!r.key||u.includes(r.key))&&(!r.excludeKey||!u.includes(r.excludeKey))&&!d.startsWith("encrypted:"))d=w(d,n);i.push(`${u}="${d}"`)}return i.join(`
|
|
6
|
+
`)}function W(e){let t=((e||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase();return{publicKeyName:t?`DOTENV_PUBLIC_KEY_${t}`:"DOTENV_PUBLIC_KEY",privateKeyName:t?`DOTENV_PRIVATE_KEY_${t}`:"DOTENV_PRIVATE_KEY"}}function me(e,n){let t,r=!1;for(let i of e.split(`
|
|
7
|
+
`)){let s=i.trim();if(!s||s.startsWith("#"))continue;let o=s.match(/^([^=]+)=(.*)$/);if(!o?.[1]||o[2]===void 0)continue;let c=o[1].trim(),a=o[2].trim().replace(/^["']|["']$/g,"");if(c===n)t=a;else if(a.startsWith("encrypted:")||a.startsWith("enc:"))r=!0}return t&&r?t:void 0}function Wn(e={}){let n=e.cwd||process.cwd(),t=A(n,e.file||".env"),r=A(n,e.keysFile||".env.keys");if(!S(t))return{success:!1,error:`File not found: ${t}`};try{let i,s,o=me(O(t,"utf-8"),W(e.file).publicKeyName);if(o)i=o;else if(S(r)){let u=O(r,"utf-8"),{parsed:d}=I(u),{publicKeyName:f,privateKeyName:p}=W(e.file);if(i=d[f]||"",s=d[p]||"",!i||!s){let E=k();i=E.publicKey,s=E.privateKey;let l=`
|
|
8
8
|
${f}="${i}"
|
|
9
9
|
${p}="${s}"
|
|
10
10
|
`;h(r,u+l,"utf-8")}}else{let u=k();i=u.publicKey,s=u.privateKey;let{publicKeyName:d,privateKeyName:f}=W(e.file),p=`# .env.keys - Keep this file secure and never commit to source control
|
|
11
11
|
${d}="${i}"
|
|
12
12
|
${f}="${s}"
|
|
13
|
-
`;h(r,p,"utf-8")}let
|
|
14
|
-
\u2714 key added to ${e.keysFile||".env.keys"}`}}catch(i){return{success:!1,error:`Failed to encrypt: ${i instanceof Error?i.message:"Unknown error"}`}}}function en(e={}){let n=e.cwd||process.cwd(),t=A(n,e.file||".env"),r=A(n,e.keysFile||".env.keys");if(!S(t))return{success:!1,error:`File not found: ${t}`};if(!S(r))return{success:!1,error:`Keys file not found: ${r}`};try{let i=
|
|
15
|
-
`),l=[];for(let v of E){let
|
|
16
|
-
`);if(e.stdout)return{success:!0,output:
|
|
17
|
-
`),
|
|
18
|
-
${E}="${
|
|
19
|
-
${l}="${
|
|
20
|
-
`,h(s,
|
|
21
|
-
`);return h(i,v,"utf-8"),{success:!0,output:`set ${e}${t.plain?"":" with encryption"} (${t.file||".env"})`}}catch(o){return{success:!1,error:`Failed to set: ${o instanceof Error?o.message:"Unknown error"}`}}}function Hn(e,n={}){let t=n.cwd||process.cwd(),r=A(t,n.file||".env");if(!S(r))return{success:!1,error:`File not found: ${r}`};try{let i,s=A(t,n.keysFile||".env.keys"),
|
|
22
|
-
`);break;case"json":default:E=n.prettyPrint?JSON.stringify(p,null,2):JSON.stringify(p);break}return{success:!0,output:E}}catch(i){return{success:!1,error:`Failed to get: ${i instanceof Error?i.message:"Unknown error"}`}}}function Xn(e,n={}){let t=n.cwd||process.cwd(),r=A(t,n.keysFile||".env.keys");if(!S(r))return{success:!1,error:`Keys file not found: ${r}`};try{let i=
|
|
23
|
-
`),u=e.file||".env",d=ee(u).replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),f=d?`DOTENV_PUBLIC_KEY_${d}`:"DOTENV_PUBLIC_KEY",p=d?`DOTENV_PRIVATE_KEY_${d}`:"DOTENV_PRIVATE_KEY",E=!1,l=!1;for(let g=0;g<
|
|
13
|
+
`;h(r,p,"utf-8")}let c=O(t,"utf-8"),a=ye(c,i,W(e.file).publicKeyName,e);if(e.stdout)return{success:!0,output:a};return h(t,a,"utf-8"),{success:!0,output:`\u2714 encrypted (${e.file||".env"})
|
|
14
|
+
\u2714 key added to ${e.keysFile||".env.keys"}`}}catch(i){return{success:!1,error:`Failed to encrypt: ${i instanceof Error?i.message:"Unknown error"}`}}}function en(e={}){let n=e.cwd||process.cwd(),t=A(n,e.file||".env"),r=A(n,e.keysFile||".env.keys");if(!S(t))return{success:!1,error:`File not found: ${t}`};if(!S(r))return{success:!1,error:`Keys file not found: ${r}`};try{let i=O(r,"utf-8"),{parsed:s}=I(i),a=((e.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=a?`DOTENV_PRIVATE_KEY_${a}`:"DOTENV_PRIVATE_KEY",d=s[u];if(!d)return{success:!1,error:`Private key not found: ${u}`};let f=[d];if(u!=="DOTENV_PRIVATE_KEY"&&s.DOTENV_PRIVATE_KEY&&s.DOTENV_PRIVATE_KEY!==d)f.push(s.DOTENV_PRIVATE_KEY);let E=O(t,"utf-8").split(`
|
|
15
|
+
`),l=[];for(let v of E){let y=v.trim();if(!y||y.startsWith("#")){l.push(v);continue}if(y.startsWith("DOTENV_PUBLIC_KEY"))continue;let T=y.match(/^([^=]+)=(.*)$/);if(!T||T[1]===void 0||T[2]===void 0){l.push(v);continue}let R=T[1].trim(),g=T[2].trim();if(g.startsWith('"')&&g.endsWith('"')||g.startsWith("'")&&g.endsWith("'"))g=g.slice(1,-1);let N=g.startsWith("encrypted:");if(e.key&&!R.includes(e.key))N=!1;if(N){let D,C;for(let Pe of f)try{D=L(g,Pe);break}catch(De){C=De}if(D===void 0)throw C instanceof Error?C:Error(`Unable to decrypt ${R}`);g=D}l.push(`${R}="${g}"`)}let m=l.join(`
|
|
16
|
+
`);if(e.stdout)return{success:!0,output:m};return h(t,m,"utf-8"),{success:!0,output:`\u2714 decrypted (${e.file||".env"})`}}catch(i){return{success:!1,error:`Failed to decrypt: ${i instanceof Error?i.message:"Unknown error"}`}}}function Gn(e,n,t={}){let r=t.cwd||process.cwd(),i=A(r,t.file||".env"),s=A(r,t.keysFile||".env.keys");try{let o="";if(S(i))o=O(i,"utf-8");let c=o.split(`
|
|
17
|
+
`),a=!1,u,p=((t.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),E=p?`DOTENV_PUBLIC_KEY_${p}`:"DOTENV_PUBLIC_KEY",l=p?`DOTENV_PRIVATE_KEY_${p}`:"DOTENV_PRIVATE_KEY";for(let y of c){let T=y.trim();if(T.startsWith(`${E}=`)){let R=T.match(/^[^=]+=["']?([^"'\n]+)["']?/);if(R)u=R[1];break}}if(u){let y=!1;if(S(s)){let T=O(s,"utf-8"),{parsed:R}=I(T);y=Boolean(R[l])}if(!y&&!process.env[l]&&!me(o,E))u=void 0}if(!t.plain&&!u){let y=k();u=y.publicKey;let T="";if(S(s))T=O(s,"utf-8");T+=`
|
|
18
|
+
${E}="${y.publicKey}"
|
|
19
|
+
${l}="${y.privateKey}"
|
|
20
|
+
`,h(s,T,"utf-8");for(let R=c.length-1;R>=0;R--){let g=c[R];if(g!==void 0&&g.trim().startsWith(`${E}=`))c.splice(R,1)}c.unshift(`${E}="${u}"`)}let m=n;if(!t.plain&&u)m=w(n,u);for(let y=0;y<c.length;y++){let T=c[y];if(T===void 0)continue;if(T.trim().startsWith(`${e}=`)){c[y]=`${e}="${m}"`,a=!0;break}}if(!a)c.push(`${e}="${m}"`);let v=c.join(`
|
|
21
|
+
`);return h(i,v,"utf-8"),{success:!0,output:`set ${e}${t.plain?"":" with encryption"} (${t.file||".env"})`}}catch(o){return{success:!1,error:`Failed to set: ${o instanceof Error?o.message:"Unknown error"}`}}}function Hn(e,n={}){let t=n.cwd||process.cwd(),r=A(t,n.file||".env");if(!S(r))return{success:!1,error:`File not found: ${r}`};try{let i,s=A(t,n.keysFile||".env.keys"),a=((n.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=a?`DOTENV_PRIVATE_KEY_${a}`:"DOTENV_PRIVATE_KEY";if(S(s)){let l=O(s,"utf-8"),{parsed:m}=I(l);i=m[u]}if(!i)i=process.env[u];let d=O(r,"utf-8"),{parsed:f}=I(d,{privateKey:i});if(e&&!n.all){let l=f[e];if(l===void 0)return{success:!1,error:`Key not found: ${e}`};return{success:!0,output:l}}let p=n.all?{...process.env,...f}:f,E;switch(n.format){case"shell":E=Object.entries(p).map(([l,m])=>`${l}=${m}`).join(" ");break;case"eval":E=Object.entries(p).map(([l,m])=>`${l}="${m}"`).join(`
|
|
22
|
+
`);break;case"json":default:E=n.prettyPrint?JSON.stringify(p,null,2):JSON.stringify(p);break}return{success:!0,output:E}}catch(i){return{success:!1,error:`Failed to get: ${i instanceof Error?i.message:"Unknown error"}`}}}function Xn(e,n={}){let t=n.cwd||process.cwd(),r=A(t,n.keysFile||".env.keys");if(!S(r))return{success:!1,error:`Keys file not found: ${r}`};try{let i=O(r,"utf-8"),{parsed:s}=I(i),a=((n.file||".env").split("/").pop()||"").replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),u=a?`DOTENV_PUBLIC_KEY_${a}`:"DOTENV_PUBLIC_KEY",d=a?`DOTENV_PRIVATE_KEY_${a}`:"DOTENV_PRIVATE_KEY";if(e){let E=s[e];if(!E)return{success:!1,error:`Key not found: ${e}`};return{success:!0,output:E}}let f={[u]:s[u],[d]:s[d]};return{success:!0,output:n.format==="shell"?`${u}=${f[u]} ${d}=${f[d]}`:JSON.stringify(f)}}catch(i){return{success:!1,error:`Failed to get keypair: ${i instanceof Error?i.message:"Unknown error"}`}}}function jn(e={}){let n=en({file:e.file,keysFile:e.keysFile,stdout:!0,cwd:e.cwd});if(!n.success)return n;let t=e.cwd||process.cwd(),r=A(t,e.file||".env"),i=A(t,e.keysFile||".env.keys");if(n.output===void 0)return{success:!1,error:"Rotation produced no decrypted content"};let s=k(),o=O(r),c=O(i),a=c.toString("utf8").split(`
|
|
23
|
+
`),u=e.file||".env",d=ee(u).replace(/^\.env\./,"").replace(/^\.env$/,"").toUpperCase(),f=d?`DOTENV_PUBLIC_KEY_${d}`:"DOTENV_PUBLIC_KEY",p=d?`DOTENV_PRIVATE_KEY_${d}`:"DOTENV_PRIVATE_KEY",E=!1,l=!1;for(let g=0;g<a.length;g++){let N=a[g];if(N===void 0)continue;if(N.startsWith(`${f}=`))a[g]=`${f}="${s.publicKey}"`,E=!0;else if(N.startsWith(`${p}=`))a[g]=`${p}="${s.privateKey}"`,l=!0}if(!E)a.push(`${f}="${s.publicKey}"`);if(!l)a.push(`${p}="${s.privateKey}"`);let m=`${a.join(`
|
|
24
24
|
`).replace(/\n+$/,"")}
|
|
25
|
-
`,v=
|
|
26
|
-
`).map((n)=>n.trim()).filter(Boolean).filter((n)=>n!==".env.example").filter((n)=>/(?:^|\/)\.env(?:\.|$)/.test(n)).filter((n)=>!n.endsWith(".env.keys"))}function
|
|
27
|
-
`),o=s.findIndex((u)=>u.startsWith(`${e}=`)),
|
|
28
|
-
`))}function
|
|
25
|
+
`,v=ye(n.output,s.publicKey,f,e),y=`${process.pid}-${Date.now()}`,T=A(Te(r),`.${ee(r)}.${y}.rotate`),R=A(Te(i),`.${ee(i)}.${y}.rotate`);try{if(h(T,v,{encoding:"utf8",mode:384}),h(R,m,{encoding:"utf8",mode:384}),e.stdout)return Z(R,i),{success:!0,output:v};Z(T,r);try{Z(R,i)}catch(g){throw h(r,o),g}return{success:!0,output:`\u2714 rotated (${e.file||".env"}) to encrypted:v2`}}catch(g){if(!S(i))h(i,c,{mode:384});return{success:!1,error:`Failed to rotate without exposing plaintext: ${g instanceof Error?g.message:"Unknown error"}`}}finally{_e(T,{force:!0}),_e(R,{force:!0})}}import _ from"process";import{platform as nn}from"os";var Re=typeof Bun<"u",ve=typeof _<"u"&&_.versions?.node!==void 0,tn=Re?"bun":ve?"node":"unknown",Jn={name:tn,version:Re?Bun.version:ve?_.version:void 0},te=nn(),Zn=te==="win32",et=te==="darwin",nt=te==="linux",Ae=Boolean(_.stdout?.isTTY),tt=typeof globalThis.window<"u",rn=Boolean(_.env.CI||_.env.CONTINUOUS_INTEGRATION||_.env.BUILD_NUMBER||_.env.RUN_ID),rt=Boolean(_.env.DEBUG||_.env.VERBOSE||_.argv.includes("--debug")||_.argv.includes("--verbose")),sn=rn||!Ae,it=Boolean(!sn&&(Ae||_.env.COLORTERM||_.env.FORCE_COLOR||_.env.TERM&&_.env.TERM!=="dumb")),ne={github:{name:"GitHub Actions",detected:Boolean(_.env.GITHUB_ACTIONS)},gitlab:{name:"GitLab CI",detected:Boolean(_.env.GITLAB_CI)},circle:{name:"CircleCI",detected:Boolean(_.env.CIRCLECI)},travis:{name:"Travis CI",detected:Boolean(_.env.TRAVIS)},jenkins:{name:"Jenkins",detected:Boolean(_.env.JENKINS_URL)},vercel:{name:"Vercel",detected:Boolean(_.env.VERCEL)},netlify:{name:"Netlify",detected:Boolean(_.env.NETLIFY)},heroku:{name:"Heroku",detected:Boolean(_.env.DYNO)},aws:{name:"AWS",detected:Boolean(_.env.AWS_REGION||_.env.AWS_LAMBDA_FUNCTION_NAME)},azure:{name:"Azure",detected:Boolean(_.env.AZURE_HTTP_USER_AGENT)},cloudflare:{name:"Cloudflare",detected:Boolean(_.env.CF_PAGES)},railway:{name:"Railway",detected:Boolean(_.env.RAILWAY_ENVIRONMENT)},render:{name:"Render",detected:Boolean(_.env.RENDER)}},on=Object.keys(ne).find((e)=>{let n=ne[e];return n!==void 0&&n.detected})||"unknown",st=ne[on]||{name:"Unknown",detected:!1};import En from"process";import{projectPath as ln}from"@stacksjs/path";import Ne from"fs";var Oe={APP_ENV:["local","dev","development","staging","prod","production"],DB_CONNECTION:["mysql","sqlite","postgres","singlestore","vitess","dynamodb"],DB_MIGRATE_FRESH:["allow","confirm","disabled"],MAIL_MAILER:["smtp","mailgun","ses","log","sendgrid","mailtrap","capture"],SEARCH_ENGINE_DRIVER:["opensearch","meilisearch","algolia","typesense"],FRONTEND_APP_ENV:["development","staging","production"]};function dt(e){return e}function dn(e){return typeof e==="string"&&(e.startsWith("encrypted:")||e.startsWith("enc:"))}var an=/(?:^|_)(?:PASSWORD|PASSWD|SECRET|TOKEN|APIKEY|API_KEY|CREDENTIAL|CREDENTIALS|PRIVATE|SALT|DSN|CERT|CIPHER|SIGNATURE|WEBHOOK)(?:_|$)|(?:^|_)(?:ACCESS|SECRET)_KEY(?:_|$)|_KEY$/,cn=/^DOTENV_(?:PUBLIC|PRIVATE)_KEY/,un=/^\$\{[^}]+\}$/;function ct(e,n={}){let{placeholders:t={},strict:r=!1}=n,i=[];for(let[s,o]of Object.entries(e)){if(!o||o.trim()==="")continue;if(dn(o))continue;if(cn.test(s))continue;if(un.test(o.trim()))continue;let c=an.test(s),a=Object.prototype.hasOwnProperty.call(t,s)&&t[s]===o;if(c&&!a){i.push({key:s,reason:"plaintext-secret"});continue}if(r)i.push({key:s,reason:"plaintext-value"})}return i}function ut(e){return e.split(`
|
|
26
|
+
`).map((n)=>n.trim()).filter(Boolean).filter((n)=>n!==".env.example").filter((n)=>/(?:^|\/)\.env(?:\.|$)/.test(n)).filter((n)=>!n.endsWith(".env.keys"))}function Ie(e){return`${e.replace(/[^a-z0-9]/gi,"").toUpperCase()}_`}function fn(e,n={}){let t=n.self?Ie(n.self):void 0,r=(n.tenants??[]).filter((o)=>typeof o==="string"&&o.trim().length>0).map((o)=>({slug:o,prefix:Ie(o)})).filter(({prefix:o})=>o!==t).sort((o,c)=>c.prefix.length-o.prefix.length),i={},s={};for(let[o,c]of Object.entries(e)){let a=r.find(({prefix:u})=>o.startsWith(u));if(a){(s[a.slug]??={})[o]=c;continue}i[o]=c}return{own:i,foreign:s}}function Et(e,n={}){return fn(e,n).own}function lt(e){return Object.entries(e.foreign).map(([n,t])=>({tenant:n,keys:Object.keys(t).sort()})).sort((n,t)=>n.tenant.localeCompare(t.tenant))}var Se=new Set;function pn(e){if(Se.has(e))return;Se.add(e);let n=J();console.warn(`[env] warning: "${e}" is encrypted but no usable private key was found for the "${n}" environment; falling back to its default. Set DOTENV_PRIVATE_KEY_${n.toUpperCase()} or ship .env.keys.`)}var gn={get:(e,n)=>{let t=e,r=t[n];if(typeof r==="string"&&(r.startsWith("encrypted:")||r.startsWith("enc:"))){let s=pe(r);if(s===void 0){pn(n),delete t[n];return}t[n]=s,r=s}let i=["_PORT","_TIMEOUT","_TTL","_SIZE","_LIMIT","_MAX","_MIN","_INTERVAL","_RETRIES","_CONCURRENCY","_WORKERS","_CONNECTIONS"];if(typeof r==="string"&&/^\d+$/.test(r)&&!r.startsWith("0")&&i.some((s)=>n.endsWith(s)))return Number(r);if(typeof r==="string"){let s=r.toLowerCase();if(s==="true")return!0;if(s==="false")return!1}return r}};function _n(){return typeof Bun<"u"?Bun.env:En.env}var he=new Proxy(_n(),gn);function Rt(e,n,t){let r=t?.path||ln(".env"),s=Ne.readFileSync(r,"utf-8").split(`
|
|
27
|
+
`),o=s.findIndex((u)=>u.startsWith(`${e}=`)),a=/[\s"'#$\\]/.test(n)?`"${n.replace(/"/g,"\\\"")}"`:n;if(o!==-1)s[o]=`${e}=${a}`;else s.push(`${e}=${a}`);Ne.writeFileSync(r,s.join(`
|
|
28
|
+
`))}function vt(e=he){let n=[],t=e;for(let[r,i]of Object.entries(Oe)){let s=t[r];if(s!==void 0&&s!==""&&!i.includes(String(s)))n.push(`${r}="${s}" is not valid. Allowed values: ${i.join(", ")}`)}return n}function At(e,n=he){let t=[],r=n;for(let i of e){let s=r[i];if(s===void 0||s===""||s===null)t.push(i)}if(t.length>0)throw Error(`[env] Missing required environment variable(s): ${t.join(", ")}. Set them in .env or your process environment before booting.`);return n}export{an as SECRET_NAME_PATTERN,J as activeEnvName,be as aesDecrypt,yn as aesEncrypt,xn as autoLoadEnv,en as decryptEnv,pe as decryptEnvValue,L as decryptValue,dt as defineEnv,Wn as encryptEnv,w as encryptValue,he as env,Oe as envEnum,W as envKeyNames,Ze as envPlugin,lt as foreignTenantKeys,k as generateKeypair,Hn as getEnv,Xn as getKeypair,q as getPrivateKey,Ae as hasTTY,tt as hasWindow,Re as isBun,rn as isCI,it as isColorSupported,rt as isDebug,dn as isEncryptedValue,mn as isLegacyEncryptedValue,nt as isLinux,et as isMacOS,sn as isMinimal,ve as isNode,Zn as isWindows,ge as loadEnv,Pn as loadEnvFiles,Rn as migrateEncryptedValue,I as parse,vn as parseEnvFromKey,fn as partitionTenantEnv,ct as plaintextSecrets,te as platform,_n as process,on as provider,st as providerInfo,At as requireEnv,Un as resetPrivateKeyCache,Yn as resolveEnvFile,Je as resolvePrivateKey,me as reusableEnvPublicKey,jn as rotateKeypair,tn as runtime,Jn as runtimeInfo,Gn as setEnv,Et as stripForeignTenantEnv,Ie as tenantEnvPrefix,ut as trackedEnvFiles,vt as validateEnv,Rt as writeEnv};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import type { BooleanValidatorType, NumberValidatorType, StringValidatorType } from '@stacksjs/ts-validation';
|
|
2
|
-
|
|
1
|
+
import type { BooleanValidatorType, EnumValidatorType, NumberValidatorType, StringValidatorType, Validator } from '@stacksjs/ts-validation';
|
|
2
|
+
/**
|
|
3
|
+
* Declare the application's environment variables.
|
|
4
|
+
*
|
|
5
|
+
* Returns the schema with its literal type intact, which is what lets
|
|
6
|
+
* {@link InferEnv} read each entry's validator.
|
|
7
|
+
*/
|
|
8
|
+
export declare function defineEnv<const TSchema extends EnvConfig>(schema: TSchema): TSchema;
|
|
3
9
|
export declare const envEnum: EnumObject;
|
|
4
10
|
declare interface EnumObject {
|
|
5
11
|
[key: string]: string[]
|
|
@@ -16,14 +22,19 @@ declare interface BooleanEnvConfig {
|
|
|
16
22
|
validation: BooleanValidatorType
|
|
17
23
|
default: boolean
|
|
18
24
|
}
|
|
19
|
-
declare interface EnumEnvConfig {
|
|
20
|
-
validation:
|
|
21
|
-
|
|
22
|
-
getAllowedValues: () => readonly string[]
|
|
23
|
-
}
|
|
24
|
-
default: string
|
|
25
|
+
declare interface EnumEnvConfig<TValues extends string = string> {
|
|
26
|
+
validation: EnumValidatorType<TValues>
|
|
27
|
+
default: TValues | string
|
|
25
28
|
}
|
|
26
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The variables the framework itself defines.
|
|
31
|
+
*
|
|
32
|
+
* Closed on purpose: `StacksEnv` is what module augmentation extends, and
|
|
33
|
+
* {@link InferEnv} subtracts the keys named here. Were those keys read off
|
|
34
|
+
* `StacksEnv` instead, an augmentation built from `InferEnv` would reference
|
|
35
|
+
* the interface it is augmenting and TypeScript would reject the cycle.
|
|
36
|
+
*/
|
|
37
|
+
export declare interface FrameworkEnv {
|
|
27
38
|
APP_NAME: string | undefined
|
|
28
39
|
APP_ENV: 'local' | 'dev' | 'development' | 'stage' | 'staging' | 'prod' | 'production' | undefined
|
|
29
40
|
APP_KEY: string | undefined
|
|
@@ -35,6 +46,12 @@ export declare interface StacksEnv {
|
|
|
35
46
|
APP_COMING_SOON_SECRET: string | undefined
|
|
36
47
|
APP_ROOT: string | undefined
|
|
37
48
|
DEBUG: boolean | undefined
|
|
49
|
+
FILESYSTEM_DISK: string | undefined
|
|
50
|
+
HCLOUD_TOKEN: string | undefined
|
|
51
|
+
HETZNER_API_TOKEN: string | undefined
|
|
52
|
+
DOTENV_PRIVATE_KEY: string | undefined
|
|
53
|
+
DOTENV_PUBLIC_KEY: string | undefined
|
|
54
|
+
SUDO_PASSWORD: string | undefined
|
|
38
55
|
PORT: number | undefined
|
|
39
56
|
PORT_BACKEND: number | undefined
|
|
40
57
|
PORT_ADMIN: number | undefined
|
|
@@ -81,6 +98,9 @@ export declare interface StacksEnv {
|
|
|
81
98
|
AWS_REGION: string | undefined
|
|
82
99
|
AWS_HOSTED_ZONE_ID: string | undefined
|
|
83
100
|
AWS_S3_BUCKET: string | undefined
|
|
101
|
+
AWS_BUCKET: string | undefined
|
|
102
|
+
AWS_URL: string | undefined
|
|
103
|
+
AWS_PROFILE: string | undefined
|
|
84
104
|
AWS_S3_PREFIX: string | undefined
|
|
85
105
|
AWS_SES_REGION: string | undefined
|
|
86
106
|
MAIL_MAILER: string | undefined
|
|
@@ -235,11 +255,74 @@ export declare interface StacksEnv {
|
|
|
235
255
|
VONAGE_API_SECRET: string | undefined
|
|
236
256
|
VONAGE_FROM_NUMBER: string | undefined
|
|
237
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* Every environment variable the application can read through `env`.
|
|
260
|
+
*
|
|
261
|
+
* Extends the framework's own set; an application adds its variables by
|
|
262
|
+
* augmenting this interface from `config/env.ts`, which is the file that
|
|
263
|
+
* already declares them:
|
|
264
|
+
*
|
|
265
|
+
* ```ts
|
|
266
|
+
* const envSchema = defineEnv({
|
|
267
|
+
* STRIPE_WEBHOOK_SECRET: { validation: schema.string(), default: '' },
|
|
268
|
+
* })
|
|
269
|
+
*
|
|
270
|
+
* declare module '@stacksjs/env' {
|
|
271
|
+
* interface StacksEnv extends InferEnv<typeof envSchema> {}
|
|
272
|
+
* }
|
|
273
|
+
*
|
|
274
|
+
* export default envSchema
|
|
275
|
+
* ```
|
|
276
|
+
*
|
|
277
|
+
* Nothing is generated: the types follow the schema, so they are the same on a
|
|
278
|
+
* fresh clone, in CI, and in production. They used to come from a generated
|
|
279
|
+
* `storage/framework/types/env.d.ts` whose key set was scraped from whichever
|
|
280
|
+
* `.env` happened to be on the machine running the generator, and whose types
|
|
281
|
+
* were read off each variable's live value there - so a production-only
|
|
282
|
+
* variable could never be typed at all, and one that was set locally could be
|
|
283
|
+
* `number` on one machine and `string` on another.
|
|
284
|
+
*/
|
|
285
|
+
export declare interface StacksEnv extends FrameworkEnv {}
|
|
238
286
|
export declare interface FrontendEnv {
|
|
239
287
|
FRONTEND_APP_ENV: 'local' | 'development' | 'staging' | 'production'
|
|
240
288
|
FRONTEND_APP_URL: string
|
|
241
289
|
}
|
|
242
|
-
|
|
243
|
-
|
|
290
|
+
export type EnvValueConfig = StringEnvConfig | NumberEnvConfig | BooleanEnvConfig | EnumEnvConfig<any>;
|
|
291
|
+
/**
|
|
292
|
+
* The shape of `config/env.ts`.
|
|
293
|
+
*
|
|
294
|
+
* Keyed by plain string rather than by a generated `EnvKey` union. That union
|
|
295
|
+
* came from `storage/framework/env.ts` - a file this package cannot see from an
|
|
296
|
+
* installed app, so the import resolved to `any` and the constraint silently
|
|
297
|
+
* did nothing anyway. More importantly it had the dependency backwards: an
|
|
298
|
+
* application could not declare its own variable until a generator had scraped
|
|
299
|
+
* that variable out of `.env` first.
|
|
300
|
+
*/
|
|
301
|
+
export type EnvConfig = Record<string, EnvValueConfig>;
|
|
302
|
+
/**
|
|
303
|
+
* A key that can be written back to an `.env` file.
|
|
304
|
+
*
|
|
305
|
+
* Every declared variable, with autocompletion, without rejecting one the
|
|
306
|
+
* types do not know about yet.
|
|
307
|
+
*/
|
|
308
|
+
export type EnvKey = keyof StacksEnv | (string & {});
|
|
309
|
+
/** The value type a single `config/env.ts` entry describes. */
|
|
310
|
+
declare type EnvValueOf<TEntry> = TEntry extends { validation: Validator<infer TValue> }
|
|
311
|
+
? TValue
|
|
312
|
+
: TEntry extends { default: infer TDefault }
|
|
313
|
+
? TDefault
|
|
314
|
+
: string;
|
|
315
|
+
/**
|
|
316
|
+
* The `StacksEnv` members an application's `config/env.ts` contributes.
|
|
317
|
+
*
|
|
318
|
+
* Each entry is typed by its validator, so `schema.number()` is a `number` and
|
|
319
|
+
* `schema.enum(['a', 'b'])` is `'a' | 'b'`, and every variable is optional
|
|
320
|
+
* because the process may simply not have it set. Keys the framework already
|
|
321
|
+
* declares are dropped: re-stating one with a different type is what makes a
|
|
322
|
+
* merged declaration fail to compile.
|
|
323
|
+
*/
|
|
324
|
+
export type InferEnv<TSchema> = {
|
|
325
|
+
[K in Exclude<keyof TSchema, keyof FrameworkEnv>]: EnvValueOf<TSchema[K]> | undefined
|
|
326
|
+
}
|
|
244
327
|
export type EnvSchema = EnvConfig;
|
|
245
328
|
export type FrontendEnvKeys = keyof FrontendEnv;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/env",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.72.
|
|
5
|
+
"version": "0.72.81",
|
|
6
6
|
"description": "Stacks env helper methods.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -52,13 +52,14 @@
|
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "bun build.ts",
|
|
54
54
|
"typecheck": "bun tsc --noEmit",
|
|
55
|
+
"typecheck:types": "bun tsc --noEmit -p tsconfig.type-tests.json --pretty false",
|
|
55
56
|
"prepublishOnly": "bun run build"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"@stacksjs/path": "0.72.
|
|
59
|
+
"@stacksjs/path": "0.72.81"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
62
|
"better-dx": "^0.2.24",
|
|
62
|
-
"@stacksjs/validation": "0.72.
|
|
63
|
+
"@stacksjs/validation": "0.72.81"
|
|
63
64
|
}
|
|
64
65
|
}
|