@orcapt/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/QUICK_START.md +241 -0
- package/README.md +949 -0
- package/bin/orca.js +406 -0
- package/package.json +58 -0
- package/src/commands/db.js +248 -0
- package/src/commands/fetch-doc.js +220 -0
- package/src/commands/kickstart-node.js +431 -0
- package/src/commands/kickstart-python.js +360 -0
- package/src/commands/lambda.js +736 -0
- package/src/commands/login.js +277 -0
- package/src/commands/storage.js +911 -0
- package/src/commands/ui.js +286 -0
- package/src/config.js +62 -0
- package/src/utils/docker-helper.js +357 -0
- package/src/utils/index.js +349 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orca Login Command
|
|
3
|
+
* Authenticates users before using kickstart commands
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const ora = require('ora');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const os = require('os');
|
|
12
|
+
const https = require('https');
|
|
13
|
+
const http = require('http');
|
|
14
|
+
const { API_BASE_URL, API_ENDPOINTS } = require('../config');
|
|
15
|
+
|
|
16
|
+
// Config file location in user's home directory
|
|
17
|
+
const CONFIG_DIR = path.join(os.homedir(), '.orca');
|
|
18
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Make API request to authenticate
|
|
22
|
+
*/
|
|
23
|
+
function authenticate(mode, workspace, token) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
// Parse API URL from config
|
|
26
|
+
const apiUrl = new URL(API_ENDPOINTS.AUTH, API_BASE_URL);
|
|
27
|
+
const hostname = apiUrl.hostname;
|
|
28
|
+
const pathName = apiUrl.pathname;
|
|
29
|
+
const isHttps = apiUrl.protocol === 'https:';
|
|
30
|
+
const httpModule = isHttps ? https : http;
|
|
31
|
+
// Map legacy 'dev' selection to 'pro' for the API
|
|
32
|
+
const modeValue = mode === 'team' ? 'team' : 'dev';
|
|
33
|
+
|
|
34
|
+
const postData = JSON.stringify({
|
|
35
|
+
workspace,
|
|
36
|
+
token,
|
|
37
|
+
mode: modeValue
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const options = {
|
|
41
|
+
hostname,
|
|
42
|
+
port: apiUrl.port || (isHttps ? 443 : 80),
|
|
43
|
+
path: pathName,
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const req = httpModule.request(options, (res) => {
|
|
52
|
+
let data = '';
|
|
53
|
+
|
|
54
|
+
res.on('data', (chunk) => {
|
|
55
|
+
data += chunk;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
res.on('end', () => {
|
|
59
|
+
try {
|
|
60
|
+
const response = JSON.parse(data);
|
|
61
|
+
if (response.pass === true) {
|
|
62
|
+
resolve(true);
|
|
63
|
+
} else {
|
|
64
|
+
resolve(false);
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
reject(new Error('Invalid response from server'));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
req.on('error', (error) => {
|
|
73
|
+
reject(error);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
req.write(postData);
|
|
77
|
+
req.end();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Save credentials to config file
|
|
83
|
+
*/
|
|
84
|
+
function saveCredentials(mode, workspace, token) {
|
|
85
|
+
try {
|
|
86
|
+
// Create .orca directory if it doesn't exist
|
|
87
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
88
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const config = {
|
|
92
|
+
mode,
|
|
93
|
+
workspace,
|
|
94
|
+
token,
|
|
95
|
+
authenticated: true,
|
|
96
|
+
timestamp: new Date().toISOString()
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
100
|
+
return true;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error(chalk.red('Failed to save credentials:', error.message));
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Login command handler
|
|
109
|
+
*/
|
|
110
|
+
async function login() {
|
|
111
|
+
console.log(chalk.cyan('\n============================================================'));
|
|
112
|
+
console.log(chalk.cyan('🔐 Orca Login'));
|
|
113
|
+
console.log(chalk.cyan('============================================================\n'));
|
|
114
|
+
|
|
115
|
+
let authenticated = false;
|
|
116
|
+
let retryCount = 0;
|
|
117
|
+
const MAX_RETRIES = 3;
|
|
118
|
+
|
|
119
|
+
while (!authenticated && retryCount < MAX_RETRIES) {
|
|
120
|
+
try {
|
|
121
|
+
// Ask for mode
|
|
122
|
+
const modeAnswer = await inquirer.prompt([
|
|
123
|
+
{
|
|
124
|
+
type: 'list',
|
|
125
|
+
name: 'mode',
|
|
126
|
+
message: 'Select your Orca mode:',
|
|
127
|
+
choices: [
|
|
128
|
+
{ name: 'Sandbox/Pro mode', value: 'dev' },
|
|
129
|
+
{ name: 'Team mode', value: 'team' }
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
// Ask for workspace name
|
|
135
|
+
const workspaceAnswer = await inquirer.prompt([
|
|
136
|
+
{
|
|
137
|
+
type: 'input',
|
|
138
|
+
name: 'workspace',
|
|
139
|
+
message: 'Enter your workspace name:',
|
|
140
|
+
validate: (input) => {
|
|
141
|
+
if (input.trim().length === 0) {
|
|
142
|
+
return 'Workspace name cannot be empty';
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
// Ask for token
|
|
150
|
+
const tokenAnswer = await inquirer.prompt([
|
|
151
|
+
{
|
|
152
|
+
type: 'password',
|
|
153
|
+
name: 'token',
|
|
154
|
+
message: 'Enter your authentication token:',
|
|
155
|
+
mask: '*',
|
|
156
|
+
validate: (input) => {
|
|
157
|
+
if (input.trim().length === 0) {
|
|
158
|
+
return 'Token cannot be empty';
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
const spinner = ora('Authenticating...').start();
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const isAuthenticated = await authenticate(
|
|
169
|
+
modeAnswer.mode,
|
|
170
|
+
workspaceAnswer.workspace.trim(),
|
|
171
|
+
tokenAnswer.token.trim()
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
if (isAuthenticated) {
|
|
175
|
+
spinner.succeed(chalk.green('Authentication successful!'));
|
|
176
|
+
|
|
177
|
+
// Save credentials
|
|
178
|
+
const saved = saveCredentials(
|
|
179
|
+
modeAnswer.mode,
|
|
180
|
+
workspaceAnswer.workspace.trim(),
|
|
181
|
+
tokenAnswer.token.trim()
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (saved) {
|
|
185
|
+
console.log(chalk.green('\n✓ Credentials saved successfully'));
|
|
186
|
+
console.log(chalk.cyan('\nYou can now use:'), chalk.white('orca kickstart <language>'));
|
|
187
|
+
console.log(chalk.cyan('============================================================\n'));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
authenticated = true;
|
|
191
|
+
} else {
|
|
192
|
+
spinner.fail(chalk.red('Authentication failed'));
|
|
193
|
+
retryCount++;
|
|
194
|
+
|
|
195
|
+
if (retryCount < MAX_RETRIES) {
|
|
196
|
+
console.log(chalk.yellow(`\n⚠ Invalid credentials. Please try again (${retryCount}/${MAX_RETRIES})\n`));
|
|
197
|
+
} else {
|
|
198
|
+
console.log(chalk.red('\n✗ Maximum retry attempts reached. Please try again later.\n'));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
spinner.fail(chalk.red('Authentication error'));
|
|
203
|
+
console.log(chalk.red(`Error: ${error.message}`));
|
|
204
|
+
retryCount++;
|
|
205
|
+
|
|
206
|
+
if (retryCount < MAX_RETRIES) {
|
|
207
|
+
console.log(chalk.yellow(`\n⚠ Please try again (${retryCount}/${MAX_RETRIES})\n`));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (error.isTtyError) {
|
|
212
|
+
console.error(chalk.red('Prompt couldn\'t be rendered in the current environment'));
|
|
213
|
+
} else {
|
|
214
|
+
console.error(chalk.red('An error occurred:', error.message));
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (!authenticated) {
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Check if user is logged in
|
|
227
|
+
*/
|
|
228
|
+
function isLoggedIn() {
|
|
229
|
+
try {
|
|
230
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
235
|
+
return config.authenticated === true;
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get current credentials
|
|
243
|
+
*/
|
|
244
|
+
function getCredentials() {
|
|
245
|
+
try {
|
|
246
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
251
|
+
} catch (error) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Clear credentials (logout)
|
|
258
|
+
*/
|
|
259
|
+
function clearCredentials() {
|
|
260
|
+
try {
|
|
261
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
262
|
+
fs.unlinkSync(CONFIG_FILE);
|
|
263
|
+
}
|
|
264
|
+
return true;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
module.exports = {
|
|
271
|
+
login,
|
|
272
|
+
isLoggedIn,
|
|
273
|
+
getCredentials,
|
|
274
|
+
clearCredentials,
|
|
275
|
+
CONFIG_FILE
|
|
276
|
+
};
|
|
277
|
+
|