rampup 0.1.1 ā 0.1.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.
- package/auth.js +71 -99
- package/index.js +25 -39
- package/package.json +1 -1
package/auth.js
CHANGED
|
@@ -7,7 +7,6 @@ import fs from 'fs/promises';
|
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import os from 'os';
|
|
9
9
|
import open from 'open';
|
|
10
|
-
import http from 'http';
|
|
11
10
|
|
|
12
11
|
const CONFIG_DIR = path.join(os.homedir(), '.ramp');
|
|
13
12
|
const TOKEN_FILE = path.join(CONFIG_DIR, 'credentials.json');
|
|
@@ -142,112 +141,85 @@ export async function getUserInfo() {
|
|
|
142
141
|
};
|
|
143
142
|
}
|
|
144
143
|
|
|
144
|
+
const API_BASE = process.env.RAMP_API_URL || 'https://app.rampup.dev';
|
|
145
|
+
|
|
145
146
|
/**
|
|
146
|
-
* Login via browser OAuth flow
|
|
147
|
-
* Opens browser for Google sign-in,
|
|
147
|
+
* Login via browser OAuth flow with polling
|
|
148
|
+
* Opens browser for Google sign-in, polls for completion
|
|
148
149
|
*/
|
|
149
150
|
export async function loginWithBrowser() {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
color: white;
|
|
193
|
-
}
|
|
194
|
-
.container {
|
|
195
|
-
text-align: center;
|
|
196
|
-
padding: 40px;
|
|
197
|
-
}
|
|
198
|
-
h1 { color: #4ade80; margin-bottom: 10px; }
|
|
199
|
-
p { color: #94a3b8; }
|
|
200
|
-
.close-hint { margin-top: 20px; font-size: 14px; }
|
|
201
|
-
</style>
|
|
202
|
-
</head>
|
|
203
|
-
<body>
|
|
204
|
-
<div class="container">
|
|
205
|
-
<h1>ā Login Successful</h1>
|
|
206
|
-
<p>Welcome, ${displayName || email}!</p>
|
|
207
|
-
<p class="close-hint">You can close this window and return to the terminal.</p>
|
|
208
|
-
</div>
|
|
209
|
-
</body>
|
|
210
|
-
</html>
|
|
211
|
-
`);
|
|
212
|
-
|
|
213
|
-
// Close server and resolve
|
|
214
|
-
server.close();
|
|
215
|
-
resolve({ email, displayName, uid });
|
|
216
|
-
} else {
|
|
217
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
218
|
-
res.end('<h1>Login Failed</h1><p>Missing credentials</p>');
|
|
219
|
-
server.close();
|
|
220
|
-
reject(new Error('Missing credentials in callback'));
|
|
221
|
-
}
|
|
222
|
-
} else if (url.pathname === '/') {
|
|
223
|
-
// Redirect to Firebase auth
|
|
224
|
-
res.writeHead(302, {
|
|
225
|
-
Location: `https://app.rampup.dev/cli-login?redirect=http://localhost:${PORT}/callback`,
|
|
226
|
-
});
|
|
227
|
-
res.end();
|
|
228
|
-
} else {
|
|
229
|
-
res.writeHead(404);
|
|
230
|
-
res.end('Not found');
|
|
151
|
+
// Create a login session
|
|
152
|
+
const sessionResponse = await fetch(`${API_BASE}/api/blitz/auth/session`, {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: { 'Content-Type': 'application/json' },
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (!sessionResponse.ok) {
|
|
158
|
+
throw new Error('Failed to create login session');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { sessionId } = await sessionResponse.json();
|
|
162
|
+
|
|
163
|
+
// Open browser to login page with session ID
|
|
164
|
+
const loginUrl = `${API_BASE}/cli-login?session=${sessionId}`;
|
|
165
|
+
|
|
166
|
+
console.log(`\nOpening browser for authentication...`);
|
|
167
|
+
console.log(`If browser doesn't open, visit: ${loginUrl}\n`);
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
await open(loginUrl);
|
|
171
|
+
} catch (err) {
|
|
172
|
+
console.log(`Could not open browser automatically.`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Poll for session completion
|
|
176
|
+
const pollInterval = 2000; // 2 seconds
|
|
177
|
+
const maxAttempts = 150; // 5 minutes
|
|
178
|
+
let attempts = 0;
|
|
179
|
+
|
|
180
|
+
while (attempts < maxAttempts) {
|
|
181
|
+
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
182
|
+
attempts++;
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
const pollResponse = await fetch(`${API_BASE}/api/blitz/auth/session/${sessionId}`);
|
|
186
|
+
|
|
187
|
+
if (pollResponse.status === 410) {
|
|
188
|
+
throw new Error('Login session expired');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (!pollResponse.ok) {
|
|
192
|
+
continue;
|
|
231
193
|
}
|
|
232
|
-
});
|
|
233
194
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
195
|
+
const session = await pollResponse.json();
|
|
196
|
+
|
|
197
|
+
if (session.status === 'complete') {
|
|
198
|
+
// Save credentials
|
|
199
|
+
await saveCredentials({
|
|
200
|
+
idToken: session.idToken,
|
|
201
|
+
refreshToken: session.refreshToken,
|
|
202
|
+
email: session.email,
|
|
203
|
+
displayName: session.displayName,
|
|
204
|
+
uid: session.uid,
|
|
205
|
+
expiresAt: Date.now() + 3600 * 1000,
|
|
206
|
+
});
|
|
237
207
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
208
|
+
return {
|
|
209
|
+
email: session.email,
|
|
210
|
+
displayName: session.displayName,
|
|
211
|
+
uid: session.uid,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
} catch (err) {
|
|
215
|
+
if (err.message === 'Login session expired') {
|
|
216
|
+
throw err;
|
|
242
217
|
}
|
|
243
|
-
|
|
218
|
+
// Continue polling on network errors
|
|
219
|
+
}
|
|
220
|
+
}
|
|
244
221
|
|
|
245
|
-
|
|
246
|
-
setTimeout(() => {
|
|
247
|
-
server.close();
|
|
248
|
-
reject(new Error('Login timed out'));
|
|
249
|
-
}, 5 * 60 * 1000);
|
|
250
|
-
});
|
|
222
|
+
throw new Error('Login timed out');
|
|
251
223
|
}
|
|
252
224
|
|
|
253
225
|
export default {
|
package/index.js
CHANGED
|
@@ -992,49 +992,35 @@ program
|
|
|
992
992
|
console.log(banner);
|
|
993
993
|
console.log(chalk.bold.blue('š Login\n'));
|
|
994
994
|
|
|
995
|
-
const configDir = path.join(process.env.HOME, '.ramp');
|
|
996
|
-
const authFile = path.join(configDir, 'auth.json');
|
|
997
|
-
|
|
998
995
|
// Check if already logged in
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
console.log(chalk.dim('\nLogged out.\n'));
|
|
1012
|
-
}
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
} catch {}
|
|
1016
|
-
|
|
1017
|
-
console.log(chalk.dim('Create an account at: https://rampup.dev\n'));
|
|
1018
|
-
|
|
1019
|
-
const { email, token } = await inquirer.prompt([
|
|
1020
|
-
{
|
|
1021
|
-
type: 'input',
|
|
1022
|
-
name: 'email',
|
|
1023
|
-
message: 'Email:'
|
|
1024
|
-
},
|
|
1025
|
-
{
|
|
1026
|
-
type: 'password',
|
|
1027
|
-
name: 'token',
|
|
1028
|
-
message: 'API Token (from rampup.dev/settings):'
|
|
996
|
+
const userInfo = await getUserInfo();
|
|
997
|
+
if (userInfo) {
|
|
998
|
+
console.log(chalk.green(`Already logged in as ${userInfo.email}\n`));
|
|
999
|
+
const { logout } = await inquirer.prompt([{
|
|
1000
|
+
type: 'confirm',
|
|
1001
|
+
name: 'logout',
|
|
1002
|
+
message: 'Log out?',
|
|
1003
|
+
default: false
|
|
1004
|
+
}]);
|
|
1005
|
+
if (logout) {
|
|
1006
|
+
await clearCredentials();
|
|
1007
|
+
console.log(chalk.dim('\nLogged out.\n'));
|
|
1029
1008
|
}
|
|
1030
|
-
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1031
1011
|
|
|
1032
|
-
//
|
|
1033
|
-
|
|
1034
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
1035
|
-
await fs.writeFile(authFile, JSON.stringify({ email, token, created: new Date().toISOString() }, null, 2));
|
|
1012
|
+
// Browser-based OAuth login
|
|
1013
|
+
const spinner = ora('Opening browser for authentication...').start();
|
|
1036
1014
|
|
|
1037
|
-
|
|
1015
|
+
try {
|
|
1016
|
+
const result = await loginWithBrowser();
|
|
1017
|
+
spinner.succeed(chalk.green(`Logged in as ${result.displayName || result.email}`));
|
|
1018
|
+
console.log(chalk.dim('\nYou can now use all Ramp CLI features.\n'));
|
|
1019
|
+
} catch (error) {
|
|
1020
|
+
spinner.fail(chalk.red('Login failed'));
|
|
1021
|
+
console.log(chalk.dim(`\nError: ${error.message}\n`));
|
|
1022
|
+
console.log(chalk.dim('Try again or visit https://app.rampup.dev to create an account.\n'));
|
|
1023
|
+
}
|
|
1038
1024
|
});
|
|
1039
1025
|
|
|
1040
1026
|
program
|