@dinanathdash/envault 1.0.0 → 1.1.0

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/.env ADDED
@@ -0,0 +1,20 @@
1
+ # Environment Variables Example
2
+
3
+ Copy this file to `.env.local` and fill in your values.
4
+
5
+ ## Supabase Configuration
6
+ NEXT_PUBLIC_SUPABASE_URL=your_supabase_url_here
7
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key_here
8
+
9
+ ## Encryption Key (Required)
10
+ # Generate a new key with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
11
+ # IMPORTANT: Keep this secret and never commit it to version control
12
+ # If you lose this key, all encrypted data becomes unrecoverable
13
+ ENCRYPTION_KEY=your_64_character_hex_encryption_key_here
14
+
15
+ ## Supabase Service Role Key (Required)
16
+ SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key_here
17
+
18
+ # Redis (Upstash)
19
+ UPSTASH_REDIS_REST_URL=your_upstash_redis_rest_url_here
20
+ UPSTASH_REDIS_REST_TOKEN=your_upstash_redis_rest_token_here
package/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # [1.1.0](https://github.com/DinanathDash/Envault/compare/v1.0.2...v1.1.0) (2026-02-01)
2
+
3
+
4
+ ### Features
5
+
6
+ * Implement CLI device authentication, add new CLI API routes for projects and secrets, and enhance CLI commands with improved warnings. ([e4871c4](https://github.com/DinanathDash/Envault/commit/e4871c453d7e3974e94505e1f65014350a15a53a))
7
+
8
+ ## [1.0.2](https://github.com/DinanathDash/Envault/compare/v1.0.1...v1.0.2) (2026-02-01)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * sync version and verify automated release ([ab54ab2](https://github.com/DinanathDash/Envault/commit/ab54ab2b4a9ac045ea986d34d9187ab4c705c76e))
14
+
15
+ # 1.0.0 (2026-02-01)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **ci:** upgrade node to v22 for semantic-release ([fcdd294](https://github.com/DinanathDash/Envault/commit/fcdd29467dad11ddbe33190df04afd6ba03bfde0))
21
+
22
+
23
+ ### Features
24
+
25
+ * Add comprehensive authentication flows including password reset, email confirmation, and update password with new UI components and email templates. ([c1da2ed](https://github.com/DinanathDash/Envault/commit/c1da2ed12a5669e76ad2d28d1c37564e55c3aeee))
26
+ * add landing page animations and update auth pages ([3c04f52](https://github.com/DinanathDash/Envault/commit/3c04f529ffa6dc2cf3e0bfdadb95fa5491a810f0))
27
+ * Add Open Graph and Twitter image metadata, including a new `open-graph.png` asset. ([3291026](https://github.com/DinanathDash/Envault/commit/3291026e2311b5d1f80016a769ba8c0fab2171d5))
28
+ * Add project governance documents, update README, and implement async secret decryption and user sign-out. ([380c88a](https://github.com/DinanathDash/Envault/commit/380c88accae92a7c0583c0bdd28963f55fc523f1))
29
+ * Add variable value visibility toggle, implement Tooltip component, and refine UI spacing and responsiveness. ([25fd618](https://github.com/DinanathDash/Envault/commit/25fd618f58977f8ef128105ac3d59466498c0637))
30
+ * document Upstash Redis integration and add rounded corners to favicon. ([7d68a5d](https://github.com/DinanathDash/Envault/commit/7d68a5d944b66547199268bfc5a93dc16fc0cfa6))
31
+ * Implement .env file download functionality and update application icons. ([81db44b](https://github.com/DinanathDash/Envault/commit/81db44b9094c21a5bbc314cd427b049fbdaff580))
32
+ * Implement amber theme for landing page and optimize session monitoring for public routes. ([e8634f2](https://github.com/DinanathDash/Envault/commit/e8634f2ac4d3e2561fc27c2d466ace91dcee0b00))
33
+ * implement CLI authentication and device flow ([85f794f](https://github.com/DinanathDash/Envault/commit/85f794feffa3256c1bb9f40fd37de28962fe045c))
34
+ * Implement core application structure with user authentication, project and environment variable management, and a comprehensive UI component library. ([1990916](https://github.com/DinanathDash/Envault/commit/1990916e90d2277b503c69363a4409e2c6d34db3))
35
+ * Implement key wrapping and rotation, add GitHub authentication, and enhance variable dialog with upsert logic and status indicators. ([a73783e](https://github.com/DinanathDash/Envault/commit/a73783ecedbd36d947fdd9b7ab39e7e38ea4edb1))
36
+ * Implement user authentication, project management, and bulk .env variable import with encryption. ([aa890cf](https://github.com/DinanathDash/Envault/commit/aa890cf9c4eee958648e5c82a8af4e0234cd5026))
37
+ * Introduce preloader component, global loading state, and skeleton UIs for dashboard and project views. ([3f052d6](https://github.com/DinanathDash/Envault/commit/3f052d6300133398505e43748a97e7aac2f29624))
38
+ * Refactor key rotation to use chunked processing and job management, integrate Upstash Redis for caching, and add Vercel Analytics. ([17ba173](https://github.com/DinanathDash/Envault/commit/17ba173e03c8f139f98069b6b04a0b77c9dea428))
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dinanath Dash
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Envault CLI
2
+
3
+ <p align="center">
4
+ <b>Secure Environment Variable Management for Modern Teams</b>
5
+ </p>
6
+
7
+ <p align="center">
8
+ Securely push, pull, and manage your secrets directly from your terminal with the same ease as `git push`.
9
+ </p>
10
+
11
+ ---
12
+
13
+ ## Features
14
+
15
+ - šŸ”’ **End-to-End Encryption**: Secrets are encrypted before they leave your machine.
16
+ - šŸ”‘ **Device Flow Authentication**: Secure, browser-based login mechanism.
17
+ - šŸš€ **Zero-Config**: Works with your existing `.env` files.
18
+ - ⚔ **Framework Agnostic**: Works with Next.js, Node.js, Python, Go, etc.
19
+
20
+ ## Installation
21
+
22
+ You can run Envault directly using `npx` (recommended) or install it globally.
23
+
24
+ ### Using Number (Zero Install)
25
+ ```bash
26
+ npx @dinanathdash/envault login
27
+ ```
28
+
29
+ ### Global Install
30
+ ```bash
31
+ npm install -g @dinanathdash/envault
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ### 1. Login
37
+ Authenticate your machine securely.
38
+ ```bash
39
+ envault login
40
+ ```
41
+
42
+ ### 2. Initialize Project
43
+ Link your current folder to an Envault project.
44
+ ```bash
45
+ envault init
46
+ ```
47
+
48
+ ### 3. Deploy Secrets
49
+ Push your local `.env` variables to the secure cloud vault.
50
+ ```bash
51
+ envault deploy
52
+ ```
53
+
54
+ ### 4. Pull Secrets
55
+ Fetch the latest secrets from the cloud and update your `.env` file.
56
+ ```bash
57
+ envault pull
58
+ ```
59
+
60
+ ## License
61
+
62
+ MIT Ā© [Envault](https://envault.tech)
package/bin/envault.js CHANGED
@@ -7,6 +7,10 @@ import { login } from '../src/commands/login.js';
7
7
  import { init } from '../src/commands/init.js';
8
8
  import { deploy } from '../src/commands/deploy.js';
9
9
  import { pull } from '../src/commands/pull.js';
10
+ import { createRequire } from 'module';
11
+
12
+ const require = createRequire(import.meta.url);
13
+ const pkg = require('../package.json');
10
14
 
11
15
  const program = new Command();
12
16
 
@@ -26,7 +30,7 @@ const showLogo = () => {
26
30
  program
27
31
  .name('envault')
28
32
  .description('Cliff-side security for your environment variables')
29
- .version('1.0.0')
33
+ .version(pkg.version)
30
34
  .hook('preAction', (thisCommand) => {
31
35
  // Show logo on all commands? Maybe too noisy.
32
36
  // Let's show it only on help or specific ones.
@@ -50,6 +54,7 @@ program.command('deploy')
50
54
  .description('Deploy local .env to Envault (Encrypt & Push)')
51
55
  .option('-p, --project <id>', 'Project ID')
52
56
  .option('--dry-run', 'Show what would change without pushing')
57
+ .option('-f, --force', 'Skip confirmation prompts')
53
58
  .action(async (options) => {
54
59
  await deploy(options);
55
60
  });
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@dinanathdash/envault",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Envault CLI - Securely manage your environment variables",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/DinanathDash/Envault.git"
8
+ },
5
9
  "main": "src/index.js",
6
10
  "bin": {
7
11
  "envault": "./bin/envault.js"
@@ -25,7 +29,16 @@
25
29
  "conf": "^12.0.0",
26
30
  "dotenv": "^16.3.1",
27
31
  "inquirer": "^9.2.11",
28
- "ora": "^7.0.1",
29
- "open": "^10.0.3"
32
+ "open": "^10.0.3",
33
+ "ora": "^7.0.1"
34
+ },
35
+ "devDependencies": {
36
+ "@semantic-release/changelog": "^6.0.3",
37
+ "@semantic-release/exec": "^7.1.0",
38
+ "@semantic-release/git": "^10.0.1",
39
+ "semantic-release": "^25.0.3"
40
+ },
41
+ "overrides": {
42
+ "tar": "^7.5.7"
30
43
  }
31
- }
44
+ }
@@ -0,0 +1,24 @@
1
+ const config = {
2
+ branches: ['main'],
3
+ plugins: [
4
+ '@semantic-release/commit-analyzer',
5
+ '@semantic-release/release-notes-generator',
6
+ [
7
+ '@semantic-release/changelog',
8
+ {
9
+ changelogFile: 'CHANGELOG.md',
10
+ },
11
+ ],
12
+ '@semantic-release/npm', // Updates package.json and publishes
13
+ [
14
+ '@semantic-release/git',
15
+ {
16
+ assets: ['package.json', 'package-lock.json', 'CHANGELOG.md', 'README.md'],
17
+ message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
18
+ },
19
+ ],
20
+ '@semantic-release/github',
21
+ ],
22
+ };
23
+
24
+ export default config;
@@ -1,3 +1,5 @@
1
+ import boxen from 'boxen';
2
+ import inquirer from 'inquirer';
1
3
 
2
4
  import fs from 'fs';
3
5
  import dotenv from 'dotenv';
@@ -41,6 +43,57 @@ export async function deploy(options) {
41
43
  return;
42
44
  }
43
45
 
46
+ if (!options.force) {
47
+ let projectName = 'Envault';
48
+ try {
49
+ // Attempt to fetch project name. If fails, fallback to 'Envault'
50
+ // We use the list endpoint as we know it exists from init.js
51
+ const { data } = await api.get('/projects');
52
+ const projects = data.projects || data.data || [];
53
+ const project = projects.find(p => p.id === projectId);
54
+ if (project) {
55
+ projectName = project.name;
56
+ }
57
+ } catch (e) {
58
+ // Ignore error and use default
59
+ }
60
+
61
+ const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://envault.tech';
62
+
63
+ console.log(boxen(
64
+ chalk.red.bold('WARNING: OVERWRITING REMOTE SECRETS') +
65
+ '\n\n' +
66
+ chalk.white('You are about to ') + chalk.red.bold('DEPLOY') + chalk.white(' local variables to your project:') +
67
+ '\n' +
68
+ chalk.cyan.bold(projectName) +
69
+ '\n\n' +
70
+ chalk.white('Existing secrets in the project will be ') + chalk.red.bold('OVERWRITTEN') + chalk.white(' by values in your .env.') +
71
+ '\n\n' +
72
+ chalk.dim('We recommend checking the dashboard for differences:') +
73
+ '\n' +
74
+ chalk.cyan(`${appUrl}/projects/${projectId}`),
75
+ {
76
+ padding: 1,
77
+ margin: 1,
78
+ borderStyle: 'double',
79
+ borderColor: 'red',
80
+ title: 'Deploy Warning',
81
+ titleAlignment: 'center'
82
+ }
83
+ ));
84
+
85
+ const { confirm } = await inquirer.prompt([{
86
+ type: 'confirm',
87
+ name: 'confirm',
88
+ message: `Are you sure you want to deploy ${secrets.length} secrets to the project?`,
89
+ default: false
90
+ }]);
91
+ if (!confirm) {
92
+ console.log(chalk.yellow('Operation cancelled.'));
93
+ return;
94
+ }
95
+ }
96
+
44
97
  const spinner = ora('Encrypting and deploying secrets...').start();
45
98
 
46
99
  try {
@@ -43,17 +43,46 @@ export async function init() {
43
43
  }
44
44
 
45
45
  if (projects.length === 0) {
46
- console.log(chalk.yellow('No projects found. Create one in the dashboard first.'));
47
- return;
46
+ console.log(chalk.yellow('No existing projects found.'));
48
47
  }
49
48
 
50
- const { projectId } = await inquirer.prompt([{
49
+ const { selectedProjectId } = await inquirer.prompt([{
51
50
  type: 'list',
52
- name: 'projectId',
51
+ name: 'selectedProjectId',
53
52
  message: 'Select the project to link:',
54
- choices: projects.map(p => ({ name: p.name, value: p.id }))
53
+ choices: [
54
+ new inquirer.Separator(),
55
+ { name: '+ Create New Project', value: 'CREATE_NEW' },
56
+ new inquirer.Separator(),
57
+ ...projects.map(p => ({ name: p.name, value: p.id }))
58
+ ]
55
59
  }]);
56
60
 
57
- fs.writeFileSync('envault.json', JSON.stringify({ projectId }, null, 2));
58
- console.log(chalk.green(`\nāœ” Project linked! (ID: ${projectId})`));
61
+ let projectId = selectedProjectId;
62
+
63
+ if (selectedProjectId === 'CREATE_NEW') {
64
+ const { newProjectName } = await inquirer.prompt([{
65
+ type: 'input',
66
+ name: 'newProjectName',
67
+ message: 'Enter name for the new project:',
68
+ validate: input => input.trim().length > 0 ? true : 'Project name cannot be empty'
69
+ }]);
70
+
71
+ const createSpinner = ora('Creating project...').start();
72
+ try {
73
+ const { data } = await api.post('/projects', { name: newProjectName });
74
+ projectId = data.project.id;
75
+ createSpinner.succeed(chalk.green(`Project "${data.project.name}" created!`));
76
+ } catch (error) {
77
+ createSpinner.fail('Failed to create project.');
78
+ console.error(chalk.red(handleApiError(error)));
79
+ return; // Exit if creation fails
80
+ }
81
+ }
82
+
83
+ // Only write config if we have a valid projectId
84
+ if (projectId) {
85
+ fs.writeFileSync('envault.json', JSON.stringify({ projectId }, null, 2));
86
+ console.log(chalk.green(`\nāœ” Project linked! (ID: ${projectId})`));
87
+ }
59
88
  }
@@ -5,6 +5,7 @@ import ora from 'ora';
5
5
  import open from 'open';
6
6
  import { api, handleApiError } from '../lib/api.js';
7
7
  import { setToken } from '../lib/config.js';
8
+ import os from 'os';
8
9
 
9
10
  export async function login() {
10
11
  console.log(chalk.blue(' Starting Device Authentication Flow...\n'));
@@ -13,8 +14,16 @@ export async function login() {
13
14
  const spinner = ora('Contacting Envault servers...').start();
14
15
  let deviceCode, userCode, verificationUri, interval;
15
16
 
17
+ const deviceInfo = {
18
+ hostname: os.hostname(),
19
+ platform: os.platform(),
20
+ release: os.release(),
21
+ type: os.type(),
22
+ arch: os.arch()
23
+ };
24
+
16
25
  try {
17
- const { data } = await api.post('/auth/device/code');
26
+ const { data } = await api.post('/auth/device/code', { device_info: deviceInfo });
18
27
  deviceCode = data.device_code;
19
28
  userCode = data.user_code; // 8-char
20
29
  verificationUri = data.verification_uri;
@@ -2,6 +2,8 @@
2
2
  import fs from 'fs';
3
3
  import chalk from 'chalk';
4
4
  import ora from 'ora';
5
+ import boxen from 'boxen';
6
+
5
7
  import inquirer from 'inquirer';
6
8
  import { api, handleApiError } from '../lib/api.js';
7
9
 
@@ -22,13 +24,50 @@ export async function pull(options) {
22
24
  }
23
25
 
24
26
  if (fs.existsSync('.env') && !options.force) {
27
+ let projectName = 'Envault';
28
+ try {
29
+ const { data } = await api.get('/projects');
30
+ const projects = data.projects || data.data || [];
31
+ const project = projects.find(p => p.id === projectId);
32
+ if (project) {
33
+ projectName = project.name;
34
+ }
35
+ } catch (e) {
36
+ // Ignore
37
+ }
38
+
39
+ const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://envault.tech';
40
+
41
+ console.log(boxen(
42
+ chalk.red.bold('WARNING: POTENTIAL DATA LOSS') +
43
+ '\n\n' +
44
+ chalk.white('You are about to ') + chalk.red.bold('OVERWRITE') + chalk.white(' your local ') + chalk.yellow('.env') + chalk.white(' file.') +
45
+ '\n\n' +
46
+ chalk.white('Any local changes not synced to ') + chalk.cyan.bold(projectName) + chalk.white(' will be ') + chalk.red.bold('PERMANENTLY LOST.') +
47
+ '\n\n' +
48
+ chalk.dim('We recommend checking the dashboard for differences:') +
49
+ '\n' +
50
+ chalk.cyan(`${appUrl}/projects/${projectId}`),
51
+ {
52
+ padding: 1,
53
+ margin: 1,
54
+ borderStyle: 'double',
55
+ borderColor: 'red',
56
+ title: 'Sync Warning',
57
+ titleAlignment: 'center'
58
+ }
59
+ ));
60
+
25
61
  const { confirm } = await inquirer.prompt([{
26
62
  type: 'confirm',
27
63
  name: 'confirm',
28
- message: 'This will overwrite your current .env file. Continue?',
64
+ message: 'Are you sure you want to overwrite your local .env file?',
29
65
  default: false
30
66
  }]);
31
- if (!confirm) return;
67
+ if (!confirm) {
68
+ console.log(chalk.yellow('Operation cancelled.'));
69
+ return;
70
+ }
32
71
  }
33
72
 
34
73
  const spinner = ora('Fetching secrets...').start();
package/src/lib/api.js CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  import axios from 'axios';
3
- import { getToken, getApiUrl } from './config.js';
3
+ import { getToken, getApiUrl, clearToken } from './config.js';
4
4
 
5
5
  export const api = axios.create({
6
6
  baseURL: getApiUrl(),
@@ -17,6 +17,28 @@ api.interceptors.request.use((config) => {
17
17
  return config;
18
18
  });
19
19
 
20
+ // Handle token expiration
21
+ api.interceptors.response.use(
22
+ (response) => response,
23
+ (error) => {
24
+ if (error.response?.status === 401) {
25
+ const errorMsg = error.response?.data?.error;
26
+ if (errorMsg === 'token_expired') {
27
+ console.error('\nāŒ Your session has expired (tokens are valid for 3 days).');
28
+ console.error('Please run "envault login" to authenticate again.\n');
29
+ clearToken();
30
+ process.exit(1);
31
+ } else if (errorMsg === 'Invalid token' || errorMsg === 'Missing or invalid authorization header') {
32
+ console.error('\nāŒ Authentication required.');
33
+ console.error('Please run "envault login" to authenticate.\n');
34
+ clearToken();
35
+ process.exit(1);
36
+ }
37
+ }
38
+ return Promise.reject(error);
39
+ }
40
+ );
41
+
20
42
  export function handleApiError(error) {
21
43
  if (error.response) {
22
44
  return error.response.data.error || error.response.statusText;
package/src/lib/config.js CHANGED
@@ -26,6 +26,10 @@ export function clearToken() {
26
26
  }
27
27
 
28
28
  export function getApiUrl() {
29
- // Default to localhost for dev, but should check env
30
- return process.env.ENVAULT_API_URL || 'http://localhost:3000/api/cli';
29
+ // Check for developer override first
30
+ if (process.env.ENVAULT_API_URL) {
31
+ return process.env.ENVAULT_API_URL;
32
+ }
33
+ // Default to production for the published package
34
+ return 'https://envault.tech/api/cli';
31
35
  }