@edgible-team/cli 1.2.2 → 1.2.4

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 (47) hide show
  1. package/LICENSE +2 -0
  2. package/dist/client/api-client.d.ts +51 -0
  3. package/dist/client/api-client.d.ts.map +1 -1
  4. package/dist/client/api-client.js +65 -0
  5. package/dist/commands/ai.d.ts.map +1 -1
  6. package/dist/commands/ai.js +23 -20
  7. package/dist/commands/application.d.ts.map +1 -1
  8. package/dist/commands/application.js +713 -94
  9. package/dist/generated/compose-constants.d.ts +14 -0
  10. package/dist/generated/compose-constants.d.ts.map +1 -0
  11. package/dist/generated/compose-constants.js +22 -0
  12. package/dist/services/application/ApplicationService.d.ts +41 -0
  13. package/dist/services/application/ApplicationService.d.ts.map +1 -1
  14. package/dist/services/application/ApplicationService.js +107 -0
  15. package/dist/types/AgentConfig.d.ts +13 -0
  16. package/dist/types/AgentConfig.d.ts.map +1 -1
  17. package/dist/types/ApiRequests.d.ts +8 -0
  18. package/dist/types/ApiRequests.d.ts.map +1 -1
  19. package/dist/types/Application.d.ts +6 -0
  20. package/dist/types/Application.d.ts.map +1 -1
  21. package/dist/types/CaddyJson.d.ts +43 -1
  22. package/dist/types/CaddyJson.d.ts.map +1 -1
  23. package/dist/types/models/ApplicationApiKey.d.ts +63 -0
  24. package/dist/types/models/ApplicationApiKey.d.ts.map +1 -0
  25. package/dist/types/models/ApplicationApiKey.js +5 -0
  26. package/dist/types/models/ApplicationAuthExchangeToken.d.ts +69 -0
  27. package/dist/types/models/ApplicationAuthExchangeToken.d.ts.map +1 -0
  28. package/dist/types/models/ApplicationAuthExchangeToken.js +5 -0
  29. package/dist/types/models/ApplicationAuthSession.d.ts +68 -0
  30. package/dist/types/models/ApplicationAuthSession.d.ts.map +1 -0
  31. package/dist/types/models/ApplicationAuthSession.js +5 -0
  32. package/dist/types/models/ApplicationData.d.ts +33 -0
  33. package/dist/types/models/ApplicationData.d.ts.map +1 -1
  34. package/dist/types/models/ApplicationShortCode.d.ts +79 -0
  35. package/dist/types/models/ApplicationShortCode.d.ts.map +1 -0
  36. package/dist/types/models/ApplicationShortCode.js +5 -0
  37. package/dist/types/route.d.ts +4 -0
  38. package/dist/types/route.d.ts.map +1 -1
  39. package/dist/types/validation/schemas.d.ts +21 -0
  40. package/dist/types/validation/schemas.d.ts.map +1 -1
  41. package/dist/types/validation/schemas.js +14 -1
  42. package/package.json +2 -2
  43. package/recipes/compose/open-webui/docker-compose.yml +26 -1
  44. package/dist/detection/tools.d.ts +0 -16
  45. package/dist/detection/tools.d.ts.map +0 -1
  46. package/dist/detection/tools.js +0 -305
  47. package/recipes/compose/open-webui/.env +0 -1
@@ -173,6 +173,12 @@ Examples:
173
173
  : (typeof options.hostnames === 'string' && options.hostnames.trim().length > 0
174
174
  ? options.hostnames.split(',').map(s => s.trim()).filter(Boolean)
175
175
  : []);
176
+ // Organization auth settings
177
+ let requireOrgAuth = options.requireOrgAuth || false;
178
+ let allowedOrgs = [];
179
+ if (options.allowedOrgs) {
180
+ allowedOrgs = options.allowedOrgs.split(',').map(s => s.trim()).filter(Boolean);
181
+ }
176
182
  if (!options.noInteractive) {
177
183
  // Prompt for HTTPS upgrade if protocol is http and --https-upgrade wasn't explicitly set
178
184
  if (protocolUnion === 'http' && options.httpsUpgrade === undefined) {
@@ -200,6 +206,40 @@ Examples:
200
206
  if (addHostnames && typeof addHostnames === 'string') {
201
207
  hostnames = addHostnames.split(',').map((s) => s.trim()).filter((s) => s.length > 0);
202
208
  }
209
+ // Prompt for organization authentication
210
+ if (options.requireOrgAuth === undefined) {
211
+ const { enableOrgAuth } = await inquirer_1.default.prompt([
212
+ {
213
+ type: 'confirm',
214
+ name: 'enableOrgAuth',
215
+ message: 'Require organization authentication to access this application?',
216
+ default: false,
217
+ },
218
+ ]);
219
+ requireOrgAuth = enableOrgAuth;
220
+ if (requireOrgAuth) {
221
+ const { allowOtherOrgs } = await inquirer_1.default.prompt([
222
+ {
223
+ type: 'confirm',
224
+ name: 'allowOtherOrgs',
225
+ message: 'Allow other organizations to access this application?',
226
+ default: false,
227
+ },
228
+ ]);
229
+ if (allowOtherOrgs) {
230
+ const { orgIds } = await inquirer_1.default.prompt([
231
+ {
232
+ type: 'input',
233
+ name: 'orgIds',
234
+ message: 'Enter comma-separated organization IDs to allow access:',
235
+ },
236
+ ]);
237
+ if (orgIds && typeof orgIds === 'string') {
238
+ allowedOrgs = orgIds.split(',').map((s) => s.trim()).filter((s) => s.length > 0);
239
+ }
240
+ }
241
+ }
242
+ }
203
243
  // Prompt for managed gateway option
204
244
  if (gatewayIds.length === 0) {
205
245
  const { useManaged } = await inquirer_1.default.prompt([
@@ -212,41 +252,55 @@ Examples:
212
252
  ]);
213
253
  useManagedGateway = useManaged;
214
254
  if (!useManagedGateway) {
215
- // Try to offer a list of gateways (via service), else fallback to manual input
216
- try {
217
- const gatewaysResp = await gatewayService.listGateways();
218
- const gatewayChoices = gatewaysResp.gateways.map((g) => ({
219
- name: `${g.device.name} (${g.device.id})`,
220
- value: g.device.id,
221
- }));
222
- if (gatewayChoices.length > 0) {
223
- const { selectedGateways } = await inquirer_1.default.prompt([
255
+ // Ask if they want to assign a gateway at all
256
+ const { assignGateway } = await inquirer_1.default.prompt([
257
+ {
258
+ type: 'confirm',
259
+ name: 'assignGateway',
260
+ message: 'Assign a gateway to this application? (No = local/internal access only)',
261
+ default: true,
262
+ },
263
+ ]);
264
+ if (assignGateway) {
265
+ // Try to offer a list of gateways (via service), else fallback to manual input
266
+ try {
267
+ const gatewaysResp = await gatewayService.listGateways();
268
+ const gatewayChoices = gatewaysResp.gateways.map((g) => ({
269
+ name: `${g.device.name} (${g.device.id})`,
270
+ value: g.device.id,
271
+ }));
272
+ if (gatewayChoices.length > 0) {
273
+ const { selectedGateways } = await inquirer_1.default.prompt([
274
+ {
275
+ type: 'checkbox',
276
+ name: 'selectedGateways',
277
+ message: 'Select gateway device(s):',
278
+ choices: gatewayChoices,
279
+ validate: (vals) => vals.length > 0 ? true : 'Select at least one gateway',
280
+ },
281
+ ]);
282
+ gatewayIds = selectedGateways;
283
+ }
284
+ }
285
+ catch (error) {
286
+ logger.warn('Failed to list gateways', error);
287
+ }
288
+ if (gatewayIds.length === 0) {
289
+ const ans2 = await inquirer_1.default.prompt([
224
290
  {
225
- type: 'checkbox',
226
- name: 'selectedGateways',
227
- message: 'Select gateway device(s):',
228
- choices: gatewayChoices,
229
- validate: (vals) => vals.length > 0 ? true : 'Select at least one gateway',
291
+ type: 'input',
292
+ name: 'gatewayIds',
293
+ message: 'Enter comma-separated gateway device IDs (or leave empty for no gateway):',
294
+ validate: (v) => true, // Allow empty input
230
295
  },
231
296
  ]);
232
- gatewayIds = selectedGateways;
297
+ if (ans2.gatewayIds && ans2.gatewayIds.trim()) {
298
+ gatewayIds = (0, input_parser_1.parseGatewayIds)(ans2.gatewayIds);
299
+ }
233
300
  }
234
301
  }
235
- catch (error) {
236
- logger.warn('Failed to list gateways', error);
237
- }
238
- if (gatewayIds.length === 0) {
239
- const ans2 = await inquirer_1.default.prompt([
240
- {
241
- type: 'input',
242
- name: 'gatewayIds',
243
- message: 'Enter comma-separated gateway device IDs:',
244
- validate: (v) => v && v.split(',').map((s) => s.trim()).filter(Boolean).length > 0
245
- ? true
246
- : 'At least one gateway ID is required',
247
- },
248
- ]);
249
- gatewayIds = (0, input_parser_1.parseGatewayIds)(ans2.gatewayIds);
302
+ else {
303
+ logger.info('Application will be created without gateway assignment (local/internal access only)');
250
304
  }
251
305
  }
252
306
  }
@@ -303,7 +357,7 @@ Examples:
303
357
  throw new Error('--device-id (serving) is required');
304
358
  }
305
359
  if (!useManagedGateway && gatewayIds.length === 0) {
306
- throw new Error('--gateway-ids is required (at least one) or use --use-managed-gateway');
360
+ logger.warn('No gateways assigned - application will only be accessible locally/internally');
307
361
  }
308
362
  const subtype = 'local-preexisting';
309
363
  // If interactive, allow choosing a local workload
@@ -394,6 +448,12 @@ Examples:
394
448
  if (hostnames.length > 0) {
395
449
  console.log(chalk_1.default.gray(`Additional hostnames: ${hostnames.join(', ')}`));
396
450
  }
451
+ if (requireOrgAuth) {
452
+ console.log(chalk_1.default.gray(`Organization authentication: ${chalk_1.default.green('Enabled')}`));
453
+ if (allowedOrgs.length > 0) {
454
+ console.log(chalk_1.default.gray(`Allowed organizations: ${allowedOrgs.join(', ')}`));
455
+ }
456
+ }
397
457
  const result = await applicationService.createApplicationProgrammatically({
398
458
  name: appName,
399
459
  description,
@@ -404,6 +464,8 @@ Examples:
404
464
  gatewayIds: useManagedGateway ? undefined : gatewayIds,
405
465
  useManagedGateway,
406
466
  subtype,
467
+ requireOrgAuth,
468
+ allowedOrganizations: allowedOrgs.length > 0 ? allowedOrgs : undefined,
407
469
  });
408
470
  console.log(chalk_1.default.green('\n✓ Application created successfully!'));
409
471
  console.log(chalk_1.default.blue('\n📋 Application Details:'));
@@ -560,41 +622,55 @@ Examples:
560
622
  ]);
561
623
  useManagedGateway = useManaged;
562
624
  if (!useManagedGateway) {
563
- // Try to offer a list of gateways (via service), else fallback to manual input
564
- try {
565
- const gatewaysResp = await gatewayService.listGateways();
566
- const gatewayChoices = gatewaysResp.gateways.map((g) => ({
567
- name: `${g.device.name} (${g.device.id})`,
568
- value: g.device.id,
569
- }));
570
- if (gatewayChoices.length > 0) {
571
- const { selectedGateways } = await inquirer_1.default.prompt([
625
+ // Ask if they want to assign a gateway at all
626
+ const { assignGateway } = await inquirer_1.default.prompt([
627
+ {
628
+ type: 'confirm',
629
+ name: 'assignGateway',
630
+ message: 'Assign a gateway to this application? (No = local/internal access only)',
631
+ default: true,
632
+ },
633
+ ]);
634
+ if (assignGateway) {
635
+ // Try to offer a list of gateways (via service), else fallback to manual input
636
+ try {
637
+ const gatewaysResp = await gatewayService.listGateways();
638
+ const gatewayChoices = gatewaysResp.gateways.map((g) => ({
639
+ name: `${g.device.name} (${g.device.id})`,
640
+ value: g.device.id,
641
+ }));
642
+ if (gatewayChoices.length > 0) {
643
+ const { selectedGateways } = await inquirer_1.default.prompt([
644
+ {
645
+ type: 'checkbox',
646
+ name: 'selectedGateways',
647
+ message: 'Select gateway device(s):',
648
+ choices: gatewayChoices,
649
+ validate: (vals) => vals.length > 0 ? true : 'Select at least one gateway',
650
+ },
651
+ ]);
652
+ gatewayIds = selectedGateways;
653
+ }
654
+ }
655
+ catch (error) {
656
+ logger.warn('Failed to list gateways', error);
657
+ }
658
+ if (gatewayIds.length === 0) {
659
+ const ans2 = await inquirer_1.default.prompt([
572
660
  {
573
- type: 'checkbox',
574
- name: 'selectedGateways',
575
- message: 'Select gateway device(s):',
576
- choices: gatewayChoices,
577
- validate: (vals) => vals.length > 0 ? true : 'Select at least one gateway',
661
+ type: 'input',
662
+ name: 'gatewayIds',
663
+ message: 'Enter comma-separated gateway device IDs (or leave empty for no gateway):',
664
+ validate: (v) => true, // Allow empty input
578
665
  },
579
666
  ]);
580
- gatewayIds = selectedGateways;
667
+ if (ans2.gatewayIds && ans2.gatewayIds.trim()) {
668
+ gatewayIds = (0, input_parser_1.parseGatewayIds)(ans2.gatewayIds);
669
+ }
581
670
  }
582
671
  }
583
- catch (error) {
584
- logger.warn('Failed to list gateways', error);
585
- }
586
- if (gatewayIds.length === 0) {
587
- const ans2 = await inquirer_1.default.prompt([
588
- {
589
- type: 'input',
590
- name: 'gatewayIds',
591
- message: 'Enter comma-separated gateway device IDs:',
592
- validate: (v) => v && v.split(',').map((s) => s.trim()).filter(Boolean).length > 0
593
- ? true
594
- : 'At least one gateway ID is required',
595
- },
596
- ]);
597
- gatewayIds = (0, input_parser_1.parseGatewayIds)(ans2.gatewayIds);
672
+ else {
673
+ logger.info('Application will be created without gateway assignment (local/internal access only)');
598
674
  }
599
675
  }
600
676
  }
@@ -651,14 +727,14 @@ Examples:
651
727
  throw new Error('--device-id (serving) is required');
652
728
  }
653
729
  if (!useManagedGateway && gatewayIds.length === 0) {
654
- throw new Error('--gateway-ids is required (at least one) or use --use-managed-gateway');
730
+ logger.warn('No gateways assigned - application will only be accessible locally/internally');
655
731
  }
656
732
  // Run docker compose up
657
733
  console.log(chalk_1.default.blue(`\nRunning docker compose up...`));
658
734
  try {
659
735
  const composeDir = path.dirname(composeFilePath);
660
736
  const composeFileName = path.basename(composeFilePath);
661
- (0, child_process_1.execSync)(`docker compose -f ${composeFileName} up -d`, {
737
+ (0, child_process_1.execSync)(`docker compose -f "${composeFileName}" up -d`, {
662
738
  cwd: composeDir,
663
739
  stdio: 'inherit',
664
740
  });
@@ -926,41 +1002,55 @@ Examples:
926
1002
  ]);
927
1003
  useManagedGateway = useManaged;
928
1004
  if (!useManagedGateway) {
929
- // Try to offer a list of gateways (via service), else fallback to manual input
930
- try {
931
- const gatewaysResp = await gatewayService.listGateways();
932
- const gatewayChoices = gatewaysResp.gateways.map((g) => ({
933
- name: `${g.device.name} (${g.device.id})`,
934
- value: g.device.id,
935
- }));
936
- if (gatewayChoices.length > 0) {
937
- const { selectedGateways } = await inquirer_1.default.prompt([
1005
+ // Ask if they want to assign a gateway at all
1006
+ const { assignGateway } = await inquirer_1.default.prompt([
1007
+ {
1008
+ type: 'confirm',
1009
+ name: 'assignGateway',
1010
+ message: 'Assign a gateway to this application? (No = local/internal access only)',
1011
+ default: true,
1012
+ },
1013
+ ]);
1014
+ if (assignGateway) {
1015
+ // Try to offer a list of gateways (via service), else fallback to manual input
1016
+ try {
1017
+ const gatewaysResp = await gatewayService.listGateways();
1018
+ const gatewayChoices = gatewaysResp.gateways.map((g) => ({
1019
+ name: `${g.device.name} (${g.device.id})`,
1020
+ value: g.device.id,
1021
+ }));
1022
+ if (gatewayChoices.length > 0) {
1023
+ const { selectedGateways } = await inquirer_1.default.prompt([
1024
+ {
1025
+ type: 'checkbox',
1026
+ name: 'selectedGateways',
1027
+ message: 'Select gateway device(s):',
1028
+ choices: gatewayChoices,
1029
+ validate: (vals) => vals.length > 0 ? true : 'Select at least one gateway',
1030
+ },
1031
+ ]);
1032
+ gatewayIds = selectedGateways;
1033
+ }
1034
+ }
1035
+ catch (error) {
1036
+ logger.warn('Failed to list gateways', error);
1037
+ }
1038
+ if (gatewayIds.length === 0) {
1039
+ const ans2 = await inquirer_1.default.prompt([
938
1040
  {
939
- type: 'checkbox',
940
- name: 'selectedGateways',
941
- message: 'Select gateway device(s):',
942
- choices: gatewayChoices,
943
- validate: (vals) => vals.length > 0 ? true : 'Select at least one gateway',
1041
+ type: 'input',
1042
+ name: 'gatewayIds',
1043
+ message: 'Enter comma-separated gateway device IDs (or leave empty for no gateway):',
1044
+ validate: (v) => true, // Allow empty input
944
1045
  },
945
1046
  ]);
946
- gatewayIds = selectedGateways;
1047
+ if (ans2.gatewayIds && ans2.gatewayIds.trim()) {
1048
+ gatewayIds = (0, input_parser_1.parseGatewayIds)(ans2.gatewayIds);
1049
+ }
947
1050
  }
948
1051
  }
949
- catch (error) {
950
- logger.warn('Failed to list gateways', error);
951
- }
952
- if (gatewayIds.length === 0) {
953
- const ans2 = await inquirer_1.default.prompt([
954
- {
955
- type: 'input',
956
- name: 'gatewayIds',
957
- message: 'Enter comma-separated gateway device IDs:',
958
- validate: (v) => v && v.split(',').map((s) => s.trim()).filter(Boolean).length > 0
959
- ? true
960
- : 'At least one gateway ID is required',
961
- },
962
- ]);
963
- gatewayIds = (0, input_parser_1.parseGatewayIds)(ans2.gatewayIds);
1052
+ else {
1053
+ logger.info('Application will be created without gateway assignment (local/internal access only)');
964
1054
  }
965
1055
  }
966
1056
  }
@@ -1017,7 +1107,7 @@ Examples:
1017
1107
  throw new Error('--device-id (serving) is required');
1018
1108
  }
1019
1109
  if (!useManagedGateway && gatewayIds.length === 0) {
1020
- throw new Error('--gateway-ids is required (at least one) or use --use-managed-gateway');
1110
+ logger.warn('No gateways assigned - application will only be accessible locally/internally');
1021
1111
  }
1022
1112
  // Build configuration
1023
1113
  const configuration = {
@@ -1258,5 +1348,534 @@ Examples:
1258
1348
  requireAuth: true,
1259
1349
  requireOrganization: true,
1260
1350
  }));
1351
+ // API Keys subcommand group
1352
+ const apiKeysCommand = appCommand
1353
+ .command('api-keys')
1354
+ .description('Manage application API keys')
1355
+ .alias('keys');
1356
+ apiKeysCommand
1357
+ .command('list')
1358
+ .description('List API keys for an application')
1359
+ .option('-i, --app-id <id>', 'Application ID')
1360
+ .option('--json', 'Output as JSON')
1361
+ .alias('ls')
1362
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
1363
+ const container = (0, container_1.getContainer)();
1364
+ const logger = container.get(types_1.TYPES.Logger);
1365
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
1366
+ const applicationService = container.get(types_1.TYPES.ApplicationService);
1367
+ (0, config_validator_1.validateConfig)(configRepository, {
1368
+ requireAuth: true,
1369
+ requireOrganization: true,
1370
+ });
1371
+ let appId = options.appId;
1372
+ if (!appId) {
1373
+ const applications = await applicationService.getApplications();
1374
+ if (applications.length === 0) {
1375
+ console.log(chalk_1.default.yellow('⚠ No applications configured'));
1376
+ return;
1377
+ }
1378
+ const { selectedAppId } = await inquirer_1.default.prompt([
1379
+ {
1380
+ type: 'list',
1381
+ name: 'selectedAppId',
1382
+ message: 'Select application:',
1383
+ choices: applications.map((app) => ({
1384
+ name: `${app.name} (${app.id})`,
1385
+ value: app.id,
1386
+ })),
1387
+ },
1388
+ ]);
1389
+ appId = selectedAppId;
1390
+ }
1391
+ if (!appId) {
1392
+ throw new Error('Application ID is required');
1393
+ }
1394
+ const keys = await applicationService.listApiKeys(appId);
1395
+ if (options.json) {
1396
+ console.log(JSON.stringify({ keys }, null, 2));
1397
+ return;
1398
+ }
1399
+ if (keys.length === 0) {
1400
+ console.log(chalk_1.default.yellow('⚠ No API keys configured'));
1401
+ console.log(chalk_1.default.gray('Use "edgible application api-keys create" to create an API key'));
1402
+ return;
1403
+ }
1404
+ console.log(chalk_1.default.bold('\n🔑 API Keys:\n'));
1405
+ keys.forEach((key, index) => {
1406
+ console.log(`${index + 1}. ${chalk_1.default.cyan(key.name)}`);
1407
+ console.log(` ID: ${chalk_1.default.gray(key.id)}`);
1408
+ console.log(` Prefix: ${chalk_1.default.gray(key.keyPrefix)}`);
1409
+ console.log(` Created: ${chalk_1.default.gray(new Date(key.createdAt).toLocaleString())}`);
1410
+ console.log(` Status: ${key.enabled ? chalk_1.default.green('Enabled') : chalk_1.default.red('Disabled')}`);
1411
+ if (key.expiresAt) {
1412
+ console.log(` Expires: ${chalk_1.default.gray(new Date(key.expiresAt).toLocaleString())}`);
1413
+ }
1414
+ if (key.lastUsedAt) {
1415
+ console.log(` Last used: ${chalk_1.default.gray(new Date(key.lastUsedAt).toLocaleString())}`);
1416
+ }
1417
+ console.log();
1418
+ });
1419
+ }, {
1420
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
1421
+ requireAuth: true,
1422
+ requireOrganization: true,
1423
+ }));
1424
+ apiKeysCommand
1425
+ .command('create')
1426
+ .description('Create a new API key')
1427
+ .option('-i, --app-id <id>', 'Application ID')
1428
+ .option('-n, --name <name>', 'Key name')
1429
+ .option('--expires <date>', 'Expiration date (ISO format)')
1430
+ .alias('new')
1431
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
1432
+ const container = (0, container_1.getContainer)();
1433
+ const logger = container.get(types_1.TYPES.Logger);
1434
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
1435
+ const applicationService = container.get(types_1.TYPES.ApplicationService);
1436
+ (0, config_validator_1.validateConfig)(configRepository, {
1437
+ requireAuth: true,
1438
+ requireOrganization: true,
1439
+ });
1440
+ let appId = options.appId;
1441
+ if (!appId) {
1442
+ const applications = await applicationService.getApplications();
1443
+ if (applications.length === 0) {
1444
+ console.log(chalk_1.default.yellow('⚠ No applications configured'));
1445
+ return;
1446
+ }
1447
+ const { selectedAppId } = await inquirer_1.default.prompt([
1448
+ {
1449
+ type: 'list',
1450
+ name: 'selectedAppId',
1451
+ message: 'Select application:',
1452
+ choices: applications.map((app) => ({
1453
+ name: `${app.name} (${app.id})`,
1454
+ value: app.id,
1455
+ })),
1456
+ },
1457
+ ]);
1458
+ appId = selectedAppId;
1459
+ }
1460
+ if (!appId) {
1461
+ throw new Error('Application ID is required');
1462
+ }
1463
+ let name = options.name;
1464
+ if (!name) {
1465
+ const { keyName } = await inquirer_1.default.prompt([
1466
+ {
1467
+ type: 'input',
1468
+ name: 'keyName',
1469
+ message: 'Enter a name for this API key:',
1470
+ validate: (input) => input.trim().length > 0 || 'Name is required',
1471
+ },
1472
+ ]);
1473
+ name = keyName;
1474
+ }
1475
+ if (!name) {
1476
+ throw new Error('Name is required');
1477
+ }
1478
+ const result = await applicationService.createApiKey(appId, name, options.expires);
1479
+ console.log(chalk_1.default.green('\n✓ API key created successfully!\n'));
1480
+ console.log(chalk_1.default.bold.red('⚠️ IMPORTANT: Save this API key now. It will not be shown again!\n'));
1481
+ console.log(chalk_1.default.cyan('API Key:'), chalk_1.default.bold(result.apiKey));
1482
+ console.log(chalk_1.default.gray('\nKey Details:'));
1483
+ console.log(` Name: ${result.keyData.name}`);
1484
+ console.log(` Key ID: ${result.keyData.id}`);
1485
+ console.log(` Key Prefix: ${result.keyData.keyPrefix}`);
1486
+ console.log(` Full ID: ${result.keyData.keyPrefix}-${result.keyData.id}`);
1487
+ if (result.keyData.expiresAt) {
1488
+ console.log(` Expires: ${new Date(result.keyData.expiresAt).toLocaleString()}`);
1489
+ }
1490
+ console.log();
1491
+ }, {
1492
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
1493
+ requireAuth: true,
1494
+ requireOrganization: true,
1495
+ }));
1496
+ apiKeysCommand
1497
+ .command('delete')
1498
+ .description('Delete an API key')
1499
+ .option('-i, --app-id <id>', 'Application ID')
1500
+ .option('-k, --key-id <id>', 'API Key ID')
1501
+ .option('-f, --force', 'Skip confirmation prompt')
1502
+ .alias('rm')
1503
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
1504
+ const container = (0, container_1.getContainer)();
1505
+ const logger = container.get(types_1.TYPES.Logger);
1506
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
1507
+ const applicationService = container.get(types_1.TYPES.ApplicationService);
1508
+ (0, config_validator_1.validateConfig)(configRepository, {
1509
+ requireAuth: true,
1510
+ requireOrganization: true,
1511
+ });
1512
+ let appId = options.appId;
1513
+ if (!appId) {
1514
+ const applications = await applicationService.getApplications();
1515
+ if (applications.length === 0) {
1516
+ console.log(chalk_1.default.yellow('⚠ No applications configured'));
1517
+ return;
1518
+ }
1519
+ const { selectedAppId } = await inquirer_1.default.prompt([
1520
+ {
1521
+ type: 'list',
1522
+ name: 'selectedAppId',
1523
+ message: 'Select application:',
1524
+ choices: applications.map((app) => ({
1525
+ name: `${app.name} (${app.id})`,
1526
+ value: app.id,
1527
+ })),
1528
+ },
1529
+ ]);
1530
+ appId = selectedAppId;
1531
+ }
1532
+ if (!appId) {
1533
+ throw new Error('Application ID is required');
1534
+ }
1535
+ let keyId = options.keyId;
1536
+ if (!keyId) {
1537
+ const keys = await applicationService.listApiKeys(appId);
1538
+ if (keys.length === 0) {
1539
+ console.log(chalk_1.default.yellow('⚠ No API keys configured'));
1540
+ return;
1541
+ }
1542
+ const { selectedKeyId } = await inquirer_1.default.prompt([
1543
+ {
1544
+ type: 'list',
1545
+ name: 'selectedKeyId',
1546
+ message: 'Select API key to delete:',
1547
+ choices: keys.map((key) => ({
1548
+ name: `${key.name} (${key.keyPrefix})`,
1549
+ value: key.id,
1550
+ })),
1551
+ },
1552
+ ]);
1553
+ keyId = selectedKeyId;
1554
+ }
1555
+ if (!options.force) {
1556
+ const { confirm } = await inquirer_1.default.prompt([
1557
+ {
1558
+ type: 'confirm',
1559
+ name: 'confirm',
1560
+ message: 'Are you sure you want to delete this API key?',
1561
+ default: false,
1562
+ },
1563
+ ]);
1564
+ if (!confirm) {
1565
+ console.log(chalk_1.default.gray('Deletion cancelled'));
1566
+ return;
1567
+ }
1568
+ }
1569
+ if (!keyId) {
1570
+ throw new Error('Key ID is required');
1571
+ }
1572
+ await applicationService.deleteApiKey(appId, keyId);
1573
+ console.log(chalk_1.default.green('\n✓ API key deleted successfully!'));
1574
+ }, {
1575
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
1576
+ requireAuth: true,
1577
+ requireOrganization: true,
1578
+ }));
1579
+ // Short Codes subcommand group
1580
+ const shortCodesCommand = appCommand
1581
+ .command('short-codes')
1582
+ .description('Manage application short codes')
1583
+ .alias('codes');
1584
+ shortCodesCommand
1585
+ .command('list')
1586
+ .description('List short codes for an application')
1587
+ .option('-i, --app-id <id>', 'Application ID')
1588
+ .option('--json', 'Output as JSON')
1589
+ .alias('ls')
1590
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
1591
+ const container = (0, container_1.getContainer)();
1592
+ const logger = container.get(types_1.TYPES.Logger);
1593
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
1594
+ const applicationService = container.get(types_1.TYPES.ApplicationService);
1595
+ (0, config_validator_1.validateConfig)(configRepository, {
1596
+ requireAuth: true,
1597
+ requireOrganization: true,
1598
+ });
1599
+ let appId = options.appId;
1600
+ if (!appId) {
1601
+ const applications = await applicationService.getApplications();
1602
+ if (applications.length === 0) {
1603
+ console.log(chalk_1.default.yellow('⚠ No applications configured'));
1604
+ return;
1605
+ }
1606
+ const { selectedAppId } = await inquirer_1.default.prompt([
1607
+ {
1608
+ type: 'list',
1609
+ name: 'selectedAppId',
1610
+ message: 'Select application:',
1611
+ choices: applications.map((app) => ({
1612
+ name: `${app.name} (${app.id})`,
1613
+ value: app.id,
1614
+ })),
1615
+ },
1616
+ ]);
1617
+ appId = selectedAppId;
1618
+ }
1619
+ if (!appId) {
1620
+ throw new Error('Application ID is required');
1621
+ }
1622
+ const codes = await applicationService.listShortCodes(appId);
1623
+ if (options.json) {
1624
+ console.log(JSON.stringify({ codes }, null, 2));
1625
+ return;
1626
+ }
1627
+ if (codes.length === 0) {
1628
+ console.log(chalk_1.default.yellow('⚠ No short codes configured'));
1629
+ console.log(chalk_1.default.gray('Use "edgible application short-codes create" to create a short code'));
1630
+ return;
1631
+ }
1632
+ console.log(chalk_1.default.bold('\n🔗 Short Codes:\n'));
1633
+ codes.forEach((code, index) => {
1634
+ console.log(`${index + 1}. ${chalk_1.default.cyan(code.name)}`);
1635
+ console.log(` Code: ${chalk_1.default.bold.green(code.code)}`);
1636
+ console.log(` ID: ${chalk_1.default.gray(code.id)}`);
1637
+ console.log(` Created: ${chalk_1.default.gray(new Date(code.createdAt).toLocaleString())}`);
1638
+ console.log(` Status: ${code.enabled ? chalk_1.default.green('Enabled') : chalk_1.default.red('Disabled')}`);
1639
+ console.log(` Uses: ${chalk_1.default.gray(code.usedCount)}${code.maxUses ? ` / ${code.maxUses}` : ''}`);
1640
+ if (code.expiresAt) {
1641
+ console.log(` Expires: ${chalk_1.default.gray(new Date(code.expiresAt).toLocaleString())}`);
1642
+ }
1643
+ console.log();
1644
+ });
1645
+ }, {
1646
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
1647
+ requireAuth: true,
1648
+ requireOrganization: true,
1649
+ }));
1650
+ shortCodesCommand
1651
+ .command('create')
1652
+ .description('Create a new short code')
1653
+ .option('-i, --app-id <id>', 'Application ID')
1654
+ .option('-n, --name <name>', 'Code name/description')
1655
+ .option('--expires <date>', 'Expiration date (ISO format)')
1656
+ .option('--max-uses <number>', 'Maximum number of uses')
1657
+ .alias('new')
1658
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
1659
+ const container = (0, container_1.getContainer)();
1660
+ const logger = container.get(types_1.TYPES.Logger);
1661
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
1662
+ const applicationService = container.get(types_1.TYPES.ApplicationService);
1663
+ (0, config_validator_1.validateConfig)(configRepository, {
1664
+ requireAuth: true,
1665
+ requireOrganization: true,
1666
+ });
1667
+ let appId = options.appId;
1668
+ if (!appId) {
1669
+ const applications = await applicationService.getApplications();
1670
+ if (applications.length === 0) {
1671
+ console.log(chalk_1.default.yellow('⚠ No applications configured'));
1672
+ return;
1673
+ }
1674
+ const { selectedAppId } = await inquirer_1.default.prompt([
1675
+ {
1676
+ type: 'list',
1677
+ name: 'selectedAppId',
1678
+ message: 'Select application:',
1679
+ choices: applications.map((app) => ({
1680
+ name: `${app.name} (${app.id})`,
1681
+ value: app.id,
1682
+ })),
1683
+ },
1684
+ ]);
1685
+ appId = selectedAppId;
1686
+ }
1687
+ if (!appId) {
1688
+ throw new Error('Application ID is required');
1689
+ }
1690
+ let name = options.name;
1691
+ if (!name) {
1692
+ const { codeName } = await inquirer_1.default.prompt([
1693
+ {
1694
+ type: 'input',
1695
+ name: 'codeName',
1696
+ message: 'Enter a name/description for this short code:',
1697
+ validate: (input) => input.trim().length > 0 || 'Name is required',
1698
+ },
1699
+ ]);
1700
+ name = codeName;
1701
+ }
1702
+ if (!name) {
1703
+ throw new Error('Name is required');
1704
+ }
1705
+ const maxUses = options.maxUses ? parseInt(options.maxUses) : undefined;
1706
+ const code = await applicationService.createShortCode(appId, name, options.expires, maxUses);
1707
+ console.log(chalk_1.default.green('\n✓ Short code created successfully!\n'));
1708
+ console.log(chalk_1.default.bold('Share this code:'), chalk_1.default.bold.green(code.code));
1709
+ console.log(chalk_1.default.gray('\nCode Details:'));
1710
+ console.log(` Name: ${code.name}`);
1711
+ console.log(` ID: ${code.id}`);
1712
+ if (code.maxUses) {
1713
+ console.log(` Max uses: ${code.maxUses}`);
1714
+ }
1715
+ if (code.expiresAt) {
1716
+ console.log(` Expires: ${new Date(code.expiresAt).toLocaleString()}`);
1717
+ }
1718
+ console.log();
1719
+ }, {
1720
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
1721
+ requireAuth: true,
1722
+ requireOrganization: true,
1723
+ }));
1724
+ shortCodesCommand
1725
+ .command('delete')
1726
+ .description('Delete a short code')
1727
+ .option('-i, --app-id <id>', 'Application ID')
1728
+ .option('-c, --code-id <id>', 'Short Code ID')
1729
+ .option('-f, --force', 'Skip confirmation prompt')
1730
+ .alias('rm')
1731
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
1732
+ const container = (0, container_1.getContainer)();
1733
+ const logger = container.get(types_1.TYPES.Logger);
1734
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
1735
+ const applicationService = container.get(types_1.TYPES.ApplicationService);
1736
+ (0, config_validator_1.validateConfig)(configRepository, {
1737
+ requireAuth: true,
1738
+ requireOrganization: true,
1739
+ });
1740
+ let appId = options.appId;
1741
+ if (!appId) {
1742
+ const applications = await applicationService.getApplications();
1743
+ if (applications.length === 0) {
1744
+ console.log(chalk_1.default.yellow('⚠ No applications configured'));
1745
+ return;
1746
+ }
1747
+ const { selectedAppId } = await inquirer_1.default.prompt([
1748
+ {
1749
+ type: 'list',
1750
+ name: 'selectedAppId',
1751
+ message: 'Select application:',
1752
+ choices: applications.map((app) => ({
1753
+ name: `${app.name} (${app.id})`,
1754
+ value: app.id,
1755
+ })),
1756
+ },
1757
+ ]);
1758
+ appId = selectedAppId;
1759
+ }
1760
+ if (!appId) {
1761
+ throw new Error('Application ID is required');
1762
+ }
1763
+ let codeId = options.codeId;
1764
+ if (!codeId) {
1765
+ const codes = await applicationService.listShortCodes(appId);
1766
+ if (codes.length === 0) {
1767
+ console.log(chalk_1.default.yellow('⚠ No short codes configured'));
1768
+ return;
1769
+ }
1770
+ const { selectedCodeId } = await inquirer_1.default.prompt([
1771
+ {
1772
+ type: 'list',
1773
+ name: 'selectedCodeId',
1774
+ message: 'Select short code to delete:',
1775
+ choices: codes.map((code) => ({
1776
+ name: `${code.name} (${code.code})`,
1777
+ value: code.id,
1778
+ })),
1779
+ },
1780
+ ]);
1781
+ codeId = selectedCodeId;
1782
+ }
1783
+ if (!options.force) {
1784
+ const { confirm } = await inquirer_1.default.prompt([
1785
+ {
1786
+ type: 'confirm',
1787
+ name: 'confirm',
1788
+ message: 'Are you sure you want to delete this short code?',
1789
+ default: false,
1790
+ },
1791
+ ]);
1792
+ if (!confirm) {
1793
+ console.log(chalk_1.default.gray('Deletion cancelled'));
1794
+ return;
1795
+ }
1796
+ }
1797
+ if (!codeId) {
1798
+ throw new Error('Code ID is required');
1799
+ }
1800
+ await applicationService.deleteShortCode(appId, codeId);
1801
+ console.log(chalk_1.default.green('\n✓ Short code deleted successfully!'));
1802
+ }, {
1803
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
1804
+ requireAuth: true,
1805
+ requireOrganization: true,
1806
+ }));
1807
+ shortCodesCommand
1808
+ .command('toggle')
1809
+ .description('Enable or disable a short code')
1810
+ .option('-i, --app-id <id>', 'Application ID')
1811
+ .option('-c, --code-id <id>', 'Short Code ID')
1812
+ .action((0, command_wrapper_1.wrapCommand)(async (options) => {
1813
+ const container = (0, container_1.getContainer)();
1814
+ const logger = container.get(types_1.TYPES.Logger);
1815
+ const configRepository = container.get(types_1.TYPES.ConfigRepository);
1816
+ const applicationService = container.get(types_1.TYPES.ApplicationService);
1817
+ (0, config_validator_1.validateConfig)(configRepository, {
1818
+ requireAuth: true,
1819
+ requireOrganization: true,
1820
+ });
1821
+ let appId = options.appId;
1822
+ if (!appId) {
1823
+ const applications = await applicationService.getApplications();
1824
+ if (applications.length === 0) {
1825
+ console.log(chalk_1.default.yellow('⚠ No applications configured'));
1826
+ return;
1827
+ }
1828
+ const { selectedAppId } = await inquirer_1.default.prompt([
1829
+ {
1830
+ type: 'list',
1831
+ name: 'selectedAppId',
1832
+ message: 'Select application:',
1833
+ choices: applications.map((app) => ({
1834
+ name: `${app.name} (${app.id})`,
1835
+ value: app.id,
1836
+ })),
1837
+ },
1838
+ ]);
1839
+ appId = selectedAppId;
1840
+ }
1841
+ if (!appId) {
1842
+ throw new Error('Application ID is required');
1843
+ }
1844
+ let codeId = options.codeId;
1845
+ if (!codeId) {
1846
+ const codes = await applicationService.listShortCodes(appId);
1847
+ if (codes.length === 0) {
1848
+ console.log(chalk_1.default.yellow('⚠ No short codes configured'));
1849
+ return;
1850
+ }
1851
+ const { selectedCodeId } = await inquirer_1.default.prompt([
1852
+ {
1853
+ type: 'list',
1854
+ name: 'selectedCodeId',
1855
+ message: 'Select short code to toggle:',
1856
+ choices: codes.map((code) => ({
1857
+ name: `${code.name} (${code.code}) - ${code.enabled ? 'Enabled' : 'Disabled'}`,
1858
+ value: code.id,
1859
+ })),
1860
+ },
1861
+ ]);
1862
+ codeId = selectedCodeId;
1863
+ }
1864
+ if (!codeId || !appId) {
1865
+ throw new Error('Application ID and Code ID are required');
1866
+ }
1867
+ // Get current status
1868
+ const codes = await applicationService.listShortCodes(appId);
1869
+ const code = codes.find((c) => c.id === codeId);
1870
+ if (!code) {
1871
+ throw new Error('Short code not found');
1872
+ }
1873
+ await applicationService.updateShortCode(appId, codeId, { enabled: !code.enabled });
1874
+ console.log(chalk_1.default.green(`\n✓ Short code ${code.enabled ? 'disabled' : 'enabled'} successfully!`));
1875
+ }, {
1876
+ configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
1877
+ requireAuth: true,
1878
+ requireOrganization: true,
1879
+ }));
1261
1880
  }
1262
1881
  //# sourceMappingURL=application.js.map