vaulter 0.2.0 → 0.2.1
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/README.md +91 -7
- package/package.json +1 -1
- package/dist/bin/minienv-mcp.cjs +0 -17
- package/dist/bin/minienv.cjs +0 -146
package/README.md
CHANGED
|
@@ -324,20 +324,100 @@ security:
|
|
|
324
324
|
|
|
325
325
|
## Monorepo Support
|
|
326
326
|
|
|
327
|
+
Vaulter auto-discovers services with `.vaulter/` directories and supports config inheritance.
|
|
328
|
+
|
|
329
|
+
### NX Monorepo
|
|
330
|
+
|
|
327
331
|
```
|
|
328
|
-
my-
|
|
332
|
+
my-nx-workspace/
|
|
329
333
|
├── .vaulter/
|
|
330
|
-
│ ├── config.yaml
|
|
334
|
+
│ ├── config.yaml # Shared config (backend, encryption)
|
|
331
335
|
│ └── environments/
|
|
332
|
-
|
|
333
|
-
|
|
336
|
+
│ └── dev.env # Shared dev vars
|
|
337
|
+
├── apps/
|
|
338
|
+
│ ├── web/
|
|
334
339
|
│ │ └── .vaulter/
|
|
335
|
-
│ │ ├── config.yaml
|
|
340
|
+
│ │ ├── config.yaml # extends: ../../../.vaulter/config.yaml
|
|
336
341
|
│ │ └── environments/
|
|
337
|
-
│ └──
|
|
342
|
+
│ │ └── dev.env # App-specific vars
|
|
343
|
+
│ └── api/
|
|
338
344
|
│ └── .vaulter/
|
|
345
|
+
│ ├── config.yaml
|
|
346
|
+
│ └── environments/
|
|
347
|
+
├── libs/ # No .vaulter needed for libs
|
|
348
|
+
├── nx.json
|
|
349
|
+
└── package.json
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
# From workspace root
|
|
354
|
+
vaulter services # List: web, api
|
|
355
|
+
|
|
356
|
+
# Sync all apps
|
|
357
|
+
vaulter sync -e dev --all
|
|
358
|
+
|
|
359
|
+
# Sync single app (from root or app dir)
|
|
360
|
+
vaulter sync -e dev -s api
|
|
361
|
+
cd apps/api && vaulter sync -e dev
|
|
362
|
+
|
|
363
|
+
# NX run with env vars
|
|
364
|
+
eval $(vaulter export -e dev -s api) && nx serve api
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Turborepo
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
my-turbo-monorepo/
|
|
371
|
+
├── .vaulter/
|
|
372
|
+
│ ├── config.yaml # Root config
|
|
373
|
+
│ └── environments/
|
|
374
|
+
├── apps/
|
|
375
|
+
│ ├── web/
|
|
376
|
+
│ │ ├── .vaulter/
|
|
377
|
+
│ │ │ ├── config.yaml # extends: ../../../.vaulter/config.yaml
|
|
378
|
+
│ │ │ └── environments/
|
|
379
|
+
│ │ └── package.json
|
|
380
|
+
│ └── docs/
|
|
381
|
+
│ └── .vaulter/
|
|
382
|
+
├── packages/ # Shared packages (no .vaulter)
|
|
383
|
+
├── turbo.json
|
|
384
|
+
└── package.json
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# List discovered services
|
|
389
|
+
vaulter services
|
|
390
|
+
|
|
391
|
+
# Batch sync before turbo build
|
|
392
|
+
vaulter sync -e prd --all && turbo build
|
|
393
|
+
|
|
394
|
+
# Export for specific app
|
|
395
|
+
cd apps/web && eval $(vaulter export -e dev)
|
|
396
|
+
|
|
397
|
+
# Turbo with env passthrough (turbo.json)
|
|
398
|
+
# { "pipeline": { "build": { "env": ["DATABASE_URL", "API_KEY"] } } }
|
|
399
|
+
vaulter export -e prd -s web --format=shell >> apps/web/.env
|
|
400
|
+
turbo build --filter=web
|
|
339
401
|
```
|
|
340
402
|
|
|
403
|
+
### Service Config Inheritance
|
|
404
|
+
|
|
405
|
+
```yaml
|
|
406
|
+
# apps/api/.vaulter/config.yaml
|
|
407
|
+
extends: ../../../.vaulter/config.yaml # Inherit root config
|
|
408
|
+
|
|
409
|
+
service: api # Override service name
|
|
410
|
+
|
|
411
|
+
# Override or add service-specific settings
|
|
412
|
+
sync:
|
|
413
|
+
required:
|
|
414
|
+
prd:
|
|
415
|
+
- DATABASE_URL
|
|
416
|
+
- REDIS_URL
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Commands
|
|
420
|
+
|
|
341
421
|
```bash
|
|
342
422
|
# List services
|
|
343
423
|
vaulter services
|
|
@@ -345,8 +425,12 @@ vaulter services
|
|
|
345
425
|
# Sync all services
|
|
346
426
|
vaulter sync -e dev --all
|
|
347
427
|
|
|
348
|
-
# Sync specific services
|
|
428
|
+
# Sync specific services (glob supported)
|
|
349
429
|
vaulter sync -e dev -s api,worker
|
|
430
|
+
vaulter sync -e dev -s "svc-*"
|
|
431
|
+
|
|
432
|
+
# Batch export
|
|
433
|
+
vaulter export -e prd --all --format=json
|
|
350
434
|
```
|
|
351
435
|
|
|
352
436
|
## MCP Tools
|
package/package.json
CHANGED
package/dist/bin/minienv-mcp.cjs
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";var Q=Object.create;var _=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var ee=Object.getPrototypeOf,ne=Object.prototype.hasOwnProperty;var te=(n,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of J(e))!ne.call(n,i)&&i!==r&&_(n,i,{get:()=>e[i],enumerable:!(t=X(e,i))||t.enumerable});return n};var E=(n,e,r)=>(r=n!=null?Q(ee(n)):{},te(e||!n||!n.__esModule?_(r,"default",{value:n,enumerable:!0}):r,n));process.setMaxListeners(50);var G=require("@modelcontextprotocol/sdk/server/index.js"),Z=require("@modelcontextprotocol/sdk/server/stdio.js"),p=require("@modelcontextprotocol/sdk/types.js");var I=require("s3db.js"),re=`file://${process.env.HOME||"/tmp"}/.minienv/store`,ie="minienv-default-dev-key",g=class{db=null;resource=null;connectionString;passphrase;initialized=!1;constructor(e={}){this.connectionString=e.connectionString||re,this.passphrase=e.passphrase||ie}async connect(){this.initialized||(this.db=new I.S3db({connectionString:this.connectionString,passphrase:this.passphrase}),await this.db.connect(),this.resource=await this.db.createResource({name:"environment-variables",attributes:{key:"string|required",value:"secret|required",project:"string|required",service:"string|optional",environment:"enum:dev,stg,prd,sbx,dr|required",tags:"array|items:string|optional",metadata:{description:"string|optional",owner:"string|optional",rotateAfter:"date|optional",source:"enum:manual,sync,import|optional"}},partitions:{byProject:{fields:{project:"string"}},byProjectEnv:{fields:{project:"string",environment:"string"}},byProjectServiceEnv:{fields:{project:"string",service:"string",environment:"string"}}},behavior:"body-overflow",timestamps:!0,asyncPartitions:!0}),this.initialized=!0)}ensureConnected(){if(!this.initialized||!this.resource)throw new Error("MiniEnvClient not initialized. Call connect() first.")}async get(e,r,t,i){this.ensureConnected();let s=i?"byProjectServiceEnv":"byProjectEnv",o=i?{project:r,service:i,environment:t}:{project:r,environment:t};return(await this.resource.list({partition:s,partitionValues:o})).find(l=>l.key===e)||null}async set(e){this.ensureConnected();let r=await this.get(e.key,e.project,e.environment,e.service);return r?await this.resource.update(r.id,{value:e.value,tags:e.tags,metadata:{...r.metadata,...e.metadata,source:e.metadata?.source||"manual"}}):await this.resource.insert({...e,metadata:{...e.metadata,source:e.metadata?.source||"manual"}})}async delete(e,r,t,i){this.ensureConnected();let s=await this.get(e,r,t,i);return s?(await this.resource.delete(s.id),!0):!1}async list(e={}){this.ensureConnected();let{project:r,service:t,environment:i,limit:s,offset:o}=e,a,c;r&&t&&i?(a="byProjectServiceEnv",c={project:r,service:t,environment:i}):r&&i?(a="byProjectEnv",c={project:r,environment:i}):r&&(a="byProject",c={project:r});let l={};return a&&c&&(l.partition=a,l.partitionValues=c),s&&(l.limit=s),o&&(l.offset=o),await this.resource.list(l)}async insertMany(e){this.ensureConnected();let r=[];for(let t of e){let i=await this.set(t);r.push(i)}return r}async deleteAll(e,r,t){this.ensureConnected();let i=await this.list({project:e,environment:r,service:t}),s=0;for(let o of i)await this.resource.delete(o.id),s++;return s}async export(e,r,t){let i=await this.list({project:e,environment:r,service:t}),s={};for(let o of i)s[o.key]=o.value;return s}async sync(e,r,t,i,s={}){this.ensureConnected();let o=await this.list({project:r,environment:t,service:i}),a=new Map(o.map(l=>[l.key,l])),c={added:[],updated:[],deleted:[],unchanged:[],conflicts:[]};for(let[l,d]of Object.entries(e)){let u=a.get(l);u?u.value!==d?(await this.set({key:l,value:d,project:r,environment:t,service:i,metadata:{source:s.source||"sync"}}),c.updated.push(l)):c.unchanged.push(l):(await this.set({key:l,value:d,project:r,environment:t,service:i,metadata:{source:s.source||"sync"}}),c.added.push(l)),a.delete(l)}for(let[l]of a)c.deleted.push(l);return c}async disconnect(){this.db&&(await this.db.disconnect(),this.db=null,this.resource=null,this.initialized=!1)}isConnected(){return this.initialized}getConnectionString(){return this.connectionString}};var v=E(require("node:fs"),1),f=E(require("node:path"),1),A=require("yaml");function se(n){let e=new URL(n);if(e.protocol==="s3:"){let r=e.hostname,t=e.pathname.slice(1),i=e.searchParams.get("region")||void 0;return{bucket:r,key:t,region:i}}if(e.protocol==="http:"||e.protocol==="https:"){let r=`${e.protocol}//${e.host}`,t=e.pathname.slice(1).split("/"),i=t[0],s=t.slice(1).join("/");return{bucket:i,key:s,endpoint:r,accessKeyId:e.username||void 0,secretAccessKey:e.password||void 0}}throw new Error(`Unsupported S3 URL format: ${n}`)}async function oe(n){try{let{S3Client:e,GetObjectCommand:r}=await import("@aws-sdk/client-s3"),t={};n.region&&(t.region=n.region),n.endpoint&&(t.endpoint=n.endpoint,t.forcePathStyle=!0),n.accessKeyId&&n.secretAccessKey&&(t.credentials={accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey});let i=new e(t),s=new r({Bucket:n.bucket,Key:n.key}),o=await i.send(s);if(!o.Body)throw new Error("Empty response from S3");return(await o.Body.transformToString()).trim()}catch(e){throw e.code==="ERR_MODULE_NOT_FOUND"||e.message?.includes("Cannot find module")?new Error("AWS SDK not installed. To use S3 key source, install: pnpm add @aws-sdk/client-s3"):new Error(`Failed to fetch key from S3: ${e.message}`)}}async function T(n){let e=se(n);return oe(e)}var ae=".minienv",O="config.yaml",ce=5,M=10,V={version:"1",project:"",environments:["dev","stg","prd","sbx","dr"],default_environment:"dev",sync:{conflict:"local"},security:{paranoid:!1,confirm_production:!0,auto_encrypt:{patterns:["*_KEY","*_SECRET","*_TOKEN","*_PASSWORD","*_CREDENTIAL","DATABASE_URL","REDIS_URL"]}}};function $(n=process.cwd()){let e=f.default.resolve(n),r=0;for(;r<ce;){let t=f.default.join(e,ae),i=f.default.join(t,O);if(v.default.existsSync(i))return t;let s=f.default.dirname(e);if(s===e)break;e=s,r++}return null}function le(n){if(!v.default.existsSync(n))throw new Error(`Config file not found: ${n}`);let e=v.default.readFileSync(n,"utf-8");return(0,A.parse)(e)||{}}function C(n,e){let r={...n};for(let t of Object.keys(e)){let i=e[t],s=r[t];i!=null&&typeof i=="object"&&!Array.isArray(i)&&s!==null&&s!==void 0&&typeof s=="object"&&!Array.isArray(s)?r[t]=C(s,i):i!==void 0&&(r[t]=i)}return r}function N(n,e=new Set,r=0){if(r>M)throw new Error(`Config inheritance depth exceeded (max ${M})`);let t=f.default.resolve(n);if(e.has(t))throw new Error(`Circular config inheritance detected: ${t}`);e.add(t);let i=le(t);if(i.extends){let s=f.default.resolve(f.default.dirname(t),i.extends),o=N(s,e,r+1),{extends:a,...c}=i;return C(o,c)}return C(V,i)}function w(n){let e=$(n);if(!e)return{...V};let r=f.default.join(e,O);return N(r)}function de(n){return f.default.join(n,"environments")}function D(n,e){return f.default.join(de(n),`${e}.env`)}async function j(n){let e=n.encryption?.key_source||[];for(let r of e)if("env"in r){let t=process.env[r.env];if(t)return t}else if("file"in r){let t=f.default.resolve(r.file);if(v.default.existsSync(t))return v.default.readFileSync(t,"utf-8").trim()}else if("s3"in r)try{let t=await T(r.s3);if(t)return t}catch(t){process.env.MINIENV_VERBOSE&&console.warn(`Failed to load key from S3: ${t.message}`)}return process.env.MINIENV_KEY?process.env.MINIENV_KEY:null}var K=E(require("node:fs"),1),P=100;function F(n,e={}){let r=K.default.readFileSync(n,"utf-8");return ue(r,e)}function ue(n,e={}){let{expand:r=!0,env:t=process.env}=e,i={},s=n.split(/\r?\n/),o=0;for(;o<s.length;){let a=s[o].trim();if(o++,!a||a.startsWith("#")||a.startsWith(";"))continue;let c=a.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$/);if(!c)continue;let l=c[1],d=c[2];if(d.startsWith('"')){let u=pe(d,s,o);d=u.value,o=u.nextIndex}else if(d.startsWith("'")){let u=fe(d,s,o);d=u.value,o=u.nextIndex}else if(d.startsWith("`")){let u=me(d,s,o);d=u.value,o=u.nextIndex}else{let u=d.indexOf("#");u>0&&(d=d.substring(0,u).trim())}r&&(d=ge(d,{...t,...i})),i[l]=d}return i}function pe(n,e,r){let t=n.substring(1),i=0,s="",o=0,a=r;for(;i<P;){for(;o<t.length;){let c=t[o];if(c==="\\"&&o+1<t.length){let l=t[o+1];switch(l){case"n":s+=`
|
|
3
|
-
`;break;case"r":s+="\r";break;case"t":s+=" ";break;case'"':s+='"';break;case"\\":s+="\\";break;case"$":s+="$";break;default:s+=c+l}o+=2}else{if(c==='"')return{value:s,nextIndex:a};s+=c,o++}}if(a>=e.length)break;s+=`
|
|
4
|
-
`,t=e[a],a++,o=0,i++}return{value:s,nextIndex:a}}function fe(n,e,r){let t=n.substring(1),i=0,s="",o=0,a=r;for(;i<P;){for(;o<t.length;){let c=t[o];if(c==="'"&&t[o+1]!=="'")return{value:s,nextIndex:a};c==="'"&&t[o+1]==="'"?(s+="'",o+=2):(s+=c,o++)}if(a>=e.length)break;s+=`
|
|
5
|
-
`,t=e[a],a++,o=0,i++}return{value:s,nextIndex:a}}function me(n,e,r){let t=n.substring(1),i=0,s="",o=0,a=r;for(;i<P;){let c=t.indexOf("`",o);if(c!==-1)return s+=t.substring(o,c),{value:s,nextIndex:a};if(s+=t.substring(o),a>=e.length)break;s+=`
|
|
6
|
-
`,t=e[a],a++,o=0,i++}return{value:s,nextIndex:a}}function ge(n,e){return n=n.replace(/\$\{([a-zA-Z_][a-zA-Z0-9_]*):-([^}]*)\}/g,(r,t,i)=>e[t]??i),n=n.replace(/\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g,(r,t)=>e[t]??""),n=n.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g,(r,t)=>e[t]??""),n}var L=E(require("node:fs"),1);async function ve(){let n=null;try{n=w()}catch{}let e=n?.backend?.url,r=n?await j(n):void 0;return{client:new g({connectionString:e||void 0,passphrase:r||void 0}),config:n}}function U(){return[{name:"minienv_get",description:"Get the value of an environment variable",inputSchema:{type:"object",properties:{key:{type:"string",description:"The name of the environment variable"},environment:{type:"string",description:"Environment (dev/stg/prd/sbx/dr)",enum:["dev","stg","prd","sbx","dr"],default:"dev"},project:{type:"string",description:"Project name (optional, defaults to config)"},service:{type:"string",description:"Service name for monorepos (optional)"}},required:["key"]}},{name:"minienv_set",description:"Set an environment variable value",inputSchema:{type:"object",properties:{key:{type:"string",description:"The name of the environment variable"},value:{type:"string",description:"The value to set"},environment:{type:"string",description:"Environment (dev/stg/prd/sbx/dr)",enum:["dev","stg","prd","sbx","dr"],default:"dev"},project:{type:"string",description:"Project name (optional, defaults to config)"},service:{type:"string",description:"Service name for monorepos (optional)"}},required:["key","value"]}},{name:"minienv_delete",description:"Delete an environment variable",inputSchema:{type:"object",properties:{key:{type:"string",description:"The name of the environment variable to delete"},environment:{type:"string",description:"Environment (dev/stg/prd/sbx/dr)",enum:["dev","stg","prd","sbx","dr"],default:"dev"},project:{type:"string",description:"Project name (optional, defaults to config)"},service:{type:"string",description:"Service name for monorepos (optional)"}},required:["key"]}},{name:"minienv_list",description:"List all environment variables for a project/environment",inputSchema:{type:"object",properties:{environment:{type:"string",description:"Environment (dev/stg/prd/sbx/dr)",enum:["dev","stg","prd","sbx","dr"],default:"dev"},project:{type:"string",description:"Project name (optional, defaults to config)"},service:{type:"string",description:"Service name for monorepos (optional)"},showValues:{type:"boolean",description:"Show values (default: false for security)",default:!1}}}},{name:"minienv_export",description:"Export environment variables in shell format",inputSchema:{type:"object",properties:{environment:{type:"string",description:"Environment (dev/stg/prd/sbx/dr)",enum:["dev","stg","prd","sbx","dr"],default:"dev"},project:{type:"string",description:"Project name (optional, defaults to config)"},service:{type:"string",description:"Service name for monorepos (optional)"},format:{type:"string",description:"Output format",enum:["shell","env","json","yaml"],default:"shell"}}}},{name:"minienv_sync",description:"Sync local .env file with backend storage",inputSchema:{type:"object",properties:{environment:{type:"string",description:"Environment (dev/stg/prd/sbx/dr)",enum:["dev","stg","prd","sbx","dr"],default:"dev"},project:{type:"string",description:"Project name (optional, defaults to config)"},service:{type:"string",description:"Service name for monorepos (optional)"},dryRun:{type:"boolean",description:"Show what would be changed without making changes",default:!1}}}}]}async function z(n,e){let{client:r,config:t}=await ve(),i=e.project||t?.project||"",s=e.environment||t?.default_environment||"dev",o=e.service;if(!i)return{content:[{type:"text",text:"Error: Project not specified. Either set project in args or run from a directory with .minienv/config.yaml"}]};try{switch(await r.connect(),n){case"minienv_get":{let a=e.key,c=await r.get(a,i,s,o);return{content:[{type:"text",text:c!==null?c.value:`Variable ${a} not found`}]}}case"minienv_set":{let a=e.key,c=e.value;return await r.set({key:a,value:c,project:i,environment:s,service:o,metadata:{source:"manual"}}),{content:[{type:"text",text:`\u2713 Set ${a} in ${i}/${s}`}]}}case"minienv_delete":{let a=e.key;return{content:[{type:"text",text:await r.delete(a,i,s,o)?`\u2713 Deleted ${a}`:`Variable ${a} not found`}]}}case"minienv_list":{let a=e.showValues||!1,c=await r.list({project:i,environment:s,service:o});if(c.length===0)return{content:[{type:"text",text:`No variables found for ${i}/${s}`}]};let l=c.map(d=>a?`${d.key}=${d.value}`:d.key);return{content:[{type:"text",text:`Variables in ${i}/${s}:
|
|
7
|
-
${l.join(`
|
|
8
|
-
`)}`}]}}case"minienv_export":{let a=e.format||"shell",c=await r.export(i,s,o),l;switch(a){case"json":l=JSON.stringify(c,null,2);break;case"yaml":l=Object.entries(c).map(([d,u])=>`${d}: "${u.replace(/"/g,'\\"')}"`).join(`
|
|
9
|
-
`);break;case"env":l=Object.entries(c).map(([d,u])=>`${d}=${u}`).join(`
|
|
10
|
-
`);break;default:l=Object.entries(c).map(([d,u])=>`export ${d}="${u.replace(/"/g,'\\"')}"`).join(`
|
|
11
|
-
`)}return{content:[{type:"text",text:l}]}}case"minienv_sync":{let a=e.dryRun||!1,c=$();if(!c)return{content:[{type:"text",text:"Error: No .minienv directory found"}]};let l=D(c,s);if(!L.default.existsSync(l))return{content:[{type:"text",text:`Error: Environment file not found: ${l}`}]};let d=F(l);if(a){let k=await r.export(i,s,o),x=[],b=[],S=[];for(let[m,Y]of Object.entries(d))m in k?k[m]!==Y&&b.push(m):x.push(m);for(let m of Object.keys(k))m in d||S.push(m);let h=["Dry run - changes that would be made:"];return x.length>0&&h.push(` Add: ${x.join(", ")}`),b.length>0&&h.push(` Update: ${b.join(", ")}`),S.length>0&&h.push(` Delete: ${S.join(", ")}`),x.length===0&&b.length===0&&S.length===0&&h.push(" No changes needed"),{content:[{type:"text",text:h.join(`
|
|
12
|
-
`)}]}}let u=await r.sync(d,i,s,o,{source:"sync"}),y=[`\u2713 Synced ${i}/${s}`];return u.added.length>0&&y.push(` Added: ${u.added.length}`),u.updated.length>0&&y.push(` Updated: ${u.updated.length}`),u.deleted.length>0&&y.push(` Deleted: ${u.deleted.length}`),u.unchanged.length>0&&y.push(` Unchanged: ${u.unchanged.length}`),{content:[{type:"text",text:y.join(`
|
|
13
|
-
`)}]}}default:return{content:[{type:"text",text:`Unknown tool: ${n}`}]}}}finally{await r.disconnect()}}var q=["dev","stg","prd","sbx","dr"];async function W(){let n=null;try{n=w()}catch{}let e=n?.backend?.url,r=n?await j(n):void 0;return{client:new g({connectionString:e||void 0,passphrase:r||void 0}),config:n}}function ye(n){let e=n.match(/^minienv:\/\/([^/]+)\/([^/]+)(?:\/([^/]+))?$/);if(!e)return null;let[,r,t,i]=e;return q.includes(t)?{project:r,environment:t,service:i}:null}async function H(){let{config:n}=await W();if(!n?.project)return[];let e=n.project,r=n.environments||q,t=n.service,i=[];for(let s of r){let o=t?`minienv://${e}/${s}/${t}`:`minienv://${e}/${s}`;i.push({uri:o,name:`${e}/${s}${t?`/${t}`:""}`,description:`Environment variables for ${e} in ${s}`,mimeType:"text/plain"})}return i}async function B(n){let e=ye(n);if(!e)throw new Error(`Invalid resource URI: ${n}. Expected format: minienv://project/environment[/service]`);let{project:r,environment:t,service:i}=e,{client:s}=await W();try{await s.connect();let o=await s.export(r,t,i),a=Object.entries(o);if(a.length===0)return{contents:[{uri:n,mimeType:"text/plain",text:`# No variables found for ${r}/${t}`}]};let c=a.map(([l,d])=>`${l}=${d}`).join(`
|
|
14
|
-
`);return{contents:[{uri:n,mimeType:"text/plain",text:`# Environment: ${r}/${t}${i?`/${i}`:""}
|
|
15
|
-
# Variables: ${a.length}
|
|
16
|
-
|
|
17
|
-
${c}`}]}}finally{await s.disconnect()}}var he="minienv",Ee="0.1.0";function xe(){let n=new G.Server({name:he,version:Ee},{capabilities:{tools:{},resources:{}}});return n.setRequestHandler(p.ListToolsRequestSchema,async()=>({tools:U()})),n.setRequestHandler(p.CallToolRequestSchema,async e=>{let{name:r,arguments:t}=e.params;try{return await z(r,t||{})}catch(i){let s=i instanceof Error?i.message:String(i);throw new p.McpError(p.ErrorCode.InternalError,s)}}),n.setRequestHandler(p.ListResourcesRequestSchema,async()=>({resources:await H()})),n.setRequestHandler(p.ReadResourceRequestSchema,async e=>{let{uri:r}=e.params;try{return await B(r)}catch(t){let i=t instanceof Error?t.message:String(t);throw new p.McpError(p.ErrorCode.InternalError,i)}}),n}async function R(){let n=xe(),e=new Z.StdioServerTransport;await n.connect(e),process.on("SIGINT",async()=>{await n.close(),process.exit(0)}),process.on("SIGTERM",async()=>{await n.close(),process.exit(0)})}(process.argv[1]?.endsWith("server.js")||process.argv[1]?.endsWith("server.ts"))&&R().catch(n=>{console.error("Failed to start MCP server:",n),process.exit(1)});R().catch(n=>{console.error("Failed to start MCP server:",n),process.exit(1)});
|
package/dist/bin/minienv.cjs
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";var Be=Object.create;var q=Object.defineProperty;var We=Object.getOwnPropertyDescriptor;var ze=Object.getOwnPropertyNames;var Ye=Object.getPrototypeOf,He=Object.prototype.hasOwnProperty;var qe=(n,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ze(e))!He.call(n,i)&&i!==o&&q(n,i,{get:()=>e[i],enumerable:!(r=We(e,i))||r.enumerable});return n};var h=(n,e,o)=>(o=n!=null?Be(Ye(n)):{},qe(e||!n||!n.__esModule?q(o,"default",{value:n,enumerable:!0}):o,n));process.setMaxListeners(50);var Je=h(require("minimist"),1);var k=h(require("node:fs"),1),x=h(require("node:path"),1),X=require("yaml");function Qe(n){let e=new URL(n);if(e.protocol==="s3:"){let o=e.hostname,r=e.pathname.slice(1),i=e.searchParams.get("region")||void 0;return{bucket:o,key:r,region:i}}if(e.protocol==="http:"||e.protocol==="https:"){let o=`${e.protocol}//${e.host}`,r=e.pathname.slice(1).split("/"),i=r[0],t=r.slice(1).join("/");return{bucket:i,key:t,endpoint:o,accessKeyId:e.username||void 0,secretAccessKey:e.password||void 0}}throw new Error(`Unsupported S3 URL format: ${n}`)}async function Ze(n){try{let{S3Client:e,GetObjectCommand:o}=await import("@aws-sdk/client-s3"),r={};n.region&&(r.region=n.region),n.endpoint&&(r.endpoint=n.endpoint,r.forcePathStyle=!0),n.accessKeyId&&n.secretAccessKey&&(r.credentials={accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey});let i=new e(r),t=new o({Bucket:n.bucket,Key:n.key}),s=await i.send(t);if(!s.Body)throw new Error("Empty response from S3");return(await s.Body.transformToString()).trim()}catch(e){throw e.code==="ERR_MODULE_NOT_FOUND"||e.message?.includes("Cannot find module")?new Error("AWS SDK not installed. To use S3 key source, install: pnpm add @aws-sdk/client-s3"):new Error(`Failed to fetch key from S3: ${e.message}`)}}async function Q(n){let e=Qe(n);return Ze(e)}var Xe=".minienv",W="config.yaml",en=5,Z=10,ee={version:"1",project:"",environments:["dev","stg","prd","sbx","dr"],default_environment:"dev",sync:{conflict:"local"},security:{paranoid:!1,confirm_production:!0,auto_encrypt:{patterns:["*_KEY","*_SECRET","*_TOKEN","*_PASSWORD","*_CREDENTIAL","DATABASE_URL","REDIS_URL"]}}};function w(n=process.cwd()){let e=x.default.resolve(n),o=0;for(;o<en;){let r=x.default.join(e,Xe),i=x.default.join(r,W);if(k.default.existsSync(i))return r;let t=x.default.dirname(e);if(t===e)break;e=t,o++}return null}function nn(n){if(!k.default.existsSync(n))throw new Error(`Config file not found: ${n}`);let e=k.default.readFileSync(n,"utf-8");return(0,X.parse)(e)||{}}function B(n,e){let o={...n};for(let r of Object.keys(e)){let i=e[r],t=o[r];i!=null&&typeof i=="object"&&!Array.isArray(i)&&t!==null&&t!==void 0&&typeof t=="object"&&!Array.isArray(t)?o[r]=B(t,i):i!==void 0&&(o[r]=i)}return o}function ne(n,e=new Set,o=0){if(o>Z)throw new Error(`Config inheritance depth exceeded (max ${Z})`);let r=x.default.resolve(n);if(e.has(r))throw new Error(`Circular config inheritance detected: ${r}`);e.add(r);let i=nn(r);if(i.extends){let t=x.default.resolve(x.default.dirname(r),i.extends),s=ne(t,e,o+1),{extends:f,...l}=i;return B(s,l)}return B(ee,i)}function D(n){let e=w(n);if(!e)return{...ee};let o=x.default.join(e,W);return ne(o)}function oe(n,e){if(n.project)return n.project;let o=e||process.cwd();return x.default.basename(o)}function re(n){return x.default.join(n,"environments")}function P(n,e){return x.default.join(re(n),`${e}.env`)}function te(n){return w(n)!==null}async function y(n){let e=n.encryption?.key_source||[];for(let o of e)if("env"in o){let r=process.env[o.env];if(r)return r}else if("file"in o){let r=x.default.resolve(o.file);if(k.default.existsSync(r))return k.default.readFileSync(r,"utf-8").trim()}else if("s3"in o)try{let r=await Q(o.s3);if(r)return r}catch(r){process.env.MINIENV_VERBOSE&&console.warn(`Failed to load key from S3: ${r.message}`)}return process.env.MINIENV_KEY?process.env.MINIENV_KEY:null}function ie(n,e,o={}){let r={version:"1",project:e,...o};k.default.existsSync(n)||k.default.mkdirSync(n,{recursive:!0});let i=re(n);k.default.existsSync(i)||k.default.mkdirSync(i,{recursive:!0});let t=x.default.join(n,W),s=`# MiniEnv Configuration
|
|
3
|
-
# Version: 1
|
|
4
|
-
|
|
5
|
-
version: "1"
|
|
6
|
-
|
|
7
|
-
# Project identification
|
|
8
|
-
project: ${e}
|
|
9
|
-
# service: optional-service-name
|
|
10
|
-
|
|
11
|
-
# Backend configuration
|
|
12
|
-
# backend:
|
|
13
|
-
# url: s3://bucket/envs?region=us-east-1
|
|
14
|
-
# url: file://${process.env.HOME}/.minienv/store
|
|
15
|
-
# url: memory://test
|
|
16
|
-
|
|
17
|
-
# Encryption settings
|
|
18
|
-
# encryption:
|
|
19
|
-
# key_source:
|
|
20
|
-
# - env: MINIENV_KEY
|
|
21
|
-
# - file: .minienv/.key
|
|
22
|
-
|
|
23
|
-
# Available environments
|
|
24
|
-
environments:
|
|
25
|
-
- dev
|
|
26
|
-
- stg
|
|
27
|
-
- prd
|
|
28
|
-
- sbx
|
|
29
|
-
- dr
|
|
30
|
-
|
|
31
|
-
# Default environment
|
|
32
|
-
default_environment: dev
|
|
33
|
-
|
|
34
|
-
# Sync behavior
|
|
35
|
-
sync:
|
|
36
|
-
conflict: local # local | remote | prompt | error
|
|
37
|
-
|
|
38
|
-
# Security settings
|
|
39
|
-
security:
|
|
40
|
-
confirm_production: true
|
|
41
|
-
auto_encrypt:
|
|
42
|
-
patterns:
|
|
43
|
-
- "*_KEY"
|
|
44
|
-
- "*_SECRET"
|
|
45
|
-
- "*_TOKEN"
|
|
46
|
-
- "*_PASSWORD"
|
|
47
|
-
- "DATABASE_URL"
|
|
48
|
-
`;k.default.writeFileSync(t,s)}var A=h(require("node:fs"),1),N=h(require("node:path"),1);async function se(n){let{args:e,verbose:o,dryRun:r,jsonOutput:i}=n;if(te()){let c=w();e.force||(i?console.log(JSON.stringify({error:"already_initialized",path:c})):(console.error(`MiniEnv already initialized at ${c}`),console.error("Use --force to reinitialize")),process.exit(1))}let t=e.project||e.p||N.default.basename(process.cwd()),s=N.default.join(process.cwd(),".minienv");if(o&&(console.log(`Initializing minienv for project: ${t}`),console.log(`Config directory: ${s}`)),r){i?console.log(JSON.stringify({action:"init",project:t,configDir:s,dryRun:!0})):(console.log("Dry run - would create:"),console.log(` ${s}/config.yaml`),console.log(` ${s}/environments/`));return}ie(s,t);let f=N.default.join(s,".gitignore");A.default.existsSync(f)||A.default.writeFileSync(f,`# MiniEnv sensitive files
|
|
49
|
-
.key
|
|
50
|
-
*.key
|
|
51
|
-
*.pem
|
|
52
|
-
`);let l=N.default.join(s,"environments"),u=["dev","stg","prd","sbx","dr"];for(let c of u){let a=N.default.join(l,`${c}.env`);A.default.existsSync(a)||A.default.writeFileSync(a,`# ${c.toUpperCase()} Environment Variables
|
|
53
|
-
# Add your ${c} environment variables here
|
|
54
|
-
# Example: DATABASE_URL=postgres://localhost/${c}_db
|
|
55
|
-
`)}i?console.log(JSON.stringify({success:!0,project:t,configDir:s,files:["config.yaml",".gitignore",...u.map(c=>`environments/${c}.env`)]})):(console.log(`\u2713 Initialized minienv for project: ${t}`),console.log(` Config: ${s}/config.yaml`),console.log(` Environments: ${l}/`),console.log(""),console.log("Next steps:"),console.log(" 1. Edit .minienv/config.yaml to configure your backend"),console.log(" 2. Add environment variables to .minienv/environments/*.env"),console.log(' 3. Run "minienv sync -e dev" to sync with backend'))}var ce=require("s3db.js"),on=`file://${process.env.HOME||"/tmp"}/.minienv/store`,rn="minienv-default-dev-key",m=class{db=null;resource=null;connectionString;passphrase;initialized=!1;constructor(e={}){this.connectionString=e.connectionString||on,this.passphrase=e.passphrase||rn}async connect(){this.initialized||(this.db=new ce.S3db({connectionString:this.connectionString,passphrase:this.passphrase}),await this.db.connect(),this.resource=await this.db.createResource({name:"environment-variables",attributes:{key:"string|required",value:"secret|required",project:"string|required",service:"string|optional",environment:"enum:dev,stg,prd,sbx,dr|required",tags:"array|items:string|optional",metadata:{description:"string|optional",owner:"string|optional",rotateAfter:"date|optional",source:"enum:manual,sync,import|optional"}},partitions:{byProject:{fields:{project:"string"}},byProjectEnv:{fields:{project:"string",environment:"string"}},byProjectServiceEnv:{fields:{project:"string",service:"string",environment:"string"}}},behavior:"body-overflow",timestamps:!0,asyncPartitions:!0}),this.initialized=!0)}ensureConnected(){if(!this.initialized||!this.resource)throw new Error("MiniEnvClient not initialized. Call connect() first.")}async get(e,o,r,i){this.ensureConnected();let t=i?"byProjectServiceEnv":"byProjectEnv",s=i?{project:o,service:i,environment:r}:{project:o,environment:r};return(await this.resource.list({partition:t,partitionValues:s})).find(u=>u.key===e)||null}async set(e){this.ensureConnected();let o=await this.get(e.key,e.project,e.environment,e.service);return o?await this.resource.update(o.id,{value:e.value,tags:e.tags,metadata:{...o.metadata,...e.metadata,source:e.metadata?.source||"manual"}}):await this.resource.insert({...e,metadata:{...e.metadata,source:e.metadata?.source||"manual"}})}async delete(e,o,r,i){this.ensureConnected();let t=await this.get(e,o,r,i);return t?(await this.resource.delete(t.id),!0):!1}async list(e={}){this.ensureConnected();let{project:o,service:r,environment:i,limit:t,offset:s}=e,f,l;o&&r&&i?(f="byProjectServiceEnv",l={project:o,service:r,environment:i}):o&&i?(f="byProjectEnv",l={project:o,environment:i}):o&&(f="byProject",l={project:o});let u={};return f&&l&&(u.partition=f,u.partitionValues=l),t&&(u.limit=t),s&&(u.offset=s),await this.resource.list(u)}async insertMany(e){this.ensureConnected();let o=[];for(let r of e){let i=await this.set(r);o.push(i)}return o}async deleteAll(e,o,r){this.ensureConnected();let i=await this.list({project:e,environment:o,service:r}),t=0;for(let s of i)await this.resource.delete(s.id),t++;return t}async export(e,o,r){let i=await this.list({project:e,environment:o,service:r}),t={};for(let s of i)t[s.key]=s.value;return t}async sync(e,o,r,i,t={}){this.ensureConnected();let s=await this.list({project:o,environment:r,service:i}),f=new Map(s.map(u=>[u.key,u])),l={added:[],updated:[],deleted:[],unchanged:[],conflicts:[]};for(let[u,c]of Object.entries(e)){let a=f.get(u);a?a.value!==c?(await this.set({key:u,value:c,project:o,environment:r,service:i,metadata:{source:t.source||"sync"}}),l.updated.push(u)):l.unchanged.push(u):(await this.set({key:u,value:c,project:o,environment:r,service:i,metadata:{source:t.source||"sync"}}),l.added.push(u)),f.delete(u)}for(let[u]of f)l.deleted.push(u);return l}async disconnect(){this.db&&(await this.db.disconnect(),this.db=null,this.resource=null,this.initialized=!1)}isConnected(){return this.initialized}getConnectionString(){return this.connectionString}};async function ae(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,jsonOutput:f}=n,l=e._[1];l||(console.error("Error: Key name is required"),console.error("Usage: minienv get <key> [-e <env>]"),process.exit(1)),r||(console.error("Error: Project not specified and no config found"),console.error('Run "minienv init" or specify --project'),process.exit(1)),s&&console.error(`Getting ${l} for ${r}/${i||"(no service)"}/${t}`);let u=e.backend||e.b||o?.backend?.url,c=o?await y(o):void 0,a=new m({connectionString:u||void 0,passphrase:c||void 0});try{await a.connect();let g=await a.get(l,r,t,i);g||(f?console.log(JSON.stringify({error:"not_found",key:l,project:r,environment:t})):console.error(`Variable ${l} not found`),process.exit(1)),console.log(f?JSON.stringify({key:g.key,value:g.value,project:g.project,service:g.service,environment:g.environment,tags:g.tags,metadata:g.metadata,createdAt:g.createdAt,updatedAt:g.updatedAt}):g.value)}finally{await a.disconnect()}}function tn(n){return n==="prd"||n==="dr"}async function le(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,dryRun:f,jsonOutput:l}=n,u=e._[1],c=e._[2];if(u||(console.error("Error: Key name is required"),console.error("Usage: minienv set <key> <value> [-e <env>]"),process.exit(1)),c===void 0&&(console.error("Error: Value is required"),console.error("Usage: minienv set <key> <value> [-e <env>]"),process.exit(1)),r||(console.error("Error: Project not specified and no config found"),console.error('Run "minienv init" or specify --project'),process.exit(1)),tn(t)&&o?.security?.confirm_production&&!e.force&&(console.error(`Warning: You are modifying ${t} (production) environment`),console.error("Use --force to confirm this action"),process.exit(1)),s&&console.error(`Setting ${u} for ${r}/${i||"(no service)"}/${t}`),f){console.log(l?JSON.stringify({action:"set",key:u,project:r,service:i,environment:t,dryRun:!0}):`Dry run - would set ${u} in ${r}/${t}`);return}let a=e.backend||e.b||o?.backend?.url,g=o?await y(o):void 0,d=new m({connectionString:a||void 0,passphrase:g||void 0});try{await d.connect();let p=await d.set({key:u,value:c,project:r,service:i,environment:t,metadata:{source:"manual"}});console.log(l?JSON.stringify({success:!0,key:p.key,project:p.project,service:p.service,environment:p.environment,createdAt:p.createdAt,updatedAt:p.updatedAt}):`\u2713 Set ${u} in ${r}/${t}`)}finally{await d.disconnect()}}function sn(n){return n==="prd"||n==="dr"}async function fe(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,dryRun:f,jsonOutput:l}=n,u=e._[1];if(u||(console.error("Error: Key name is required"),console.error("Usage: minienv delete <key> [-e <env>]"),process.exit(1)),r||(console.error("Error: Project not specified and no config found"),console.error('Run "minienv init" or specify --project'),process.exit(1)),sn(t)&&o?.security?.confirm_production&&!e.force&&(console.error(`Warning: You are deleting from ${t} (production) environment`),console.error("Use --force to confirm this action"),process.exit(1)),s&&console.error(`Deleting ${u} from ${r}/${i||"(no service)"}/${t}`),f){console.log(l?JSON.stringify({action:"delete",key:u,project:r,service:i,environment:t,dryRun:!0}):`Dry run - would delete ${u} from ${r}/${t}`);return}let c=e.backend||e.b||o?.backend?.url,a=o?await y(o):void 0,g=new m({connectionString:c||void 0,passphrase:a||void 0});try{await g.connect(),await g.delete(u,r,t,i)||(l?console.log(JSON.stringify({error:"not_found",key:u,project:r,environment:t})):console.error(`Variable ${u} not found`),process.exit(1)),console.log(l?JSON.stringify({success:!0,deleted:u,project:r,service:i,environment:t}):`\u2713 Deleted ${u} from ${r}/${t}`)}finally{await g.disconnect()}}function ue(n,e=!1){return e?n:n.length<=8?"****":n.substring(0,4)+"****"+n.substring(n.length-4)}function cn(n,e){if(n.length===0)return"No variables found";let o=Math.max(4,...n.map(s=>s.key.length)),r=e?Math.max(5,...n.map(s=>ue(s.value,e).length)):12,i=3,t=[];t.push("KEY".padEnd(o)+" "+"VALUE".padEnd(r)+" ENV"),t.push("-".repeat(o+r+i+4));for(let s of n)t.push(s.key.padEnd(o)+" "+ue(s.value,e).padEnd(r)+" "+s.environment);return t.join(`
|
|
56
|
-
`)}async function ge(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,jsonOutput:f}=n;r||(console.error("Error: Project not specified and no config found"),console.error('Run "minienv init" or specify --project'),process.exit(1)),s&&console.error(`Listing variables for ${r}/${i||"(no service)"}/${t}`);let l=e.backend||e.b||o?.backend?.url,u=o?await y(o):void 0,c=new m({connectionString:l||void 0,passphrase:u||void 0});try{await c.connect();let a=await c.list({project:r,service:i,environment:e.all?void 0:t});if(f)console.log(JSON.stringify({project:r,service:i,environment:e.all?"all":t,count:a.length,variables:a.map(g=>({key:g.key,value:g.value,environment:g.environment,tags:g.tags,metadata:g.metadata,createdAt:g.createdAt,updatedAt:g.updatedAt}))}));else{let g=e.verbose||e.v||!1;console.log(cn(a,g)),!g&&a.length>0&&(console.log(""),console.log("(use -v to show full values)"))}}finally{await c.disconnect()}}var de=h(require("node:fs"),1),z=100;function K(n,e={}){let o=de.default.readFileSync(n,"utf-8");return pe(o,e)}function pe(n,e={}){let{expand:o=!0,env:r=process.env}=e,i={},t=n.split(/\r?\n/),s=0;for(;s<t.length;){let f=t[s].trim();if(s++,!f||f.startsWith("#")||f.startsWith(";"))continue;let l=f.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$/);if(!l)continue;let u=l[1],c=l[2];if(c.startsWith('"')){let a=an(c,t,s);c=a.value,s=a.nextIndex}else if(c.startsWith("'")){let a=ln(c,t,s);c=a.value,s=a.nextIndex}else if(c.startsWith("`")){let a=fn(c,t,s);c=a.value,s=a.nextIndex}else{let a=c.indexOf("#");a>0&&(c=c.substring(0,a).trim())}o&&(c=un(c,{...r,...i})),i[u]=c}return i}function an(n,e,o){let r=n.substring(1),i=0,t="",s=0,f=o;for(;i<z;){for(;s<r.length;){let l=r[s];if(l==="\\"&&s+1<r.length){let u=r[s+1];switch(u){case"n":t+=`
|
|
57
|
-
`;break;case"r":t+="\r";break;case"t":t+=" ";break;case'"':t+='"';break;case"\\":t+="\\";break;case"$":t+="$";break;default:t+=l+u}s+=2}else{if(l==='"')return{value:t,nextIndex:f};t+=l,s++}}if(f>=e.length)break;t+=`
|
|
58
|
-
`,r=e[f],f++,s=0,i++}return{value:t,nextIndex:f}}function ln(n,e,o){let r=n.substring(1),i=0,t="",s=0,f=o;for(;i<z;){for(;s<r.length;){let l=r[s];if(l==="'"&&r[s+1]!=="'")return{value:t,nextIndex:f};l==="'"&&r[s+1]==="'"?(t+="'",s+=2):(t+=l,s++)}if(f>=e.length)break;t+=`
|
|
59
|
-
`,r=e[f],f++,s=0,i++}return{value:t,nextIndex:f}}function fn(n,e,o){let r=n.substring(1),i=0,t="",s=0,f=o;for(;i<z;){let l=r.indexOf("`",s);if(l!==-1)return t+=r.substring(s,l),{value:t,nextIndex:f};if(t+=r.substring(s),f>=e.length)break;t+=`
|
|
60
|
-
`,r=e[f],f++,s=0,i++}return{value:t,nextIndex:f}}function un(n,e){return n=n.replace(/\$\{([a-zA-Z_][a-zA-Z0-9_]*):-([^}]*)\}/g,(o,r,i)=>e[r]??i),n=n.replace(/\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g,(o,r)=>e[r]??""),n=n.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g,(o,r)=>e[r]??""),n}function L(n){let e=[];for(let[o,r]of Object.entries(n))if(r.includes(`
|
|
61
|
-
`)||r.includes(" ")||r.includes("#")||r.includes('"')||r.includes("'")||r.includes("$")||r.includes("=")){let t=r.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t");e.push(`${o}="${t}"`)}else e.push(`${o}=${r}`);return e.join(`
|
|
62
|
-
`)}async function T(n={}){return new Promise((e,o)=>{let r="";process.stdin.setEncoding("utf8"),process.stdin.on("data",i=>{r+=i}),process.stdin.on("end",()=>{try{let i=pe(r,n);e(i)}catch(i){o(i)}}),process.stdin.on("error",o)})}function F(){return!process.stdin.isTTY}function gn(n){return/[^a-zA-Z0-9_\-.:\/]/.test(n)?"'"+n.replace(/'/g,`'"'"'`)+"'":n}function me(n){return Object.entries(n).map(([e,o])=>`export ${e}=${gn(o)}`).join(`
|
|
63
|
-
`)}function dn(n){return JSON.stringify(n,null,2)}function pn(n){return Object.entries(n).map(([e,o])=>o.includes(":")||o.includes("#")||o.includes(`
|
|
64
|
-
`)||o.startsWith(" ")||o.endsWith(" ")||o===""||o==="true"||o==="false"||o==="null"||!isNaN(Number(o))?`${e}: "${o.replace(/"/g,'\\"').replace(/\n/g,"\\n")}"`:`${e}: ${o}`).join(`
|
|
65
|
-
`)}function mn(n){return Object.entries(n).map(([e,o])=>`${e.toLowerCase()} = "${o.replace(/"/g,'\\"')}"`).join(`
|
|
66
|
-
`)}async function ve(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,jsonOutput:f}=n;r||(console.error("Error: Project not specified and no config found"),console.error('Run "minienv init" or specify --project'),process.exit(1));let l="shell";if(e.format){let g=["shell","json","yaml","env","tfvars"];g.includes(e.format)||(console.error(`Error: Invalid format "${e.format}"`),console.error(`Valid formats: ${g.join(", ")}`),process.exit(1)),l=e.format}else f&&(l="json");s&&console.error(`Exporting ${r}/${i||"(no service)"}/${t} as ${l}`);let u=e.backend||e.b||o?.backend?.url,c=o?await y(o):void 0,a=new m({connectionString:u||void 0,passphrase:c||void 0});try{await a.connect();let g=await a.export(r,t,i),d;switch(l){case"shell":d=me(g);break;case"json":d=dn(g);break;case"yaml":d=pn(g);break;case"env":d=L(g);break;case"tfvars":d=mn(g);break;default:d=me(g)}console.log(d)}finally{await a.disconnect()}}var we=h(require("node:fs"),1),je=h(require("node:path"),1);var V=h(require("node:fs"),1),$=h(require("node:path"),1);var ye=".minienv",he="config.yaml",vn=5;function I(n=process.cwd()){let e=[],o=new Set;function r(i,t){if(t>vn)return;let s=$.default.resolve(i);if(!o.has(s)){o.add(s);try{let f=V.default.readdirSync(s,{withFileTypes:!0});for(let l of f){if(!l.isDirectory()||yn(l.name))continue;let u=$.default.join(s,l.name),c=$.default.join(u,ye),a=$.default.join(c,he);if(V.default.existsSync(a))try{let g=D(u),d=g.service||l.name;e.push({name:d,path:u,configDir:c,config:g})}catch{}r(u,t+1)}}catch{}}}return r(n,0),e}function yn(n){return["node_modules",".git",".svn",".hg","dist","build","coverage",".cache",".next",".nuxt",".output","__pycache__","venv",".venv","vendor","target",".terraform",".terragrunt-cache"].includes(n)||n.startsWith(".")}function be(n,e){let o=e.split(",").map(r=>r.trim()).filter(Boolean);return o.length===0?n:n.filter(r=>o.some(i=>i===r.name?!0:i.includes("*")?new RegExp("^"+i.replace(/\*/g,".*").replace(/\?/g,".")+"$").test(r.name):!1))}function U(n=process.cwd()){let e=$.default.resolve(n),o=null;for(;;){let r=$.default.join(e,ye),i=$.default.join(r,he);V.default.existsSync(i)&&(o=e);let t=$.default.dirname(e);if(t===e)break;e=t}return o}function Ee(n){if(n.length===0)return"No services found";let e=["Services found:"];for(let o of n){let r=$.default.relative(process.cwd(),o.path);e.push(` \u2022 ${o.name} (${r||"."})`)}return e.join(`
|
|
67
|
-
`)}async function Se(n,e,o,r={}){let{concurrency:i=1,stopOnError:t=!1,verbose:s=!1,onProgress:f}=r,l=[],u=0,c=0;for(let a=0;a<n.length;a++){let g=n[a];f&&f(a,n.length,g);let d=Date.now();try{let p=await o(g,e),v=Date.now()-d;l.push({service:g,environment:e,result:p,duration:v}),u++}catch(p){let v=Date.now()-d;if(l.push({service:g,environment:e,error:p instanceof Error?p:new Error(String(p)),duration:v}),c++,t)break}}return{total:n.length,successful:u,failed:c,operations:l}}function xe(n,e){let o=[];if(o.push(""),o.push("Batch Operation Summary:"),o.push(` Total: ${n.total}`),o.push(` Successful: ${n.successful}`),o.push(` Failed: ${n.failed}`),o.push(""),n.failed>0){o.push("Failures:");for(let r of n.operations)r.error&&o.push(` \u2717 ${r.service.name}: ${r.error.message}`);o.push("")}if(e){o.push("Details:");for(let r of n.operations)o.push(` ${e(r)}`)}return o.join(`
|
|
68
|
-
`)}function ke(n){return{total:n.total,successful:n.successful,failed:n.failed,operations:n.operations.map(e=>({service:e.service.name,path:e.service.path,environment:e.environment,success:!e.error,error:e.error?.message,duration:e.duration,result:e.result}))}}function $e(n){return n==="prd"||n==="dr"}async function Ce(n,e){let{args:o,config:r,project:i,service:t,environment:s,verbose:f,dryRun:l,jsonOutput:u}=n,c=e?.config||r,a=e?.config.project||i,g=e?.name||t,d;if(F()&&!e)f&&console.error("Reading variables from stdin..."),d=await T();else{let E=o.file||o.f,S;if(E&&!e)S=je.default.resolve(E);else{let j=e?.configDir||w();if(!j)throw new Error("No config directory found and no file specified");S=P(j,s)}if(!we.default.existsSync(S))throw new Error(`File not found: ${S}`);f&&console.error(`Reading variables from ${S}`),d=K(S)}f&&console.error(`Found ${Object.keys(d).length} local variables`);let p=o.backend||o.b||c?.backend?.url,v=c?await y(c):void 0,b=new m({connectionString:p||void 0,passphrase:v||void 0});try{if(await b.connect(),l){let E=await b.export(a,s,g),S=[],j=[],C=[],M=[];for(let[O,Ge]of Object.entries(d))O in E?E[O]!==Ge?j.push(O):M.push(O):S.push(O);for(let O of Object.keys(E))O in d||C.push(O);return{added:S,updated:j,deleted:C,unchanged:M,conflicts:[]}}return await b.sync(d,a,s,g,{source:"sync"})}finally{await b.disconnect()}}async function Oe(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,dryRun:f,jsonOutput:l}=n,u=e.all,c=e.service||e.s;if(u||c&&c.includes(",")){await hn(n);return}r||(console.error("Error: Project not specified and no config found"),console.error('Run "minienv init" or specify --project'),process.exit(1)),$e(t)&&o?.security?.confirm_production&&!e.force&&(console.error(`Warning: You are syncing to ${t} (production) environment`),console.error("Use --force to confirm this action"),process.exit(1));try{let a=await Ce(n);l?console.log(JSON.stringify({success:!0,dryRun:f,project:r,service:i,environment:t,added:a.added,updated:a.updated,deleted:a.deleted,unchanged:a.unchanged,conflicts:a.conflicts})):f?(console.log("Dry run - changes that would be made:"),a.added.length>0&&console.log(` Add (${a.added.length}): ${a.added.join(", ")}`),a.updated.length>0&&console.log(` Update (${a.updated.length}): ${a.updated.join(", ")}`),a.deleted.length>0&&console.log(` Delete (${a.deleted.length}): ${a.deleted.join(", ")}`),a.unchanged.length>0&&console.log(` Unchanged: ${a.unchanged.length} variables`),a.added.length===0&&a.updated.length===0&&a.deleted.length===0&&console.log(" No changes needed")):(console.log(`\u2713 Synced ${r}/${t}`),a.added.length>0&&console.log(` Added: ${a.added.length} (${a.added.join(", ")})`),a.updated.length>0&&console.log(` Updated: ${a.updated.length} (${a.updated.join(", ")})`),a.deleted.length>0&&console.log(` Deleted: ${a.deleted.length} (${a.deleted.join(", ")})`),a.unchanged.length>0&&console.log(` Unchanged: ${a.unchanged.length}`))}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}}async function hn(n){let{args:e,environment:o,verbose:r,dryRun:i,jsonOutput:t}=n,s=U();s||(console.error("Error: Not inside a monorepo"),console.error("Run this command from within a project that has nested .minienv directories"),process.exit(1));let f=I(s);f.length===0&&(console.error("Error: No services found in monorepo"),process.exit(1));let l=e.service||e.s;if(l&&!e.all&&(f=be(f,l),f.length===0)){console.error(`Error: No services match pattern: ${l}`),console.error(""),console.error("Available services:");let c=I(s);for(let a of c)console.error(` \u2022 ${a.name}`);process.exit(1)}r&&(console.error(Ee(f)),console.error("")),$e(o)&&!e.force&&(console.error(`Warning: You are syncing ${f.length} services to ${o} (production)`),console.error("Use --force to confirm this action"),process.exit(1));let u=await Se(f,o,async(c,a)=>Ce({...n,config:c.config},c),{verbose:r,onProgress:r?(c,a,g)=>{console.error(`[${c+1}/${a}] Syncing ${g.name}...`)}:void 0});console.log(t?JSON.stringify(ke(u)):xe(u,c=>{if(c.error)return`\u2717 ${c.service.name}: ${c.error.message}`;let a=c.result,g=a.added.length+a.updated.length+a.deleted.length;return`\u2713 ${c.service.name}: ${g} changes (${c.duration}ms)`})),u.failed>0&&process.exit(1)}var _=h(require("node:fs"),1),Y=h(require("node:path"),1);async function Pe(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,dryRun:f,jsonOutput:l}=n;r||(console.error("Error: Project not specified and no config found"),console.error('Run "minienv init" or specify --project'),process.exit(1));let u=e.output||e.o||e.file||e.f,c=null;if(u)c=Y.default.resolve(u);else{let p=w();p&&(c=P(p,t))}s&&(console.error(`Pulling ${r}/${i||"(no service)"}/${t}`),console.error(c?`Output: ${c}`:"Output: stdout"));let a=e.backend||e.b||o?.backend?.url,g=o?await y(o):void 0,d=new m({connectionString:a||void 0,passphrase:g||void 0});try{await d.connect();let p=await d.export(r,t,i),v=Object.keys(p).length;if(v===0){l?console.log(JSON.stringify({warning:"no_variables",project:r,service:i,environment:t})):console.error(`Warning: No variables found for ${r}/${t}`);return}let b=L(p);if(f){l?console.log(JSON.stringify({dryRun:!0,project:r,service:i,environment:t,variableCount:v,outputPath:c,variables:Object.keys(p)})):(console.log(`Dry run - would pull ${v} variables:`),console.log(` Variables: ${Object.keys(p).join(", ")}`),console.log(c?` Output: ${c}`:" Output: stdout"));return}if(c){_.default.existsSync(c)&&!e.force&&(console.error(`Warning: File exists: ${c}`),console.error("Use --force to overwrite"),process.exit(1));let E=Y.default.dirname(c);_.default.existsSync(E)||_.default.mkdirSync(E,{recursive:!0}),_.default.writeFileSync(c,b+`
|
|
69
|
-
`),console.log(l?JSON.stringify({success:!0,project:r,service:i,environment:t,variableCount:v,outputPath:c}):`\u2713 Pulled ${v} variables to ${c}`)}else console.log(l?JSON.stringify({success:!0,project:r,service:i,environment:t,variables:p}):b)}finally{await d.disconnect()}}var Ne=h(require("node:fs"),1),Re=h(require("node:path"),1);function bn(n){return n==="prd"||n==="dr"}async function Ae(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,dryRun:f,jsonOutput:l}=n;r||(console.error("Error: Project not specified and no config found"),console.error('Run "minienv init" or specify --project'),process.exit(1)),bn(t)&&o?.security?.confirm_production&&!e.force&&(console.error(`Warning: You are pushing to ${t} (production) environment`),console.error("Use --force to confirm this action"),process.exit(1));let u;if(F())s&&console.error("Reading variables from stdin..."),u=await T();else{let p=e.file||e.f,v;if(p)v=Re.default.resolve(p);else{let b=w();b||(console.error("Error: No config directory found and no file specified"),console.error("Use -f <file> to specify the .env file"),process.exit(1)),v=P(b,t)}Ne.default.existsSync(v)||(console.error(`Error: File not found: ${v}`),process.exit(1)),s&&console.error(`Reading variables from ${v}`),u=K(v)}let c=Object.keys(u).length;if(c===0){l?console.log(JSON.stringify({warning:"no_variables",message:"No variables found in source"})):console.error("Warning: No variables found in source");return}s&&console.error(`Found ${c} variables to push`);let a=e.backend||e.b||o?.backend?.url,g=o?await y(o):void 0,d=new m({connectionString:a||void 0,passphrase:g||void 0});try{if(await d.connect(),f){let b=await d.export(r,t,i),E=[],S=[],j=[];for(let[C,M]of Object.entries(u))C in b?b[C]!==M?S.push(C):j.push(C):E.push(C);l?console.log(JSON.stringify({dryRun:!0,project:r,service:i,environment:t,changes:{add:E,update:S,unchanged:j}})):(console.log("Dry run - changes that would be made:"),E.length>0&&console.log(` Add (${E.length}): ${E.join(", ")}`),S.length>0&&console.log(` Update (${S.length}): ${S.join(", ")}`),j.length>0&&console.log(` Unchanged: ${j.length} variables`),E.length===0&&S.length===0&&console.log(" No changes needed"));return}let p=0,v=0;for(let[b,E]of Object.entries(u)){let S=await d.get(b,r,t,i);await d.set({key:b,value:E,project:r,service:i,environment:t,metadata:{source:"sync"}}),S?v++:p++}l?console.log(JSON.stringify({success:!0,project:r,service:i,environment:t,added:p,updated:v,total:c})):(console.log(`\u2713 Pushed ${c} variables to ${r}/${t}`),p>0&&console.log(` Added: ${p}`),v>0&&console.log(` Updated: ${v}`))}finally{await d.disconnect()}}function En(n){return Buffer.from(n).toString("base64")}function J(n){return n.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/--+/g,"-").replace(/^-|-$/g,"")}async function Ie(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,jsonOutput:f}=n;r||(console.error("Error: Project not specified"),process.exit(1));let l=e.namespace||e.n||o?.integrations?.kubernetes?.namespace||`${r}-${t}`,u=o?.integrations?.kubernetes?.secret_name||(i?`${i}-secrets`:`${r}-secrets`);s&&console.error(`Generating K8s Secret: ${l}/${u}`);let c=e.backend||e.b||o?.backend?.url,a=o?await y(o):void 0,g=new m({connectionString:c||void 0,passphrase:a||void 0});try{await g.connect();let d=await g.export(r,t,i);if(Object.keys(d).length===0){console.error("Warning: No variables found");return}let p=Sn(J(u),J(l),d,{project:r,service:i,environment:t,managedBy:"minienv"});console.log(f?JSON.stringify({kind:"Secret",name:u,namespace:l,variableCount:Object.keys(d).length}):p)}finally{await g.disconnect()}}async function _e(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,jsonOutput:f}=n;r||(console.error("Error: Project not specified"),process.exit(1));let l=e.namespace||e.n||o?.integrations?.kubernetes?.namespace||`${r}-${t}`,u=o?.integrations?.kubernetes?.configmap_name||(i?`${i}-config`:`${r}-config`);s&&console.error(`Generating K8s ConfigMap: ${l}/${u}`);let c=e.backend||e.b||o?.backend?.url,a=o?await y(o):void 0,g=new m({connectionString:c||void 0,passphrase:a||void 0});try{await g.connect();let d=await g.export(r,t,i);if(Object.keys(d).length===0){console.error("Warning: No variables found");return}let p=xn(J(u),J(l),d,{project:r,service:i,environment:t,managedBy:"minienv"});console.log(f?JSON.stringify({kind:"ConfigMap",name:u,namespace:l,variableCount:Object.keys(d).length}):p)}finally{await g.disconnect()}}function Sn(n,e,o,r){let i=["# Generated by minienv","# DO NOT EDIT - changes will be overwritten","apiVersion: v1","kind: Secret","metadata:",` name: ${n}`,` namespace: ${e}`," labels:"];for(let[t,s]of Object.entries(r))s&&i.push(` app.kubernetes.io/${t}: "${s}"`);i.push("type: Opaque"),i.push("data:");for(let[t,s]of Object.entries(o))i.push(` ${t}: ${En(s)}`);return i.join(`
|
|
70
|
-
`)}function xn(n,e,o,r){let i=["# Generated by minienv","# DO NOT EDIT - changes will be overwritten","apiVersion: v1","kind: ConfigMap","metadata:",` name: ${n}`,` namespace: ${e}`," labels:"];for(let[t,s]of Object.entries(r))s&&i.push(` app.kubernetes.io/${t}: "${s}"`);i.push("data:");for(let[t,s]of Object.entries(o))s.includes(":")||s.includes("#")||s.includes(`
|
|
71
|
-
`)||s.startsWith(" ")||s.endsWith(" ")?i.push(` ${t}: "${s.replace(/"/g,'\\"').replace(/\n/g,"\\n")}"`):i.push(` ${t}: ${s}`);return i.join(`
|
|
72
|
-
`)}async function De(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,jsonOutput:f}=n;r||(console.error("Error: Project not specified"),process.exit(1)),s&&console.error(`Generating Helm values for ${r}/${t}`);let l=e.backend||e.b||o?.backend?.url,u=o?await y(o):void 0,c=new m({connectionString:l||void 0,passphrase:u||void 0});try{await c.connect();let a=await c.export(r,t,i);if(Object.keys(a).length===0){console.error("Warning: No variables found");return}if(f)console.log(JSON.stringify({format:"helm-values",project:r,environment:t,variableCount:Object.keys(a).length}));else{let g=kn(a,{project:r,service:i,environment:t});console.log(g)}}finally{await c.disconnect()}}function kn(n,e){let o=["# Generated by minienv",`# Project: ${e.project}`,`# Environment: ${e.environment}`,e.service?`# Service: ${e.service}`:null,"# DO NOT EDIT - changes will be overwritten","","# Environment variables (plain)","env:"].filter(Boolean);for(let[r,i]of Object.entries(n))o.push(` ${r}: ${Me(i)}`);o.push(""),o.push("# Secrets (same values, for use with secretKeyRef)"),o.push("secrets:");for(let[r,i]of Object.entries(n))o.push(` ${r}: ${Me(i)}`);return o.join(`
|
|
73
|
-
`)}function Me(n){return n===""||n==="true"||n==="false"||n==="null"||n==="yes"||n==="no"||!isNaN(Number(n))||n.includes(":")||n.includes("#")||n.includes(`
|
|
74
|
-
`)||n.includes('"')||n.includes("'")||n.startsWith(" ")||n.endsWith(" ")||n.startsWith("{")||n.startsWith("[")?`"${n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n")}"`:n}async function Le(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,jsonOutput:f}=n;r||(console.error("Error: Project not specified"),process.exit(1)),s&&console.error(`Generating Terraform tfvars for ${r}/${t}`);let l=e.backend||e.b||o?.backend?.url,u=o?await y(o):void 0,c=new m({connectionString:l||void 0,passphrase:u||void 0});try{await c.connect();let a=await c.export(r,t,i);if(Object.keys(a).length===0){console.error("Warning: No variables found");return}if(f)console.log(JSON.stringify({format:"tfvars",project:r,environment:t,variableCount:Object.keys(a).length}));else{let g=wn(a,{project:r,service:i,environment:t});console.log(g)}}finally{await c.disconnect()}}async function Te(n){let{args:e,config:o,project:r,service:i,environment:t,verbose:s,jsonOutput:f}=n;r||(console.error("Error: Project not specified"),process.exit(1)),s&&console.error(`Generating Terraform JSON for ${r}/${t}`);let l=e.backend||e.b||o?.backend?.url,u=o?await y(o):void 0,c=new m({connectionString:l||void 0,passphrase:u||void 0});try{await c.connect();let a=await c.export(r,t,i);if(Object.keys(a).length===0){console.error("Warning: No variables found");return}let g={};for(let[p,v]of Object.entries(a)){let b=p.toLowerCase();g[b]=v}let d={...g,env_vars:a};console.log(JSON.stringify(d,null,2))}finally{await c.disconnect()}}function wn(n,e){let o=["# Generated by minienv",`# Project: ${e.project}`,`# Environment: ${e.environment}`,e.service?`# Service: ${e.service}`:null,"# DO NOT EDIT - changes will be overwritten",""].filter(Boolean);for(let[r,i]of Object.entries(n)){let t=r.toLowerCase();o.push(`${t} = ${Ke(i)}`)}o.push(""),o.push("# All environment variables as a map"),o.push("env_vars = {");for(let[r,i]of Object.entries(n))o.push(` "${r}" = ${Ke(i)}`);return o.push("}"),o.join(`
|
|
75
|
-
`)}function Ke(n){return`"${n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}"`}var Fe=h(require("node:crypto"),1),R=h(require("node:fs"),1),G=h(require("node:path"),1);function jn(){return Fe.default.randomBytes(32).toString("base64")}async function Ve(n){let{args:e,config:o,verbose:r,dryRun:i,jsonOutput:t}=n,s=e._[1];switch(s){case"generate":case"gen":await $n(n);break;case"show":await Cn(n);break;case"rotate":await On(n);break;default:console.error(`Unknown key subcommand: ${s||"(none)"}`),console.error("Available subcommands: generate, show, rotate"),console.error(""),console.error("Examples:"),console.error(" minienv key generate # Generate new key to stdout"),console.error(" minienv key generate -o .key # Generate key to file"),console.error(" minienv key show # Show current key source"),process.exit(1)}}async function $n(n){let{args:e,verbose:o,dryRun:r,jsonOutput:i}=n,t=e.output||e.o;o&&console.error("Generating new AES-256 encryption key...");let s=jn();if(r){i?console.log(JSON.stringify({dryRun:!0,action:"generate_key",outputPath:t||"stdout",keyLength:32,algorithm:"aes-256-gcm"})):(console.log("Dry run - would generate new encryption key"),console.log(t?` Output: ${t}`:" Output: stdout"));return}if(t){let f=G.default.resolve(t);R.default.existsSync(f)&&!e.force&&(console.error(`Error: File exists: ${f}`),console.error("Use --force to overwrite"),process.exit(1));let l=G.default.dirname(f);R.default.existsSync(l)||R.default.mkdirSync(l,{recursive:!0}),R.default.writeFileSync(f,s+`
|
|
76
|
-
`,{mode:384}),i?console.log(JSON.stringify({success:!0,outputPath:f,keyLength:32,algorithm:"aes-256-gcm"})):(console.log(`\u2713 Generated encryption key: ${f}`),console.log(" Store this key securely - it cannot be recovered!"),console.log(""),console.log("To use this key:"),console.log(` 1. Set environment variable: export MINIENV_KEY=$(cat ${f})`),console.log(" 2. Or configure in .minienv/config.yaml:"),console.log(" encryption:"),console.log(" key_source:"),console.log(` - file: ${t}`))}else console.log(i?JSON.stringify({key:s,keyLength:32,algorithm:"aes-256-gcm"}):s)}async function Cn(n){let{config:e,jsonOutput:o}=n;e||(console.error("Error: No minienv configuration found"),console.error('Run "minienv init" first'),process.exit(1));let r=e.encryption?.key_source||[],i=[];for(let t of r)"env"in t?i.push({type:"env",source:t.env,available:!!process.env[t.env]}):"file"in t?i.push({type:"file",source:t.file,available:R.default.existsSync(G.default.resolve(t.file))}):"s3"in t&&i.push({type:"s3",source:t.s3,available:!1});if(i.some(t=>t.type==="env"&&t.source==="MINIENV_KEY")||i.push({type:"env",source:"MINIENV_KEY",available:!!process.env.MINIENV_KEY}),o)console.log(JSON.stringify({configured:r.length>0,sources:i,activeSource:i.find(t=>t.available)?.source||null}));else{if(console.log("Key Sources:"),i.length===0)console.log(" (none configured)");else for(let s of i){let f=s.available?"\u2713":"\u2717";console.log(` ${f} ${s.type}: ${s.source}`)}let t=i.find(s=>s.available);t?(console.log(""),console.log(`Active key source: ${t.type}:${t.source}`)):(console.log(""),console.log("Warning: No encryption key available"),console.log('Run "minienv key generate -o .minienv/.key" to create one'))}}async function On(n){let{config:e,dryRun:o,jsonOutput:r}=n;e||(console.error("Error: No minienv configuration found"),console.error('Run "minienv init" first'),process.exit(1)),r?console.log(JSON.stringify({error:"not_implemented",message:"Key rotation is not yet fully automated"})):(console.log("Key rotation steps:"),console.log(""),console.log("1. Generate a new key:"),console.log(" minienv key generate -o .minienv/.key.new"),console.log(""),console.log("2. Export current values (with old key):"),console.log(" minienv export -e <env> > vars.env"),console.log(""),console.log("3. Update to new key:"),console.log(" mv .minienv/.key.new .minienv/.key"),console.log(""),console.log("4. Re-import values (with new key):"),console.log(" cat vars.env | minienv sync -e <env>"),console.log(""),console.log("5. Clean up:"),console.log(" rm vars.env"),console.log(""),console.log("Note: Repeat steps 2-4 for each environment."),o&&(console.log(""),console.log("(dry-run mode - no changes made)")))}var H=h(require("node:path"),1);async function Ue(n){let{args:e,verbose:o,jsonOutput:r}=n,i=e._[1];switch(i){case"list":case"ls":case void 0:await Pn(n);break;default:console.error(`Unknown services subcommand: ${i}`),console.error("Available subcommands: list"),console.error(""),console.error("Examples:"),console.error(" minienv services # List all services"),console.error(" minienv services list # Same as above"),console.error(" minienv services list --json # JSON output"),process.exit(1)}}async function Pn(n){let{verbose:e,jsonOutput:o}=n,r=U();r||(o?console.log(JSON.stringify({error:"not_in_monorepo",message:"Not inside a minienv project"})):(console.error("Not inside a minienv project"),console.error('Run "minienv init" first')),process.exit(1));let i=I(r);if(o)console.log(JSON.stringify({root:r,count:i.length,services:i.map(t=>({name:t.name,path:H.default.relative(process.cwd(),t.path)||".",project:t.config.project,environments:t.config.environments||["dev","stg","prd","sbx","dr"],defaultEnvironment:t.config.default_environment||"dev"}))}));else if(i.length===0)console.log("No services found"),console.log(""),console.log("This might be a single-project setup (no nested .minienv directories)");else{console.log(`Found ${i.length} service(s) in monorepo:`),console.log("");for(let t of i){let s=H.default.relative(process.cwd(),t.path)||".";console.log(` ${t.name}`),console.log(` Path: ${s}`),console.log(` Project: ${t.config.project}`),e&&(console.log(` Environments: ${(t.config.environments||["dev","stg","prd"]).join(", ")}`),console.log(` Default: ${t.config.default_environment||"dev"}`),t.config.backend?.url&&console.log(` Backend: ${t.config.backend.url}`)),console.log("")}}}var Nn="0.1.0";function Rn(){return(0,Je.default)(process.argv.slice(2),{string:["project","p","service","s","env","e","backend","b","key","k","file","f","output","o","namespace","n","format"],boolean:["verbose","v","dry-run","json","no-color","help","h","version","force","all"],alias:{p:"project",s:"service",e:"env",b:"backend",k:"key",v:"verbose",f:"file",o:"output",h:"help",n:"namespace"},default:{verbose:!1,"dry-run":!1,json:!1,"no-color":!1}})}function An(){console.log(`
|
|
77
|
-
minienv - Multi-backend environment variable and secrets manager
|
|
78
|
-
|
|
79
|
-
Usage:
|
|
80
|
-
minienv <command> [options]
|
|
81
|
-
|
|
82
|
-
Commands:
|
|
83
|
-
init Initialize a new .minienv configuration
|
|
84
|
-
get <key> Get a single environment variable
|
|
85
|
-
set <key> <value> Set an environment variable
|
|
86
|
-
delete <key> Delete an environment variable
|
|
87
|
-
list List all environment variables
|
|
88
|
-
export Export variables for shell evaluation
|
|
89
|
-
sync Sync local .env file with backend
|
|
90
|
-
pull Pull variables from backend to local .env
|
|
91
|
-
push Push local .env to backend
|
|
92
|
-
key generate Generate a new encryption key
|
|
93
|
-
services List services in monorepo
|
|
94
|
-
config Manage configuration
|
|
95
|
-
|
|
96
|
-
Integration Commands:
|
|
97
|
-
k8s:secret Generate Kubernetes Secret YAML
|
|
98
|
-
k8s:configmap Generate Kubernetes ConfigMap YAML
|
|
99
|
-
helm:values Generate Helm values.yaml
|
|
100
|
-
tf:vars Generate Terraform .tfvars
|
|
101
|
-
tf:json Generate Terraform JSON
|
|
102
|
-
|
|
103
|
-
Global Options:
|
|
104
|
-
-p, --project <name> Project name (default: from config or directory)
|
|
105
|
-
-s, --service <name> Service name (for monorepos, supports comma-separated)
|
|
106
|
-
-e, --env <env> Environment (dev/stg/prd/sbx/dr)
|
|
107
|
-
-b, --backend <url> Backend URL override
|
|
108
|
-
-k, --key <path> Encryption key path
|
|
109
|
-
-v, --verbose Enable verbose output
|
|
110
|
-
--all Apply to all services in monorepo
|
|
111
|
-
--dry-run Show what would be done without making changes
|
|
112
|
-
--json Output in JSON format
|
|
113
|
-
--no-color Disable colored output
|
|
114
|
-
-h, --help Show this help message
|
|
115
|
-
--version Show version
|
|
116
|
-
|
|
117
|
-
Examples:
|
|
118
|
-
# Initialize project
|
|
119
|
-
minienv init
|
|
120
|
-
|
|
121
|
-
# Get a variable
|
|
122
|
-
minienv get DATABASE_URL -e prd
|
|
123
|
-
|
|
124
|
-
# Set a variable
|
|
125
|
-
minienv set API_KEY "sk-..." -e prd
|
|
126
|
-
|
|
127
|
-
# Export for shell
|
|
128
|
-
eval $(minienv export -e dev)
|
|
129
|
-
|
|
130
|
-
# Sync local .env
|
|
131
|
-
minienv sync -f .env.local -e dev
|
|
132
|
-
|
|
133
|
-
# Sync all services in monorepo
|
|
134
|
-
minienv sync -e dev --all
|
|
135
|
-
|
|
136
|
-
# Sync specific services
|
|
137
|
-
minienv sync -e dev -s svc-auth,svc-api
|
|
138
|
-
|
|
139
|
-
# List services in monorepo
|
|
140
|
-
minienv services
|
|
141
|
-
|
|
142
|
-
# Generate K8s secret
|
|
143
|
-
minienv k8s:secret -e prd | kubectl apply -f -
|
|
144
|
-
|
|
145
|
-
Documentation: https://github.com/tetis-io/minienv
|
|
146
|
-
`)}function In(){console.log(`minienv v${Nn}`)}async function _n(){let n=Rn();if(n.version){In();return}if(n.help||n.h||n._.length===0){An();return}let e=n._[0],o;try{o=D()}catch{o=null}let r=n.env||n.e||o?.default_environment||"dev",i=n.project||n.p||(o?oe(o):""),t=n.service||n.s||o?.service,s=n.verbose||n.v||!1,f=n["dry-run"]||!1,l=n.json||!1,u=n["no-color"]||!1,c={args:n,config:o,project:i,service:t,environment:r,verbose:s,dryRun:f,jsonOutput:l,noColor:u};try{switch(e){case"init":await se(c);break;case"get":await ae(c);break;case"set":await le(c);break;case"delete":case"rm":case"remove":await fe(c);break;case"list":case"ls":await ge(c);break;case"export":await ve(c);break;case"sync":await Oe(c);break;case"pull":await Pe(c);break;case"push":await Ae(c);break;case"key":await Ve(c);break;case"services":case"svc":await Ue(c);break;case"config":console.log("config command not yet implemented");break;case"k8s:secret":await Ie(c);break;case"k8s:configmap":await _e(c);break;case"helm:values":await De(c);break;case"tf:vars":await Le(c);break;case"tf:json":await Te(c);break;default:console.error(`Unknown command: ${e}`),console.error('Run "minienv --help" for usage information'),process.exit(1)}}catch(a){console.error(s?a:`Error: ${a.message}`),process.exit(1)}}_n().catch(n=>{console.error("Fatal error:",n.message),process.exit(1)});
|