novacloud22-cli 1.0.2 → 1.0.3

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 (2) hide show
  1. package/index.js +60 -96
  2. package/package.json +2 -2
package/index.js CHANGED
@@ -86,114 +86,78 @@ program
86
86
  .description('Authenticate with your NovaCloud22 account')
87
87
  .action(async () => {
88
88
  banner()
89
- const spinner = ora('Starting authentication...').start()
90
89
 
91
- // Start local server to receive token
92
- const server = http.createServer(async (req, res) => {
93
- const url = new URL(req.url, 'http://localhost:9876')
94
- const token = url.searchParams.get('token')
90
+ // Generate unique state ID for polling
91
+ const state = require('crypto').randomBytes(16).toString('hex')
92
+ const loginUrl = `${FRONTEND_URL}/cli-auth?state=${state}`
95
93
 
96
- if (token) {
97
- // Verify token with backend
98
- try {
94
+ console.log(chalk.bold('\n NovaCloud22 CLI — Login\n'))
95
+ console.log(chalk.gray(' ' + '─'.repeat(50)))
96
+ console.log(chalk.cyan('\n Login URL:'))
97
+ console.log(chalk.blue.underline(` ${loginUrl}\n`))
98
+ console.log(chalk.gray(' ' + '─'.repeat(50)))
99
+
100
+ const { action } = await inquirer.prompt([{
101
+ type: 'list',
102
+ name: 'action',
103
+ message: 'What would you like to do?',
104
+ choices: [
105
+ { name: '🌐 Open in browser', value: 'open' },
106
+ { name: '📋 Copy link', value: 'copy' },
107
+ { name: '✕ Cancel', value: 'cancel' },
108
+ ]
109
+ }])
110
+
111
+ if (action === 'cancel') {
112
+ console.log(chalk.gray('\n Login cancelled.\n'))
113
+ process.exit(0)
114
+ }
115
+
116
+ if (action === 'open') {
117
+ await open(loginUrl)
118
+ console.log(chalk.gray('\n Browser opened. Complete sign in there.\n'))
119
+ } else if (action === 'copy') {
120
+ const { execSync } = require('child_process')
121
+ try {
122
+ const platform = process.platform
123
+ if (platform === 'darwin') execSync(`echo '${loginUrl}' | pbcopy`)
124
+ else if (platform === 'win32') execSync(`echo ${loginUrl} | clip`)
125
+ else execSync(`echo '${loginUrl}' | xclip -selection clipboard`)
126
+ console.log(chalk.green('\n ✓ Link copied! Paste it in your browser.\n'))
127
+ } catch {
128
+ console.log(chalk.yellow('\n Copy this link manually:'))
129
+ console.log(chalk.blue.underline(` ${loginUrl}\n`))
130
+ }
131
+ }
132
+
133
+ // Poll backend every 2s until token received (max 5 min)
134
+ const spinner = ora('Waiting for authentication...').start()
135
+ const maxWait = 150
136
+ let waited = 0
137
+
138
+ while (waited < maxWait) {
139
+ await new Promise(r => setTimeout(r, 2000))
140
+ waited++
141
+ try {
142
+ const res = await axios.get(`${API_BASE}/cli-auth/poll?state=${state}`)
143
+ if (res.data.ready && res.data.token) {
144
+ const token = res.data.token
99
145
  const verifyRes = await axios.get(`${API_BASE}/user/profile`, {
100
146
  headers: { Authorization: `Bearer ${token}` }
101
147
  })
102
148
  saveToken(token)
103
- res.writeHead(200, { 'Content-Type': 'text/html' })
104
- res.end(`
105
- <html><body style="font-family:sans-serif;text-align:center;padding:3rem;background:#0f0c29;color:white">
106
- <h2>✅ Logged in successfully!</h2>
107
- <p>You can close this tab and return to the terminal.</p>
108
- <p style="color:rgba(255,255,255,0.5);font-size:0.9rem">NovaCloud22 CLI</p>
109
- </body></html>
110
- `)
111
- server.close()
112
149
  spinner.succeed(chalk.green(`Logged in as ${verifyRes.data.email}`))
113
150
  console.log(chalk.gray('\n Run novacloud22 init to set up your project\n'))
114
- } catch {
115
- res.writeHead(400, { 'Content-Type': 'text/html' })
116
- res.end('<html><body>Authentication failed. Please try again.</body></html>')
117
- server.close()
118
- spinner.fail('Authentication failed')
151
+ process.exit(0)
119
152
  }
120
- } else {
121
- res.writeHead(400)
122
- res.end('No token received')
153
+ } catch {
154
+ // keep polling
123
155
  }
124
- })
125
-
126
- server.listen(9876, async () => {
127
- spinner.stop()
128
- const loginUrl = `${FRONTEND_URL}/cli-auth?callback=http://localhost:9876`
129
-
130
- console.log(chalk.bold('\n NovaCloud22 CLI — Login\n'))
131
- console.log(chalk.gray(' ' + '─'.repeat(50)))
132
- console.log(chalk.cyan('\n Login URL:'))
133
- console.log(chalk.blue.underline(` ${loginUrl}\n`))
134
- console.log(chalk.gray(' ' + '─'.repeat(50)))
135
-
136
- const { action } = await inquirer.prompt([{
137
- type: 'list',
138
- name: 'action',
139
- message: 'What would you like to do?',
140
- choices: [
141
- { name: '🌐 Open in browser', value: 'open' },
142
- { name: '📋 Copy link', value: 'copy' },
143
- { name: '✕ Cancel', value: 'cancel' },
144
- ]
145
- }])
146
-
147
- if (action === 'open') {
148
- await open(loginUrl)
149
- console.log(chalk.gray('\n Browser opened. Complete sign in there.\n'))
150
- console.log(chalk.gray(' Waiting for authentication...'))
151
- } else if (action === 'copy') {
152
- // Copy to clipboard using pbcopy (mac) / clip (win) / xclip (linux)
153
- const { execSync } = require('child_process')
154
- try {
155
- const platform = process.platform
156
- if (platform === 'darwin') execSync(`echo '${loginUrl}' | pbcopy`)
157
- else if (platform === 'win32') execSync(`echo ${loginUrl} | clip`)
158
- else execSync(`echo '${loginUrl}' | xclip -selection clipboard`)
159
- console.log(chalk.green('\n ✓ Link copied to clipboard!'))
160
- console.log(chalk.gray(' Paste it in your browser to sign in.\n'))
161
- console.log(chalk.gray(' Waiting for authentication...'))
162
- } catch {
163
- console.log(chalk.yellow('\n Could not copy automatically. Copy this link manually:'))
164
- console.log(chalk.blue.underline(` ${loginUrl}\n`))
165
- }
166
- } else {
167
- console.log(chalk.gray('\n Login cancelled.\n'))
168
- server.close()
169
- process.exit(0)
170
- }
171
- })
172
-
173
- server.on('error', () => {
174
- spinner.fail('Could not start local server on port 9876')
175
- console.log(chalk.yellow('\n Manual login: Go to ' + FRONTEND_URL + '/signin'))
176
- console.log(chalk.yellow(' Then run: novacloud22 login --token YOUR_TOKEN\n'))
177
- })
178
- })
179
-
180
- // LOGIN WITH TOKEN (manual fallback)
181
- program
182
- .command('login:token <token>')
183
- .description('Login with a token directly')
184
- .action(async (token) => {
185
- const spinner = ora('Verifying token...').start()
186
- try {
187
- const res = await axios.get(`${API_BASE}/user/profile`, {
188
- headers: { Authorization: `Bearer ${token}` }
189
- })
190
- saveToken(token)
191
- spinner.succeed(chalk.green(`Logged in as ${res.data.email}`))
192
- } catch {
193
- spinner.fail('Invalid token')
194
156
  }
195
- })
196
157
 
158
+ spinner.fail('Login timed out. Please try again.')
159
+ process.exit(1)
160
+ })
197
161
  // INIT
198
162
  program
199
163
  .command('init')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "novacloud22-cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Deploy static websites to NovaCloud22",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -30,4 +30,4 @@
30
30
  "engines": {
31
31
  "node": ">=14.0.0"
32
32
  }
33
- }
33
+ }