@l4yercak3/cli 1.2.3 → 1.2.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@l4yercak3/cli",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "Icing on the L4yercak3 - The sweet finishing touch for your Layer Cake integration",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -3,6 +3,8 @@
3
3
  * Main command for setting up boilerplate integration
4
4
  */
5
5
 
6
+ const fs = require('fs');
7
+ const path = require('path');
6
8
  const configManager = require('../config/config-manager');
7
9
  const backendClient = require('../api/backend-client');
8
10
  const projectDetector = require('../detectors');
@@ -10,7 +12,6 @@ const fileGenerator = require('../generators');
10
12
  const { generateProjectPathHash } = require('../utils/file-utils');
11
13
  const inquirer = require('inquirer');
12
14
  const chalk = require('chalk');
13
- const path = require('path');
14
15
  const pkg = require('../../package.json');
15
16
 
16
17
  /**
@@ -209,87 +210,120 @@ async function handleSpread() {
209
210
  let apiKey;
210
211
 
211
212
  try {
212
- // First, check if organization already has API keys
213
- console.log(chalk.gray(' Checking existing API keys...'));
214
- let existingKeys = null;
215
-
216
- try {
217
- existingKeys = await backendClient.listApiKeys(organizationId);
218
- } catch (listError) {
219
- // If listing fails, continue to try generating
220
- console.log(chalk.gray(' Could not check existing keys, attempting to generate...'));
221
- }
222
-
223
- if (existingKeys && existingKeys.canCreateMore === false) {
224
- // At API key limit - inform user and exit (only if explicitly false, not undefined)
225
- console.log(chalk.yellow(` ⚠️ You've reached your API key limit (${existingKeys.keys?.length || 0} key(s))`));
226
- if (existingKeys.limitDescription) {
227
- console.log(chalk.gray(` ${existingKeys.limitDescription}`));
213
+ // First, check if .env.local already has an API key configured
214
+ const envPath = path.join(detection.projectPath, '.env.local');
215
+ let existingEnvKey = null;
216
+ if (fs.existsSync(envPath)) {
217
+ try {
218
+ const envContent = fs.readFileSync(envPath, 'utf8');
219
+ const match = envContent.match(/^L4YERCAK3_API_KEY=(.+)$/m);
220
+ if (match && match[1] && match[1].startsWith('sk_')) {
221
+ existingEnvKey = match[1].trim();
222
+ }
223
+ } catch {
224
+ // Ignore read errors
228
225
  }
229
- console.log(chalk.cyan('\n To continue, either:'));
230
- console.log(chalk.gray(' • Delete an existing key at https://app.l4yercak3.com?openWindow=integrations&panel=api-keys'));
231
- console.log(chalk.gray(' • Upgrade your plan at https://app.l4yercak3.com?openWindow=store\n'));
232
- process.exit(0);
233
- } else if (existingKeys && existingKeys.keys && existingKeys.keys.length > 0) {
234
- // Has existing keys - offer to reuse or generate new
235
- const activeKeys = existingKeys.keys.filter(k => k.status === 'active');
226
+ }
236
227
 
237
- if (activeKeys.length > 0) {
238
- console.log(chalk.gray(` Found ${activeKeys.length} active API key(s)\n`));
228
+ if (existingEnvKey) {
229
+ // Found existing API key in .env.local
230
+ const keyPreview = `${existingEnvKey.substring(0, 12)}...`;
231
+ console.log(chalk.green(` ✅ Found existing API key in .env.local (${keyPreview})\n`));
239
232
 
240
- const keyChoices = activeKeys.map(key => ({
241
- name: `${key.name} (${key.keyPreview})`,
242
- value: key.id,
243
- }));
244
- keyChoices.push({ name: ' Generate a new API key', value: '__generate__' });
245
- keyChoices.push({ name: '⏭️ Skip - I already have my key configured', value: '__skip__' });
233
+ const { useExisting } = await inquirer.prompt([
234
+ {
235
+ type: 'list',
236
+ name: 'useExisting',
237
+ message: 'What would you like to do?',
238
+ choices: [
239
+ { name: 'Keep existing API key (recommended)', value: 'keep' },
240
+ { name: 'Generate a new API key', value: 'generate' },
241
+ ],
242
+ },
243
+ ]);
246
244
 
247
- const { keyChoice } = await inquirer.prompt([
248
- {
249
- type: 'list',
250
- name: 'keyChoice',
251
- message: 'Which API key would you like to use?',
252
- choices: keyChoices,
253
- },
254
- ]);
245
+ if (useExisting === 'keep') {
246
+ apiKey = null; // Will preserve existing key in .env.local
247
+ console.log(chalk.green(` ✅ Keeping existing API key\n`));
248
+ } else {
249
+ apiKey = await generateNewApiKey(organizationId);
250
+ }
251
+ } else {
252
+ // No existing key in .env.local - check backend for keys
253
+ console.log(chalk.gray(' Checking existing API keys...'));
254
+ let existingKeys = null;
255
+
256
+ try {
257
+ existingKeys = await backendClient.listApiKeys(organizationId);
258
+ } catch (listError) {
259
+ // If listing fails, continue to try generating
260
+ console.log(chalk.gray(' Could not check existing keys, attempting to generate...'));
261
+ }
255
262
 
256
- if (keyChoice === '__generate__') {
257
- apiKey = await generateNewApiKey(organizationId);
258
- } else if (keyChoice === '__skip__') {
259
- apiKey = null; // Will skip writing API key to .env.local
260
- console.log(chalk.green(` ✅ Skipping API key setup - using existing configuration\n`));
261
- } else {
262
- // User selected existing key - we only have the preview, not the full key
263
- // They need to use the key they have stored or get it from dashboard
264
- const selectedKey = activeKeys.find(k => k.id === keyChoice);
265
- console.log(chalk.yellow(`\n ⚠️ For security, we can't retrieve the full API key.`));
266
- console.log(chalk.gray(` You selected: ${selectedKey.name} (${selectedKey.keyPreview})`));
267
- console.log(chalk.gray(` If you have this key stored, enter it below.`));
268
- console.log(chalk.gray(` Otherwise, generate a new key or find it at:`));
269
- console.log(chalk.gray(` https://app.l4yercak3.com?openWindow=integrations&panel=api-keys\n`));
270
-
271
- const { existingKey } = await inquirer.prompt([
263
+ if (existingKeys && existingKeys.canCreateMore === false) {
264
+ // At API key limit - inform user and exit (only if explicitly false, not undefined)
265
+ console.log(chalk.yellow(` ⚠️ You've reached your API key limit (${existingKeys.keys?.length || 0} key(s))`));
266
+ if (existingKeys.limitDescription) {
267
+ console.log(chalk.gray(` ${existingKeys.limitDescription}`));
268
+ }
269
+ console.log(chalk.cyan('\n To continue, either:'));
270
+ console.log(chalk.gray(' • Delete an existing key at https://app.l4yercak3.com?openWindow=integrations&panel=api-keys'));
271
+ console.log(chalk.gray(' • Upgrade your plan at https://app.l4yercak3.com?openWindow=store\n'));
272
+ process.exit(0);
273
+ } else if (existingKeys && existingKeys.keys && existingKeys.keys.length > 0) {
274
+ // Has existing keys on backend - offer to reuse or generate new
275
+ const activeKeys = existingKeys.keys.filter(k => k.status === 'active');
276
+
277
+ if (activeKeys.length > 0) {
278
+ console.log(chalk.gray(` Found ${activeKeys.length} active API key(s)\n`));
279
+
280
+ const keyChoices = activeKeys.map(key => ({
281
+ name: `Use ${key.name} (${key.keyPreview})`,
282
+ value: key.id,
283
+ }));
284
+ keyChoices.push({ name: '➕ Generate a new API key', value: '__generate__' });
285
+
286
+ const { keyChoice } = await inquirer.prompt([
272
287
  {
273
- type: 'input',
274
- name: 'existingKey',
275
- message: 'Enter your API key (or press Enter to generate new):',
288
+ type: 'list',
289
+ name: 'keyChoice',
290
+ message: 'Which API key would you like to use?',
291
+ choices: keyChoices,
276
292
  },
277
293
  ]);
278
294
 
279
- if (existingKey.trim()) {
280
- apiKey = existingKey.trim();
281
- console.log(chalk.green(` ✅ Using existing API key\n`));
282
- } else {
295
+ if (keyChoice === '__generate__') {
283
296
  apiKey = await generateNewApiKey(organizationId);
297
+ } else {
298
+ // User selected existing key - prompt for the full key
299
+ const selectedKey = activeKeys.find(k => k.id === keyChoice);
300
+ console.log(chalk.yellow(`\n ⚠️ For security, we can't retrieve the full API key.`));
301
+ console.log(chalk.gray(` You selected: ${selectedKey.name} (${selectedKey.keyPreview})`));
302
+ console.log(chalk.gray(` Enter the key if you have it, or press Enter to generate a new one.\n`));
303
+
304
+ const { existingKey } = await inquirer.prompt([
305
+ {
306
+ type: 'input',
307
+ name: 'existingKey',
308
+ message: 'Enter your API key (or press Enter to generate new):',
309
+ },
310
+ ]);
311
+
312
+ if (existingKey.trim()) {
313
+ apiKey = existingKey.trim();
314
+ console.log(chalk.green(` ✅ Using existing API key\n`));
315
+ } else {
316
+ apiKey = await generateNewApiKey(organizationId);
317
+ }
284
318
  }
319
+ } else {
320
+ // Only revoked keys exist - generate new
321
+ apiKey = await generateNewApiKey(organizationId);
285
322
  }
286
323
  } else {
287
- // Only revoked keys exist - generate new
324
+ // No existing keys - generate one
288
325
  apiKey = await generateNewApiKey(organizationId);
289
326
  }
290
- } else {
291
- // No existing keys - generate one
292
- apiKey = await generateNewApiKey(organizationId);
293
327
  }
294
328
  } catch (error) {
295
329
  // Handle specific error codes