three-blocks-login 0.1.8 → 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.
Files changed (4) hide show
  1. package/LICENSE +182 -0
  2. package/README.md +1 -1
  3. package/bin/login.js +442 -12
  4. package/package.json +1 -1
package/LICENSE ADDED
@@ -0,0 +1,182 @@
1
+ Three.js Blocks Software License Agreement
2
+
3
+ Proprietary Software — All Rights Reserved
4
+ Copyright (c) 2025 three-blocks
5
+
6
+ ================================================================================
7
+
8
+ LICENSE NOTICE
9
+
10
+ This software and all associated packages, including but not limited to:
11
+ - @three-blocks/core
12
+ - @three-blocks/starter
13
+ - create-three-blocks-starter
14
+ - All related tools, examples, and documentation code
15
+
16
+ are licensed exclusively to active, paid subscribers of the threejs-blocks
17
+ project. Without a valid and current subscription, you are NOT permitted to
18
+ use this software.
19
+
20
+ ================================================================================
21
+
22
+ PERMITTED USAGE (Active Subscribers Only)
23
+
24
+ Subject to maintaining an active, paid subscription, you are granted a
25
+ non-exclusive, non-transferable license to:
26
+
27
+ ✓ Use the software in personal and commercial projects via the public API
28
+ ✓ Deploy applications incorporating the software to production environments
29
+ ✓ Integrate the software into your applications as a functional component
30
+ ✓ Access updates, bug fixes, and new features during active subscription
31
+
32
+ ================================================================================
33
+
34
+ RESTRICTIONS
35
+
36
+ You may NOT:
37
+
38
+ ✗ Reverse engineer, decompile, disassemble, or attempt to derive the source
39
+ code, underlying algorithms, or techniques employed in this software
40
+ ✗ Study, analyze, inspect, or learn from the implementation details, code
41
+ structure, or internal workings of this software
42
+ ✗ Modify, adapt, translate, or create derivative works
43
+ ✗ Copy, share, distribute, publish, or resell any part of the software
44
+ ✗ Sublicense or transfer rights to any third party
45
+ ✗ Remove, alter, or obscure this license header or any copyright notices
46
+ ✗ Use this software after your subscription has expired or been terminated
47
+
48
+ ================================================================================
49
+
50
+ AI AND MACHINE LEARNING PROHIBITION
51
+
52
+ The use of this source code for artificial intelligence and machine learning
53
+ purposes is strictly prohibited. Specifically, you may NOT:
54
+
55
+ ✗ Use this source code, in whole or in part, to train, fine-tune, or develop
56
+ any artificial intelligence models, machine learning systems, or large
57
+ language models (LLMs)
58
+
59
+ ✗ Feed this code into AI-assisted development tools for the purpose of
60
+ generating derivative code or training said tools
61
+
62
+ ✗ Use automated transformation tools or AI systems to create modified versions
63
+ or derivatives of this software
64
+
65
+ ✗ Extract patterns, algorithms, or techniques from this code using automated
66
+ or AI-assisted analysis for incorporation into other software
67
+
68
+ ✗ Use this code as training data for code completion, code generation, or
69
+ code suggestion tools
70
+
71
+ This prohibition extends to any form of automated learning, pattern extraction,
72
+ or knowledge transfer that involves processing this source code through machine
73
+ learning pipelines, regardless of whether the output is used commercially or
74
+ privately.
75
+
76
+ ================================================================================
77
+
78
+ SUBSCRIPTION REQUIREMENT
79
+
80
+ This license is valid only while you maintain an active, paid subscription to
81
+ the threejs-blocks service. Upon expiration or termination of your subscription:
82
+
83
+ 1. Your license to use this software immediately terminates
84
+ 2. You must cease all use of the software
85
+ 3. You must remove the software from all projects and systems
86
+ 4. You must not deploy or distribute any applications containing this software
87
+
88
+ Failure to comply with these requirements constitutes copyright infringement
89
+ and breach of contract.
90
+
91
+ ================================================================================
92
+
93
+ PACKAGE-SPECIFIC NOTES
94
+
95
+ @three-blocks/core:
96
+ - Core library with proprietary algorithms and implementations
97
+ - Protected by code obfuscation and this license
98
+ - UNLICENSED - Subscription required
99
+
100
+ @three-blocks/starter:
101
+ - Starter template for building Three.js applications
102
+ - Includes licensed code and dependencies on @three-blocks/core
103
+ - UNLICENSED - Subscription required
104
+
105
+ create-three-blocks-starter:
106
+ - Scaffolding tool for creating new projects
107
+ - Publicly available for convenience but proprietary
108
+ - UNLICENSED - Creates projects that require subscription
109
+
110
+ three-blocks-login:
111
+ - Authentication helper for accessing private packages
112
+ - MIT Licensed - May be used independently
113
+
114
+ ================================================================================
115
+
116
+ ENFORCEMENT
117
+
118
+ Unauthorized use, reproduction, distribution, or violation of the AI/ML
119
+ prohibition is strictly prohibited and may result in:
120
+
121
+ • Immediate termination of your license and subscription
122
+ • Legal action for copyright infringement
123
+ • Claims for damages and recovery of costs
124
+ • Civil liability under applicable copyright law
125
+ • Criminal penalties under applicable law
126
+
127
+ We employ various technical and legal measures to detect unauthorized use,
128
+ including but not limited to code fingerprinting, usage analytics, and
129
+ regular compliance audits.
130
+
131
+ ================================================================================
132
+
133
+ ACCEPTANCE OF TERMS
134
+
135
+ By using this software, you acknowledge that you have read, understood, and
136
+ agree to be bound by the complete terms of this license agreement.
137
+
138
+ If you do not agree to these terms, you are not authorized to use, access,
139
+ or download this software.
140
+
141
+ ================================================================================
142
+
143
+ DISCLAIMER OF WARRANTY
144
+
145
+ THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
146
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
147
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
148
+
149
+ ================================================================================
150
+
151
+ LIMITATION OF LIABILITY
152
+
153
+ IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR
154
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING
155
+ FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
156
+ IN THE SOFTWARE.
157
+
158
+ ================================================================================
159
+
160
+ CONTACT AND COMPLIANCE
161
+
162
+ For licensing inquiries, subscription management, and compliance questions:
163
+
164
+ Web: https://threejs-blocks.com/license
165
+ Email: support@threejs-blocks.com
166
+
167
+ For license violations or to report unauthorized use:
168
+ Email: legal@threejs-blocks.com
169
+
170
+ ================================================================================
171
+
172
+ GOVERNING LAW
173
+
174
+ This license shall be governed by and construed in accordance with the laws
175
+ of the jurisdiction in which three-blocks operates, without regard to its
176
+ conflict of law provisions.
177
+
178
+ ================================================================================
179
+
180
+ Last Updated: January 2025
181
+ Version: 1.0.0
182
+
package/README.md CHANGED
@@ -9,7 +9,7 @@ Minimal, dependency-free CLI for authenticating to Three Blocks private npm regi
9
9
  npx -y three-blocks-login@latest
10
10
 
11
11
  # Using pnpm (recommended - no warnings)
12
- pnpm dlx three-blocks-login@latest@latest
12
+ npx -y three-blocks-login@latest@latest
13
13
  ```
14
14
 
15
15
  ## Authentication Modes
package/bin/login.js CHANGED
@@ -1,4 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ /*!
3
+ three-blocks-login
4
+ Copyright (c) 2025 three-blocks
5
+ MIT License - See https://threejs-blocks.com/license
6
+ */
2
7
  // Minimal, dependency-free CLI
3
8
  // Node 18+ required (built-in fetch)
4
9
 
@@ -377,9 +382,387 @@ loadEnvFromDotfile( process.cwd() );
377
382
  const BROKER_URL =
378
383
  args.endpoint ||
379
384
  process.env.THREE_BLOCKS_BROKER_URL ||
380
- "https://www.threejs-blocks.com/api/npm/token"; // your Astro broker endpoint
385
+ "https://www.threejs-blocks.com/api/npm/token";
386
+
387
+ const OAUTH_DEVICE_CODE_URL =
388
+ process.env.THREE_BLOCKS_OAUTH_DEVICE_URL ||
389
+ "https://www.threejs-blocks.com/api/cli/device-code";
390
+
391
+ const OAUTH_TOKEN_URL =
392
+ process.env.THREE_BLOCKS_OAUTH_TOKEN_URL ||
393
+ "https://www.threejs-blocks.com/api/cli/token";
394
+
395
+ // Browser login method flag
396
+ const USE_BROWSER_LOGIN = args[ 'browser' ] || args.browser;
397
+ const USE_KEY_LOGIN = args[ 'key' ] || args.key;
398
+
399
+ const openBrowser = async ( url ) => {
400
+
401
+ const { exec } = await import( "node:child_process" );
402
+ const platform = process.platform;
403
+ let command;
404
+
405
+ if ( platform === 'darwin' ) {
406
+
407
+ command = `open "${url}"`;
408
+
409
+ } else if ( platform === 'win32' ) {
410
+
411
+ command = `start "" "${url}"`;
412
+
413
+ } else {
414
+
415
+ // Linux and others
416
+ command = `xdg-open "${url}" || sensible-browser "${url}" || x-www-browser "${url}"`;
417
+
418
+ }
419
+
420
+ return new Promise( ( resolve ) => {
421
+
422
+ exec( command, ( error ) => {
423
+
424
+ resolve( ! error );
425
+
426
+ } );
427
+
428
+ } );
429
+
430
+ };
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
+
504
+ const promptChoice = async ( label, choices ) => {
505
+
506
+ return await new Promise( ( resolve ) => {
507
+
508
+ const stdin = process.stdin;
509
+ const stdout = process.stdout;
510
+ let selected = 0;
511
+ const cleanup = () => {
512
+
513
+ stdin.removeListener( 'data', onData );
514
+ if ( stdin.isTTY ) stdin.setRawMode( false );
515
+ stdin.pause();
516
+
517
+ };
518
+
519
+ const render = () => {
520
+
521
+ // Clear previous lines and redraw
522
+ for ( let i = 0; i < choices.length; i ++ ) {
523
+
524
+ const prefix = i === selected ? cyan( '› ' ) : ' ';
525
+ const text = i === selected ? bold( choices[ i ] ) : dim( choices[ i ] );
526
+ stdout.write( `${prefix}${text}\n` );
527
+
528
+ }
529
+
530
+ };
531
+
532
+ const clearLines = () => {
533
+
534
+ for ( let i = 0; i < choices.length; i ++ ) {
535
+
536
+ readline.moveCursor( stdout, 0, - 1 );
537
+ readline.clearLine( stdout, 0 );
538
+
539
+ }
540
+
541
+ };
542
+
543
+ const onData = ( chunk ) => {
544
+
545
+ const str = String( chunk );
546
+ for ( const ch of str ) {
547
+
548
+ if ( ch === '\u0003' ) {
549
+
550
+ cleanup();
551
+ process.exit( 1 );
552
+
553
+ }
554
+
555
+ if ( ch === '\r' || ch === '\n' ) {
556
+
557
+ cleanup();
558
+ return resolve( selected );
559
+
560
+ }
561
+
562
+ // Arrow keys come as escape sequences
563
+ if ( ch === '\u001b' ) continue;
564
+ if ( ch === '[' ) continue;
565
+ if ( ch === 'A' || ch === 'k' ) {
566
+
567
+ // Up
568
+ clearLines();
569
+ selected = ( selected - 1 + choices.length ) % choices.length;
570
+ render();
571
+
572
+ } else if ( ch === 'B' || ch === 'j' ) {
573
+
574
+ // Down
575
+ clearLines();
576
+ selected = ( selected + 1 ) % choices.length;
577
+ render();
578
+
579
+ } else if ( ch === '\t' || ch === ' ' ) {
580
+
581
+ // Tab or Space to toggle
582
+ clearLines();
583
+ selected = ( selected + 1 ) % choices.length;
584
+ render();
585
+
586
+ } else if ( ch === '1' ) {
587
+
588
+ cleanup();
589
+ return resolve( 0 );
590
+
591
+ } else if ( ch === '2' ) {
592
+
593
+ cleanup();
594
+ return resolve( 1 );
595
+
596
+ }
597
+
598
+ }
599
+
600
+ };
601
+
602
+ stdout.write( `${label}\n` );
603
+ render();
604
+ stdin.setEncoding( 'utf8' );
605
+ if ( stdin.isTTY ) stdin.setRawMode( true );
606
+ stdin.resume();
607
+ stdin.on( 'data', onData );
608
+
609
+ } );
610
+
611
+ };
612
+
613
+ const startDeviceCodeFlow = async () => {
614
+
615
+ logDebug( `POST ${OAUTH_DEVICE_CODE_URL}` );
616
+ const res = await fetch( OAUTH_DEVICE_CODE_URL, {
617
+ method: 'POST',
618
+ headers: {
619
+ 'content-type': 'application/json',
620
+ 'accept': 'application/json',
621
+ },
622
+ body: JSON.stringify( { client_id: 'three-blocks-cli' } ),
623
+ } );
624
+
625
+ if ( ! res.ok ) {
626
+
627
+ const text = await res.text().catch( () => '' );
628
+ throw new CliError(
629
+ `Failed to start browser login (HTTP ${res.status})`,
630
+ { suggestion: 'Check your network connection and try again.', stdout: text }
631
+ );
632
+
633
+ }
634
+
635
+ return await res.json();
636
+
637
+ };
638
+
639
+ const pollForToken = async ( deviceCode, interval, expiresIn ) => {
640
+
641
+ const startTime = Date.now();
642
+ const expiresAt = startTime + ( expiresIn * 1000 );
643
+ let pollInterval = interval * 1000;
644
+
645
+ while ( Date.now() < expiresAt ) {
646
+
647
+ await new Promise( ( r ) => setTimeout( r, pollInterval ) );
648
+
649
+ logDebug( `Polling ${OAUTH_TOKEN_URL} for token...` );
650
+ const res = await fetch( OAUTH_TOKEN_URL, {
651
+ method: 'POST',
652
+ headers: {
653
+ 'content-type': 'application/json',
654
+ 'accept': 'application/json',
655
+ },
656
+ body: JSON.stringify( { device_code: deviceCode } ),
657
+ } );
658
+
659
+ const data = await res.json().catch( () => ( {} ) );
660
+
661
+ if ( res.ok && data.access_token ) {
662
+
663
+ return data.access_token;
664
+
665
+ }
666
+
667
+ if ( data.error === 'authorization_pending' ) {
668
+
669
+ // User hasn't authorized yet, keep polling
670
+ continue;
671
+
672
+ }
673
+
674
+ if ( data.error === 'slow_down' ) {
675
+
676
+ // Increase polling interval
677
+ pollInterval += 1000;
678
+ continue;
679
+
680
+ }
681
+
682
+ if ( data.error === 'expired_token' ) {
683
+
684
+ throw new CliError(
685
+ 'Browser login timed out. Please try again.',
686
+ { suggestion: 'Run the login command again and complete authorization in your browser.' }
687
+ );
688
+
689
+ }
690
+
691
+ if ( data.error ) {
692
+
693
+ throw new CliError(
694
+ `Browser login failed: ${data.error_description || data.error}`,
695
+ { suggestion: 'Try again or use the secret key method instead.' }
696
+ );
697
+
698
+ }
699
+
700
+ }
701
+
702
+ throw new CliError(
703
+ 'Browser login timed out.',
704
+ { suggestion: 'Run the login command again and complete authorization within 15 minutes.' }
705
+ );
706
+
707
+ };
708
+
709
+ const browserLogin = async () => {
710
+
711
+ log.info( bold( cyan( 'Three Blocks CLI' ) ) + ' ' + dim( `[mode: ${MODE}]` ) );
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...' ) );
715
+ console.log( '' );
716
+
717
+ // Start device code flow
718
+ let deviceData;
719
+ let browserOpened = false;
720
+ try {
721
+
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.' );
727
+
728
+ } catch ( error ) {
729
+
730
+ if ( openSpinner.enabled ) openSpinner.fail( 'Failed to start browser login.' );
731
+ throw error;
732
+
733
+ }
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
+
739
+ console.log( '' );
740
+ log.info( yellow( 'Browser didn\'t open? Use the URL below to sign in:' ) );
741
+ console.log( '' );
742
+ console.log( ` ${cyan( verification_uri_complete || verification_uri )}` );
743
+ console.log( '' );
744
+ log.info( dim( 'Waiting for authorization...' ) );
745
+
746
+ const waitSpinner = createSpinner();
747
+ if ( waitSpinner.enabled ) waitSpinner.start( 'Waiting for browser authorization...' );
748
+
749
+ try {
750
+
751
+ const licenseKey = await pollForToken( device_code, interval || 2, expires_in || 900 );
752
+ if ( waitSpinner.enabled ) waitSpinner.succeed( 'Authorization successful!' );
753
+ else log.ok( green( 'Authorization successful!' ) );
754
+ console.log( '' );
755
+ return licenseKey;
756
+
757
+ } catch ( error ) {
758
+
759
+ if ( waitSpinner.enabled ) waitSpinner.fail( 'Authorization failed.' );
760
+ throw error;
761
+
762
+ }
763
+
764
+ };
381
765
 
382
- console.log( BROKER_URL );
383
766
  const promptHidden = async ( label ) => {
384
767
 
385
768
  return await new Promise( ( resolve ) => {
@@ -490,15 +873,46 @@ const log = {
490
873
 
491
874
  console.log( '' );
492
875
  log.info( bold( yellow( 'Three Blocks Login' ) ) + ' ' + dim( `[mode: ${MODE}]` ) );
493
- log.info( dim( 'Enter your license key to retrieve a scoped npm token.' ) );
494
- log.info( dim( 'Tip: paste it here; input is hidden. Press Enter to submit.' ) );
495
- LICENSE = await promptHidden( `${cyan( '›' )} License key ${dim( '(tb_…)' )}: ` );
496
- if ( ! LICENSE ) {
876
+ console.log( '' );
497
877
 
498
- fail(
499
- "License key is required to continue.",
500
- { suggestion: "Paste your tb_… key or rerun with --license." }
501
- );
878
+ // Determine login method
879
+ let useBrowserLogin = USE_BROWSER_LOGIN;
880
+ let useKeyLogin = USE_KEY_LOGIN;
881
+
882
+ // If neither flag is set and we're interactive, show menu
883
+ if ( ! useBrowserLogin && ! useKeyLogin ) {
884
+
885
+ log.info( dim( 'Select login method:' ) );
886
+ console.log( '' );
887
+ const choice = await promptChoice( '', [
888
+ 'Log in with Three Blocks account (opens browser)',
889
+ 'Paste Secret Key manually'
890
+ ] );
891
+ console.log( '' );
892
+ useBrowserLogin = choice === 0;
893
+ useKeyLogin = choice === 1;
894
+
895
+ }
896
+
897
+ if ( useBrowserLogin ) {
898
+
899
+ // Browser-based OAuth login
900
+ LICENSE = await browserLogin();
901
+
902
+ } else {
903
+
904
+ // Manual secret key entry
905
+ log.info( dim( 'Enter your license key to retrieve a scoped npm token.' ) );
906
+ log.info( dim( 'Tip: paste it here; input is hidden. Press Enter to submit.' ) );
907
+ LICENSE = await promptHidden( `${cyan( '›' )} License key ${dim( '(tb_…)' )}: ` );
908
+ if ( ! LICENSE ) {
909
+
910
+ fail(
911
+ "License key is required to continue.",
912
+ { suggestion: "Paste your tb_… key or rerun with --license." }
913
+ );
914
+
915
+ }
502
916
 
503
917
  }
504
918
 
@@ -536,7 +950,21 @@ const log = {
536
950
 
537
951
  }
538
952
 
539
- const tokenData = await fetchToken( BROKER_URL, LICENSE_CLEAN, CHANNEL );
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
+
540
968
  const {
541
969
  registry,
542
970
  token,
@@ -877,7 +1305,9 @@ async function fetchToken( endpoint, license, channel ) {
877
1305
  let suggestion = "Request failed. Please retry.";
878
1306
  if ( res.status === 401 || res.status === 403 ) {
879
1307
 
880
- suggestion = "Authentication failed. Verify your license or access rights.";
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.";
881
1311
 
882
1312
  } else if ( res.status === 404 ) {
883
1313
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-blocks-login",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Fetch a short-lived token from the three-blocks broker and configure npm for the current context.",
5
5
  "type": "module",
6
6
  "bin": {