maxpool 1.21.0 → 1.21.2
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/package.json +1 -1
- package/src/index.js +5 -1
- package/src/oauth.js +23 -1
- package/src/tui.js +7 -3
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -29,7 +29,7 @@ net.setDefaultAutoSelectFamilyAttemptTimeout(
|
|
|
29
29
|
);
|
|
30
30
|
import { Prober } from './prober.js';
|
|
31
31
|
import { CapacityLedger } from './capacity-ledger.js';
|
|
32
|
-
import { loginOAuth, fetchProfile, refreshAccessToken, isTokenExpiringSoon, tokenFingerprint } from './oauth.js';
|
|
32
|
+
import { loginOAuth, fetchProfile, refreshAccessToken, isTokenExpiringSoon, tokenFingerprint, isLoginCancelled } from './oauth.js';
|
|
33
33
|
import { TUI } from './tui.js';
|
|
34
34
|
import { RestartController } from './restart-controller.js';
|
|
35
35
|
import { resolveAccounts } from './account-config.js';
|
|
@@ -1637,6 +1637,10 @@ async function loginOAuthCommand() {
|
|
|
1637
1637
|
try {
|
|
1638
1638
|
creds = await loginOAuth();
|
|
1639
1639
|
} catch (err) {
|
|
1640
|
+
if (isLoginCancelled(err)) {
|
|
1641
|
+
console.error('Login cancelled.');
|
|
1642
|
+
process.exit(0);
|
|
1643
|
+
}
|
|
1640
1644
|
console.error(`OAuth login failed: ${err.message}`);
|
|
1641
1645
|
console.error('');
|
|
1642
1646
|
console.error('Alternatives:');
|
package/src/oauth.js
CHANGED
|
@@ -520,6 +520,17 @@ export async function loginOAuth() {
|
|
|
520
520
|
* Race the callback server promise against manual code entry from stdin.
|
|
521
521
|
* The user can paste the full callback URL or just the authorization code.
|
|
522
522
|
*/
|
|
523
|
+
// Rejection sentinel for a user-cancelled login — `err === LOGIN_CANCELLED` (or
|
|
524
|
+
// isLoginCancelled(err)) distinguishes "changed my mind" from a real failure so the
|
|
525
|
+
// UI can say 'cancelled' instead of 'failed' and CLI flows can exit 0 quietly.
|
|
526
|
+
export const LOGIN_CANCELLED = Symbol.for('maxpool.login.cancelled');
|
|
527
|
+
export function isLoginCancelled(err) { return err === LOGIN_CANCELLED; }
|
|
528
|
+
|
|
529
|
+
export function isLoginCancelAnswer(answer) {
|
|
530
|
+
const t = String(answer || '').trim().toLowerCase();
|
|
531
|
+
return t === 'q' || t === 'quit' || t === 'cancel' || t === 'abort' || t === ':q';
|
|
532
|
+
}
|
|
533
|
+
|
|
523
534
|
function raceWithStdinCode(callbackPromise, expectedState) {
|
|
524
535
|
if (!process.stdin.isTTY) return callbackPromise;
|
|
525
536
|
|
|
@@ -534,9 +545,20 @@ function raceWithStdinCode(callbackPromise, expectedState) {
|
|
|
534
545
|
fn(val);
|
|
535
546
|
};
|
|
536
547
|
|
|
537
|
-
|
|
548
|
+
// ESCAPE HATCH (2026-09-20). The login prompt had NO way out: a free-plan account
|
|
549
|
+
// can't complete the OAuth consent, the callback never arrives, and Ctrl+C — with
|
|
550
|
+
// no SIGINT listener on the readline — killed the whole maxpool process (measured:
|
|
551
|
+
// the owner was stuck on this exact screen and had to be told to kill the app).
|
|
552
|
+
// Now: Ctrl+C (first press) and typing q/quit/cancel/abort/:q both reject with a
|
|
553
|
+
// Cancelled sentinel the callers translate into "login cancelled", leaving the
|
|
554
|
+
// app alive. The TUI restarts itself from _doLogin's finally block.
|
|
555
|
+
const cancel = () => settle(reject, LOGIN_CANCELLED);
|
|
556
|
+
rl.on('SIGINT', cancel);
|
|
557
|
+
|
|
558
|
+
rl.question('Paste authorization code here (q or Ctrl+C to cancel): ', answer => {
|
|
538
559
|
const trimmed = answer.trim();
|
|
539
560
|
if (!trimmed) return; // empty input, keep waiting for callback
|
|
561
|
+
if (isLoginCancelAnswer(trimmed)) return cancel();
|
|
540
562
|
|
|
541
563
|
// Try to parse as a URL with ?code= parameter
|
|
542
564
|
try {
|
package/src/tui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createInterface } from 'node:readline';
|
|
2
|
-
import { fetchProfile, loginOAuth, tokenFingerprint } from './oauth.js';
|
|
2
|
+
import { fetchProfile, loginOAuth, tokenFingerprint, isLoginCancelled } from './oauth.js';
|
|
3
3
|
import { appendEventLog, setConsoleStdoutSuppressed } from './event-log.js';
|
|
4
4
|
|
|
5
5
|
// ── ANSI helpers ─────────────────────────────────────────────
|
|
@@ -1335,7 +1335,11 @@ export class TUI {
|
|
|
1335
1335
|
? `\nRe-authenticated "${name}". Returning to maxpool…\n`
|
|
1336
1336
|
: `\nAdded new account "${name}". Returning to maxpool…\n`);
|
|
1337
1337
|
} catch (e) {
|
|
1338
|
-
|
|
1338
|
+
if (isLoginCancelled(e)) {
|
|
1339
|
+
process.stdout.write('\nLogin cancelled.\n');
|
|
1340
|
+
} else {
|
|
1341
|
+
process.stdout.write(`\nLogin failed: ${e.message}\n`);
|
|
1342
|
+
}
|
|
1339
1343
|
} finally {
|
|
1340
1344
|
setConsoleStdoutSuppressed(false); // restore on every path (incl. the catch)
|
|
1341
1345
|
if (wasRunning) this.start();
|
|
@@ -2380,7 +2384,7 @@ export class TUI {
|
|
|
2380
2384
|
return ` ${bold('c')} Check & apply now ${bold('t')} Automatic updates: ${state} ↻ ${bold('Esc')} Back`;
|
|
2381
2385
|
}
|
|
2382
2386
|
case 'accounts':
|
|
2383
|
-
return ` ${bold('a')} Add account ${bold('l')} Re-auth (browser) ${bold('n')} Rename ${bold('t')} Enable/disable ${bold('d')} Delete ${bold('Esc')} Back`;
|
|
2387
|
+
return ` ${bold('a')} Add account ${bold('l')} Re-auth (browser) ${bold('n')} Rename ${bold('t')} Enable/disable ${bold('u')} Usage cap ${bold('d')} Delete ${bold('Esc')} Back`;
|
|
2384
2388
|
case 'addtype':
|
|
2385
2389
|
return ` ${bold('1')}-${bold('4')} pick a type ${bold('Esc')} Back`;
|
|
2386
2390
|
case 'routing': {
|