nvii 2.0.0 → 2.0.2

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.
Files changed (3) hide show
  1. package/LICENSE.md +23 -0
  2. package/dist/index.js +330 -222
  3. package/package.json +6 -4
package/LICENSE.md ADDED
@@ -0,0 +1,23 @@
1
+ # MIT License
2
+
3
+ ```txt
4
+ Copyright (c) 2025 Skaleway
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ ```
package/dist/index.js CHANGED
@@ -23916,6 +23916,74 @@ var {
23916
23916
  Help
23917
23917
  } = import_index.default;
23918
23918
 
23919
+ // package.json
23920
+ var package_default = {
23921
+ name: "nvii",
23922
+ version: "2.0.1",
23923
+ description: "Secure environment variable management CLI for modern development teams",
23924
+ keywords: [
23925
+ "environment",
23926
+ "variables",
23927
+ "env",
23928
+ "cli",
23929
+ "security",
23930
+ "encryption",
23931
+ "development"
23932
+ ],
23933
+ homepage: "https://nvii.dev",
23934
+ repository: {
23935
+ type: "git",
23936
+ url: "https://github.com/skaleway/nvii.git",
23937
+ directory: "packages/cli"
23938
+ },
23939
+ main: "./dist/index.js",
23940
+ bin: {
23941
+ nvii: "./dist/index.js"
23942
+ },
23943
+ types: "./dist/index.d.ts",
23944
+ module: "./dist/index.mjs",
23945
+ private: false,
23946
+ scripts: {
23947
+ build: "tsup",
23948
+ dev: "tsc && pnpm chmod && tsc -w",
23949
+ chmod: "chmod +x dist/index.js",
23950
+ "test:dev": "./dist/index.js --help",
23951
+ "start:dev": "ts-node src/index.ts || true",
23952
+ start: "node dist/index.js || true"
23953
+ },
23954
+ files: [
23955
+ "README.md",
23956
+ "LICENSE",
23957
+ "./dist"
23958
+ ],
23959
+ license: "ISC",
23960
+ devDependencies: {
23961
+ "@nvii/typescript-config": "workspace:*",
23962
+ "@swc/core": "^1.3.99",
23963
+ "@nvii/db": "workspace:*",
23964
+ "@nvii/env-helpers": "workspace:*",
23965
+ "@types/node": "^20.17.10",
23966
+ "@types/update-notifier": "^6.0.8",
23967
+ commander: "^11.1.0",
23968
+ concurrently: "^9.2.0",
23969
+ nodemon: "^3.1.10",
23970
+ "ts-node": "^10.9.2",
23971
+ "ts-node-dev": "^2.0.0",
23972
+ tsup: "^7.3.0",
23973
+ typescript: "^5.7.2"
23974
+ },
23975
+ dependencies: {
23976
+ "async-listen": "^3.0.1",
23977
+ axios: "^1.7.9",
23978
+ dotenv: "^16.4.7",
23979
+ inquirer: "^12.4.3",
23980
+ nanoid: "^3.3.7",
23981
+ ora: "^7.0.1",
23982
+ picocolors: "^1.0.0",
23983
+ "update-notifier": "7.3.1"
23984
+ }
23985
+ };
23986
+
23919
23987
  // ../env-helpers/dist/index.mjs
23920
23988
  var import_crypto = __toESM(require("crypto"), 1);
23921
23989
  var import_fs = require("fs");
@@ -26668,6 +26736,11 @@ async function unlinkProjectConfig(projectId) {
26668
26736
  return success;
26669
26737
  }
26670
26738
  }
26739
+ function getProjectInfoFromPackageJson(projectPath) {
26740
+ const packageJsonPath = (0, import_path.join)(projectPath, "package.json");
26741
+ const packageJson = JSON.parse((0, import_fs.readFileSync)(packageJsonPath, "utf8"));
26742
+ return { name: packageJson.name, description: packageJson.description };
26743
+ }
26671
26744
 
26672
26745
  // src/commands/crypt.ts
26673
26746
  var import_picocolors2 = __toESM(require_picocolors());
@@ -27043,41 +27116,47 @@ ${error.response.data.error}`));
27043
27116
  }
27044
27117
 
27045
27118
  // src/commands/new.ts
27046
- async function promptUser(message) {
27119
+ async function promptUser(message, defaultValue) {
27047
27120
  const response = await esm_default12.prompt([
27048
27121
  {
27049
27122
  type: "input",
27050
27123
  name: "answer",
27051
- message: import_picocolors7.default.cyan(message)
27124
+ message: import_picocolors7.default.cyan(message),
27125
+ default: defaultValue || ""
27052
27126
  }
27053
27127
  ]);
27054
27128
  return response.answer.trim();
27055
27129
  }
27056
27130
  async function createProject() {
27131
+ const ora = (await import("ora")).default;
27132
+ const spinner = ora({ text: import_picocolors7.default.cyan("Creating project..."), color: "cyan" });
27057
27133
  try {
27058
27134
  if (!isLogedIn()) {
27059
27135
  console.log(import_picocolors7.default.red("You must be logged in to create a new project."));
27060
27136
  await login();
27061
27137
  }
27062
- const projectName = await promptUser("Enter your project name:");
27138
+ const { name, description } = getProjectInfoFromPackageJson(process.cwd());
27139
+ const projectName = await promptUser("Enter your project name:", name);
27063
27140
  if (!projectName) {
27064
- console.error(import_picocolors7.default.red("\u274C Project name cannot be empty."));
27065
- process.exit(1);
27141
+ spinner.fail(import_picocolors7.default.red("Project name cannot be empty."));
27142
+ spinner.stop();
27143
+ return;
27066
27144
  }
27067
27145
  const projectDescription = await promptUser(
27068
- "Enter project description (optional):"
27146
+ "Enter project description (optional):",
27147
+ description
27069
27148
  );
27070
27149
  const userConfig = await readConfigFile();
27071
27150
  if (!userConfig?.userId || !userConfig?.deviceId) {
27072
- console.error(
27073
- import_picocolors7.default.red("\u274C Invalid user credentials. Please log in again.")
27074
- );
27151
+ spinner.fail(import_picocolors7.default.red("Invalid user credentials. Please log in again."));
27152
+ spinner.stop();
27075
27153
  await login();
27076
27154
  return;
27077
27155
  }
27078
27156
  const envs = await readEnvFile();
27079
27157
  const encryptedEnvs = encryptEnvValues(envs, userConfig.userId);
27080
27158
  await unlinkProject(false);
27159
+ spinner.start();
27081
27160
  const client = await getConfiguredClient();
27082
27161
  const response = await client.post(`/projects/${userConfig.userId}`, {
27083
27162
  name: projectName,
@@ -27088,17 +27167,21 @@ async function createProject() {
27088
27167
  const projectId = response.data.data.id;
27089
27168
  const branchName = "main";
27090
27169
  await writeProjectConfig(projectId, branchName);
27170
+ spinner.succeed(import_picocolors7.default.green("Project created and configuration saved!"));
27091
27171
  } catch (error) {
27092
27172
  if (error.response) {
27093
- console.error(import_picocolors7.default.yellow(`
27173
+ spinner.fail(import_picocolors7.default.yellow(`
27094
27174
  ${error.response.data.error}`));
27175
+ spinner.stop();
27095
27176
  return;
27096
27177
  }
27097
- if (error.message.includes("User force closed the prompt with SIGINT")) {
27098
- console.log(import_picocolors7.default.yellow("\nProject create cancelled."));
27178
+ if (error.message && error.message.includes("User force closed the prompt with SIGINT")) {
27179
+ spinner.stop();
27180
+ spinner.fail(import_picocolors7.default.yellow("\nProject create cancelled."));
27099
27181
  return;
27100
27182
  }
27101
- console.error(import_picocolors7.default.red("\u274C Error creating project:"), error.message);
27183
+ spinner.fail(import_picocolors7.default.red("Error creating project:"));
27184
+ spinner.stop();
27102
27185
  process.exit(1);
27103
27186
  }
27104
27187
  }
@@ -27839,165 +27922,8 @@ ${error.response.data.error}`));
27839
27922
  }
27840
27923
  };
27841
27924
 
27842
- // src/commands/tag.ts
27843
- var import_picocolors15 = __toESM(require_picocolors());
27844
- async function createTag(args) {
27845
- const oraModule = await import("ora");
27846
- const ora = oraModule.spinners.aesthetic;
27847
- let tagName = "";
27848
- let versionId = "";
27849
- if (args) {
27850
- if (args.name) {
27851
- tagName = args.name;
27852
- }
27853
- if (args.version) {
27854
- versionId = args.version;
27855
- }
27856
- }
27857
- try {
27858
- if (!isLogedIn()) {
27859
- console.log(import_picocolors15.default.red("You must be logged in to create tags."));
27860
- await login();
27861
- return;
27862
- }
27863
- const userConfig = await readConfigFile();
27864
- if (!userConfig?.userId) {
27865
- console.log(import_picocolors15.default.red("No user ID found. Please log in again."));
27866
- return;
27867
- }
27868
- const config = await readProjectConfig();
27869
- if (!config) {
27870
- console.log(
27871
- import_picocolors15.default.red("Cannot read local .nvii folder currently. Try again.")
27872
- );
27873
- process.exit(1);
27874
- }
27875
- const projectId = config.projectId;
27876
- if (!projectId) {
27877
- console.error(
27878
- import_picocolors15.default.red(
27879
- "\u274C Project not linked. Please run 'nvii link' to link your project first."
27880
- )
27881
- );
27882
- process.exit(1);
27883
- }
27884
- const client = await getConfiguredClient();
27885
- if (!versionId) {
27886
- const versionsResponse = await client.get(
27887
- `/projects/${userConfig.userId}/${projectId}/versions?limit=1`
27888
- );
27889
- const versions = versionsResponse.data;
27890
- if (versions.length === 0) {
27891
- console.log(import_picocolors15.default.yellow("No versions available to tag."));
27892
- return;
27893
- }
27894
- versionId = versions[0].id;
27895
- }
27896
- if (!tagName) {
27897
- const { inputTagName } = await esm_default12.prompt([
27898
- {
27899
- type: "input",
27900
- name: "inputTagName",
27901
- message: "Enter tag name:",
27902
- validate: (input) => {
27903
- if (!input.trim())
27904
- return "Tag name cannot be empty";
27905
- if (!/^[a-zA-Z0-9._-]+$/.test(input))
27906
- return "Tag name can only contain letters, numbers, dots, underscores, and hyphens";
27907
- return true;
27908
- }
27909
- }
27910
- ]);
27911
- tagName = inputTagName;
27912
- }
27913
- const response = await client.post(
27914
- `/projects/${userConfig.userId}/${projectId}/versions/tags`,
27915
- {
27916
- versionId,
27917
- tagName
27918
- }
27919
- );
27920
- console.log(
27921
- import_picocolors15.default.green(
27922
- `\u2705 Successfully created tag '${tagName}' for version ${versionId?.slice(0, 8)}`
27923
- )
27924
- );
27925
- } catch (error) {
27926
- if (error.response?.status === 409) {
27927
- console.error(
27928
- import_picocolors15.default.red("\u274C Tag name already exists. Choose a different name.")
27929
- );
27930
- } else {
27931
- console.error(import_picocolors15.default.red("Error creating tag:"), error.message);
27932
- }
27933
- process.exit(1);
27934
- }
27935
- }
27936
- async function listTags() {
27937
- try {
27938
- if (!isLogedIn()) {
27939
- console.log(import_picocolors15.default.red("You must be logged in to list tags."));
27940
- await login();
27941
- return;
27942
- }
27943
- const userConfig = await readConfigFile();
27944
- if (!userConfig?.userId) {
27945
- console.log(import_picocolors15.default.red("No user ID found. Please log in again."));
27946
- return;
27947
- }
27948
- const config = await readProjectConfig();
27949
- if (!config) {
27950
- console.log(
27951
- import_picocolors15.default.red("Cannot read local .nvii folder currently. Try again.")
27952
- );
27953
- process.exit(1);
27954
- }
27955
- const projectId = config.projectId;
27956
- if (!projectId) {
27957
- console.error(
27958
- import_picocolors15.default.red(
27959
- "\u274C Project not linked. Please run 'nvii link' to link your project first."
27960
- )
27961
- );
27962
- process.exit(1);
27963
- }
27964
- const client = await getConfiguredClient();
27965
- const response = await client.get(
27966
- `/projects/${userConfig.userId}/${projectId}/versions/tags`
27967
- );
27968
- const tags = response.data;
27969
- if (!tags || tags.length === 0) {
27970
- console.log(import_picocolors15.default.yellow("No tags found for this project."));
27971
- return;
27972
- }
27973
- console.log(import_picocolors15.default.bold(`
27974
- \u{1F3F7}\uFE0F Tags for project ${import_picocolors15.default.cyan(projectId)}`));
27975
- console.log(import_picocolors15.default.dim("--------------------------------------------------"));
27976
- tags.forEach((tag) => {
27977
- console.log(
27978
- `${import_picocolors15.default.yellow(tag.name)} -> ${import_picocolors15.default.dim(`version ${tag.versionId.slice(0, 8)}`)}`
27979
- );
27980
- console.log(` ${tag.description || "No description"}`);
27981
- console.log(` ${new Date(tag.createdAt).toLocaleDateString()}`);
27982
- console.log(import_picocolors15.default.dim("--------------------------------------------------"));
27983
- });
27984
- } catch (error) {
27985
- if (error.response) {
27986
- console.error(import_picocolors15.default.yellow(`
27987
- ${error.response.data.error}`));
27988
- return;
27989
- }
27990
- if (error.message.includes("User force closed the prompt with SIGINT")) {
27991
- console.log(import_picocolors15.default.yellow("\nTag cancelled."));
27992
- return;
27993
- }
27994
- console.error(import_picocolors15.default.red("Error listing tags:"), error.message);
27995
- process.exit(1);
27996
- }
27997
- }
27998
-
27999
27925
  // src/commands/branch.ts
28000
- var import_picocolors16 = __toESM(require_picocolors());
27926
+ var import_picocolors15 = __toESM(require_picocolors());
28001
27927
  async function createBranch(args) {
28002
27928
  let branchName = "";
28003
27929
  let baseVersionId = "";
@@ -28011,26 +27937,26 @@ async function createBranch(args) {
28011
27937
  }
28012
27938
  try {
28013
27939
  if (!isLogedIn()) {
28014
- console.log(import_picocolors16.default.red("You must be logged in to create branches."));
27940
+ console.log(import_picocolors15.default.red("You must be logged in to create branches."));
28015
27941
  await login();
28016
27942
  return;
28017
27943
  }
28018
27944
  const userConfig = await readConfigFile();
28019
27945
  if (!userConfig?.userId) {
28020
- console.log(import_picocolors16.default.red("No user ID found. Please log in again."));
27946
+ console.log(import_picocolors15.default.red("No user ID found. Please log in again."));
28021
27947
  return;
28022
27948
  }
28023
27949
  const config = await readProjectConfig();
28024
27950
  if (!config) {
28025
27951
  console.log(
28026
- import_picocolors16.default.red("Cannot read local .nvii folder currently. Try again.")
27952
+ import_picocolors15.default.red("Cannot read local .nvii folder currently. Try again.")
28027
27953
  );
28028
27954
  process.exit(1);
28029
27955
  }
28030
27956
  const projectId = config.projectId;
28031
27957
  if (!projectId) {
28032
27958
  console.error(
28033
- import_picocolors16.default.red(
27959
+ import_picocolors15.default.red(
28034
27960
  "\u274C Project not linked. Please run 'nvii link' to link your project first."
28035
27961
  )
28036
27962
  );
@@ -28060,7 +27986,7 @@ async function createBranch(args) {
28060
27986
  );
28061
27987
  const versions = versionsResponse.data;
28062
27988
  if (versions.length === 0) {
28063
- console.log(import_picocolors16.default.yellow("No versions available to branch from."));
27989
+ console.log(import_picocolors15.default.yellow("No versions available to branch from."));
28064
27990
  return;
28065
27991
  }
28066
27992
  baseVersionId = versions[0].id;
@@ -28074,21 +28000,21 @@ async function createBranch(args) {
28074
28000
  }
28075
28001
  );
28076
28002
  if (!response || !response.data) {
28077
- console.log(import_picocolors16.default.yellow("Oops an error occurred creating new branch."));
28003
+ console.log(import_picocolors15.default.yellow("Oops an error occurred creating new branch."));
28078
28004
  process.exit(1);
28079
28005
  }
28080
28006
  console.log(
28081
- import_picocolors16.default.green(
28007
+ import_picocolors15.default.green(
28082
28008
  `\u2705 Successfully created branch '${branchName}' from version ${baseVersionId?.slice(0, 8)}`
28083
28009
  )
28084
28010
  );
28085
28011
  } catch (error) {
28086
28012
  if (error.response?.status === 409) {
28087
28013
  console.error(
28088
- import_picocolors16.default.red("\u274C Branch name already exists. Choose a different name.")
28014
+ import_picocolors15.default.red("\u274C Branch name already exists. Choose a different name.")
28089
28015
  );
28090
28016
  } else {
28091
- console.error(import_picocolors16.default.red("Error creating branch:"), error.message);
28017
+ console.error(import_picocolors15.default.red("Error creating branch:"), error.message);
28092
28018
  }
28093
28019
  process.exit(1);
28094
28020
  }
@@ -28098,26 +28024,26 @@ async function listBranches() {
28098
28024
  const ora = oraModule.default;
28099
28025
  try {
28100
28026
  if (!isLogedIn()) {
28101
- console.log(import_picocolors16.default.red("You must be logged in to list branches."));
28027
+ console.log(import_picocolors15.default.red("You must be logged in to list branches."));
28102
28028
  await login();
28103
28029
  return;
28104
28030
  }
28105
28031
  const userConfig = await readConfigFile();
28106
28032
  if (!userConfig?.userId) {
28107
- console.log(import_picocolors16.default.red("No user ID found. Please log in again."));
28033
+ console.log(import_picocolors15.default.red("No user ID found. Please log in again."));
28108
28034
  return;
28109
28035
  }
28110
28036
  const config = await readProjectConfig();
28111
28037
  if (!config) {
28112
28038
  console.log(
28113
- import_picocolors16.default.red("Cannot read local .nvii folder currently. Try again.")
28039
+ import_picocolors15.default.red("Cannot read local .nvii folder currently. Try again.")
28114
28040
  );
28115
28041
  process.exit(1);
28116
28042
  }
28117
28043
  const projectId = config.projectId;
28118
28044
  if (!projectId) {
28119
28045
  console.error(
28120
- import_picocolors16.default.red(
28046
+ import_picocolors15.default.red(
28121
28047
  "\u274C Project not linked. Please run 'nvii link' to link your project first."
28122
28048
  )
28123
28049
  );
@@ -28131,34 +28057,34 @@ async function listBranches() {
28131
28057
  spinner.stop();
28132
28058
  const branches = response.data;
28133
28059
  if (!branches || branches.length === 0) {
28134
- console.log(import_picocolors16.default.yellow("No branches found for this project."));
28060
+ console.log(import_picocolors15.default.yellow("No branches found for this project."));
28135
28061
  return;
28136
28062
  }
28137
- console.log(import_picocolors16.default.bold(`
28138
- \u{1F33F} Branches for project ${import_picocolors16.default.cyan(projectId)}`));
28139
- console.log(import_picocolors16.default.dim("--------------------------------------------------"));
28063
+ console.log(import_picocolors15.default.bold(`
28064
+ \u{1F33F} Branches for project ${import_picocolors15.default.cyan(projectId)}`));
28065
+ console.log(import_picocolors15.default.dim("--------------------------------------------------"));
28140
28066
  const projectConfig = await readProjectConfig();
28141
28067
  branches.forEach((branch) => {
28142
- const isActive = branch.isActive ? import_picocolors16.default.green("* ") : " ";
28068
+ const isActive = branch.isActive ? import_picocolors15.default.green("* ") : " ";
28143
28069
  console.log(
28144
- `${isActive}${import_picocolors16.default.cyan(projectConfig?.branch === branch.name ? `*${branch.name}` : branch.name)} -> ${import_picocolors16.default.dim(`version ${branch.baseVersionId.slice(0, 8)}`)}`
28070
+ `${isActive}${import_picocolors15.default.cyan(projectConfig?.branch === branch.name ? `*${branch.name}` : branch.name)} -> ${import_picocolors15.default.dim(`version ${branch.baseVersionId.slice(0, 8)}`)}`
28145
28071
  );
28146
28072
  console.log(
28147
28073
  ` Created: ${new Date(branch.createdAt).toLocaleDateString()}`
28148
28074
  );
28149
- console.log(import_picocolors16.default.dim("--------------------------------------------------"));
28075
+ console.log(import_picocolors15.default.dim("--------------------------------------------------"));
28150
28076
  });
28151
28077
  } catch (error) {
28152
28078
  if (error.response) {
28153
- console.error(import_picocolors16.default.yellow(`
28079
+ console.error(import_picocolors15.default.yellow(`
28154
28080
  ${error.response.data.error}`));
28155
28081
  return;
28156
28082
  }
28157
28083
  if (error.message.includes("User force closed the prompt with SIGINT")) {
28158
- console.log(import_picocolors16.default.yellow("\nBranch create cancelled."));
28084
+ console.log(import_picocolors15.default.yellow("\nBranch create cancelled."));
28159
28085
  return;
28160
28086
  }
28161
- console.error(import_picocolors16.default.red("Error listing branches:"), error.message);
28087
+ console.error(import_picocolors15.default.red("Error listing branches:"), error.message);
28162
28088
  process.exit(1);
28163
28089
  }
28164
28090
  }
@@ -28171,26 +28097,26 @@ async function switchBranch(args) {
28171
28097
  }
28172
28098
  try {
28173
28099
  if (!isLogedIn()) {
28174
- console.log(import_picocolors16.default.red("You must be logged in to switch branches."));
28100
+ console.log(import_picocolors15.default.red("You must be logged in to switch branches."));
28175
28101
  await login();
28176
28102
  return;
28177
28103
  }
28178
28104
  const userConfig = await readConfigFile();
28179
28105
  if (!userConfig?.userId) {
28180
- console.log(import_picocolors16.default.red("No user ID found. Please log in again."));
28106
+ console.log(import_picocolors15.default.red("No user ID found. Please log in again."));
28181
28107
  return;
28182
28108
  }
28183
28109
  const config = await readProjectConfig();
28184
28110
  if (!config) {
28185
28111
  console.log(
28186
- import_picocolors16.default.red("Cannot read local .nvii folder currently. Try again.")
28112
+ import_picocolors15.default.red("Cannot read local .nvii folder currently. Try again.")
28187
28113
  );
28188
28114
  process.exit(1);
28189
28115
  }
28190
28116
  const projectId = config.projectId;
28191
28117
  if (!projectId) {
28192
28118
  console.error(
28193
- import_picocolors16.default.red(
28119
+ import_picocolors15.default.red(
28194
28120
  "\u274C Project not linked. Please run 'nvii link' to link your project first."
28195
28121
  )
28196
28122
  );
@@ -28203,7 +28129,7 @@ async function switchBranch(args) {
28203
28129
  );
28204
28130
  const branches = branchesResponse.data;
28205
28131
  if (!branches || branches.length === 0) {
28206
- console.log(import_picocolors16.default.yellow("No branches found for this project."));
28132
+ console.log(import_picocolors15.default.yellow("No branches found for this project."));
28207
28133
  return;
28208
28134
  }
28209
28135
  const { selectedBranch } = await esm_default12.prompt([
@@ -28224,39 +28150,39 @@ async function switchBranch(args) {
28224
28150
  );
28225
28151
  branchName = remoteUpdateResponse.data.name;
28226
28152
  await writeProjectConfig(projectId, branchName);
28227
- console.log(import_picocolors16.default.green(`\u2705 Switched to branch '${branchName}'`));
28153
+ console.log(import_picocolors15.default.green(`\u2705 Switched to branch '${branchName}'`));
28228
28154
  } catch (error) {
28229
28155
  if (error.response) {
28230
- console.error(import_picocolors16.default.yellow(`
28156
+ console.error(import_picocolors15.default.yellow(`
28231
28157
  ${error.response.data.error}`));
28232
28158
  return;
28233
28159
  }
28234
28160
  if (error.message.includes("User force closed the prompt with SIGINT")) {
28235
- console.log(import_picocolors16.default.yellow("\nBranch switch cancelled."));
28161
+ console.log(import_picocolors15.default.yellow("\nBranch switch cancelled."));
28236
28162
  return;
28237
28163
  }
28238
28164
  if (error.response?.status === 404) {
28239
- console.error(import_picocolors16.default.red("\u274C Branch not found."));
28165
+ console.error(import_picocolors15.default.red("\u274C Branch not found."));
28240
28166
  } else {
28241
- console.error(import_picocolors16.default.red("Error switching branch:"), error.message);
28167
+ console.error(import_picocolors15.default.red("Error switching branch:"), error.message);
28242
28168
  }
28243
28169
  process.exit(1);
28244
28170
  }
28245
28171
  }
28246
28172
 
28247
28173
  // src/commands/rollback.ts
28248
- var import_picocolors17 = __toESM(require_picocolors());
28174
+ var import_picocolors16 = __toESM(require_picocolors());
28249
28175
  var skipConfirmationPrompt = async (skipConfirmation, description, id) => {
28250
28176
  if (!skipConfirmation) {
28251
28177
  const { confirmRollback } = await esm_default12.prompt([
28252
28178
  {
28253
28179
  type: "confirm",
28254
28180
  name: "confirmRollback",
28255
- message: `Are you sure you want to rollback to <${import_picocolors17.default.dim(`${description} - id: ${id}`)}>?`
28181
+ message: `Are you sure you want to rollback to <${import_picocolors16.default.dim(`${description} - id: ${id}`)}>?`
28256
28182
  }
28257
28183
  ]);
28258
28184
  if (!confirmRollback) {
28259
- console.log(import_picocolors17.default.cyan("Skipping rollback..."));
28185
+ console.log(import_picocolors16.default.cyan("Skipping rollback..."));
28260
28186
  process.exit(0);
28261
28187
  }
28262
28188
  }
@@ -28274,7 +28200,7 @@ async function rollback(args) {
28274
28200
  }
28275
28201
  try {
28276
28202
  if (!isLogedIn()) {
28277
- console.log(import_picocolors17.default.red("You must be logged in to roll back."));
28203
+ console.log(import_picocolors16.default.red("You must be logged in to roll back."));
28278
28204
  await login();
28279
28205
  return;
28280
28206
  }
@@ -28282,14 +28208,14 @@ async function rollback(args) {
28282
28208
  const config = await readProjectConfig();
28283
28209
  if (!config) {
28284
28210
  console.log(
28285
- import_picocolors17.default.red("Cannot read local .nvii folder currently. Try again.")
28211
+ import_picocolors16.default.red("Cannot read local .nvii folder currently. Try again.")
28286
28212
  );
28287
28213
  process.exit(1);
28288
28214
  }
28289
28215
  const projectId = config.projectId;
28290
28216
  if (!userConfig?.userId || !projectId) {
28291
28217
  console.error(
28292
- import_picocolors17.default.red(
28218
+ import_picocolors16.default.red(
28293
28219
  "Project not linked or user not configured. Please run 'nvii link'."
28294
28220
  )
28295
28221
  );
@@ -28302,7 +28228,7 @@ async function rollback(args) {
28302
28228
  );
28303
28229
  const version = response2.data;
28304
28230
  if (!version) {
28305
- console.log(import_picocolors17.default.red(`Version with id <${versionId}> not found.`));
28231
+ console.log(import_picocolors16.default.red(`Version with id <${versionId}> not found.`));
28306
28232
  return;
28307
28233
  }
28308
28234
  await skipConfirmationPrompt(
@@ -28310,16 +28236,16 @@ async function rollback(args) {
28310
28236
  version.description,
28311
28237
  version.id
28312
28238
  );
28313
- console.log(import_picocolors17.default.cyan("Updating local .env file..."));
28239
+ console.log(import_picocolors16.default.cyan("Updating local .env file..."));
28314
28240
  const values2 = await writeEnvFile(
28315
28241
  version?.content
28316
28242
  );
28317
28243
  if (!values2) {
28318
- console.error(import_picocolors17.default.red("\nOops an unexpected error occurred."));
28244
+ console.error(import_picocolors16.default.red("\nOops an unexpected error occurred."));
28319
28245
  process.exit(1);
28320
28246
  }
28321
28247
  console.log(
28322
- import_picocolors17.default.green(
28248
+ import_picocolors16.default.green(
28323
28249
  "\u2705 Local .env file has been updated to match the rollback version."
28324
28250
  )
28325
28251
  );
@@ -28330,7 +28256,7 @@ async function rollback(args) {
28330
28256
  );
28331
28257
  const versions = versionsResponse.data;
28332
28258
  if (versions.length < 2) {
28333
- console.log(import_picocolors17.default.yellow("Not enough versions to roll back."));
28259
+ console.log(import_picocolors16.default.yellow("Not enough versions to roll back."));
28334
28260
  return;
28335
28261
  }
28336
28262
  const { versionIdToRollback } = await esm_default12.prompt([
@@ -28350,7 +28276,7 @@ async function rollback(args) {
28350
28276
  const versionToRollback = response.data;
28351
28277
  if (!versionToRollback.content) {
28352
28278
  console.error(
28353
- import_picocolors17.default.red("Selected version has no content. Cannot roll back.")
28279
+ import_picocolors16.default.red("Selected version has no content. Cannot roll back.")
28354
28280
  );
28355
28281
  return;
28356
28282
  }
@@ -28359,19 +28285,176 @@ async function rollback(args) {
28359
28285
  versionToRollback.description,
28360
28286
  versionToRollback.id
28361
28287
  );
28362
- console.log(import_picocolors17.default.cyan("Updating local .env file..."));
28288
+ console.log(import_picocolors16.default.cyan("Updating local .env file..."));
28363
28289
  const values = await writeEnvFile(
28364
28290
  versionToRollback?.content
28365
28291
  );
28366
28292
  if (!values) {
28367
- console.error(import_picocolors17.default.red("\nOops an unexpected error occurred."));
28293
+ console.error(import_picocolors16.default.red("\nOops an unexpected error occurred."));
28368
28294
  process.exit(1);
28369
28295
  }
28370
28296
  console.log(
28371
- import_picocolors17.default.green(
28297
+ import_picocolors16.default.green(
28372
28298
  "\u2705 Local .env file has been updated to match the rollback version."
28373
28299
  )
28374
28300
  );
28301
+ } catch (error) {
28302
+ if (error.response) {
28303
+ console.error(import_picocolors16.default.yellow(`
28304
+ ${error.response.data.error}`));
28305
+ return;
28306
+ }
28307
+ if (error.message.includes("User force closed the prompt with SIGINT")) {
28308
+ console.log(import_picocolors16.default.yellow("\nRollback cancelled."));
28309
+ return;
28310
+ }
28311
+ console.error(import_picocolors16.default.red("\nError during rollback:"), error.message);
28312
+ process.exit(1);
28313
+ }
28314
+ }
28315
+
28316
+ // src/commands/tag.ts
28317
+ var import_picocolors17 = __toESM(require_picocolors());
28318
+ async function createTag(args) {
28319
+ const oraModule = await import("ora");
28320
+ const ora = oraModule.spinners.aesthetic;
28321
+ let tagName = "";
28322
+ let versionId = "";
28323
+ if (args) {
28324
+ if (args.name) {
28325
+ tagName = args.name;
28326
+ }
28327
+ if (args.version) {
28328
+ versionId = args.version;
28329
+ }
28330
+ }
28331
+ try {
28332
+ if (!isLogedIn()) {
28333
+ console.log(import_picocolors17.default.red("You must be logged in to create tags."));
28334
+ await login();
28335
+ return;
28336
+ }
28337
+ const userConfig = await readConfigFile();
28338
+ if (!userConfig?.userId) {
28339
+ console.log(import_picocolors17.default.red("No user ID found. Please log in again."));
28340
+ return;
28341
+ }
28342
+ const config = await readProjectConfig();
28343
+ if (!config) {
28344
+ console.log(
28345
+ import_picocolors17.default.red("Cannot read local .nvii folder currently. Try again.")
28346
+ );
28347
+ process.exit(1);
28348
+ }
28349
+ const projectId = config.projectId;
28350
+ if (!projectId) {
28351
+ console.error(
28352
+ import_picocolors17.default.red(
28353
+ "\u274C Project not linked. Please run 'nvii link' to link your project first."
28354
+ )
28355
+ );
28356
+ process.exit(1);
28357
+ }
28358
+ const client = await getConfiguredClient();
28359
+ if (!versionId) {
28360
+ const versionsResponse = await client.get(
28361
+ `/projects/${userConfig.userId}/${projectId}/versions?limit=1`
28362
+ );
28363
+ const versions = versionsResponse.data;
28364
+ if (versions.length === 0) {
28365
+ console.log(import_picocolors17.default.yellow("No versions available to tag."));
28366
+ return;
28367
+ }
28368
+ versionId = versions[0].id;
28369
+ }
28370
+ if (!tagName) {
28371
+ const { inputTagName } = await esm_default12.prompt([
28372
+ {
28373
+ type: "input",
28374
+ name: "inputTagName",
28375
+ message: "Enter tag name:",
28376
+ validate: (input) => {
28377
+ if (!input.trim())
28378
+ return "Tag name cannot be empty";
28379
+ if (!/^[a-zA-Z0-9._-]+$/.test(input))
28380
+ return "Tag name can only contain letters, numbers, dots, underscores, and hyphens";
28381
+ return true;
28382
+ }
28383
+ }
28384
+ ]);
28385
+ tagName = inputTagName;
28386
+ }
28387
+ const response = await client.post(
28388
+ `/projects/${userConfig.userId}/${projectId}/versions/tags`,
28389
+ {
28390
+ versionId,
28391
+ tagName
28392
+ }
28393
+ );
28394
+ console.log(
28395
+ import_picocolors17.default.green(
28396
+ `\u2705 Successfully created tag '${tagName}' for version ${versionId?.slice(0, 8)}`
28397
+ )
28398
+ );
28399
+ } catch (error) {
28400
+ if (error.response?.status === 409) {
28401
+ console.error(
28402
+ import_picocolors17.default.red("\u274C Tag name already exists. Choose a different name.")
28403
+ );
28404
+ } else {
28405
+ console.error(import_picocolors17.default.red("Error creating tag:"), error.message);
28406
+ }
28407
+ process.exit(1);
28408
+ }
28409
+ }
28410
+ async function listTags() {
28411
+ try {
28412
+ if (!isLogedIn()) {
28413
+ console.log(import_picocolors17.default.red("You must be logged in to list tags."));
28414
+ await login();
28415
+ return;
28416
+ }
28417
+ const userConfig = await readConfigFile();
28418
+ if (!userConfig?.userId) {
28419
+ console.log(import_picocolors17.default.red("No user ID found. Please log in again."));
28420
+ return;
28421
+ }
28422
+ const config = await readProjectConfig();
28423
+ if (!config) {
28424
+ console.log(
28425
+ import_picocolors17.default.red("Cannot read local .nvii folder currently. Try again.")
28426
+ );
28427
+ process.exit(1);
28428
+ }
28429
+ const projectId = config.projectId;
28430
+ if (!projectId) {
28431
+ console.error(
28432
+ import_picocolors17.default.red(
28433
+ "\u274C Project not linked. Please run 'nvii link' to link your project first."
28434
+ )
28435
+ );
28436
+ process.exit(1);
28437
+ }
28438
+ const client = await getConfiguredClient();
28439
+ const response = await client.get(
28440
+ `/projects/${userConfig.userId}/${projectId}/versions/tags`
28441
+ );
28442
+ const tags = response.data;
28443
+ if (!tags || tags.length === 0) {
28444
+ console.log(import_picocolors17.default.yellow("No tags found for this project."));
28445
+ return;
28446
+ }
28447
+ console.log(import_picocolors17.default.bold(`
28448
+ \u{1F3F7}\uFE0F Tags for project ${import_picocolors17.default.cyan(projectId)}`));
28449
+ console.log(import_picocolors17.default.dim("--------------------------------------------------"));
28450
+ tags.forEach((tag) => {
28451
+ console.log(
28452
+ `${import_picocolors17.default.yellow(tag.name)} -> ${import_picocolors17.default.dim(`version ${tag.versionId.slice(0, 8)}`)}`
28453
+ );
28454
+ console.log(` ${tag.description || "No description"}`);
28455
+ console.log(` ${new Date(tag.createdAt).toLocaleDateString()}`);
28456
+ console.log(import_picocolors17.default.dim("--------------------------------------------------"));
28457
+ });
28375
28458
  } catch (error) {
28376
28459
  if (error.response) {
28377
28460
  console.error(import_picocolors17.default.yellow(`
@@ -28379,19 +28462,44 @@ ${error.response.data.error}`));
28379
28462
  return;
28380
28463
  }
28381
28464
  if (error.message.includes("User force closed the prompt with SIGINT")) {
28382
- console.log(import_picocolors17.default.yellow("\nRollback cancelled."));
28465
+ console.log(import_picocolors17.default.yellow("\nTag cancelled."));
28383
28466
  return;
28384
28467
  }
28385
- console.error(import_picocolors17.default.red("\nError during rollback:"), error.message);
28468
+ console.error(import_picocolors17.default.red("Error listing tags:"), error.message);
28386
28469
  process.exit(1);
28387
28470
  }
28388
28471
  }
28389
28472
 
28473
+ // src/lib/utils.ts
28474
+ var import_update_notifier = __toESM(require("update-notifier"));
28475
+ var import_picocolors18 = __toESM(require_picocolors());
28476
+ function checkForUpdates({
28477
+ pkg,
28478
+ message,
28479
+ updateCheckInterval = 1e3 * 60 * 60 * 24 * 7
28480
+ // Default: 7 days
28481
+ }) {
28482
+ const notifier = (0, import_update_notifier.default)({
28483
+ pkg,
28484
+ updateCheckInterval
28485
+ });
28486
+ if (notifier.update) {
28487
+ notifier.notify({
28488
+ isGlobal: true,
28489
+ message: message ?? `\u{1F680} Whoa! A new version (${import_picocolors18.default.green("{latestVersion}")}) is out! (You have ${import_picocolors18.default.red("{currentVersion}")})
28490
+ \u2728 Upgrade with: ${import_picocolors18.default.blue("{updateCommand}")}
28491
+ Don't miss out on the cool stuff!`
28492
+ });
28493
+ }
28494
+ }
28495
+
28390
28496
  // src/index.ts
28391
28497
  var program2 = new Command();
28498
+ var cliVersion = package_default.version || "1.0.0";
28499
+ checkForUpdates({ pkg: package_default });
28392
28500
  program2.name("nvii").description(
28393
28501
  "Secure environment variable management for modern development teams"
28394
- ).version("1.0.0").configureHelp({
28502
+ ).version(cliVersion).configureHelp({
28395
28503
  sortSubcommands: true,
28396
28504
  showGlobalOptions: true
28397
28505
  }).addHelpText(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nvii",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Secure environment variable management CLI for modern development teams",
5
5
  "keywords": [
6
6
  "environment",
@@ -33,6 +33,7 @@
33
33
  "devDependencies": {
34
34
  "@swc/core": "^1.3.99",
35
35
  "@types/node": "^20.17.10",
36
+ "@types/update-notifier": "^6.0.8",
36
37
  "commander": "^11.1.0",
37
38
  "concurrently": "^9.2.0",
38
39
  "nodemon": "^3.1.10",
@@ -41,8 +42,8 @@
41
42
  "tsup": "^7.3.0",
42
43
  "typescript": "^5.7.2",
43
44
  "@nvii/typescript-config": "0.0.0",
44
- "@nvii/env-helpers": "0.0.1",
45
- "@nvii/db": "1.0.0"
45
+ "@nvii/db": "1.0.0",
46
+ "@nvii/env-helpers": "0.0.1"
46
47
  },
47
48
  "dependencies": {
48
49
  "async-listen": "^3.0.1",
@@ -51,7 +52,8 @@
51
52
  "inquirer": "^12.4.3",
52
53
  "nanoid": "^3.3.7",
53
54
  "ora": "^7.0.1",
54
- "picocolors": "^1.0.0"
55
+ "picocolors": "^1.0.0",
56
+ "update-notifier": "7.3.1"
55
57
  },
56
58
  "scripts": {
57
59
  "build": "tsup",