three-blocks-login 0.1.9 → 0.1.11

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 (3) hide show
  1. package/LICENSE +199 -74
  2. package/bin/login.js +134 -178
  3. package/package.json +1 -1
package/LICENSE CHANGED
@@ -1,7 +1,10 @@
1
1
  Three.js Blocks Software License Agreement
2
+ Version 2.0 — Effective January 2026
2
3
 
3
4
  Proprietary Software — All Rights Reserved
4
- Copyright (c) 2025 three-blocks
5
+ Copyright (c) 2026 three-blocks
6
+
7
+ Full License Terms: https://threejs-blocks.com/license
5
8
 
6
9
  ================================================================================
7
10
 
@@ -9,25 +12,26 @@ LICENSE NOTICE
9
12
 
10
13
  This software and all associated packages, including but not limited to:
11
14
  - @three-blocks/core
15
+ - @three-blocks/pro
12
16
  - @three-blocks/starter
13
17
  - create-three-blocks-starter
14
18
  - All related tools, examples, and documentation code
15
19
 
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
20
+ are licensed exclusively to active, paid subscribers of the Three.js Blocks
21
+ project. Without a valid and current subscription, you are NOT permitted to
18
22
  use this software.
19
23
 
20
24
  ================================================================================
21
25
 
22
26
  PERMITTED USAGE (Active Subscribers Only)
23
27
 
24
- Subject to maintaining an active, paid subscription, you are granted a
25
- non-exclusive, non-transferable license to:
28
+ Subject to maintaining an active, paid subscription, you are granted a
29
+ non-exclusive, non-transferable, non-sublicensable license to:
26
30
 
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
+ + Use the software in personal and commercial projects via the public API
32
+ + Deploy applications incorporating the software to production environments
33
+ + Integrate the software into your applications as a functional component
34
+ + Access updates, bug fixes, and new features during active subscription
31
35
 
32
36
  ================================================================================
33
37
 
@@ -35,58 +39,112 @@ RESTRICTIONS
35
39
 
36
40
  You may NOT:
37
41
 
38
- Reverse engineer, decompile, disassemble, or attempt to derive the source
42
+ - Reverse engineer, decompile, disassemble, or attempt to derive the source
39
43
  code, underlying algorithms, or techniques employed in this software
40
- Study, analyze, inspect, or learn from the implementation details, code
44
+ - Study, analyze, inspect, or learn from the implementation details, code
41
45
  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
46
+ - Modify, adapt, translate, or create derivative works
47
+ - Copy, share, distribute, publish, or resell any part of the software
48
+ - Sublicense or transfer rights to any third party
49
+ - Remove, alter, or obscure this license header or any copyright notices
50
+ - Use this software after your subscription has expired or been terminated
47
51
 
48
52
  ================================================================================
49
53
 
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
+ SUBLICENSING AND REDISTRIBUTION PROHIBITION
55
+
56
+ This license is strictly non-transferable and non-sublicensable. You may NOT:
57
+
58
+ - Sublicense, relicense, or transfer any rights granted herein to any third
59
+ party under any circumstances
60
+ - Create any SDK, library, framework, plugin, extension, or middleware that
61
+ redistributes, bundles, or incorporates this software for use by third
62
+ parties
63
+ - Bundle this software into products, applications, or services where
64
+ end-users do not hold their own valid subscription to Three.js Blocks
65
+ - Offer this software as part of any hosted service, software-as-a-service
66
+ (SaaS), platform-as-a-service (PaaS), or similar cloud-based offering
67
+ where third parties access the software's functionality
68
+ - Create wrapper libraries, abstraction layers, or integration packages that
69
+ obscure, circumvent, or eliminate the subscription requirement from
70
+ downstream users
71
+ - Include this software in any product, template, boilerplate, starter kit,
72
+ code generator, or scaffolding tool intended for distribution to third
73
+ parties
74
+ - Provide access to this software through any API, service endpoint, or
75
+ programmatic interface that enables third-party usage
76
+ - License, sell, rent, lease, or otherwise commercially exploit access to
77
+ this software to any third party
78
+
79
+ THIRD-PARTY INTEGRATION REQUIREMENT:
80
+ If you develop any software, SDK, library, framework, application, or service
81
+ that incorporates, depends upon, or integrates with this software, each
82
+ end-user of your software must independently hold their own valid, active
83
+ subscription to Three.js Blocks. You may not use your subscription to provide,
84
+ enable, or facilitate access to this software to any third party. Any attempt
85
+ to circumvent this requirement through technical or contractual means is
86
+ expressly prohibited and constitutes a material breach of this license.
54
87
 
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
88
+ ================================================================================
70
89
 
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.
90
+ AI, MACHINE LEARNING, AND AUTOMATED ANALYSIS PROHIBITION
91
+
92
+ The use of this software, source code, compiled code, documentation, outputs,
93
+ or any data generated by this software for artificial intelligence, machine
94
+ learning, or automated analysis purposes is strictly prohibited. You may NOT:
95
+
96
+ - Use this code, in whole or in part, to train, fine-tune, pre-train, or
97
+ develop any artificial intelligence models, machine learning systems,
98
+ neural networks, or large language models (LLMs)
99
+ - Use this code for reinforcement learning from human feedback (RLHF),
100
+ constitutional AI training, or any similar AI alignment or training
101
+ methodology
102
+ - Create embeddings, vector representations, semantic indices, or any other
103
+ mathematical or computational representations of this code
104
+ - Store this code in vector databases, retrieval systems, knowledge bases,
105
+ or any storage mechanism intended for AI/ML retrieval-augmented generation
106
+ (RAG) or similar AI-assisted retrieval
107
+ - Generate synthetic data, pseudocode, paraphrased code, or derivative
108
+ representations from this codebase for any purpose
109
+ - Use automated tools, scripts, or AI systems to extract patterns,
110
+ algorithms, architectural knowledge, or implementation techniques from
111
+ this software
112
+ - Input this code into AI coding assistants, code completion tools, or
113
+ any AI-powered development environment for the purpose of analysis,
114
+ learning, pattern extraction, or code generation
115
+ - Use this code as context, examples, few-shot prompts, or reference
116
+ material for AI code generation, code completion, or code suggestion
117
+ - Feed this code into any automated transformation tool, transpiler, or
118
+ code converter that uses AI/ML techniques
119
+ - Use any output, behavior, or data generated by this software to train
120
+ or improve any AI/ML system
121
+
122
+ This prohibition applies to all AI/ML systems including but not limited to:
123
+ large language models (LLMs), code completion tools (e.g., GitHub Copilot,
124
+ Amazon CodeWhisperer, and similar tools), code generation systems, neural
125
+ networks, transformer models, diffusion models, and any future AI technologies
126
+ regardless of their architecture or methodology.
127
+
128
+ This prohibition is perpetual and survives any termination or expiration of
129
+ this license agreement.
75
130
 
76
131
  ================================================================================
77
132
 
78
133
  SUBSCRIPTION REQUIREMENT
79
134
 
80
135
  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:
136
+ the Three.js Blocks service. Upon expiration or termination of your
137
+ subscription:
82
138
 
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
139
+ 1. Your license to use this software immediately and automatically terminates
140
+ 2. You must immediately cease all use of the software
141
+ 3. You must remove the software from all projects, systems, and deployments
142
+ 4. You must not deploy, distribute, or make available any applications
143
+ containing this software
144
+ 5. You must delete all copies of this software in your possession or control
87
145
 
88
146
  Failure to comply with these requirements constitutes copyright infringement
89
- and breach of contract.
147
+ and breach of contract, and may result in legal action.
90
148
 
91
149
  ================================================================================
92
150
 
@@ -95,48 +153,73 @@ PACKAGE-SPECIFIC NOTES
95
153
  @three-blocks/core:
96
154
  - Core library with proprietary algorithms and implementations
97
155
  - Protected by code obfuscation and this license
98
- - UNLICENSED - Subscription required
156
+ - Subscription required
157
+
158
+ @three-blocks/pro:
159
+ - Advanced physics engine with proprietary implementations
160
+ - Worker-based architecture with SharedArrayBuffer
161
+ - Protected by code obfuscation and this license
162
+ - Subscription required
99
163
 
100
164
  @three-blocks/starter:
101
165
  - Starter template for building Three.js applications
102
166
  - Includes licensed code and dependencies on @three-blocks/core
103
- - UNLICENSED - Subscription required
167
+ - Subscription required
104
168
 
105
169
  create-three-blocks-starter:
106
170
  - Scaffolding tool for creating new projects
107
171
  - 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
172
+ - Creates projects that require subscription
113
173
 
114
174
  ================================================================================
115
175
 
116
176
  ENFORCEMENT
117
177
 
118
- Unauthorized use, reproduction, distribution, or violation of the AI/ML
119
- prohibition is strictly prohibited and may result in:
178
+ Unauthorized use, reproduction, distribution, reverse engineering, sublicensing,
179
+ or violation of the AI/ML prohibition is strictly prohibited and may result in:
120
180
 
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
181
+ * Immediate termination of your license and subscription without refund
182
+ * Legal action for copyright infringement
183
+ * Legal action for breach of contract
184
+ * Claims for damages, including actual damages, lost profits, and statutory
185
+ damages where available
186
+ * Recovery of attorneys' fees and costs of enforcement
187
+ * Injunctive relief to prevent further unauthorized use
188
+ * Civil liability under applicable copyright, trade secret, and contract law
189
+ * Criminal penalties under applicable law, including but not limited to the
190
+ Computer Fraud and Abuse Act (CFAA) and equivalent international statutes
126
191
 
127
192
  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.
193
+ including but not limited to code fingerprinting, license validation, usage
194
+ analytics, and regular compliance audits. We reserve the right to pursue all
195
+ available legal remedies against violators.
196
+
197
+ ================================================================================
198
+
199
+ INDEMNIFICATION
200
+
201
+ You agree to indemnify, defend, and hold harmless three-blocks, its affiliates,
202
+ officers, directors, employees, and agents from and against any and all claims,
203
+ damages, obligations, losses, liabilities, costs, and expenses (including
204
+ reasonable attorneys' fees) arising from: (a) your use of the software;
205
+ (b) your violation of any term of this license; (c) your violation of any
206
+ third-party right, including any intellectual property or privacy right; or
207
+ (d) any claim that your use of the software caused damage to a third party.
130
208
 
131
209
  ================================================================================
132
210
 
133
211
  ACCEPTANCE OF TERMS
134
212
 
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.
213
+ By downloading, installing, copying, accessing, or otherwise using this
214
+ software, you acknowledge that you have read, understood, and agree to be
215
+ bound by the complete terms of this license agreement.
137
216
 
138
217
  If you do not agree to these terms, you are not authorized to use, access,
139
- or download this software.
218
+ download, install, or copy this software.
219
+
220
+ If you are accepting these terms on behalf of an organization, you represent
221
+ and warrant that you have the authority to bind that organization to these
222
+ terms.
140
223
 
141
224
  ================================================================================
142
225
 
@@ -144,16 +227,56 @@ DISCLAIMER OF WARRANTY
144
227
 
145
228
  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
146
229
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
147
- FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
230
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NONINFRINGEMENT.
231
+
232
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU.
233
+ SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
234
+ SERVICING, REPAIR, OR CORRECTION.
148
235
 
149
236
  ================================================================================
150
237
 
151
238
  LIMITATION OF LIABILITY
152
239
 
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.
240
+ IN NO EVENT SHALL THREE-BLOCKS, ITS AFFILIATES, LICENSORS, OR SUPPLIERS BE
241
+ LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, OR
242
+ EXEMPLARY DAMAGES, INCLUDING BUT NOT LIMITED TO DAMAGES FOR LOSS OF PROFITS,
243
+ GOODWILL, USE, DATA, OR OTHER INTANGIBLE LOSSES, ARISING OUT OF OR IN
244
+ CONNECTION WITH THIS LICENSE OR THE USE OR INABILITY TO USE THE SOFTWARE,
245
+ EVEN IF THREE-BLOCKS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
246
+
247
+ IN NO EVENT SHALL THREE-BLOCKS'S TOTAL CUMULATIVE LIABILITY TO YOU FOR ALL
248
+ CLAIMS ARISING OUT OF OR RELATED TO THIS LICENSE OR THE SOFTWARE EXCEED THE
249
+ AMOUNTS PAID BY YOU TO THREE-BLOCKS FOR THE SOFTWARE DURING THE TWELVE (12)
250
+ MONTHS IMMEDIATELY PRECEDING THE EVENT GIVING RISE TO LIABILITY.
251
+
252
+ SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
253
+ CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU.
254
+
255
+ ================================================================================
256
+
257
+ SEVERABILITY
258
+
259
+ If any provision of this license is held to be unenforceable or invalid, that
260
+ provision shall be enforced to the maximum extent possible, and the other
261
+ provisions shall remain in full force and effect.
262
+
263
+ ================================================================================
264
+
265
+ WAIVER
266
+
267
+ The failure of three-blocks to enforce any right or provision of this license
268
+ shall not constitute a waiver of such right or provision. No waiver of any
269
+ term of this license shall be deemed a further or continuing waiver of such
270
+ term or any other term.
271
+
272
+ ================================================================================
273
+
274
+ ENTIRE AGREEMENT
275
+
276
+ This license constitutes the entire agreement between you and three-blocks
277
+ regarding the software and supersedes all prior agreements, understandings,
278
+ and communications, whether written or oral, regarding the subject matter
279
+ hereof.
157
280
 
158
281
  ================================================================================
159
282
 
@@ -169,14 +292,16 @@ For license violations or to report unauthorized use:
169
292
 
170
293
  ================================================================================
171
294
 
172
- GOVERNING LAW
295
+ GOVERNING LAW AND JURISDICTION
173
296
 
174
297
  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.
298
+ of Japan, without regard to its conflict of law provisions. Any dispute arising
299
+ out of or relating to this license or the software shall be subject to the
300
+ exclusive jurisdiction of the courts located in Tokyo, Japan, and you hereby
301
+ consent to the personal jurisdiction of such courts.
177
302
 
178
303
  ================================================================================
179
304
 
180
- Last Updated: January 2025
181
- Version: 1.0.0
305
+ Last Updated: January 2026
306
+ Version: 2.0
182
307
 
package/bin/login.js CHANGED
@@ -24,7 +24,6 @@ const bold = ( s ) => ESC( 1 ) + s + reset;
24
24
  const dim = ( s ) => ESC( 2 ) + s + reset;
25
25
  const red = ( s ) => ESC( 31 ) + s + reset;
26
26
  const green = ( s ) => ESC( 32 ) + s + reset;
27
- const yellow = ( s ) => ESC( 33 ) + s + reset;
28
27
  const cyan = ( s ) => ESC( 36 ) + s + reset;
29
28
  const plainBanner = `[three-blocks-login@${pkg.version}]`;
30
29
  const banner = cyan( plainBanner );
@@ -106,90 +105,6 @@ const quoteArg = ( value ) => {
106
105
 
107
106
  const formatCommand = ( cmd, args = [] ) => [ cmd, ...args ].map( quoteArg ).join( " " );
108
107
 
109
- const HEADER_WIDTH = 96;
110
- const LEFT_WIDTH = 60;
111
- const RIGHT_WIDTH = HEADER_WIDTH - LEFT_WIDTH - 3;
112
-
113
- const repeatChar = ( ch, len ) => ch.repeat( Math.max( 0, len ) );
114
- const stripAnsi = ( value ) => String( value ?? '' ).replace( /\u001b\[[0-9;]*m/g, '' );
115
- const ellipsize = ( value, width ) => {
116
-
117
- const str = String( value ?? '' );
118
- const plain = stripAnsi( str );
119
- if ( plain.length <= width ) return str;
120
- if ( width <= 1 ) return plain.slice( 0, width );
121
- const truncated = plain.slice( 0, width - 1 ) + '…';
122
- return plain === str ? truncated : truncated;
123
-
124
- };
125
-
126
- const visibleLength = ( value ) => stripAnsi( String( value ?? '' ) ).length;
127
- const padText = ( value, width, align = 'left' ) => {
128
-
129
- const text = ellipsize( value, width );
130
- const current = visibleLength( text );
131
- const remaining = width - current;
132
- if ( remaining <= 0 ) return text;
133
- if ( align === 'center' ) {
134
-
135
- const left = Math.floor( remaining / 2 );
136
- const right = remaining - left;
137
- return `${' '.repeat( left )}${text}${' '.repeat( right )}`;
138
-
139
- }
140
-
141
- if ( align === 'right' ) {
142
-
143
- return `${' '.repeat( remaining )}${text}`;
144
-
145
- }
146
-
147
- return `${text}${' '.repeat( remaining )}`;
148
-
149
- };
150
-
151
- const makeHeaderRow = ( left, right = '', leftAlign = 'left', rightAlign = 'left' ) =>
152
- `│${padText( left, LEFT_WIDTH, leftAlign )}│${padText( right, RIGHT_WIDTH, rightAlign )}│`;
153
-
154
- const HEADER_COLOR = ESC( 33 );
155
- const CONTENT_COLOR = ESC( 90 ); // bright black (grey)
156
- const reapplyColor = ( value, color ) => {
157
-
158
- const str = String( value ?? '' );
159
- return `${color}${str.split( reset ).join( `${reset}${color}` )}${reset}`;
160
-
161
- };
162
-
163
- const applyHeaderColor = ( row, { keepContentYellow = false, tintContent = true } = {} ) => {
164
-
165
- if ( keepContentYellow ) return reapplyColor( row, HEADER_COLOR );
166
- if ( ! row.startsWith( '│' ) || ! row.endsWith( '│' ) ) return reapplyColor( row, HEADER_COLOR );
167
- const match = row.match( /^│(.*)│(.*)│$/ );
168
- if ( ! match ) return reapplyColor( row, HEADER_COLOR );
169
- const [ , leftContent, rightContent ] = match;
170
- const leftSegment = tintContent ? reapplyColor( leftContent, CONTENT_COLOR ) : leftContent;
171
- const rightSegment = tintContent ? reapplyColor( rightContent, CONTENT_COLOR ) : rightContent;
172
- return `${HEADER_COLOR}│${reset}${leftSegment}${HEADER_COLOR}│${reset}${rightSegment}${HEADER_COLOR}│${reset}`;
173
-
174
- };
175
-
176
- const formatRegistryShort = ( value ) => {
177
-
178
- if ( ! value ) return '';
179
- try {
180
-
181
- const u = new URL( value );
182
- const pathname = ( u.pathname || '' ).replace( /\/$/, '' );
183
- return `${u.host}${pathname}`;
184
-
185
- } catch {
186
-
187
- return String( value );
188
-
189
- }
190
-
191
- };
192
-
193
108
  const maskLicense = ( s ) => {
194
109
 
195
110
  if ( ! s ) return '••••';
@@ -269,87 +184,37 @@ const USER_DISPLAY_NAME = getUserDisplayName();
269
184
 
270
185
  const renderEnvHeader = ( {
271
186
  scope,
272
- registry,
273
187
  expiresAt,
274
- tmpFile,
275
188
  licenseMasked,
276
- licenseId,
277
- channel,
278
189
  status,
279
190
  plan,
280
- teamName,
281
- teamId,
282
- repository,
283
- domain,
284
- region,
285
191
  userDisplayName,
286
192
  } ) => {
287
193
 
288
- const title = `─── Three Blocks Login v${CLI_VERSION} `;
289
- const separatorRow = makeHeaderRow( repeatChar( '─', LEFT_WIDTH ), repeatChar( '─', RIGHT_WIDTH ) );
290
- const channelDisplay = String( channel || '' ).toUpperCase() || 'STABLE';
291
- const registryShort = formatRegistryShort( registry );
292
-
293
194
  const displayName = userDisplayName || USER_DISPLAY_NAME;
294
- const welcomeLine = displayName ? `Welcome back ${displayName}!` : 'Welcome back!';
295
- const scopeLine = `Scope: ${scope}`;
195
+ const welcomeLine = displayName ? `Welcome back, ${displayName}!` : 'Welcome back!';
296
196
 
297
197
  const planLabel = normalizePlan( plan );
298
- const teamLabel = teamName || teamId ? ` · Team: ${teamName || teamId}` : '';
299
- const subscriptionLine = `Plan: ${planLabel}${teamLabel}`;
300
- const channelLine = `Channel: ${channelDisplay}${region ? ` · Region: ${region}` : ''}`;
301
-
302
- const repositoryBase = repository ? `Repository: ${repository}` : 'Repository: —';
303
- const repositoryLine = registryShort ? `${repositoryBase} → ${registryShort}` : repositoryBase;
304
- const registryLine = `Registry: ${registryShort || ( registry || '—' )}`;
305
-
306
- let domainValue = domain || '';
307
- if ( ! domainValue && registry ) {
308
-
309
- try {
310
-
311
- domainValue = new URL( registry ).host;
198
+ const planLine = `${planLabel} · ${scope}`;
312
199
 
313
- } catch {}
314
-
315
- }
316
-
317
- const domainLineText = `Domain: ${domainValue || '—'}`;
318
- const regionLineText = `Region: ${region || '—'}`;
319
-
320
- const licenseLine = `License: ${licenseMasked}${licenseId ? ` · ${licenseId}` : ''}`;
321
200
  const expiresLine = formatExpiryLabel( expiresAt );
201
+ const licenseLine = `${licenseMasked} · ${expiresLine}`;
322
202
 
323
- const ascii = [
324
- 'THREE.JS',
325
- ' ______ __ ______ ______ __ __ ______ ',
326
- '/\\ == \\ /\\ \\ /\\ __ \\ /\\ ___\\ /\\ \\/ / /\\ ___\\ ',
327
- '\\ \\ __< \\ \\ \\____ \\ \\ \\/\\ \\ \\ \\ \\____ \\ \\ _"-. \\ \\___ \\ ',
328
- ' \\ \\_____\\ \\ \\_____\\ \\ \\_____\\ \\ \\_____\\ \\ \\_\\ \\_\\ \\/\\_____\\',
329
- ' \\/_____\/ \\/_____/ \\/_____/ \\/_____/ \\/_/ \/_/ \\/_____/'
330
- ];
331
203
  const statusMessage = status?.message || ( status?.ok ? 'access granted' : status ? 'no active access' : 'pending' );
332
- const statusText = status?.ok
333
- ? green( bold( `Authenticated — ${statusMessage}` ) )
204
+ const statusLine = status?.ok
205
+ ? green( `✓ Authenticated — ${statusMessage}` )
334
206
  : status
335
- ? red( bold( `Not authenticated — ${statusMessage}` ) )
336
- : dim( bold( `Status: ${statusMessage}` ) );
337
-
338
- const lines = [
339
- applyHeaderColor( `╭${title}${repeatChar( '', HEADER_WIDTH - 2 - title.length )}╮`, { keepContentYellow: true } ),
340
- ...ascii.map( ( row ) => applyHeaderColor( `│${padText( row, LEFT_WIDTH + RIGHT_WIDTH + 1, 'center' )}│`, { keepContentYellow: true } ) ),
341
- applyHeaderColor( separatorRow, { keepContentYellow: true } ),
342
- applyHeaderColor( makeHeaderRow( welcomeLine, scopeLine, 'center', 'center' ) ),
343
- applyHeaderColor( separatorRow, { keepContentYellow: true } ),
344
- applyHeaderColor( makeHeaderRow( subscriptionLine, channelLine ) ),
345
- applyHeaderColor( makeHeaderRow( repositoryLine, registryLine ) ),
346
- applyHeaderColor( makeHeaderRow( domainLineText, regionLineText, 'left', 'center' ) ),
347
- applyHeaderColor( makeHeaderRow( licenseLine, expiresLine ) ),
348
- applyHeaderColor( separatorRow, { keepContentYellow: true } ),
349
- applyHeaderColor( makeHeaderRow( statusText, '', 'left', 'center' ), { tintContent: false } ),
350
- applyHeaderColor( `╰${repeatChar( '─', HEADER_WIDTH - 2 )}╯`, { keepContentYellow: true } ),
351
- ];
352
- for ( const row of lines ) console.log( row );
207
+ ? red( `✗ Not authenticated — ${statusMessage}` )
208
+ : dim( `Status: ${statusMessage}` );
209
+
210
+ console.log( '' );
211
+ console.log( `${cyan( '' )} ${bold( 'three-blocks-login' )} ${dim( `v${CLI_VERSION}` )}` );
212
+ console.log( '' );
213
+ console.log( welcomeLine );
214
+ console.log( dim( planLine ) );
215
+ console.log( dim( licenseLine ) );
216
+ console.log( statusLine );
217
+ console.log( '' );
353
218
 
354
219
  };
355
220
 
@@ -382,7 +247,7 @@ loadEnvFromDotfile( process.cwd() );
382
247
  const BROKER_URL =
383
248
  args.endpoint ||
384
249
  process.env.THREE_BLOCKS_BROKER_URL ||
385
- "https://www.threejs-blocks.com/api/npm/token"; // your Astro broker endpoint
250
+ "https://www.threejs-blocks.com/api/npm/token";
386
251
 
387
252
  const OAUTH_DEVICE_CODE_URL =
388
253
  process.env.THREE_BLOCKS_OAUTH_DEVICE_URL ||
@@ -429,6 +294,79 @@ const openBrowser = async ( url ) => {
429
294
 
430
295
  };
431
296
 
297
+ const createSpinner = ( { stream = process.stderr } = {} ) => {
298
+
299
+ const enabled = !! ( stream?.isTTY && ! QUIET && ! NON_INTERACTIVE );
300
+ const frames = [ '△', '▲', '▲', '△', '○', '●', '●', '○', '□', '■', '■', '□' ];
301
+ let idx = 0;
302
+ let timer = null;
303
+ let text = '';
304
+
305
+ const clearLine = () => {
306
+
307
+ if ( ! enabled ) return;
308
+ try {
309
+
310
+ readline.clearLine( stream, 0 );
311
+ readline.cursorTo( stream, 0 );
312
+
313
+ } catch {
314
+
315
+ // best effort
316
+
317
+ }
318
+
319
+ };
320
+
321
+ const render = () => {
322
+
323
+ if ( ! enabled ) return;
324
+ clearLine();
325
+ const frame = frames[ idx ];
326
+ idx = ( idx + 1 ) % frames.length;
327
+ stream.write( `${cyan( frame )} ${text}` );
328
+
329
+ };
330
+
331
+ const stop = () => {
332
+
333
+ if ( timer ) clearInterval( timer );
334
+ timer = null;
335
+ clearLine();
336
+
337
+ };
338
+
339
+ const start = ( nextText ) => {
340
+
341
+ if ( ! enabled ) return;
342
+ stop();
343
+ text = String( nextText ?? '' );
344
+ idx = 0;
345
+ render();
346
+ timer = setInterval( render, 60 );
347
+
348
+ };
349
+
350
+ const succeed = ( msg ) => {
351
+
352
+ if ( ! enabled ) return;
353
+ stop();
354
+ stream.write( `${green( "✔" )} ${msg || text}\n` );
355
+
356
+ };
357
+
358
+ const fail = ( msg ) => {
359
+
360
+ if ( ! enabled ) return;
361
+ stop();
362
+ stream.write( `${red( "✖" )} ${msg || text}\n` );
363
+
364
+ };
365
+
366
+ return { enabled, start, stop, succeed, fail };
367
+
368
+ };
369
+
432
370
  const promptChoice = async ( label, choices ) => {
433
371
 
434
372
  return await new Promise( ( resolve ) => {
@@ -637,52 +575,54 @@ const pollForToken = async ( deviceCode, interval, expiresIn ) => {
637
575
  const browserLogin = async () => {
638
576
 
639
577
  log.info( bold( cyan( 'Three Blocks CLI' ) ) + ' ' + dim( `[mode: ${MODE}]` ) );
640
- log.info( dim( 'Opening browser to log in...' ) );
578
+ const openSpinner = createSpinner();
579
+ if ( openSpinner.enabled ) openSpinner.start( 'Opening browser to log in...' );
580
+ else log.info( dim( 'Opening browser to log in...' ) );
641
581
  console.log( '' );
642
582
 
643
583
  // Start device code flow
644
- const deviceData = await startDeviceCodeFlow();
645
- const { device_code, verification_uri, verification_uri_complete, expires_in, interval } = deviceData;
584
+ let deviceData;
585
+ let browserOpened = false;
586
+ try {
646
587
 
647
- // Try to open browser
648
- const browserOpened = await openBrowser( verification_uri_complete || verification_uri );
588
+ deviceData = await startDeviceCodeFlow();
589
+ const { verification_uri, verification_uri_complete } = deviceData;
590
+ // Try to open browser
591
+ browserOpened = await openBrowser( verification_uri_complete || verification_uri );
592
+ if ( openSpinner.enabled ) openSpinner.succeed( browserOpened ? 'Browser opened.' : 'Login URL ready.' );
649
593
 
650
- if ( ! browserOpened ) {
594
+ } catch ( error ) {
651
595
 
652
- log.warn( 'Could not open browser automatically.' );
596
+ if ( openSpinner.enabled ) openSpinner.fail( 'Failed to start browser login.' );
597
+ throw error;
653
598
 
654
599
  }
655
600
 
601
+ const { device_code, verification_uri, verification_uri_complete, expires_in, interval } = deviceData;
602
+
603
+ if ( ! browserOpened ) log.warn( 'Could not open browser automatically.' );
604
+
656
605
  console.log( '' );
657
- log.info( yellow( 'Browser didn\'t open? Use the URL below to sign in:' ) );
606
+ log.info( cyan( 'Browser didn\'t open? Use the URL below to sign in:' ) );
658
607
  console.log( '' );
659
608
  console.log( ` ${cyan( verification_uri_complete || verification_uri )}` );
660
609
  console.log( '' );
661
610
  log.info( dim( 'Waiting for authorization...' ) );
662
611
 
663
- // Show a simple spinner while waiting
664
- const spinnerFrames = [ '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' ];
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 );
612
+ const waitSpinner = createSpinner();
613
+ if ( waitSpinner.enabled ) waitSpinner.start( 'Waiting for browser authorization...' );
672
614
 
673
615
  try {
674
616
 
675
617
  const licenseKey = await pollForToken( device_code, interval || 2, expires_in || 900 );
676
- clearInterval( spinnerInterval );
677
- process.stdout.write( '\r' + ' '.repeat( 50 ) + '\r' ); // Clear spinner line
618
+ if ( waitSpinner.enabled ) waitSpinner.succeed( 'Authorization successful!' );
619
+ else log.ok( green( 'Authorization successful!' ) );
678
620
  console.log( '' );
679
- log.ok( green( 'Authorization successful!' ) );
680
621
  return licenseKey;
681
622
 
682
623
  } catch ( error ) {
683
624
 
684
- clearInterval( spinnerInterval );
685
- process.stdout.write( '\r' + ' '.repeat( 50 ) + '\r' );
625
+ if ( waitSpinner.enabled ) waitSpinner.fail( 'Authorization failed.' );
686
626
  throw error;
687
627
 
688
628
  }
@@ -770,7 +710,7 @@ const log = {
770
710
  },
771
711
  warn: ( msg ) => {
772
712
 
773
- if ( ! QUIET ) console.error( `${yellow( "⚠" )} ${msg}` );
713
+ if ( ! QUIET ) console.error( `${cyan( "⚠" )} ${msg}` );
774
714
 
775
715
  },
776
716
  error: ( msg ) => {
@@ -798,7 +738,7 @@ const log = {
798
738
  }
799
739
 
800
740
  console.log( '' );
801
- log.info( bold( yellow( 'Three Blocks Login' ) ) + ' ' + dim( `[mode: ${MODE}]` ) );
741
+ log.info( bold( cyan( 'Three Blocks Login' ) ) + ' ' + dim( `[mode: ${MODE}]` ) );
802
742
  console.log( '' );
803
743
 
804
744
  // Determine login method
@@ -876,7 +816,21 @@ const log = {
876
816
 
877
817
  }
878
818
 
879
- const tokenData = await fetchToken( BROKER_URL, LICENSE_CLEAN, CHANNEL );
819
+ const brokerSpinner = createSpinner();
820
+ if ( brokerSpinner.enabled ) brokerSpinner.start( 'Verifying secret key with broker...' );
821
+ let tokenData;
822
+ try {
823
+
824
+ tokenData = await fetchToken( BROKER_URL, LICENSE_CLEAN, CHANNEL );
825
+ if ( brokerSpinner.enabled ) brokerSpinner.succeed( 'Broker verified secret key.' );
826
+
827
+ } catch ( error ) {
828
+
829
+ if ( brokerSpinner.enabled ) brokerSpinner.fail( 'Broker verification failed.' );
830
+ throw error;
831
+
832
+ }
833
+
880
834
  const {
881
835
  registry,
882
836
  token,
@@ -1217,7 +1171,9 @@ async function fetchToken( endpoint, license, channel ) {
1217
1171
  let suggestion = "Request failed. Please retry.";
1218
1172
  if ( res.status === 401 || res.status === 403 ) {
1219
1173
 
1220
- suggestion = "Authentication failed. Verify your license or access rights.";
1174
+ suggestion = "Authentication failed. The broker did not accept your license key. "
1175
+ + "If THREE_BLOCKS_SECRET_KEY (or a local .env) is set, verify it contains your active tb_… key, "
1176
+ + "or unset it to be prompted again.";
1221
1177
 
1222
1178
  } else if ( res.status === 404 ) {
1223
1179
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-blocks-login",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
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": {