design-lazyyy-cli 0.2.0 → 0.3.0

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  **Control Figma Desktop from your terminal. No API key needed.**
6
6
 
7
7
  [![MIT License](https://img.shields.io/badge/license-MIT-7c3aed?style=flat-square)](LICENSE)
8
- [![Node.js](https://img.shields.io/badge/node-%3E%3D18-7c3aed?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
8
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D24-7c3aed?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
9
9
  [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Windows%20%7C%20Linux-7c3aed?style=flat-square)]()
10
10
 
11
11
  ---
@@ -33,7 +33,7 @@ all through a single CLI connected to Figma Desktop via Chrome DevTools Protocol
33
33
 
34
34
  ### Prerequisites
35
35
 
36
- - **Node.js** >= 18
36
+ - **Node.js** >= 24
37
37
  - **Figma Desktop** (free account works)
38
38
 
39
39
  ### Installation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "design-lazyyy-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "CLI for managing Figma design systems. Create variables, components, and more. No API key required.",
5
5
  "author": "plugin87",
6
6
  "license": "MIT",
@@ -19,7 +19,7 @@
19
19
  "variables"
20
20
  ],
21
21
  "engines": {
22
- "node": ">=18"
22
+ "node": ">=24"
23
23
  },
24
24
  "dependencies": {
25
25
  "chalk": "^5.3.0",
package/src/index.js CHANGED
@@ -11,6 +11,13 @@ import { createInterface } from 'readline';
11
11
  import { homedir, platform } from 'os';
12
12
  import { FigJamClient } from './figjam-client.js';
13
13
 
14
+ // Auth — offline hash-based verification
15
+ import { createHash } from 'crypto';
16
+ const VALID_TOKEN_HASHES = [
17
+ // SHA-256 hashes of valid tokens (add more with: echo -n "token" | shasum -a 256)
18
+ '065ea2d80d8e1e61025f115d01d08518b00615047a3ec14bd4e6f7d4f8813929',
19
+ ];
20
+
14
21
  // Platform detection
15
22
  const IS_WINDOWS = platform() === 'win32';
16
23
  const IS_MAC = platform() === 'darwin';
@@ -95,6 +102,36 @@ function saveConfig(config) {
95
102
  writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
96
103
  }
97
104
 
105
+ // Helper: Hash token with SHA-256
106
+ function hashToken(token) {
107
+ return createHash('sha256').update(token).digest('hex');
108
+ }
109
+
110
+ // Helper: Verify token offline against known hashes
111
+ function verifyToken(token) {
112
+ return VALID_TOKEN_HASHES.includes(hashToken(token));
113
+ }
114
+
115
+ // Helper: Check API key (gate all commands)
116
+ function checkApiKey() {
117
+ const config = loadConfig();
118
+ if (!config.token) {
119
+ console.log(chalk.red('\n✗ Token required.\n'));
120
+ console.log(chalk.white(' Get a token from plugin87, then run:\n'));
121
+ console.log(chalk.cyan(' design-lazyyy-cli login <token>\n'));
122
+ process.exit(1);
123
+ }
124
+ if (!verifyToken(config.token)) {
125
+ console.log(chalk.red('\n✗ Token invalid or revoked.\n'));
126
+ console.log(chalk.white(' Get a new token from plugin87, then run:\n'));
127
+ console.log(chalk.cyan(' design-lazyyy-cli login <token>\n'));
128
+ delete config.token;
129
+ saveConfig(config);
130
+ process.exit(1);
131
+ }
132
+ return true;
133
+ }
134
+
98
135
  // Resolve engine binary path (local node_modules)
99
136
  const __filename2 = fileURLToPath(import.meta.url);
100
137
  const __pkgRoot = dirname(dirname(__filename2));
@@ -115,8 +152,9 @@ function figmaUse(args, options = {}) {
115
152
  }
116
153
  }
117
154
 
118
- // Helper: Check connection
155
+ // Helper: Check connection (also gates on API key)
119
156
  function checkConnection() {
157
+ checkApiKey();
120
158
  const result = figmaUse('status', { silent: true });
121
159
  if (!result || result.includes('Not connected')) {
122
160
  console.log(chalk.red('\n✗ Not connected to Figma\n'));
@@ -178,18 +216,20 @@ program
178
216
  program.action(async () => {
179
217
  const config = loadConfig();
180
218
 
219
+ // Auth gate
220
+ checkApiKey();
221
+
181
222
  // First time? Run init
182
223
  if (!config.patched || !checkDependencies(true)) {
183
224
  showBanner();
184
225
  console.log(chalk.white(' Welcome! Let\'s get you set up.\n'));
185
- console.log(chalk.gray(' This takes about 30 seconds. No API key needed.\n'));
186
226
 
187
227
  // Step 1: Check Node version
188
228
  console.log(chalk.blue('Step 1/4: ') + 'Checking Node.js...');
189
229
  const nodeVersion = process.version;
190
230
  const nodeMajor = parseInt(nodeVersion.slice(1).split('.')[0]);
191
- if (nodeMajor < 18) {
192
- console.log(chalk.red(` ✗ Node.js ${nodeVersion} is too old. Please upgrade to Node 18+`));
231
+ if (nodeMajor < 24) {
232
+ console.log(chalk.red(` ✗ Node.js ${nodeVersion} is too old. Please upgrade to Node 24+`));
193
233
  process.exit(1);
194
234
  }
195
235
  console.log(chalk.green(` ✓ Node.js ${nodeVersion}`));
@@ -338,17 +378,17 @@ program
338
378
  .command('init')
339
379
  .description('Interactive setup wizard')
340
380
  .action(async () => {
381
+ checkApiKey();
341
382
  showBanner();
342
383
 
343
384
  console.log(chalk.white(' Welcome! Let\'s get you set up.\n'));
344
- console.log(chalk.gray(' This takes about 30 seconds. No API key needed.\n'));
345
385
 
346
386
  // Step 1: Check Node version
347
387
  console.log(chalk.blue('Step 1/4: ') + 'Checking Node.js...');
348
388
  const nodeVersion = process.version;
349
389
  const nodeMajor = parseInt(nodeVersion.slice(1).split('.')[0]);
350
- if (nodeMajor < 18) {
351
- console.log(chalk.red(` ✗ Node.js ${nodeVersion} is too old. Please upgrade to Node 18+`));
390
+ if (nodeMajor < 24) {
391
+ console.log(chalk.red(` ✗ Node.js ${nodeVersion} is too old. Please upgrade to Node 24+`));
352
392
  process.exit(1);
353
393
  }
354
394
  console.log(chalk.green(` ✓ Node.js ${nodeVersion}`));
@@ -447,12 +487,55 @@ program
447
487
  execSync('design-lazyyy-cli init', { stdio: 'inherit' });
448
488
  });
449
489
 
490
+ // ============ LOGIN ============
491
+
492
+ program
493
+ .command('login [token]')
494
+ .description('Authenticate with a token from plugin87')
495
+ .action(async (token) => {
496
+ if (!token) {
497
+ token = await prompt(chalk.white('Enter token: '));
498
+ }
499
+ token = token.trim();
500
+ if (!token) {
501
+ console.log(chalk.red('\n✗ Token cannot be empty.\n'));
502
+ process.exit(1);
503
+ }
504
+
505
+ if (!verifyToken(token)) {
506
+ console.log(chalk.red('\n✗ Invalid token.\n'));
507
+ process.exit(1);
508
+ }
509
+
510
+ const config = loadConfig();
511
+ config.token = token;
512
+ saveConfig(config);
513
+ console.log(chalk.green('\n✓ Token verified! Welcome.\n'));
514
+ });
515
+
516
+ // ============ LOGOUT ============
517
+
518
+ program
519
+ .command('logout')
520
+ .description('Remove saved token')
521
+ .action(() => {
522
+ const config = loadConfig();
523
+ if (!config.token) {
524
+ console.log(chalk.yellow('\nNo token saved.\n'));
525
+ return;
526
+ }
527
+ delete config.token;
528
+ saveConfig(config);
529
+ console.log(chalk.green('\n✓ Token removed. You are logged out.\n'));
530
+ });
531
+
450
532
  // ============ STATUS ============
451
533
 
452
534
  program
453
535
  .command('status')
454
536
  .description('Check connection to Figma')
455
537
  .action(() => {
538
+ checkApiKey();
456
539
  // Check if first run
457
540
  const config = loadConfig();
458
541
  if (!config.patched && !checkDependencies(true)) {
@@ -469,6 +552,7 @@ program
469
552
  .command('connect')
470
553
  .description('Start Figma with remote debugging enabled')
471
554
  .action(async () => {
555
+ checkApiKey();
472
556
  // Check if first run
473
557
  const config = loadConfig();
474
558
  if (!config.patched) {