@l4yercak3/cli 1.2.3 → 1.2.6
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 +1 -1
- package/src/commands/spread.js +102 -68
package/package.json
CHANGED
package/src/commands/spread.js
CHANGED
|
@@ -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
|
|
213
|
-
|
|
214
|
-
let
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
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
|
-
|
|
238
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
console.log(chalk.
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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: '
|
|
274
|
-
name: '
|
|
275
|
-
message: '
|
|
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 (
|
|
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
|
-
//
|
|
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
|
|
@@ -535,7 +569,7 @@ async function handleSpread() {
|
|
|
535
569
|
organizationName,
|
|
536
570
|
applicationId,
|
|
537
571
|
projectPathHash,
|
|
538
|
-
apiKey: `${apiKey.substring(0, 10)}
|
|
572
|
+
apiKey: apiKey ? `${apiKey.substring(0, 10)}...` : '(using existing)', // Store partial key for reference only
|
|
539
573
|
backendUrl,
|
|
540
574
|
features,
|
|
541
575
|
oauthProviders,
|