rampup 0.1.2 → 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/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 {
|