create-three-blocks-starter 0.0.9 → 0.0.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/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
@@ -8,7 +8,7 @@ Authenticate to the private registry first (one time per project):
8
8
 
9
9
  ```bash
10
10
  # Using pnpm (recommended - no warnings)
11
- pnpm dlx three-blocks-login@latest@latest --mode project --scope @three-blocks --channel stable
11
+ npx -y three-blocks-login@latest@latest --mode project --scope @three-blocks --channel stable
12
12
 
13
13
  # Using npx (may show harmless npm config warnings)
14
14
  npx -y three-blocks-login@latest --mode project --scope @three-blocks --channel stable
@@ -75,6 +75,6 @@ pnpm --filter create-three-blocks-starter run dev:sync
75
75
  ## Publish
76
76
 
77
77
  ```bash
78
- pnpm dlx three-blocks-login@latest --mode project --scope @three-blocks
78
+ npx -y three-blocks-login@latest --mode project --scope @three-blocks
79
79
  pnpm --filter create-three-blocks-starter publish --access restricted
80
80
  ```
package/bin/index.js CHANGED
@@ -1,4 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ /*!
3
+ create-three-blocks-starter
4
+ Copyright (c) 2025 three-blocks
5
+ UNLICENSED - See https://threejs-blocks.com/license
6
+ */
2
7
  // Node 18+
3
8
  // Usage:
4
9
  // THREE_BLOCKS_SECRET_KEY=sk_live_... npx create-three-blocks-starter my-app
@@ -326,6 +331,297 @@ async function ensureEmptyDir( dir ) {
326
331
 
327
332
  }
328
333
 
334
+ const OAUTH_DEVICE_CODE_URL =
335
+ process.env.THREE_BLOCKS_OAUTH_DEVICE_URL ||
336
+ 'https://www.threejs-blocks.com/api/cli/device-code';
337
+
338
+ const OAUTH_TOKEN_URL =
339
+ process.env.THREE_BLOCKS_OAUTH_TOKEN_URL ||
340
+ 'https://www.threejs-blocks.com/api/cli/token';
341
+
342
+ const openBrowser = async ( url ) => {
343
+
344
+ const { exec: execCallback } = await import( 'node:child_process' );
345
+ const platform = process.platform;
346
+ let command;
347
+
348
+ if ( platform === 'darwin' ) {
349
+
350
+ command = `open "${url}"`;
351
+
352
+ } else if ( platform === 'win32' ) {
353
+
354
+ command = `start "" "${url}"`;
355
+
356
+ } else {
357
+
358
+ command = `xdg-open "${url}" || sensible-browser "${url}" || x-www-browser "${url}"`;
359
+
360
+ }
361
+
362
+ return new Promise( ( resolve ) => {
363
+
364
+ execCallback( command, ( error ) => {
365
+
366
+ resolve( ! error );
367
+
368
+ } );
369
+
370
+ } );
371
+
372
+ };
373
+
374
+ async function promptChoice( label, choices ) {
375
+
376
+ return await new Promise( ( resolve ) => {
377
+
378
+ const stdin = process.stdin;
379
+ const stdout = process.stdout;
380
+ let selected = 0;
381
+ const cleanup = () => {
382
+
383
+ stdin.removeListener( 'data', onData );
384
+ if ( stdin.isTTY ) stdin.setRawMode( false );
385
+ stdin.pause();
386
+
387
+ };
388
+
389
+ const render = () => {
390
+
391
+ for ( let i = 0; i < choices.length; i ++ ) {
392
+
393
+ const prefix = i === selected ? cyan( '› ' ) : ' ';
394
+ const text = i === selected ? bold( choices[ i ] ) : dim( choices[ i ] );
395
+ stdout.write( `${prefix}${text}\n` );
396
+
397
+ }
398
+
399
+ };
400
+
401
+ const clearLines = () => {
402
+
403
+ for ( let i = 0; i < choices.length; i ++ ) {
404
+
405
+ readline.moveCursor( stdout, 0, - 1 );
406
+ readline.clearLine( stdout, 0 );
407
+
408
+ }
409
+
410
+ };
411
+
412
+ const onData = ( chunk ) => {
413
+
414
+ const str = String( chunk );
415
+ for ( const ch of str ) {
416
+
417
+ if ( ch === '\u0003' ) {
418
+
419
+ cleanup();
420
+ process.exit( 1 );
421
+
422
+ }
423
+
424
+ if ( ch === '\r' || ch === '\n' ) {
425
+
426
+ cleanup();
427
+ return resolve( selected );
428
+
429
+ }
430
+
431
+ if ( ch === '\u001b' ) continue;
432
+ if ( ch === '[' ) continue;
433
+ if ( ch === 'A' || ch === 'k' ) {
434
+
435
+ clearLines();
436
+ selected = ( selected - 1 + choices.length ) % choices.length;
437
+ render();
438
+
439
+ } else if ( ch === 'B' || ch === 'j' ) {
440
+
441
+ clearLines();
442
+ selected = ( selected + 1 ) % choices.length;
443
+ render();
444
+
445
+ } else if ( ch === '\t' || ch === ' ' ) {
446
+
447
+ // Tab or Space to toggle
448
+ clearLines();
449
+ selected = ( selected + 1 ) % choices.length;
450
+ render();
451
+
452
+ } else if ( ch === '1' ) {
453
+
454
+ cleanup();
455
+ return resolve( 0 );
456
+
457
+ } else if ( ch === '2' ) {
458
+
459
+ cleanup();
460
+ return resolve( 1 );
461
+
462
+ }
463
+
464
+ }
465
+
466
+ };
467
+
468
+ stdout.write( `${label}\n` );
469
+ render();
470
+ stdin.setEncoding( 'utf8' );
471
+ if ( stdin.isTTY ) stdin.setRawMode( true );
472
+ stdin.resume();
473
+ stdin.on( 'data', onData );
474
+
475
+ } );
476
+
477
+ }
478
+
479
+ const startDeviceCodeFlow = async () => {
480
+
481
+ logDebug( `POST ${OAUTH_DEVICE_CODE_URL}` );
482
+ const res = await fetch( OAUTH_DEVICE_CODE_URL, {
483
+ method: 'POST',
484
+ headers: {
485
+ 'content-type': 'application/json',
486
+ 'accept': 'application/json',
487
+ },
488
+ body: JSON.stringify( { client_id: 'create-three-blocks-starter' } ),
489
+ } );
490
+
491
+ if ( ! res.ok ) {
492
+
493
+ const text = await res.text().catch( () => '' );
494
+ throw new CliError(
495
+ `Failed to start browser login (HTTP ${res.status})`,
496
+ { suggestion: 'Check your network connection and try again.', stdout: text }
497
+ );
498
+
499
+ }
500
+
501
+ return await res.json();
502
+
503
+ };
504
+
505
+ const pollForToken = async ( deviceCode, interval, expiresIn ) => {
506
+
507
+ const startTime = Date.now();
508
+ const expiresAt = startTime + ( expiresIn * 1000 );
509
+ let pollInterval = interval * 1000;
510
+
511
+ while ( Date.now() < expiresAt ) {
512
+
513
+ await new Promise( ( r ) => setTimeout( r, pollInterval ) );
514
+
515
+ logDebug( `Polling ${OAUTH_TOKEN_URL} for token...` );
516
+ const res = await fetch( OAUTH_TOKEN_URL, {
517
+ method: 'POST',
518
+ headers: {
519
+ 'content-type': 'application/json',
520
+ 'accept': 'application/json',
521
+ },
522
+ body: JSON.stringify( { device_code: deviceCode } ),
523
+ } );
524
+
525
+ const data = await res.json().catch( () => ( {} ) );
526
+
527
+ if ( res.ok && data.access_token ) {
528
+
529
+ return data.access_token;
530
+
531
+ }
532
+
533
+ if ( data.error === 'authorization_pending' ) {
534
+
535
+ continue;
536
+
537
+ }
538
+
539
+ if ( data.error === 'slow_down' ) {
540
+
541
+ pollInterval += 1000;
542
+ continue;
543
+
544
+ }
545
+
546
+ if ( data.error === 'expired_token' ) {
547
+
548
+ throw new CliError(
549
+ 'Browser login timed out. Please try again.',
550
+ { suggestion: 'Run the command again and complete authorization in your browser.' }
551
+ );
552
+
553
+ }
554
+
555
+ if ( data.error ) {
556
+
557
+ throw new CliError(
558
+ `Browser login failed: ${data.error_description || data.error}`,
559
+ { suggestion: 'Try again or use the secret key method instead.' }
560
+ );
561
+
562
+ }
563
+
564
+ }
565
+
566
+ throw new CliError(
567
+ 'Browser login timed out.',
568
+ { suggestion: 'Run the command again and complete authorization within 15 minutes.' }
569
+ );
570
+
571
+ };
572
+
573
+ const browserLogin = async ( channel ) => {
574
+
575
+ logInfo( bold( cyan( 'Three Blocks Starter' ) ) + ' ' + dim( `[channel: ${channel}]` ) );
576
+ logInfo( dim( 'Opening browser to log in...' ) );
577
+ console.log( '' );
578
+
579
+ const deviceData = await startDeviceCodeFlow();
580
+ const { device_code, verification_uri, verification_uri_complete, expires_in, interval } = deviceData;
581
+
582
+ const browserOpened = await openBrowser( verification_uri_complete || verification_uri );
583
+
584
+ if ( ! browserOpened ) {
585
+
586
+ logWarn( 'Could not open browser automatically.' );
587
+
588
+ }
589
+
590
+ console.log( '' );
591
+ logInfo( yellow( 'Browser didn\'t open? Use the URL below to sign in:' ) );
592
+ console.log( '' );
593
+ console.log( ` ${cyan( verification_uri_complete || verification_uri )}` );
594
+ console.log( '' );
595
+ logInfo( dim( 'Waiting for authorization...' ) );
596
+
597
+ const spinnerFrames = [ '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' ];
598
+ let spinnerIdx = 0;
599
+ const spinnerInterval = setInterval( () => {
600
+
601
+ process.stdout.write( `\r${cyan( spinnerFrames[ spinnerIdx ] )} Waiting for browser authorization...` );
602
+ spinnerIdx = ( spinnerIdx + 1 ) % spinnerFrames.length;
603
+
604
+ }, 100 );
605
+
606
+ try {
607
+
608
+ const licenseKey = await pollForToken( device_code, interval || 2, expires_in || 900 );
609
+ clearInterval( spinnerInterval );
610
+ process.stdout.write( '\r' + ' '.repeat( 50 ) + '\r' );
611
+ console.log( '' );
612
+ logSuccess( green( 'Authorization successful!' ) );
613
+ return licenseKey;
614
+
615
+ } catch ( error ) {
616
+
617
+ clearInterval( spinnerInterval );
618
+ process.stdout.write( '\r' + ' '.repeat( 50 ) + '\r' );
619
+ throw error;
620
+
621
+ }
622
+
623
+ };
624
+
329
625
  async function promptHidden( label ) {
330
626
 
331
627
  return await new Promise( ( resolve ) => {
@@ -745,6 +1041,10 @@ async function main() {
745
1041
  const targetDir = path.resolve( process.cwd(), appName );
746
1042
  await ensureEmptyDir( targetDir );
747
1043
 
1044
+ // Check for --browser or --key flags
1045
+ const useBrowserFlag = args.includes( '--browser' ) || args.includes( '-b' );
1046
+ const useKeyFlag = args.includes( '--key' ) || args.includes( '-k' );
1047
+
748
1048
  // 1) License key (env or prompt)
749
1049
  let license = process.env.THREE_BLOCKS_SECRET_KEY;
750
1050
  if ( license ) {
@@ -755,10 +1055,41 @@ async function main() {
755
1055
 
756
1056
  console.log( '' );
757
1057
  logInfo( bold( cyan( 'Three Blocks Starter' ) ) + ' ' + dim( `[channel: ${channel}]` ) );
758
- logInfo( dim( 'Enter your license key to continue.' ) );
759
- logInfo( dim( 'Tip: paste it here; input is hidden. Press Enter to submit.' ) );
760
- license = await promptHidden( `${STEP_ICON}${bold( 'License key' )} ${dim( '(tb_…)' )}: ` );
761
- if ( ! license ) die( 'License key is required to install private packages.' );
1058
+ console.log( '' );
1059
+
1060
+ // Determine login method
1061
+ let useBrowserLogin = useBrowserFlag;
1062
+ let useKeyLogin = useKeyFlag;
1063
+
1064
+ // If neither flag is set, show menu
1065
+ if ( ! useBrowserLogin && ! useKeyLogin ) {
1066
+
1067
+ logInfo( dim( 'Select login method:' ) );
1068
+ console.log( '' );
1069
+ const choice = await promptChoice( '', [
1070
+ 'Log in with Three Blocks account (opens browser)',
1071
+ 'Paste Secret Key manually'
1072
+ ] );
1073
+ console.log( '' );
1074
+ useBrowserLogin = choice === 0;
1075
+ useKeyLogin = choice === 1;
1076
+
1077
+ }
1078
+
1079
+ if ( useBrowserLogin ) {
1080
+
1081
+ // Browser-based OAuth login
1082
+ license = await browserLogin( channel );
1083
+
1084
+ } else {
1085
+
1086
+ // Manual secret key entry
1087
+ logInfo( dim( 'Enter your license key to continue.' ) );
1088
+ logInfo( dim( 'Tip: paste it here; input is hidden. Press Enter to submit.' ) );
1089
+ license = await promptHidden( `${STEP_ICON}${bold( 'License key' )} ${dim( '(tb_…)' )}: ` );
1090
+ if ( ! license ) die( 'License key is required to install private packages.' );
1091
+
1092
+ }
762
1093
 
763
1094
  }
764
1095
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-three-blocks-starter",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Create a new Three Blocks starter app",