three-blocks-login 0.1.9 → 0.1.10
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/bin/login.js +114 -24
- package/package.json +1 -1
package/bin/login.js
CHANGED
|
@@ -382,7 +382,7 @@ loadEnvFromDotfile( process.cwd() );
|
|
|
382
382
|
const BROKER_URL =
|
|
383
383
|
args.endpoint ||
|
|
384
384
|
process.env.THREE_BLOCKS_BROKER_URL ||
|
|
385
|
-
"https://www.threejs-blocks.com/api/npm/token";
|
|
385
|
+
"https://www.threejs-blocks.com/api/npm/token";
|
|
386
386
|
|
|
387
387
|
const OAUTH_DEVICE_CODE_URL =
|
|
388
388
|
process.env.THREE_BLOCKS_OAUTH_DEVICE_URL ||
|
|
@@ -429,6 +429,78 @@ const openBrowser = async ( url ) => {
|
|
|
429
429
|
|
|
430
430
|
};
|
|
431
431
|
|
|
432
|
+
const createSpinner = ( { stream = process.stderr } = {} ) => {
|
|
433
|
+
|
|
434
|
+
const enabled = !! ( stream?.isTTY && ! QUIET && ! NON_INTERACTIVE );
|
|
435
|
+
const frames = [ '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' ];
|
|
436
|
+
let idx = 0;
|
|
437
|
+
let timer = null;
|
|
438
|
+
let text = '';
|
|
439
|
+
|
|
440
|
+
const clearLine = () => {
|
|
441
|
+
|
|
442
|
+
if ( ! enabled ) return;
|
|
443
|
+
try {
|
|
444
|
+
|
|
445
|
+
readline.clearLine( stream, 0 );
|
|
446
|
+
readline.cursorTo( stream, 0 );
|
|
447
|
+
|
|
448
|
+
} catch {
|
|
449
|
+
|
|
450
|
+
// best effort
|
|
451
|
+
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const render = () => {
|
|
457
|
+
|
|
458
|
+
if ( ! enabled ) return;
|
|
459
|
+
const frame = frames[ idx ];
|
|
460
|
+
idx = ( idx + 1 ) % frames.length;
|
|
461
|
+
clearLine();
|
|
462
|
+
stream.write( `${cyan( frame )} ${text}` );
|
|
463
|
+
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
const stop = () => {
|
|
467
|
+
|
|
468
|
+
if ( timer ) clearInterval( timer );
|
|
469
|
+
timer = null;
|
|
470
|
+
clearLine();
|
|
471
|
+
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const start = ( nextText ) => {
|
|
475
|
+
|
|
476
|
+
if ( ! enabled ) return;
|
|
477
|
+
text = String( nextText ?? '' );
|
|
478
|
+
idx = 0;
|
|
479
|
+
render();
|
|
480
|
+
timer = setInterval( render, 80 );
|
|
481
|
+
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
const succeed = ( msg ) => {
|
|
485
|
+
|
|
486
|
+
if ( ! enabled ) return;
|
|
487
|
+
stop();
|
|
488
|
+
stream.write( `${green( "✔" )} ${msg || text}\n` );
|
|
489
|
+
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
const fail = ( msg ) => {
|
|
493
|
+
|
|
494
|
+
if ( ! enabled ) return;
|
|
495
|
+
stop();
|
|
496
|
+
stream.write( `${red( "✖" )} ${msg || text}\n` );
|
|
497
|
+
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
return { enabled, start, stop, succeed, fail };
|
|
501
|
+
|
|
502
|
+
};
|
|
503
|
+
|
|
432
504
|
const promptChoice = async ( label, choices ) => {
|
|
433
505
|
|
|
434
506
|
return await new Promise( ( resolve ) => {
|
|
@@ -637,22 +709,33 @@ const pollForToken = async ( deviceCode, interval, expiresIn ) => {
|
|
|
637
709
|
const browserLogin = async () => {
|
|
638
710
|
|
|
639
711
|
log.info( bold( cyan( 'Three Blocks CLI' ) ) + ' ' + dim( `[mode: ${MODE}]` ) );
|
|
640
|
-
|
|
712
|
+
const openSpinner = createSpinner();
|
|
713
|
+
if ( openSpinner.enabled ) openSpinner.start( 'Opening browser to log in...' );
|
|
714
|
+
else log.info( dim( 'Opening browser to log in...' ) );
|
|
641
715
|
console.log( '' );
|
|
642
716
|
|
|
643
717
|
// Start device code flow
|
|
644
|
-
|
|
645
|
-
|
|
718
|
+
let deviceData;
|
|
719
|
+
let browserOpened = false;
|
|
720
|
+
try {
|
|
646
721
|
|
|
647
|
-
|
|
648
|
-
|
|
722
|
+
deviceData = await startDeviceCodeFlow();
|
|
723
|
+
const { verification_uri, verification_uri_complete } = deviceData;
|
|
724
|
+
// Try to open browser
|
|
725
|
+
browserOpened = await openBrowser( verification_uri_complete || verification_uri );
|
|
726
|
+
if ( openSpinner.enabled ) openSpinner.succeed( browserOpened ? 'Browser opened.' : 'Login URL ready.' );
|
|
649
727
|
|
|
650
|
-
|
|
728
|
+
} catch ( error ) {
|
|
651
729
|
|
|
652
|
-
|
|
730
|
+
if ( openSpinner.enabled ) openSpinner.fail( 'Failed to start browser login.' );
|
|
731
|
+
throw error;
|
|
653
732
|
|
|
654
733
|
}
|
|
655
734
|
|
|
735
|
+
const { device_code, verification_uri, verification_uri_complete, expires_in, interval } = deviceData;
|
|
736
|
+
|
|
737
|
+
if ( ! browserOpened ) log.warn( 'Could not open browser automatically.' );
|
|
738
|
+
|
|
656
739
|
console.log( '' );
|
|
657
740
|
log.info( yellow( 'Browser didn\'t open? Use the URL below to sign in:' ) );
|
|
658
741
|
console.log( '' );
|
|
@@ -660,29 +743,20 @@ const browserLogin = async () => {
|
|
|
660
743
|
console.log( '' );
|
|
661
744
|
log.info( dim( 'Waiting for authorization...' ) );
|
|
662
745
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
let spinnerIdx = 0;
|
|
666
|
-
const spinnerInterval = setInterval( () => {
|
|
667
|
-
|
|
668
|
-
process.stdout.write( `\r${cyan( spinnerFrames[ spinnerIdx ] )} Waiting for browser authorization...` );
|
|
669
|
-
spinnerIdx = ( spinnerIdx + 1 ) % spinnerFrames.length;
|
|
670
|
-
|
|
671
|
-
}, 100 );
|
|
746
|
+
const waitSpinner = createSpinner();
|
|
747
|
+
if ( waitSpinner.enabled ) waitSpinner.start( 'Waiting for browser authorization...' );
|
|
672
748
|
|
|
673
749
|
try {
|
|
674
750
|
|
|
675
751
|
const licenseKey = await pollForToken( device_code, interval || 2, expires_in || 900 );
|
|
676
|
-
|
|
677
|
-
|
|
752
|
+
if ( waitSpinner.enabled ) waitSpinner.succeed( 'Authorization successful!' );
|
|
753
|
+
else log.ok( green( 'Authorization successful!' ) );
|
|
678
754
|
console.log( '' );
|
|
679
|
-
log.ok( green( 'Authorization successful!' ) );
|
|
680
755
|
return licenseKey;
|
|
681
756
|
|
|
682
757
|
} catch ( error ) {
|
|
683
758
|
|
|
684
|
-
|
|
685
|
-
process.stdout.write( '\r' + ' '.repeat( 50 ) + '\r' );
|
|
759
|
+
if ( waitSpinner.enabled ) waitSpinner.fail( 'Authorization failed.' );
|
|
686
760
|
throw error;
|
|
687
761
|
|
|
688
762
|
}
|
|
@@ -876,7 +950,21 @@ const log = {
|
|
|
876
950
|
|
|
877
951
|
}
|
|
878
952
|
|
|
879
|
-
const
|
|
953
|
+
const brokerSpinner = createSpinner();
|
|
954
|
+
if ( brokerSpinner.enabled ) brokerSpinner.start( 'Verifying secret key with broker...' );
|
|
955
|
+
let tokenData;
|
|
956
|
+
try {
|
|
957
|
+
|
|
958
|
+
tokenData = await fetchToken( BROKER_URL, LICENSE_CLEAN, CHANNEL );
|
|
959
|
+
if ( brokerSpinner.enabled ) brokerSpinner.succeed( 'Broker verified secret key.' );
|
|
960
|
+
|
|
961
|
+
} catch ( error ) {
|
|
962
|
+
|
|
963
|
+
if ( brokerSpinner.enabled ) brokerSpinner.fail( 'Broker verification failed.' );
|
|
964
|
+
throw error;
|
|
965
|
+
|
|
966
|
+
}
|
|
967
|
+
|
|
880
968
|
const {
|
|
881
969
|
registry,
|
|
882
970
|
token,
|
|
@@ -1217,7 +1305,9 @@ async function fetchToken( endpoint, license, channel ) {
|
|
|
1217
1305
|
let suggestion = "Request failed. Please retry.";
|
|
1218
1306
|
if ( res.status === 401 || res.status === 403 ) {
|
|
1219
1307
|
|
|
1220
|
-
suggestion = "Authentication failed.
|
|
1308
|
+
suggestion = "Authentication failed. The broker did not accept your license key. "
|
|
1309
|
+
+ "If THREE_BLOCKS_SECRET_KEY (or a local .env) is set, verify it contains your active tb_… key, "
|
|
1310
|
+
+ "or unset it to be prompted again.";
|
|
1221
1311
|
|
|
1222
1312
|
} else if ( res.status === 404 ) {
|
|
1223
1313
|
|