xtra-cli 1.0.3 → 1.0.5

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 (44) hide show
  1. package/dist/bin/xtra.js +3 -137
  2. package/dist/commands/access.js +1 -184
  3. package/dist/commands/admin.js +5 -118
  4. package/dist/commands/audit.js +1 -67
  5. package/dist/commands/branch.js +1 -212
  6. package/dist/commands/checkout.js +1 -80
  7. package/dist/commands/ci.js +31 -341
  8. package/dist/commands/completion.js +85 -224
  9. package/dist/commands/diff.js +6 -162
  10. package/dist/commands/doctor.js +2 -164
  11. package/dist/commands/env.js +2 -70
  12. package/dist/commands/export.js +2 -83
  13. package/dist/commands/generate.js +3 -179
  14. package/dist/commands/history.js +4 -77
  15. package/dist/commands/import.js +1 -121
  16. package/dist/commands/init.js +7 -205
  17. package/dist/commands/integration.js +11 -188
  18. package/dist/commands/jit-run.js +5 -0
  19. package/dist/commands/local.js +16 -198
  20. package/dist/commands/login.js +16 -198
  21. package/dist/commands/login.test.js +16 -51
  22. package/dist/commands/logout.js +1 -0
  23. package/dist/commands/logs.js +3 -121
  24. package/dist/commands/profile.js +14 -184
  25. package/dist/commands/project.js +1 -165
  26. package/dist/commands/rollback.js +1 -95
  27. package/dist/commands/rotate.js +3 -93
  28. package/dist/commands/run.js +11 -215
  29. package/dist/commands/scan.js +25 -127
  30. package/dist/commands/secrets.js +14 -305
  31. package/dist/commands/simulate.js +6 -109
  32. package/dist/commands/status.js +2 -93
  33. package/dist/commands/template.js +22 -276
  34. package/dist/commands/ui.js +2 -289
  35. package/dist/commands/watch.js +17 -123
  36. package/dist/lib/api.js +1 -187
  37. package/dist/lib/api.test.js +1 -89
  38. package/dist/lib/audit.js +1 -136
  39. package/dist/lib/config.js +1 -72
  40. package/dist/lib/config.test.js +1 -47
  41. package/dist/lib/crypto.js +1 -50
  42. package/dist/lib/manifest.js +1 -52
  43. package/dist/lib/profiles.js +1 -103
  44. package/package.json +7 -2
@@ -1,77 +1,4 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.rollbackCommand = exports.historyCommand = void 0;
7
- const commander_1 = require("commander");
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const api_1 = require("../lib/api");
10
- const config_1 = require("../lib/config");
11
- exports.historyCommand = new commander_1.Command("history");
12
- exports.historyCommand
13
- .argument("<key>", "Secret key")
14
- .option("-p, --project <id>", "Project ID")
15
- .option("-e, --env <environment>", "Environment", "development")
16
- .description("View version history of a secret")
17
- .action(async (key, options) => {
18
- try {
19
- let projectId = options.project;
20
- if (!projectId) {
21
- projectId = (0, config_1.getRcConfig)().project;
22
- if (!projectId) {
23
- console.error(chalk_1.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first."));
24
- process.exit(1);
25
- }
26
- }
27
- const data = await api_1.api.getSecretHistory(projectId, options.env, key);
28
- console.log(chalk_1.default.bold(`\nHistory for ${key} (${options.env})`));
29
- console.log(chalk_1.default.gray(`Current Version: ${data.currentVersion}\n`));
30
- const history = data.history || [];
31
- if (history.length === 0) {
32
- console.log("No history found.");
33
- }
34
- else {
35
- history.forEach((h) => {
36
- const dateStr = new Date(h.updatedAt).toLocaleString();
37
- console.log(chalk_1.default.blue(`v${h.version}`) + ` - ${dateStr} by ${h.updatedBy}`);
38
- if (h.description)
39
- console.log(chalk_1.default.gray(` ${h.description}`));
40
- console.log("");
41
- });
42
- }
43
- }
44
- catch (error) {
45
- console.error(chalk_1.default.red("Error fetching history:"), error.message || error);
46
- }
47
- });
48
- exports.rollbackCommand = new commander_1.Command("rollback");
49
- exports.rollbackCommand
50
- .argument("<key>", "Secret key")
51
- .argument("<version>", "Version to rollback to")
52
- .option("-p, --project <id>", "Project ID")
53
- .option("-e, --env <environment>", "Environment", "development")
54
- .description("Rollback a secret to a previous version")
55
- .action(async (key, version, options) => {
56
- try {
57
- let projectId = options.project;
58
- if (!projectId) {
59
- projectId = (0, config_1.getRcConfig)().project;
60
- if (!projectId) {
61
- console.error(chalk_1.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first."));
62
- process.exit(1);
63
- }
64
- }
65
- console.log(chalk_1.default.yellow(`Rolling back ${key} to v${version}...`));
66
- const result = await api_1.api.rollbackSecret(projectId, options.env, key, version);
67
- if (result.success) {
68
- console.log(chalk_1.default.green(`\nSuccessfully rolled back to v${version} (New current version: v${result.version})`));
69
- }
70
- else {
71
- console.log(chalk_1.default.red("Rollback failed."));
72
- }
73
- }
74
- catch (error) {
75
- console.error(chalk_1.default.red("Error rolling back:"), error.message || error);
76
- }
77
- });
1
+ var R=Object.create;var g=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,L=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var s in t)g(e,s,{get:t[s],enumerable:!0})},h=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of A(t))!L.call(e,o)&&o!==s&&g(e,o,{get:()=>t[o],enumerable:!(r=U(t,o))||r.enumerable});return e};var p=(e,t,s)=>(s=e!=null?R(P(e)):{},h(t||!e||!e.__esModule?g(s,"default",{value:e,enumerable:!0}):s,e)),D=e=>h(g({},"__esModule",{value:!0}),e);var B={};_(B,{historyCommand:()=>I,rollbackCommand:()=>C});module.exports=D(B);var w=require("commander"),a=p(require("chalk"));var S=p(require("axios"));var v=p(require("conf")),u=p(require("fs")),b=p(require("path")),y="https://www.xtrasecurity.in/api",c=new v.default({projectName:"xtra-cli",defaults:{apiUrl:y}}),d=c.get("apiUrl");d&&!process.env.XTRA_API_URL&&(d.includes("localhost")||d.includes("xtra-security.vercel.app"))&&c.set("apiUrl",y);var l=()=>({...c.store,apiUrl:process.env.XTRA_API_URL||c.get("apiUrl")||y});var j=()=>c.get("token");var m=()=>{let e={};try{let t=b.default.join(process.cwd(),".xtrarc");u.default.existsSync(t)&&(e=JSON.parse(u.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||c.get("project")||"",env:e.env||c.get("env")||"development",branch:e.branch||c.get("branch")||"main"}};var k=p(require("fs")),x=p(require("path")),V=JSON.parse(k.readFileSync(x.join(__dirname,"../../package.json"),"utf-8")),n=()=>{let{apiUrl:e}=l(),t=j();return S.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":V.version,...t?{Authorization:`Bearer ${t}`}:{}}})},f={login:async(e,t,s)=>(await n().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,r,o="main")=>(await n().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:r,branch:o})).data,getSecretDetails:async(e,t,s,r="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${r}`)).data,syncLogs:async e=>(await n().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,r,o,i)=>(await n().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:o,sourceKey:i})).data,rotateSecret:async(e,t,s,r,o)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:o})).data,promoteSecret:async(e,t,s)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await n().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,r)=>{let o={format:e};return t&&(o.startDate=t),s&&(o.endDate=s),r&&(o.projectId=r),(await n().post("/audit/export",o,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,r)=>(await n().post("/access/request",{projectId:e,secretId:r,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await n().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=l(),s=t?`&workspaceId=${t}`:"";return(await n().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await n().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=l(),t=e?`/project?workspaceId=${e}`:"/project";return(await n().get(t)).data},getBranches:async e=>(await n().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await n().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await n().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await n().put("/branch",{id:e,...t})).data,getRoles:async()=>(await n().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await n().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await n().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await n().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await n().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await n().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await n().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await n().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,r)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(e,t,s,r,o)=>(await n().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:r,branch:o})).data,generateJitLink:async e=>(await n().post("/jit/generate",e)).data,claimJitLink:async e=>(await n().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await n().get(`/jit/${e}`)).data,post:async(e,t)=>(await n().post(e,t)).data};var I=new w.Command("history");I.argument("<key>","Secret key").option("-p, --project <id>","Project ID").option("-e, --env <environment>","Environment","development").description("View version history of a secret").action(async(e,t)=>{try{let s=t.project;s||(s=m().project,s||(console.error(a.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first.")),process.exit(1)));let r=await f.getSecretHistory(s,t.env,e);console.log(a.default.bold(`
2
+ History for ${e} (${t.env})`)),console.log(a.default.gray(`Current Version: ${r.currentVersion}
3
+ `));let o=r.history||[];o.length===0?console.log("No history found."):o.forEach(i=>{let $=new Date(i.updatedAt).toLocaleString();console.log(a.default.blue(`v${i.version}`)+` - ${$} by ${i.updatedBy}`),i.description&&console.log(a.default.gray(` ${i.description}`)),console.log("")})}catch(s){console.error(a.default.red("Error fetching history:"),s.message||s)}});var C=new w.Command("rollback");C.argument("<key>","Secret key").argument("<version>","Version to rollback to").option("-p, --project <id>","Project ID").option("-e, --env <environment>","Environment","development").description("Rollback a secret to a previous version").action(async(e,t,s)=>{try{let r=s.project;r||(r=m().project,r||(console.error(a.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first.")),process.exit(1))),console.log(a.default.yellow(`Rolling back ${e} to v${t}...`));let o=await f.rollbackSecret(r,s.env,e,t);o.success?console.log(a.default.green(`
4
+ Successfully rolled back to v${t} (New current version: v${o.version})`)):console.log(a.default.red("Rollback failed."))}catch(r){console.error(a.default.red("Error rolling back:"),r.message||r)}});0&&(module.exports={historyCommand,rollbackCommand});
@@ -1,121 +1 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.importCommand = void 0;
7
- const commander_1 = require("commander");
8
- const api_1 = require("../lib/api");
9
- const chalk_1 = __importDefault(require("chalk"));
10
- const fs_1 = __importDefault(require("fs"));
11
- const path_1 = __importDefault(require("path"));
12
- const dotenv_1 = __importDefault(require("dotenv"));
13
- const sync_1 = require("csv-parse/sync");
14
- const config_1 = require("../lib/config");
15
- exports.importCommand = new commander_1.Command("import")
16
- .description("Import secrets from a file (JSON, Dotenv, CSV)")
17
- .argument("<file>", "Path to the file to import")
18
- .option("-p, --project <projectId>", "Project ID")
19
- .option("-e, --env <environment>", "Environment (development, staging, production)", "development")
20
- .option("-b, --branch <branchName>", "Branch Name")
21
- .option("-f, --format <format>", "Input format (json, dotenv, csv). Auto-detected if omitted.")
22
- .option("--prefix <prefix>", "Add prefix to all imported keys")
23
- .option("--overwrite", "Overwrite existing secrets (default: merged, but API usually upserts)", true)
24
- .action(async (file, options) => {
25
- let { project, env, branch, format, prefix } = options;
26
- // Use config fallback
27
- if (!project)
28
- project = (0, config_1.getRcConfig)().project;
29
- if (!branch) {
30
- branch = (0, config_1.getRcConfig)().branch || "main";
31
- }
32
- // Normalize Env
33
- const envMap = { dev: "development", stg: "staging", prod: "production" };
34
- env = envMap[env] || env;
35
- if (!project) {
36
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
37
- process.exit(1);
38
- }
39
- const filePath = path_1.default.resolve(process.cwd(), file);
40
- if (!fs_1.default.existsSync(filePath)) {
41
- console.error(chalk_1.default.red(`Error: File not found: ${filePath}`));
42
- process.exit(1);
43
- }
44
- let detectedFormat = format;
45
- if (!detectedFormat) {
46
- const ext = path_1.default.extname(filePath).toLowerCase();
47
- if (ext === ".json")
48
- detectedFormat = "json";
49
- else if (ext === ".env")
50
- detectedFormat = "dotenv";
51
- else if (ext === ".csv")
52
- detectedFormat = "csv";
53
- else {
54
- console.error(chalk_1.default.red("Error: Could not detect format. Please specify -f <format>"));
55
- process.exit(1);
56
- }
57
- }
58
- const spinner = require("ora")(`Reading ${detectedFormat} file...`).start();
59
- const fileContent = fs_1.default.readFileSync(filePath, "utf-8");
60
- let secrets = {};
61
- try {
62
- switch (detectedFormat.toLowerCase()) {
63
- case "json":
64
- secrets = JSON.parse(fileContent);
65
- break;
66
- case "dotenv":
67
- secrets = dotenv_1.default.parse(fileContent);
68
- break;
69
- case "csv":
70
- const records = (0, sync_1.parse)(fileContent, {
71
- columns: true,
72
- skip_empty_lines: true
73
- });
74
- // Expect header: key, value or Key, Value
75
- records.forEach((record) => {
76
- // Try case-insensitive key lookup
77
- const key = record.key || record.Key || record.KEY;
78
- const value = record.value || record.Value || record.VALUE;
79
- if (key) {
80
- secrets[key] = value || "";
81
- }
82
- });
83
- break;
84
- default:
85
- spinner.fail(`Unsupported format: ${detectedFormat}`);
86
- process.exit(1);
87
- }
88
- if (Object.keys(secrets).length === 0) {
89
- spinner.fail("No valid secrets found in file.");
90
- return;
91
- }
92
- // Apply prefix
93
- if (prefix) {
94
- const prefixedSecrets = {};
95
- Object.entries(secrets).forEach(([key, value]) => {
96
- prefixedSecrets[`${prefix}${key}`] = value;
97
- });
98
- secrets = prefixedSecrets;
99
- }
100
- // Upload
101
- spinner.text = `Importing ${Object.keys(secrets).length} secrets to ${env} (branch: ${branch})...`;
102
- await api_1.api.setSecrets(project, env, secrets, undefined, branch);
103
- spinner.succeed(`Successfully imported ${Object.keys(secrets).length} secrets.`);
104
- // Log Audit
105
- try {
106
- const { logAudit } = require("../lib/audit");
107
- logAudit("SECRET_IMPORT", project, env, {
108
- file: path_1.default.basename(filePath),
109
- format: detectedFormat,
110
- count: Object.keys(secrets).length,
111
- branch: branch
112
- });
113
- }
114
- catch (e) { }
115
- }
116
- catch (error) {
117
- spinner.fail("Import failed.");
118
- console.error(chalk_1.default.red(error.message));
119
- process.exit(1);
120
- }
121
- });
1
+ var gt=Object.create;var S=Object.defineProperty;var dt=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var ft=Object.getPrototypeOf,lt=Object.prototype.hasOwnProperty;var b=(t,e)=>()=>(t&&(e=t(t=0)),e);var D=(t,e)=>{for(var s in e)S(t,s,{get:e[s],enumerable:!0})},J=(t,e,s,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of ut(e))!lt.call(t,n)&&n!==s&&S(t,n,{get:()=>e[n],enumerable:!(r=dt(e,n))||r.enumerable});return t};var a=(t,e,s)=>(s=t!=null?gt(ft(t)):{},J(e||!t||!t.__esModule?S(s,"default",{value:t,enumerable:!0}):s,t)),F=t=>J(S({},"__esModule",{value:!0}),t);var q,U,G,E,f,O,l,V,L,$=b(()=>{q=a(require("conf")),U=a(require("fs")),G=a(require("path")),E="https://www.xtrasecurity.in/api",f=new q.default({projectName:"xtra-cli",defaults:{apiUrl:E}}),O=f.get("apiUrl");O&&!process.env.XTRA_API_URL&&(O.includes("localhost")||O.includes("xtra-security.vercel.app"))&&f.set("apiUrl",E);l=()=>({...f.store,apiUrl:process.env.XTRA_API_URL||f.get("apiUrl")||E}),V=()=>f.get("token"),L=()=>{let t={};try{let e=G.default.join(process.cwd(),".xtrarc");U.default.existsSync(e)&&(t=JSON.parse(U.default.readFileSync(e,"utf-8")))}catch{}return{project:t.project||f.get("project")||"",env:t.env||f.get("env")||"development",branch:t.branch||f.get("branch")||"main"}}});var K,M,z,mt,o,k,P=b(()=>{K=a(require("axios"));$();M=a(require("fs")),z=a(require("path")),mt=JSON.parse(M.readFileSync(z.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=l(),e=V();return K.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":mt.version,...e?{Authorization:`Bearer ${e}`}:{}}})},k={login:async(t,e,s)=>(await o().post("/auth/cli-login",{email:t,password:e,apiKey:s})).data,getSecrets:async(t,e,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?branch=${s}`)).data,getSecretVersions:async(t,e,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(t,e,s,r,n="main")=>(await o().post(`/projects/${t}/envs/${e}/secrets`,{secrets:s,expectedVersions:r,branch:n})).data,getSecretDetails:async(t,e,s,r="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}?branch=${r}`)).data,syncLogs:async t=>(await o().post("/audit/cli-logs",{logs:t})).data,linkSecret:async(t,e,s,r,n,i)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:n,sourceKey:i})).data,rotateSecret:async(t,e,s,r,n)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:n})).data,promoteSecret:async(t,e,s)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(t,e,s,r)=>{let n={format:t};return e&&(n.startDate=e),s&&(n.endDate=s),r&&(n.projectId=r),(await o().post("/audit/export",n,{responseType:t==="csv"?"text":"json"})).data},requestAccess:async(t,e,s,r)=>(await o().post("/access/request",{projectId:t,secretId:r,reason:e,duration:s})).data,approveAccess:async(t,e)=>(await o().post("/access/approve",{requestId:t,decision:e})).data,listAccessRequests:async t=>{let{workspace:e}=l(),s=e?`&workspaceId=${e}`:"";return(await o().get(`/access/list?mode=${t}${s}`)).data},getAccessRequestStatus:async t=>(await o().get(`/access/request?id=${t}`)).data,getProjects:async()=>{let{workspace:t}=l(),e=t?`/project?workspaceId=${t}`:"/project";return(await o().get(e)).data},getBranches:async t=>(await o().get(`/branch?projectId=${t}`)).data,createBranch:async(t,e,s)=>(await o().post("/branch",{projectId:t,name:e,description:s})).data,deleteBranch:async t=>(await o().delete(`/branch/${t}`)).data,updateBranch:async(t,e)=>(await o().put("/branch",{id:t,...e})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async t=>{let e=t?`?teamId=${t}`:"";return(await o().get(`/admin/users${e}`)).data},setUserRole:async(t,e,s)=>(await o().put("/admin/users/role",{email:t,role:e,teamId:s})).data,getIntegrationStatus:async t=>(await o().get(`/integrations/${t}`)).data,getIntegrationRepos:async t=>(await o().get(`/integrations/${t}/sync`)).data.repos,syncSecretsToGithub:async t=>(await o().post("/integrations/github/sync",t)).data,exportKubernetesSecret:async(t,e)=>{let s=new URLSearchParams(e).toString();return(await o().get(`/projects/${t}/kubernetes?${s}`)).data},getSecretHistory:async(t,e,s)=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}/history`)).data,rollbackSecret:async(t,e,s,r)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(t,e,s,r,n)=>(await o().post(`/projects/${t}/envs/clone`,{fromEnv:e,toEnv:s,overwrite:r,branch:n})).data,generateJitLink:async t=>(await o().post("/jit/generate",t)).data,claimJitLink:async t=>(await o().post("/jit/claim",{token:t})).data,getJitInfo:async t=>(await o().get(`/jit/${t}`)).data,post:async(t,e)=>(await o().post(t,e)).data}});function W(){let t=H.get("masterKey");t||(t=m.default.randomBytes(32).toString("hex"),H.set("masterKey",t));let e=(0,Y.machineIdSync)();return m.default.createHash("sha256").update(t+e).digest()}var m,X,Y,Q,H,Z,tt,et=b(()=>{m=a(require("crypto")),X=a(require("conf")),Y=require("node-machine-id"),Q="aes-256-gcm",H=new X.default({projectName:"xtra-cli-crypto"});Z=t=>{let e=m.default.randomBytes(16),s=W(),r=m.default.createCipheriv(Q,s,e),n=r.update(t,"utf8","hex");n+=r.final("hex");let i=r.getAuthTag();return{iv:e.toString("hex"),content:n,tag:i.toString("hex")}},tt=t=>{let e=W(),s=Buffer.from(t.iv,"hex"),r=Buffer.from(t.tag,"hex"),n=m.default.createDecipheriv(Q,e,s);n.setAuthTag(r);let i=n.update(t.content,"hex","utf8");return i+=n.final("utf8"),i}});var nt={};D(nt,{loadAuditLogs:()=>I,logAudit:()=>ht,saveAuditLogs:()=>A,syncAuditLogs:()=>vt});function yt(t){if(!t||typeof t!="object")return t;let e={...t},s=["password","token","secret","value","apiKey","secretValue"];for(let r of Object.keys(e))s.some(n=>r.toLowerCase().includes(n))&&(e[r]="[REDACTED]");return e}async function rt(t){try{if(!l().token)return!1;let s={action:t.action,entity:"cli-project",entityId:t.projectId||"global",details:yt(t.details),timestamp:t.timestamp,projectId:t.projectId};return await k.post("/audit/cli-logs",{logs:[s]}),!0}catch(e){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",e),!1}}function ht(t,e,s,r){let n={id:(0,st.v4)(),timestamp:new Date().toISOString(),action:t,projectId:e,environment:s,details:r,synced:!1},i=I();i.push(n),A(i),rt(n).then(h=>{if(h){n.synced=!0;let w=I(),d=w.findIndex(p=>p.id===n.id);d!==-1&&(w[d].synced=!0,A(w))}}).catch(()=>{})}function I(){if(!y.default.existsSync(B))return[];try{let t=y.default.readFileSync(B,"utf-8"),e=JSON.parse(t),s=tt(e);return JSON.parse(s)}catch{return[]}}function A(t){y.default.existsSync(N)||y.default.mkdirSync(N,{recursive:!0});let e=JSON.stringify(t),s=Z(e);y.default.writeFileSync(B,JSON.stringify(s),"utf-8")}async function vt(){let t=I(),e=t.filter(r=>!r.synced);if(e.length===0)return 0;let s=0;for(let r of e)await rt(r)&&(r.synced=!0,s++);return s>0&&A(t),s}var y,T,st,N,B,ot=b(()=>{y=a(require("fs")),T=a(require("path")),st=require("uuid");et();$();P();N=T.default.join(process.cwd(),".xtra"),B=T.default.join(N,"audit.enc")});var wt={};D(wt,{importCommand:()=>xt});module.exports=F(wt);var it=require("commander");P();var x=a(require("chalk")),_=a(require("fs")),C=a(require("path")),at=a(require("dotenv")),ct=require("csv-parse/sync");$();var xt=new it.Command("import").description("Import secrets from a file (JSON, Dotenv, CSV)").argument("<file>","Path to the file to import").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (development, staging, production)","development").option("-b, --branch <branchName>","Branch Name").option("-f, --format <format>","Input format (json, dotenv, csv). Auto-detected if omitted.").option("--prefix <prefix>","Add prefix to all imported keys").option("--overwrite","Overwrite existing secrets (default: merged, but API usually upserts)",!0).action(async(t,e)=>{let{project:s,env:r,branch:n,format:i,prefix:h}=e;s||(s=L().project),n||(n=L().branch||"main"),r={dev:"development",stg:"staging",prod:"production"}[r]||r,s||(console.error(x.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1));let d=C.default.resolve(process.cwd(),t);_.default.existsSync(d)||(console.error(x.default.red(`Error: File not found: ${d}`)),process.exit(1));let p=i;if(!p){let c=C.default.extname(d).toLowerCase();c===".json"?p="json":c===".env"?p="dotenv":c===".csv"?p="csv":(console.error(x.default.red("Error: Could not detect format. Please specify -f <format>")),process.exit(1))}let v=require("ora")(`Reading ${p} file...`).start(),R=_.default.readFileSync(d,"utf-8"),g={};try{switch(p.toLowerCase()){case"json":g=JSON.parse(R);break;case"dotenv":g=at.default.parse(R);break;case"csv":(0,ct.parse)(R,{columns:!0,skip_empty_lines:!0}).forEach(u=>{let j=u.key||u.Key||u.KEY,pt=u.value||u.Value||u.VALUE;j&&(g[j]=pt||"")});break;default:v.fail(`Unsupported format: ${p}`),process.exit(1)}if(Object.keys(g).length===0){v.fail("No valid secrets found in file.");return}if(h){let c={};Object.entries(g).forEach(([u,j])=>{c[`${h}${u}`]=j}),g=c}v.text=`Importing ${Object.keys(g).length} secrets to ${r} (branch: ${n})...`,await k.setSecrets(s,r,g,void 0,n),v.succeed(`Successfully imported ${Object.keys(g).length} secrets.`);try{let{logAudit:c}=(ot(),F(nt));c("SECRET_IMPORT",s,r,{file:C.default.basename(d),format:p,count:Object.keys(g).length,branch:n})}catch{}}catch(c){v.fail("Import failed."),console.error(x.default.red(c.message)),process.exit(1)}});0&&(module.exports={importCommand});
@@ -1,205 +1,7 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.initCommand = void 0;
40
- /**
41
- * init.ts — Bootstrap a new project with .xtrarc and recommended structure
42
- */
43
- const commander_1 = require("commander");
44
- const chalk_1 = __importDefault(require("chalk"));
45
- const inquirer_1 = __importDefault(require("inquirer"));
46
- const fs = __importStar(require("fs"));
47
- const path = __importStar(require("path"));
48
- const config_1 = require("../lib/config");
49
- const RC_FILE = ".xtrarc";
50
- exports.initCommand = new commander_1.Command("init")
51
- .description("Bootstrap a new project — creates .xtrarc and recommended structure")
52
- .option("--project <id>", "Project ID (skip prompt)")
53
- .option("--env <env>", "Default environment", "development")
54
- .option("--branch <branch>", "Default branch", "main")
55
- .option("-y, --yes", "Accept all defaults without prompting", false)
56
- .action(async (options) => {
57
- const cwd = process.cwd();
58
- const rcPath = path.join(cwd, RC_FILE);
59
- console.log(chalk_1.default.bold("\n🚀 xtra init — setting up your project\n"));
60
- // Warn if already initialized
61
- if (fs.existsSync(rcPath)) {
62
- const { overwrite } = await inquirer_1.default.prompt([{
63
- type: "confirm",
64
- name: "overwrite",
65
- message: chalk_1.default.yellow(`.xtrarc already exists. Overwrite it?`),
66
- default: false,
67
- }]);
68
- if (!overwrite) {
69
- console.log(chalk_1.default.gray("Aborted."));
70
- return;
71
- }
72
- }
73
- let { project, env, branch } = options;
74
- // Interactive prompts if not --yes
75
- if (!options.yes) {
76
- // ── API Projects Fetch ─────────────────────────────────────────────
77
- const { getAuthToken } = await Promise.resolve().then(() => __importStar(require("../lib/config")));
78
- const token = getAuthToken();
79
- const ora = (await Promise.resolve().then(() => __importStar(require("ora")))).default;
80
- let remoteProjects = [];
81
- if (!token) {
82
- console.log(chalk_1.default.yellow(" ℹ Not logged in — project list unavailable. Run `xtra login` first."));
83
- console.log(chalk_1.default.yellow(" You can still enter a Project ID manually below.\n"));
84
- }
85
- else {
86
- const apiSpinner = ora("Fetching your projects...").start();
87
- try {
88
- const { api } = await Promise.resolve().then(() => __importStar(require("../lib/api")));
89
- const result = await api.getProjects();
90
- // API might return { projects: [...] } or directly an array
91
- remoteProjects = Array.isArray(result) ? result : result.projects ?? [];
92
- if (remoteProjects.length === 0) {
93
- apiSpinner.warn(chalk_1.default.yellow("No projects found in your workspace. Create one at www.xtrasecurity.in first."));
94
- }
95
- else {
96
- apiSpinner.succeed(`Found ${remoteProjects.length} project${remoteProjects.length > 1 ? "s" : ""}`);
97
- }
98
- }
99
- catch (err) {
100
- const reason = err?.response?.status === 401
101
- ? "session expired — run `xtra login` again"
102
- : err?.response?.data?.error || err?.message || "network error";
103
- apiSpinner.warn(chalk_1.default.yellow(`Could not fetch projects (${reason}). Enter the Project ID manually.`));
104
- }
105
- }
106
- const fallbackProject = project || (0, config_1.getConfigValue)("project") || "";
107
- const { project: selectedProject } = await inquirer_1.default.prompt([
108
- {
109
- type: remoteProjects.length > 0 ? "list" : "input",
110
- name: "project",
111
- message: remoteProjects.length > 0 ? "Select a project:" : "Project ID:",
112
- choices: remoteProjects.length > 0
113
- ? remoteProjects.map(p => ({ name: `${p.name} (${p.id})`, value: p.id }))
114
- : undefined,
115
- default: fallbackProject,
116
- validate: (v) => v.trim() ? true : "Project ID is required",
117
- }
118
- ]);
119
- project = selectedProject.trim();
120
- // Fetch branches for selected project
121
- let remoteBranches = [];
122
- const branchSpinner = ora("Fetching branches...").start();
123
- try {
124
- const { api } = await Promise.resolve().then(() => __importStar(require("../lib/api")));
125
- remoteBranches = await api.getBranches(project);
126
- branchSpinner.stop();
127
- }
128
- catch (err) {
129
- branchSpinner.warn(chalk_1.default.yellow("Could not fetch branches."));
130
- }
131
- const answers = await inquirer_1.default.prompt([
132
- {
133
- type: "list",
134
- name: "env",
135
- message: "Default environment:",
136
- choices: ["development", "staging", "production"],
137
- default: env || "development",
138
- },
139
- {
140
- type: remoteBranches.length > 0 ? "list" : "input",
141
- name: "branch",
142
- message: remoteBranches.length > 0 ? "Default branch:" : "Default branch name:",
143
- choices: remoteBranches.length > 0
144
- ? remoteBranches.map(b => ({ name: b.name, value: b.name }))
145
- : undefined,
146
- default: branch || (remoteBranches.length > 0 ? remoteBranches[0].name : "main"),
147
- },
148
- {
149
- type: "confirm",
150
- name: "addGitignore",
151
- message: "Add .xtrarc to .gitignore? (recommended)",
152
- default: true,
153
- },
154
- ]);
155
- env = answers.env;
156
- branch = answers.branch;
157
- // Add to .gitignore
158
- if (answers.addGitignore) {
159
- const gitignorePath = path.join(cwd, ".gitignore");
160
- let existing = "";
161
- try {
162
- existing = fs.readFileSync(gitignorePath, "utf8");
163
- }
164
- catch (_) { }
165
- if (!existing.includes(".xtrarc")) {
166
- fs.appendFileSync(gitignorePath, "\n# XtraSecurity config\n.xtrarc\n");
167
- console.log(chalk_1.default.gray(" ✔ Added .xtrarc to .gitignore"));
168
- }
169
- }
170
- }
171
- if (!project) {
172
- console.error(chalk_1.default.red("Error: Project ID is required."));
173
- process.exit(1);
174
- }
175
- // Write .xtrarc
176
- const rc = {
177
- project,
178
- env,
179
- branch,
180
- apiUrl: process.env.XTRA_API_URL || "https://www.xtrasecurity.in/api",
181
- createdAt: new Date().toISOString(),
182
- };
183
- fs.writeFileSync(rcPath, JSON.stringify(rc, null, 2), "utf8");
184
- // ── Sync global conf store so `xtra run` / `xtra secrets` pick up the new values ──
185
- (0, config_1.setConfig)("project", project);
186
- (0, config_1.setConfig)("env", env);
187
- (0, config_1.setConfig)("branch", branch);
188
- // Summary
189
- console.log(chalk_1.default.gray(` Branch : ${chalk_1.default.white(branch)}`));
190
- console.log();
191
- // ── Audit Log (Local Chain) ─────────────────────────────────────────
192
- try {
193
- const { logAudit } = await Promise.resolve().then(() => __importStar(require("../lib/audit")));
194
- logAudit("PROJECT_INIT", project, env, { branch, rcPath });
195
- }
196
- catch (e) {
197
- // Non-fatal if audit fails
198
- }
199
- console.log(chalk_1.default.bold(" Next steps:"));
200
- console.log(chalk_1.default.gray(" xtra login # authenticate"));
201
- console.log(chalk_1.default.gray(" xtra secrets list # view secrets"));
202
- console.log(chalk_1.default.gray(" xtra run node app.js # inject and run"));
203
- console.log(chalk_1.default.gray(" xtra doctor # verify everything works"));
204
- console.log();
205
- });
1
+ var ut=Object.create;var I=Object.defineProperty;var yt=Object.getOwnPropertyDescriptor;var mt=Object.getOwnPropertyNames;var ft=Object.getPrototypeOf,ht=Object.prototype.hasOwnProperty;var A=(t,e)=>()=>(t&&(e=t(t=0)),e);var C=(t,e)=>{for(var n in e)I(t,n,{get:e[n],enumerable:!0})},X=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of mt(e))!ht.call(t,s)&&s!==n&&I(t,s,{get:()=>e[s],enumerable:!(r=yt(e,s))||r.enumerable});return t};var g=(t,e,n)=>(n=t!=null?ut(ft(t)):{},X(e||!t||!t.__esModule?I(n,"default",{value:t,enumerable:!0}):n,t)),wt=t=>X(I({},"__esModule",{value:!0}),t);var H={};C(H,{clearConfig:()=>jt,deleteConfig:()=>xt,getAuthToken:()=>_,getBreakGlassSession:()=>vt,getConfig:()=>h,getConfigValue:()=>T,getProjectConfig:()=>bt,getRcConfig:()=>$t,setBreakGlassSession:()=>St,setConfig:()=>v});var z,f,N,O,p,L,h,T,v,jt,xt,_,vt,St,bt,$t,S=A(()=>{z=g(require("conf")),f=g(require("fs")),N=g(require("path")),O="https://www.xtrasecurity.in/api",p=new z.default({projectName:"xtra-cli",defaults:{apiUrl:O}}),L=p.get("apiUrl");L&&!process.env.XTRA_API_URL&&(L.includes("localhost")||L.includes("xtra-security.vercel.app"))&&p.set("apiUrl",O);h=()=>({...p.store,apiUrl:process.env.XTRA_API_URL||p.get("apiUrl")||O}),T=t=>p.get(t),v=(t,e)=>{if(p.set(t,e),t==="token"&&process.platform!=="win32"&&f.default.existsSync(p.path))try{f.default.chmodSync(p.path,384)}catch{}},jt=()=>p.clear(),xt=t=>p.delete(t),_=()=>p.get("token"),vt=()=>p.get("breakGlassSessionId"),St=t=>{t?p.set("breakGlassSessionId",t):p.delete("breakGlassSessionId")},bt=async()=>{try{let t=N.default.join(process.cwd(),"xtra.json");if(f.default.existsSync(t)){let e=f.default.readFileSync(t,"utf-8");return JSON.parse(e)}return null}catch{return null}},$t=()=>{let t={};try{let e=N.default.join(process.cwd(),".xtrarc");f.default.existsSync(e)&&(t=JSON.parse(f.default.readFileSync(e,"utf-8")))}catch{}return{project:t.project||p.get("project")||"",env:t.env||p.get("env")||"development",branch:t.branch||p.get("branch")||"main"}}});var F={};C(F,{api:()=>E});var M,Y,Q,kt,o,E,P=A(()=>{M=g(require("axios"));S();Y=g(require("fs")),Q=g(require("path")),kt=JSON.parse(Y.readFileSync(Q.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=h(),e=_();return M.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":kt.version,...e?{Authorization:`Bearer ${e}`}:{}}})},E={login:async(t,e,n)=>(await o().post("/auth/cli-login",{email:t,password:e,apiKey:n})).data,getSecrets:async(t,e,n="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?branch=${n}`)).data,getSecretVersions:async(t,e,n="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?includeVersions=true&branch=${n}`)).data,setSecrets:async(t,e,n,r,s="main")=>(await o().post(`/projects/${t}/envs/${e}/secrets`,{secrets:n,expectedVersions:r,branch:s})).data,getSecretDetails:async(t,e,n,r="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets/${n}?branch=${r}`)).data,syncLogs:async t=>(await o().post("/audit/cli-logs",{logs:t})).data,linkSecret:async(t,e,n,r,s,a)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:n,sourceProjectId:r,sourceEnv:s,sourceKey:a})).data,rotateSecret:async(t,e,n,r,s)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${n}/rotate`,{strategy:r,parsedNewValue:s})).data,promoteSecret:async(t,e,n)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${n}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(t,e,n,r)=>{let s={format:t};return e&&(s.startDate=e),n&&(s.endDate=n),r&&(s.projectId=r),(await o().post("/audit/export",s,{responseType:t==="csv"?"text":"json"})).data},requestAccess:async(t,e,n,r)=>(await o().post("/access/request",{projectId:t,secretId:r,reason:e,duration:n})).data,approveAccess:async(t,e)=>(await o().post("/access/approve",{requestId:t,decision:e})).data,listAccessRequests:async t=>{let{workspace:e}=h(),n=e?`&workspaceId=${e}`:"";return(await o().get(`/access/list?mode=${t}${n}`)).data},getAccessRequestStatus:async t=>(await o().get(`/access/request?id=${t}`)).data,getProjects:async()=>{let{workspace:t}=h(),e=t?`/project?workspaceId=${t}`:"/project";return(await o().get(e)).data},getBranches:async t=>(await o().get(`/branch?projectId=${t}`)).data,createBranch:async(t,e,n)=>(await o().post("/branch",{projectId:t,name:e,description:n})).data,deleteBranch:async t=>(await o().delete(`/branch/${t}`)).data,updateBranch:async(t,e)=>(await o().put("/branch",{id:t,...e})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async t=>{let e=t?`?teamId=${t}`:"";return(await o().get(`/admin/users${e}`)).data},setUserRole:async(t,e,n)=>(await o().put("/admin/users/role",{email:t,role:e,teamId:n})).data,getIntegrationStatus:async t=>(await o().get(`/integrations/${t}`)).data,getIntegrationRepos:async t=>(await o().get(`/integrations/${t}/sync`)).data.repos,syncSecretsToGithub:async t=>(await o().post("/integrations/github/sync",t)).data,exportKubernetesSecret:async(t,e)=>{let n=new URLSearchParams(e).toString();return(await o().get(`/projects/${t}/kubernetes?${n}`)).data},getSecretHistory:async(t,e,n)=>(await o().get(`/projects/${t}/envs/${e}/secrets/${n}/history`)).data,rollbackSecret:async(t,e,n,r)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${n}/history`,{version:r})).data,cloneEnvironment:async(t,e,n,r,s)=>(await o().post(`/projects/${t}/envs/clone`,{fromEnv:e,toEnv:n,overwrite:r,branch:s})).data,generateJitLink:async t=>(await o().post("/jit/generate",t)).data,claimJitLink:async t=>(await o().post("/jit/claim",{token:t})).data,getJitInfo:async t=>(await o().get(`/jit/${t}`)).data,post:async(t,e)=>(await o().post(t,e)).data}});function nt(){let t=W.get("masterKey");t||(t=j.default.randomBytes(32).toString("hex"),W.set("masterKey",t));let e=(0,tt.machineIdSync)();return j.default.createHash("sha256").update(t+e).digest()}var j,Z,tt,et,W,rt,st,ot=A(()=>{j=g(require("crypto")),Z=g(require("conf")),tt=require("node-machine-id"),et="aes-256-gcm",W=new Z.default({projectName:"xtra-cli-crypto"});rt=t=>{let e=j.default.randomBytes(16),n=nt(),r=j.default.createCipheriv(et,n,e),s=r.update(t,"utf8","hex");s+=r.final("hex");let a=r.getAuthTag();return{iv:e.toString("hex"),content:s,tag:a.toString("hex")}},st=t=>{let e=nt(),n=Buffer.from(t.iv,"hex"),r=Buffer.from(t.tag,"hex"),s=j.default.createDecipheriv(et,e,n);s.setAuthTag(r);let a=s.update(t.content,"hex","utf8");return a+=s.final("utf8"),a}});var ct={};C(ct,{loadAuditLogs:()=>D,logAudit:()=>At,saveAuditLogs:()=>R,syncAuditLogs:()=>Ct});function It(t){if(!t||typeof t!="object")return t;let e={...t},n=["password","token","secret","value","apiKey","secretValue"];for(let r of Object.keys(e))n.some(s=>r.toLowerCase().includes(s))&&(e[r]="[REDACTED]");return e}async function it(t){try{if(!h().token)return!1;let n={action:t.action,entity:"cli-project",entityId:t.projectId||"global",details:It(t.details),timestamp:t.timestamp,projectId:t.projectId};return await E.post("/audit/cli-logs",{logs:[n]}),!0}catch(e){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",e),!1}}function At(t,e,n,r){let s={id:(0,at.v4)(),timestamp:new Date().toISOString(),action:t,projectId:e,environment:n,details:r,synced:!1},a=D();a.push(s),R(a),it(s).then(b=>{if(b){s.synced=!0;let l=D(),$=l.findIndex(k=>k.id===s.id);$!==-1&&(l[$].synced=!0,R(l))}}).catch(()=>{})}function D(){if(!x.default.existsSync(G))return[];try{let t=x.default.readFileSync(G,"utf-8"),e=JSON.parse(t),n=st(e);return JSON.parse(n)}catch{return[]}}function R(t){x.default.existsSync(J)||x.default.mkdirSync(J,{recursive:!0});let e=JSON.stringify(t),n=rt(e);x.default.writeFileSync(G,JSON.stringify(n),"utf-8")}async function Ct(){let t=D(),e=t.filter(r=>!r.synced);if(e.length===0)return 0;let n=0;for(let r of e)await it(r)&&(r.synced=!0,n++);return n>0&&R(t),n}var x,q,at,J,G,pt=A(()=>{x=g(require("fs")),q=g(require("path")),at=require("uuid");ot();S();P();J=q.default.join(process.cwd(),".xtra"),G=q.default.join(J,"audit.enc")});var Rt={};C(Rt,{initCommand:()=>Dt});module.exports=wt(Rt);var gt=require("commander"),c=g(require("chalk")),U=g(require("inquirer")),y=g(require("fs")),K=g(require("path"));S();var Pt=".xtrarc",Dt=new gt.Command("init").description("Bootstrap a new project \u2014 creates .xtrarc and recommended structure").option("--project <id>","Project ID (skip prompt)").option("--env <env>","Default environment","development").option("--branch <branch>","Default branch","main").option("-y, --yes","Accept all defaults without prompting",!1).action(async t=>{let e=process.cwd(),n=K.join(e,Pt);if(console.log(c.default.bold(`
2
+ \u{1F680} xtra init \u2014 setting up your project
3
+ `)),y.existsSync(n)){let{overwrite:l}=await U.default.prompt([{type:"confirm",name:"overwrite",message:c.default.yellow(".xtrarc already exists. Overwrite it?"),default:!1}]);if(!l){console.log(c.default.gray("Aborted."));return}}let{project:r,env:s,branch:a}=t;if(!t.yes){let{getAuthToken:l}=await Promise.resolve().then(()=>(S(),H)),$=l(),k=(await import("ora")).default,d=[];if(!$)console.log(c.default.yellow(" \u2139 Not logged in \u2014 project list unavailable. Run `xtra login` first.")),console.log(c.default.yellow(` You can still enter a Project ID manually below.
4
+ `));else{let i=k("Fetching your projects...").start();try{let{api:u}=await Promise.resolve().then(()=>(P(),F)),w=await u.getProjects();d=Array.isArray(w)?w:w.projects??[],d.length===0?i.warn(c.default.yellow("No projects found in your workspace. Create one at www.xtrasecurity.in first.")):i.succeed(`Found ${d.length} project${d.length>1?"s":""}`)}catch(u){let w=u?.response?.status===401?"session expired \u2014 run `xtra login` again":u?.response?.data?.error||u?.message||"network error";i.warn(c.default.yellow(`Could not fetch projects (${w}). Enter the Project ID manually.`))}}let lt=r||T("project")||"",{project:dt}=await U.default.prompt([{type:d.length>0?"list":"input",name:"project",message:d.length>0?"Select a project:":"Project ID:",choices:d.length>0?d.map(i=>({name:`${i.name} (${i.id})`,value:i.id})):void 0,default:lt,validate:i=>i.trim()?!0:"Project ID is required"}]);r=dt.trim();let m=[],V=k("Fetching branches...").start();try{let{api:i}=await Promise.resolve().then(()=>(P(),F));m=await i.getBranches(r),V.stop()}catch{V.warn(c.default.yellow("Could not fetch branches."))}let B=await U.default.prompt([{type:"list",name:"env",message:"Default environment:",choices:["development","staging","production"],default:s||"development"},{type:m.length>0?"list":"input",name:"branch",message:m.length>0?"Default branch:":"Default branch name:",choices:m.length>0?m.map(i=>({name:i.name,value:i.name})):void 0,default:a||(m.length>0?m[0].name:"main")},{type:"confirm",name:"addGitignore",message:"Add .xtrarc to .gitignore? (recommended)",default:!0}]);if(s=B.env,a=B.branch,B.addGitignore){let i=K.join(e,".gitignore"),u="";try{u=y.readFileSync(i,"utf8")}catch{}u.includes(".xtrarc")||(y.appendFileSync(i,`
5
+ # XtraSecurity config
6
+ .xtrarc
7
+ `),console.log(c.default.gray(" \u2714 Added .xtrarc to .gitignore")))}}r||(console.error(c.default.red("Error: Project ID is required.")),process.exit(1));let b={project:r,env:s,branch:a,apiUrl:process.env.XTRA_API_URL||"https://www.xtrasecurity.in/api",createdAt:new Date().toISOString()};y.writeFileSync(n,JSON.stringify(b,null,2),"utf8"),v("project",r),v("env",s),v("branch",a),console.log(c.default.gray(` Branch : ${c.default.white(a)}`)),console.log();try{let{logAudit:l}=await Promise.resolve().then(()=>(pt(),ct));l("PROJECT_INIT",r,s,{branch:a,rcPath:n})}catch{}console.log(c.default.bold(" Next steps:")),console.log(c.default.gray(" xtra login # authenticate")),console.log(c.default.gray(" xtra secrets list # view secrets")),console.log(c.default.gray(" xtra run node app.js # inject and run")),console.log(c.default.gray(" xtra doctor # verify everything works")),console.log()});0&&(module.exports={initCommand});