@stackone/cli 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,13 +29,14 @@ Initialize and configure the StackOne CLI by creating configuration profiles. Th
29
29
  stackone init
30
30
  ```
31
31
 
32
+ **Options:**
33
+
34
+ - `-e, --env <environment>` - Specify the environment for the configuration profile (`production`, `staging` or custom value). Defaults to `production` if not provided. When using a custom environment, you will be prompted to enter the API URL.
35
+
32
36
  The command will interactively prompt you for:
33
37
 
34
38
  1. **Profile label** - A unique name for this configuration profile
35
- 2. **Environment** - Choose from:
36
- - `production`
37
- - `staging`
38
- - `local`
39
+ 2. **API Url** - Only when the environment is specified and is not production or staging
39
40
  3. **API Key** - Your StackOne API key
40
41
 
41
42
  **Features:**
@@ -47,7 +48,7 @@ The command will interactively prompt you for:
47
48
 
48
49
  ### `push`
49
50
 
50
- Push connector(s) file(s) to the StackOne API registry. This command requires a configuration profile created with the `init` command.
51
+ Push connector(s) file(s) to the StackOne API registry. This command can use either a configuration profile created with the `init` command or provide credentials directly via command-line options.
51
52
 
52
53
  ```bash
53
54
  stackone push --profile <profile-label> path/to/connector.s1.yaml
@@ -59,18 +60,36 @@ or
59
60
  stackone push --profile <profile-label> path/to/connectors/
60
61
  ```
61
62
 
63
+ or using direct credentials:
64
+
65
+ ```bash
66
+ stackone push --api-key <your-api-key> path/to/connector.s1.yaml
67
+ ```
68
+
69
+ or with custom API URL:
70
+
71
+ ```bash
72
+ stackone push --api-key <your-api-key> --api-url <api-url> path/to/connector.s1.yaml
73
+ ```
74
+
62
75
  **Arguments:**
63
76
 
64
77
  - `<path>` - Path to the connector file or folder with connectors to upload
65
78
 
66
79
  **Options:**
67
80
 
68
- - `-p, --profile <label>` - Configuration profile to use (required)
81
+ - `-p, --profile <label>` - Configuration profile to use
82
+ - `--api-key <api-key>` - API key to use for authentication (alternative to using a profile)
83
+ - `--api-url <api-url>` - API URL to use (defaults to `https://api.stackone.com` if not specified)
84
+
85
+ **Note:** You must provide either `--profile` or `--api-key`. If using `--api-key`, the `--api-url` option is optional and will default to the production API URL.
69
86
 
70
87
  **Features:**
71
88
 
72
- - **Profile validation**: Ensures the specified profile exists before uploading
89
+ - **Flexible authentication**: Use either a saved profile or provide credentials directly
90
+ - **Profile validation**: Ensures the specified profile exists before uploading (when using `--profile`)
73
91
  - **File validation**: Checks that the file exists and is a valid connector before attempting upload
92
+ - **Batch upload**: Supports uploading multiple connectors from a directory
74
93
 
75
94
  ### `validate`
76
95
 
@@ -106,7 +125,7 @@ Show the current version of the CLI:
106
125
 
107
126
  ```bash
108
127
  stackone --version
109
- stackone -V
128
+ stackone -v
110
129
  ```
111
130
 
112
131
  ### Local Development
package/dist/cli.cjs CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- const e=require(`./cliCore-BOwdDcP4.cjs`),t=new e.CLI;t.run();
2
+ const e=require(`./cliCore-Bba3TFak.cjs`),t=new e.CLI;t.run();
package/dist/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{CLI as e}from"./cliCore-CYhcPSJT.js";const t=new e;t.run();
2
+ import{CLI as e}from"./cliCore-CGA-wigN.js";const t=new e;t.run();
@@ -0,0 +1,7 @@
1
+ const e=require(`./chunk-CUT6urMc.cjs`),t=e.__toESM(require(`chalk`)),n=e.__toESM(require(`commander`)),r=e.__toESM(require(`inquirer`)),i=e.__toESM(require(`fs`)),a=e.__toESM(require(`os`)),o=e.__toESM(require(`path`)),s=e.__toESM(require(`@stackone/connect-sdk`)),c=e.__toESM(require(`ora`)),l=e.__toESM(require(`url`)),u=(0,o.join)((0,a.homedir)(),`.stackone`),d={profiles:{}},f=()=>{if(!(0,i.existsSync)(u))return d;try{let e=(0,i.readFileSync)(u,`utf-8`);return JSON.parse(e)}catch{return d}},p=e=>{let t=f();return t.profiles[e]},m=e=>{let t=f();return!!t.profiles[e]},h=(e,t)=>{let n=f();n.profiles[e]=t;let r=(0,o.join)((0,a.homedir)());(0,i.existsSync)(r)||(0,i.mkdirSync)(r,{recursive:!0}),(0,i.writeFileSync)(u,JSON.stringify(n,null,2),`utf-8`)},g=()=>{let e=f();return Object.keys(e.profiles)};var _=class{static info(e){console.info(t.default.blue(`ℹ`),e)}static warn(e){console.info(t.default.yellow(`⚠`),e)}static error(e){console.info(t.default.red(`✗`),e)}static success(e){console.info(t.default.green(`✓`),e)}};const v=`https://api.stackone.com`,y=`https://api.stackone-dev.com`,b=`http://localhost:4000`;var x=class{async execute({environment:e}={}){let n=e?.toLowerCase()??`production`;try{let{label:e}=await r.default.prompt([{type:`input`,name:`label`,message:`Profile label:`,validate:e=>!e||e.trim().length===0?`The profile label is required`:e.includes(` `)?`The profile label cannot contain spaces`:!0}]);if(m(e)){let{overwrite:t}=await r.default.prompt([{type:`confirm`,name:`overwrite`,message:`Configuration profile with name "${e}" already exists. Do you want to overwrite it?`,default:!1}]);t||(_.info(`Configuration profile initialization cancelled`),process.exit(0))}let i;if(n===`production`)i=v;else if(n===`staging`)i=y;else{let{customUrl:e}=await r.default.prompt([{type:`input`,name:`customUrl`,message:`API URL:`,default:b,validate:e=>{if(!e||e.trim().length===0)return`API URL is required`;try{return new URL(e),!0}catch{return`Please enter a valid URL`}}}]);i=e}let{apiKey:a}=await r.default.prompt([{type:`password`,name:`apiKey`,message:`API Key:`,validate:e=>!e||e.trim().length===0?`API Key is required`:!0}]),o={label:e,environment:n,apiUrl:i,apiKey:a};h(e,o),console.info(t.default.green(`\n✓ Configuration profile "${e}" saved successfully`)),process.exit(0)}catch(e){e.isTtyError?_.error(`Prompt couldn't be rendered in the current environment`):_.error(`Failed to initialize configuration profile: ${e}`),process.exit(1)}}};const S=`https://api.stackone.com`;var C=class{async execute({profile:e,fileOrDir:t,apiUrl:n,apiKey:r}={}){if(!e&&!r&&(_.error(`Please provide a profile or API key to use for pushing the connector.`),_.info(`You can provide these using the --profile and --api-key options.`),_.info(`Run "stackone init" to create a new configuration profile.`),process.exit(1)),e&&r&&(_.error(`Please provide either a profile or an API key, not both.`),process.exit(1)),e&&n&&_.warn(`Specifying --api-url with a profile won't have any effect. Using API url from profile.`),e&&!m(e)){_.error(`Configuration profile "${e}" not found.`),_.info(`Run "stackone init" to create a new configuration profile.`);let t=g();_.info(`Available profiles: ${t.join(`, `)||`none`}`),process.exit(1)}let a=e?p(e):{apiUrl:n??S,apiKey:r};a||(_.error(`Failed to load configuration profile "${e}".`),process.exit(1)),a.apiKey||(_.error(`API key is missing. Please provide a valid API key in the profile or via the --api-key option.`),process.exit(1)),t||(_.error(`File or directory path is required.`),process.exit(1));try{(0,i.statSync)(t)}catch{_.error(`File or directory not found: ${t}`),process.exit(1)}let o=(0,i.statSync)(t),s=a.apiUrl??S;if(o.isDirectory()){let e=T(t),n=0;e.length===0?(_.error(`No .s1.yaml connector files found in the directory: ${t}.`),process.exit(1)):_.info(`Found ${e.length} connector(s) file(s). Processing...`);for(let t of e){console.info(`
2
+ `);let e=await this.uploadFile(t,s,a.apiKey);e&&n++}console.info(`
3
+ `),_.info(`Upload completed: ${n} of ${e.length} file(s) uploaded successfully.`),process.exit(n>0?0:1)}else t.endsWith(`.s1.yaml`)||(_.error(`Only .s1.yaml files are supported for upload.`),process.exit(1));let c=await this.uploadFile(t,s,a.apiKey);process.exit(c?0:1)}async uploadFile(e,n,r){try{console.info(t.default.blue(`📤 Uploading ${(0,o.basename)(e)}...`));let i=w(e);if(!i)return!1;let a=(0,o.basename)(e),s=new FormData,c=new Blob([i],{type:`application/x-yaml`});s.append(`file`,c,a);let l=Buffer.from(r).toString(`base64`),u=await fetch(`${n}/registry/connectors`,{method:`POST`,headers:{Authorization:`Basic ${l}`},body:s});if(!u.ok){let e=await u.text();return _.error(`Upload failed: ${u.status} - ${u.statusText}`),e&&console.error(t.default.red(e)),!1}let d=await u.json();return console.info(t.default.green(`✓ Successfully uploaded ${a} with connector "${d.provider}@${d.version}"`)),!0}catch(e){return _.error(`Failed to upload file: ${e}`),!1}}};const w=e=>{let n=(0,s.loadConnector)(e),r=(0,s.validateYamlConnector)(n),i=r?.errors??[];if(r.success){let t=e.split(`/`).pop()||e;return _.success(`Connector ${t} is valid!`),n}else i.length>0?(_.error(`Connector ${e} is not valid. Please fix the following errors:\n`),i.forEach(e=>{console.info(t.default.red(`- L${e.line}: ${e.message}`))})):_.error(`Connector ${e} is not valid. Please check the file for errors.`)},T=e=>{let t=[],n=(0,i.readdirSync)(e,{withFileTypes:!0});for(let r of n){let n=(0,o.join)(e,r.name);r.isDirectory()?t.push(...T(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t};var E=class{async execute(e){let{watchMode:n,fileOrDir:r}=e,a=(0,c.default)(`Watching for changes...`),o=()=>{console.clear(),console.info(t.default.yellow(`Watch mode enabled. Press "q" to quit.
4
+ `))};if(r){try{(0,i.statSync)(r)}catch{_.error(`File or directory not found: ${r}`),process.exit(1)}if(n){let{watch:e}=await Promise.resolve().then(()=>require(`./esm-BrK-ICga.cjs`)),n=await import(`readline`),i=n.createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let s=()=>{console.info(t.default.grey(`
5
+
6
+ Exiting watch mode...`)),c.close(),a.stop(),i.close(),process.exit(0)};o(),console.info(t.default.blue(`Running connector(s) validations...`)),await D(r),a.start();let c=e(r||`.`,{ignored:/(^|[/\\])\../,persistent:!0});c.on(`change`,async e=>{o(),a.stop(),console.info(t.default.blue(`File change detected. Running connector(s) validations...`)),await D(r),a.start()}),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await D(r),process.exit(0)}}};const D=async e=>{let t=(0,i.statSync)(e);if(t.isDirectory()){let t=(0,i.readdirSync)(e),n=t.filter(e=>e.endsWith(`.s1.yaml`));if(n.length===0){_.error(`No StackOne connectors found in directory: ${e}. Connector files need to have the extension .s1.yaml.\n`);return}let r=0,a=0;for(let t of n){let n=`${e}/${t}`,o=(0,i.statSync)(n);if(o.isFile()){let e=await O(n);e?r++:a++}}_.info(`Validation completed: ${r} valid, ${a} invalid connectors.\n`)}else t.isFile()&&e.endsWith(`s1.yaml`)?await O(e):_.error(`No StackOne connector found: ${e}. Connector files need to have the extension .s1.yaml.\n`)},O=async e=>{let n=(0,s.loadConnector)(e),r=(0,s.validateYamlConnector)(n),i=r?.errors??[];if(r.success){let t=e.split(`/`).pop()||e;return _.success(`Connector ${t} is valid!\n`),!0}else if(i.length>0)return _.error(`Connector ${e} is not valid. Please fix the following errors:\n`),i.forEach(e=>{console.info(t.default.red(`- L${e.line}: ${e.message}`))}),console.info(`
7
+ `),!1;else return _.error(`Connector ${e} is not valid. Please check the file for errors.`),!1},k=()=>{try{let e=(0,l.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),t=(0,o.dirname)(e),n=(0,o.join)(t,`..`,`package.json`),r=JSON.parse((0,i.readFileSync)(n,`utf8`));return r.version}catch{return`unknown`}};var A=class{constructor(e=new n.Command,t=k()){this.program=e,this.version=t,this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let e=new x,r=new C,i=new E;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,n)=>{n(t.default.red(e))}}),this.program.command(`init`).option(`-e, --env <environment>`,`Specify the environment for the configuration profile`).description(`Initialize & create a StackOne CLI configuration profile`).action(t=>{e.execute({environment:t.env})}),this.program.command(`push`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).addArgument(new n.Argument(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,t)=>{r.execute({profile:t.profile,fileOrDir:e,apiUrl:t.apiUrl,apiKey:t.apiKey})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new n.Argument(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{i.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`version`).description(`Show version information`).action(()=>{console.info(`${t.default.greenBright(`StackOne`)} ${t.default.grey(`CLI`)} ${t.default.whiteBright(this.version)}`),process.exit(0)})}run(){this.program.parse(process.argv)}};Object.defineProperty(exports,`CLI`,{enumerable:!0,get:function(){return A}});
@@ -0,0 +1,7 @@
1
+ import e from"chalk";import{Argument as t,Command as n}from"commander";import r from"inquirer";import{existsSync as i,mkdirSync as a,readFileSync as o,readdirSync as s,statSync as c,writeFileSync as l}from"fs";import{homedir as u}from"os";import{basename as d,dirname as f,join as p}from"path";import{loadConnector as m,validateYamlConnector as h}from"@stackone/connect-sdk";import g from"ora";import{fileURLToPath as _}from"url";const v=p(u(),`.stackone`),y={profiles:{}},b=()=>{if(!i(v))return y;try{let e=o(v,`utf-8`);return JSON.parse(e)}catch{return y}},x=e=>{let t=b();return t.profiles[e]},S=e=>{let t=b();return!!t.profiles[e]},C=(e,t)=>{let n=b();n.profiles[e]=t;let r=p(u());i(r)||a(r,{recursive:!0}),l(v,JSON.stringify(n,null,2),`utf-8`)},w=()=>{let e=b();return Object.keys(e.profiles)};var T=class{static info(t){console.info(e.blue(`ℹ`),t)}static warn(t){console.info(e.yellow(`⚠`),t)}static error(t){console.info(e.red(`✗`),t)}static success(t){console.info(e.green(`✓`),t)}};const E=`https://api.stackone.com`,D=`https://api.stackone-dev.com`,O=`http://localhost:4000`;var k=class{async execute({environment:t}={}){let n=t?.toLowerCase()??`production`;try{let{label:t}=await r.prompt([{type:`input`,name:`label`,message:`Profile label:`,validate:e=>!e||e.trim().length===0?`The profile label is required`:e.includes(` `)?`The profile label cannot contain spaces`:!0}]);if(S(t)){let{overwrite:e}=await r.prompt([{type:`confirm`,name:`overwrite`,message:`Configuration profile with name "${t}" already exists. Do you want to overwrite it?`,default:!1}]);e||(T.info(`Configuration profile initialization cancelled`),process.exit(0))}let i;if(n===`production`)i=E;else if(n===`staging`)i=D;else{let{customUrl:e}=await r.prompt([{type:`input`,name:`customUrl`,message:`API URL:`,default:O,validate:e=>{if(!e||e.trim().length===0)return`API URL is required`;try{return new URL(e),!0}catch{return`Please enter a valid URL`}}}]);i=e}let{apiKey:a}=await r.prompt([{type:`password`,name:`apiKey`,message:`API Key:`,validate:e=>!e||e.trim().length===0?`API Key is required`:!0}]),o={label:t,environment:n,apiUrl:i,apiKey:a};C(t,o),console.info(e.green(`\n✓ Configuration profile "${t}" saved successfully`)),process.exit(0)}catch(e){e.isTtyError?T.error(`Prompt couldn't be rendered in the current environment`):T.error(`Failed to initialize configuration profile: ${e}`),process.exit(1)}}};const A=`https://api.stackone.com`;var j=class{async execute({profile:e,fileOrDir:t,apiUrl:n,apiKey:r}={}){if(!e&&!r&&(T.error(`Please provide a profile or API key to use for pushing the connector.`),T.info(`You can provide these using the --profile and --api-key options.`),T.info(`Run "stackone init" to create a new configuration profile.`),process.exit(1)),e&&r&&(T.error(`Please provide either a profile or an API key, not both.`),process.exit(1)),e&&n&&T.warn(`Specifying --api-url with a profile won't have any effect. Using API url from profile.`),e&&!S(e)){T.error(`Configuration profile "${e}" not found.`),T.info(`Run "stackone init" to create a new configuration profile.`);let t=w();T.info(`Available profiles: ${t.join(`, `)||`none`}`),process.exit(1)}let i=e?x(e):{apiUrl:n??A,apiKey:r};i||(T.error(`Failed to load configuration profile "${e}".`),process.exit(1)),i.apiKey||(T.error(`API key is missing. Please provide a valid API key in the profile or via the --api-key option.`),process.exit(1)),t||(T.error(`File or directory path is required.`),process.exit(1));try{c(t)}catch{T.error(`File or directory not found: ${t}`),process.exit(1)}let a=c(t),o=i.apiUrl??A;if(a.isDirectory()){let e=N(t),n=0;e.length===0?(T.error(`No .s1.yaml connector files found in the directory: ${t}.`),process.exit(1)):T.info(`Found ${e.length} connector(s) file(s). Processing...`);for(let t of e){console.info(`
2
+ `);let e=await this.uploadFile(t,o,i.apiKey);e&&n++}console.info(`
3
+ `),T.info(`Upload completed: ${n} of ${e.length} file(s) uploaded successfully.`),process.exit(n>0?0:1)}else t.endsWith(`.s1.yaml`)||(T.error(`Only .s1.yaml files are supported for upload.`),process.exit(1));let s=await this.uploadFile(t,o,i.apiKey);process.exit(s?0:1)}async uploadFile(t,n,r){try{console.info(e.blue(`📤 Uploading ${d(t)}...`));let i=M(t);if(!i)return!1;let a=d(t),o=new FormData,s=new Blob([i],{type:`application/x-yaml`});o.append(`file`,s,a);let c=Buffer.from(r).toString(`base64`),l=await fetch(`${n}/registry/connectors`,{method:`POST`,headers:{Authorization:`Basic ${c}`},body:o});if(!l.ok){let t=await l.text();return T.error(`Upload failed: ${l.status} - ${l.statusText}`),t&&console.error(e.red(t)),!1}let u=await l.json();return console.info(e.green(`✓ Successfully uploaded ${a} with connector "${u.provider}@${u.version}"`)),!0}catch(e){return T.error(`Failed to upload file: ${e}`),!1}}};const M=t=>{let n=m(t),r=h(n),i=r?.errors??[];if(r.success){let e=t.split(`/`).pop()||t;return T.success(`Connector ${e} is valid!`),n}else i.length>0?(T.error(`Connector ${t} is not valid. Please fix the following errors:\n`),i.forEach(t=>{console.info(e.red(`- L${t.line}: ${t.message}`))})):T.error(`Connector ${t} is not valid. Please check the file for errors.`)},N=e=>{let t=[],n=s(e,{withFileTypes:!0});for(let r of n){let n=p(e,r.name);r.isDirectory()?t.push(...N(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t};var P=class{async execute(t){let{watchMode:n,fileOrDir:r}=t,i=g(`Watching for changes...`),a=()=>{console.clear(),console.info(e.yellow(`Watch mode enabled. Press "q" to quit.
4
+ `))};if(r){try{c(r)}catch{T.error(`File or directory not found: ${r}`),process.exit(1)}if(n){let{watch:t}=await import(`./esm-D_hUWJ1V.js`),n=await import(`readline`),o=n.createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let s=()=>{console.info(e.grey(`
5
+
6
+ Exiting watch mode...`)),c.close(),i.stop(),o.close(),process.exit(0)};a(),console.info(e.blue(`Running connector(s) validations...`)),await F(r),i.start();let c=t(r||`.`,{ignored:/(^|[/\\])\../,persistent:!0});c.on(`change`,async t=>{a(),i.stop(),console.info(e.blue(`File change detected. Running connector(s) validations...`)),await F(r),i.start()}),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await F(r),process.exit(0)}}};const F=async e=>{let t=c(e);if(t.isDirectory()){let t=s(e),n=t.filter(e=>e.endsWith(`.s1.yaml`));if(n.length===0){T.error(`No StackOne connectors found in directory: ${e}. Connector files need to have the extension .s1.yaml.\n`);return}let r=0,i=0;for(let t of n){let n=`${e}/${t}`,a=c(n);if(a.isFile()){let e=await I(n);e?r++:i++}}T.info(`Validation completed: ${r} valid, ${i} invalid connectors.\n`)}else t.isFile()&&e.endsWith(`s1.yaml`)?await I(e):T.error(`No StackOne connector found: ${e}. Connector files need to have the extension .s1.yaml.\n`)},I=async t=>{let n=m(t),r=h(n),i=r?.errors??[];if(r.success){let e=t.split(`/`).pop()||t;return T.success(`Connector ${e} is valid!\n`),!0}else if(i.length>0)return T.error(`Connector ${t} is not valid. Please fix the following errors:\n`),i.forEach(t=>{console.info(e.red(`- L${t.line}: ${t.message}`))}),console.info(`
7
+ `),!1;else return T.error(`Connector ${t} is not valid. Please check the file for errors.`),!1},L=()=>{try{let e=_(import.meta.url),t=f(e),n=p(t,`..`,`package.json`),r=JSON.parse(o(n,`utf8`));return r.version}catch{return`unknown`}};var R=class{constructor(e=new n,t=L()){this.program=e,this.version=t,this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let n=new k,r=new j,i=new P;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(t,n)=>{n(e.red(t))}}),this.program.command(`init`).option(`-e, --env <environment>`,`Specify the environment for the configuration profile`).description(`Initialize & create a StackOne CLI configuration profile`).action(e=>{n.execute({environment:e.env})}),this.program.command(`push`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).addArgument(new t(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,t)=>{r.execute({profile:t.profile,fileOrDir:e,apiUrl:t.apiUrl,apiKey:t.apiKey})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new t(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{i.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`version`).description(`Show version information`).action(()=>{console.info(`${e.greenBright(`StackOne`)} ${e.grey(`CLI`)} ${e.whiteBright(this.version)}`),process.exit(0)})}run(){this.program.parse(process.argv)}};export{R as CLI};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- const e=require(`./cliCore-BOwdDcP4.cjs`);exports.CLI=e.CLI;
1
+ const e=require(`./cliCore-Bba3TFak.cjs`);exports.CLI=e.CLI;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{CLI as e}from"./cliCore-CYhcPSJT.js";export{e as CLI};
1
+ import{CLI as e}from"./cliCore-CGA-wigN.js";export{e as CLI};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/cli",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "description": "StackOne Connect CLI tool",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,7 +0,0 @@
1
- const e=require(`./chunk-CUT6urMc.cjs`),t=e.__toESM(require(`chalk`)),n=e.__toESM(require(`commander`)),r=e.__toESM(require(`inquirer`)),i=e.__toESM(require(`fs`)),a=e.__toESM(require(`os`)),o=e.__toESM(require(`path`)),s=e.__toESM(require(`@stackone/connect-sdk`)),c=e.__toESM(require(`ora`)),l=e.__toESM(require(`url`)),u=(0,o.join)((0,a.homedir)(),`.stackone`),d={profiles:{}},f=()=>{if(!(0,i.existsSync)(u))return d;try{let e=(0,i.readFileSync)(u,`utf-8`);return JSON.parse(e)}catch{return d}},p=e=>{let t=f();return t.profiles[e]},m=e=>{let t=f();return!!t.profiles[e]},h=(e,t)=>{let n=f();n.profiles[e]=t;let r=(0,o.join)((0,a.homedir)());(0,i.existsSync)(r)||(0,i.mkdirSync)(r,{recursive:!0}),(0,i.writeFileSync)(u,JSON.stringify(n,null,2),`utf-8`)},g=()=>{let e=f();return Object.keys(e.profiles)};var _=class{static info(e){console.info(t.default.blue(`ℹ`),e)}static warn(e){console.info(t.default.yellow(`⚠`),e)}static error(e){console.info(t.default.red(`✗`),e)}static success(e){console.info(t.default.green(`✓`),e)}};const v=`https://api.stackone.com`,y=`https://api.stackone-dev.com`,b=`http://localhost:4000`;var x=class{async execute(){try{let{label:e}=await r.default.prompt([{type:`input`,name:`label`,message:`Profile label:`,validate:e=>!e||e.trim().length===0?`The profile label is required`:e.includes(` `)?`The profile label cannot contain spaces`:!0}]);if(m(e)){let{overwrite:t}=await r.default.prompt([{type:`confirm`,name:`overwrite`,message:`Configuration profile with name "${e}" already exists. Do you want to overwrite it?`,default:!1}]);t||(_.info(`Configuration profile initialization cancelled`),process.exit(0))}let{environment:n}=await r.default.prompt([{type:`list`,name:`environment`,message:`Environment:`,choices:[`production`,`staging`,`local`]}]),i;if(n===`production`)i=v;else if(n===`staging`)i=y;else{let{customUrl:e}=await r.default.prompt([{type:`input`,name:`customUrl`,message:`API URL:`,default:b,validate:e=>{if(!e||e.trim().length===0)return`API URL is required`;try{return new URL(e),!0}catch{return`Please enter a valid URL`}}}]);i=e}let{apiKey:a}=await r.default.prompt([{type:`password`,name:`apiKey`,message:`API Key:`,validate:e=>!e||e.trim().length===0?`API Key is required`:!0}]),o={label:e,environment:n,apiUrl:i,apiKey:a};h(e,o),console.info(t.default.green(`\n✓ Configuration profile "${e}" saved successfully`)),process.exit(0)}catch(e){e.isTtyError?_.error(`Prompt couldn't be rendered in the current environment`):_.error(`Failed to initialize configuration profile: ${e}`),process.exit(1)}}},S=class{async execute(e){let{profile:t,fileOrDir:n}=e;if(t||(_.error(`Profile is required. Use --profile <label> to specify a configuration.`),_.info(`Run "stackone init" to create a new configuration profile.`),process.exit(1)),!m(t)){_.error(`Configuration profile "${t}" not found.`),_.info(`Run "stackone init" to create a new configuration profile.`);let e=g();_.info(`Available profiles: ${e.join(`, `)||`none`}`),process.exit(1)}let r=p(t);r||(_.error(`Failed to load configuration profile "${t}".`),process.exit(1)),n||(_.error(`File or directory path is required.`),process.exit(1));try{(0,i.statSync)(n)}catch{_.error(`File or directory not found: ${n}`),process.exit(1)}let a=(0,i.statSync)(n);if(a.isDirectory()){let e=w(n),t=0;e.length===0?(_.error(`No .s1.yaml connector files found in the directory: ${n}.`),process.exit(1)):_.info(`Found ${e.length} connector(s) file(s). Processing...`);for(let n of e){console.info(`
2
- `);let e=await this.uploadFile(n,r.apiUrl,r.apiKey);e&&t++}console.info(`
3
- `),_.info(`Upload completed: ${t} of ${e.length} file(s) uploaded successfully.`),process.exit(t>0?0:1)}else n.endsWith(`.s1.yaml`)||(_.error(`Only .s1.yaml files are supported for upload.`),process.exit(1));let o=await this.uploadFile(n,r.apiUrl,r.apiKey);process.exit(o?0:1)}async uploadFile(e,n,r){try{console.info(t.default.blue(`📤 Uploading ${(0,o.basename)(e)}...`));let i=C(e);if(!i)return!1;let a=(0,o.basename)(e),s=new FormData,c=new Blob([i],{type:`application/x-yaml`});s.append(`file`,c,a);let l=Buffer.from(r).toString(`base64`),u=await fetch(`${n}/registry/connectors`,{method:`POST`,headers:{Authorization:`Basic ${l}`},body:s});if(!u.ok){let e=await u.text();return _.error(`Upload failed: ${u.status} - ${u.statusText}`),e&&console.error(t.default.red(e)),!1}let d=await u.json();return console.info(t.default.green(`✓ Successfully uploaded ${a} with connector "${d.provider}@${d.version}"`)),!0}catch(e){return _.error(`Failed to upload file: ${e}`),!1}}};const C=e=>{let n=(0,s.loadConnector)(e),r=(0,s.validateYamlConnector)(n),i=r?.errors??[];if(r.success){let t=e.split(`/`).pop()||e;return _.success(`Connector ${t} is valid!`),n}else i.length>0?(_.error(`Connector ${e} is not valid. Please fix the following errors:\n`),i.forEach(e=>{console.info(t.default.red(`- L${e.line}: ${e.message}`))})):_.error(`Connector ${e} is not valid. Please check the file for errors.`)},w=e=>{let t=[],n=(0,i.readdirSync)(e,{withFileTypes:!0});for(let r of n){let n=(0,o.join)(e,r.name);r.isDirectory()?t.push(...w(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t};var T=class{async execute(e){let{watchMode:n,fileOrDir:r}=e,a=(0,c.default)(`Watching for changes...`),o=()=>{console.clear(),console.info(t.default.yellow(`Watch mode enabled. Press "q" to quit.
4
- `))};if(r){try{(0,i.statSync)(r)}catch{_.error(`File or directory not found: ${r}`),process.exit(1)}if(n){let{watch:e}=await Promise.resolve().then(()=>require(`./esm-BrK-ICga.cjs`)),n=await import(`readline`),i=n.createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let s=()=>{console.info(t.default.grey(`
5
-
6
- Exiting watch mode...`)),c.close(),a.stop(),i.close(),process.exit(0)};o(),console.info(t.default.blue(`Running connector(s) validations...`)),await E(r),a.start();let c=e(r||`.`,{ignored:/(^|[/\\])\../,persistent:!0});c.on(`change`,async e=>{o(),a.stop(),console.info(t.default.blue(`File change detected. Running connector(s) validations...`)),await E(r),a.start()}),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await E(r),process.exit(0)}}};const E=async e=>{let t=(0,i.statSync)(e);if(t.isDirectory()){let t=(0,i.readdirSync)(e),n=t.filter(e=>e.endsWith(`.s1.yaml`));if(n.length===0){_.error(`No StackOne connectors found in directory: ${e}. Connector files need to have the extension .s1.yaml.\n`);return}let r=0,a=0;for(let t of n){let n=`${e}/${t}`,o=(0,i.statSync)(n);if(o.isFile()){let e=await D(n);e?r++:a++}}_.info(`Validation completed: ${r} valid, ${a} invalid connectors.\n`)}else t.isFile()&&e.endsWith(`s1.yaml`)?await D(e):_.error(`No StackOne connector found: ${e}. Connector files need to have the extension .s1.yaml.\n`)},D=async e=>{let n=(0,s.loadConnector)(e),r=(0,s.validateYamlConnector)(n),i=r?.errors??[];if(r.success){let t=e.split(`/`).pop()||e;return _.success(`Connector ${t} is valid!\n`),!0}else if(i.length>0)return _.error(`Connector ${e} is not valid. Please fix the following errors:\n`),i.forEach(e=>{console.info(t.default.red(`- L${e.line}: ${e.message}`))}),console.info(`
7
- `),!1;else return _.error(`Connector ${e} is not valid. Please check the file for errors.`),!1},O=()=>{try{let e=(0,l.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),t=(0,o.dirname)(e),n=(0,o.join)(t,`..`,`package.json`),r=JSON.parse((0,i.readFileSync)(n,`utf8`));return r.version}catch{return`unknown`}};var k=class{constructor(e=new n.Command,t=O()){this.program=e,this.version=t,this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version)}registerCommands(){let e=new x,r=new S,i=new T;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,n)=>{n(t.default.red(e))}}),this.program.command(`init`).description(`Initialize & create a StackOne CLI configuration profile`).action(()=>{e.execute()}),this.program.command(`push`).option(`-p, --profile <label>`,`Configuration profile to use`).addArgument(new n.Argument(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,t)=>{r.execute({profile:t.profile,fileOrDir:e})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new n.Argument(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{i.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`version`).description(`Show version information`).action(()=>{console.info(`${t.default.greenBright(`StackOne`)} ${t.default.grey(`CLI`)} ${t.default.whiteBright(this.version)}`),process.exit(0)})}run(){this.program.parse(process.argv)}};Object.defineProperty(exports,`CLI`,{enumerable:!0,get:function(){return k}});
@@ -1,7 +0,0 @@
1
- import e from"chalk";import{Argument as t,Command as n}from"commander";import r from"inquirer";import{existsSync as i,mkdirSync as a,readFileSync as o,readdirSync as s,statSync as c,writeFileSync as l}from"fs";import{homedir as u}from"os";import{basename as d,dirname as f,join as p}from"path";import{loadConnector as m,validateYamlConnector as h}from"@stackone/connect-sdk";import g from"ora";import{fileURLToPath as _}from"url";const v=p(u(),`.stackone`),y={profiles:{}},b=()=>{if(!i(v))return y;try{let e=o(v,`utf-8`);return JSON.parse(e)}catch{return y}},x=e=>{let t=b();return t.profiles[e]},S=e=>{let t=b();return!!t.profiles[e]},C=(e,t)=>{let n=b();n.profiles[e]=t;let r=p(u());i(r)||a(r,{recursive:!0}),l(v,JSON.stringify(n,null,2),`utf-8`)},w=()=>{let e=b();return Object.keys(e.profiles)};var T=class{static info(t){console.info(e.blue(`ℹ`),t)}static warn(t){console.info(e.yellow(`⚠`),t)}static error(t){console.info(e.red(`✗`),t)}static success(t){console.info(e.green(`✓`),t)}};const E=`https://api.stackone.com`,D=`https://api.stackone-dev.com`,O=`http://localhost:4000`;var k=class{async execute(){try{let{label:t}=await r.prompt([{type:`input`,name:`label`,message:`Profile label:`,validate:e=>!e||e.trim().length===0?`The profile label is required`:e.includes(` `)?`The profile label cannot contain spaces`:!0}]);if(S(t)){let{overwrite:e}=await r.prompt([{type:`confirm`,name:`overwrite`,message:`Configuration profile with name "${t}" already exists. Do you want to overwrite it?`,default:!1}]);e||(T.info(`Configuration profile initialization cancelled`),process.exit(0))}let{environment:n}=await r.prompt([{type:`list`,name:`environment`,message:`Environment:`,choices:[`production`,`staging`,`local`]}]),i;if(n===`production`)i=E;else if(n===`staging`)i=D;else{let{customUrl:e}=await r.prompt([{type:`input`,name:`customUrl`,message:`API URL:`,default:O,validate:e=>{if(!e||e.trim().length===0)return`API URL is required`;try{return new URL(e),!0}catch{return`Please enter a valid URL`}}}]);i=e}let{apiKey:a}=await r.prompt([{type:`password`,name:`apiKey`,message:`API Key:`,validate:e=>!e||e.trim().length===0?`API Key is required`:!0}]),o={label:t,environment:n,apiUrl:i,apiKey:a};C(t,o),console.info(e.green(`\n✓ Configuration profile "${t}" saved successfully`)),process.exit(0)}catch(e){e.isTtyError?T.error(`Prompt couldn't be rendered in the current environment`):T.error(`Failed to initialize configuration profile: ${e}`),process.exit(1)}}},A=class{async execute(e){let{profile:t,fileOrDir:n}=e;if(t||(T.error(`Profile is required. Use --profile <label> to specify a configuration.`),T.info(`Run "stackone init" to create a new configuration profile.`),process.exit(1)),!S(t)){T.error(`Configuration profile "${t}" not found.`),T.info(`Run "stackone init" to create a new configuration profile.`);let e=w();T.info(`Available profiles: ${e.join(`, `)||`none`}`),process.exit(1)}let r=x(t);r||(T.error(`Failed to load configuration profile "${t}".`),process.exit(1)),n||(T.error(`File or directory path is required.`),process.exit(1));try{c(n)}catch{T.error(`File or directory not found: ${n}`),process.exit(1)}let i=c(n);if(i.isDirectory()){let e=M(n),t=0;e.length===0?(T.error(`No .s1.yaml connector files found in the directory: ${n}.`),process.exit(1)):T.info(`Found ${e.length} connector(s) file(s). Processing...`);for(let n of e){console.info(`
2
- `);let e=await this.uploadFile(n,r.apiUrl,r.apiKey);e&&t++}console.info(`
3
- `),T.info(`Upload completed: ${t} of ${e.length} file(s) uploaded successfully.`),process.exit(t>0?0:1)}else n.endsWith(`.s1.yaml`)||(T.error(`Only .s1.yaml files are supported for upload.`),process.exit(1));let a=await this.uploadFile(n,r.apiUrl,r.apiKey);process.exit(a?0:1)}async uploadFile(t,n,r){try{console.info(e.blue(`📤 Uploading ${d(t)}...`));let i=j(t);if(!i)return!1;let a=d(t),o=new FormData,s=new Blob([i],{type:`application/x-yaml`});o.append(`file`,s,a);let c=Buffer.from(r).toString(`base64`),l=await fetch(`${n}/registry/connectors`,{method:`POST`,headers:{Authorization:`Basic ${c}`},body:o});if(!l.ok){let t=await l.text();return T.error(`Upload failed: ${l.status} - ${l.statusText}`),t&&console.error(e.red(t)),!1}let u=await l.json();return console.info(e.green(`✓ Successfully uploaded ${a} with connector "${u.provider}@${u.version}"`)),!0}catch(e){return T.error(`Failed to upload file: ${e}`),!1}}};const j=t=>{let n=m(t),r=h(n),i=r?.errors??[];if(r.success){let e=t.split(`/`).pop()||t;return T.success(`Connector ${e} is valid!`),n}else i.length>0?(T.error(`Connector ${t} is not valid. Please fix the following errors:\n`),i.forEach(t=>{console.info(e.red(`- L${t.line}: ${t.message}`))})):T.error(`Connector ${t} is not valid. Please check the file for errors.`)},M=e=>{let t=[],n=s(e,{withFileTypes:!0});for(let r of n){let n=p(e,r.name);r.isDirectory()?t.push(...M(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t};var N=class{async execute(t){let{watchMode:n,fileOrDir:r}=t,i=g(`Watching for changes...`),a=()=>{console.clear(),console.info(e.yellow(`Watch mode enabled. Press "q" to quit.
4
- `))};if(r){try{c(r)}catch{T.error(`File or directory not found: ${r}`),process.exit(1)}if(n){let{watch:t}=await import(`./esm-D_hUWJ1V.js`),n=await import(`readline`),o=n.createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let s=()=>{console.info(e.grey(`
5
-
6
- Exiting watch mode...`)),c.close(),i.stop(),o.close(),process.exit(0)};a(),console.info(e.blue(`Running connector(s) validations...`)),await P(r),i.start();let c=t(r||`.`,{ignored:/(^|[/\\])\../,persistent:!0});c.on(`change`,async t=>{a(),i.stop(),console.info(e.blue(`File change detected. Running connector(s) validations...`)),await P(r),i.start()}),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await P(r),process.exit(0)}}};const P=async e=>{let t=c(e);if(t.isDirectory()){let t=s(e),n=t.filter(e=>e.endsWith(`.s1.yaml`));if(n.length===0){T.error(`No StackOne connectors found in directory: ${e}. Connector files need to have the extension .s1.yaml.\n`);return}let r=0,i=0;for(let t of n){let n=`${e}/${t}`,a=c(n);if(a.isFile()){let e=await F(n);e?r++:i++}}T.info(`Validation completed: ${r} valid, ${i} invalid connectors.\n`)}else t.isFile()&&e.endsWith(`s1.yaml`)?await F(e):T.error(`No StackOne connector found: ${e}. Connector files need to have the extension .s1.yaml.\n`)},F=async t=>{let n=m(t),r=h(n),i=r?.errors??[];if(r.success){let e=t.split(`/`).pop()||t;return T.success(`Connector ${e} is valid!\n`),!0}else if(i.length>0)return T.error(`Connector ${t} is not valid. Please fix the following errors:\n`),i.forEach(t=>{console.info(e.red(`- L${t.line}: ${t.message}`))}),console.info(`
7
- `),!1;else return T.error(`Connector ${t} is not valid. Please check the file for errors.`),!1},I=()=>{try{let e=_(import.meta.url),t=f(e),n=p(t,`..`,`package.json`),r=JSON.parse(o(n,`utf8`));return r.version}catch{return`unknown`}};var L=class{constructor(e=new n,t=I()){this.program=e,this.version=t,this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version)}registerCommands(){let n=new k,r=new A,i=new N;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(t,n)=>{n(e.red(t))}}),this.program.command(`init`).description(`Initialize & create a StackOne CLI configuration profile`).action(()=>{n.execute()}),this.program.command(`push`).option(`-p, --profile <label>`,`Configuration profile to use`).addArgument(new t(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,t)=>{r.execute({profile:t.profile,fileOrDir:e})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new t(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{i.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`version`).description(`Show version information`).action(()=>{console.info(`${e.greenBright(`StackOne`)} ${e.grey(`CLI`)} ${e.whiteBright(this.version)}`),process.exit(0)})}run(){this.program.parse(process.argv)}};export{L as CLI};