run method
Runs this command.
The return value is wrapped in a Future if necessary and returned by
CommandRunner.runCommand.
Implementation
@override
Future<void> run() async {
stdout.writeln('Generate a key in the mobile app → Settings → API Keys.');
stdout.write('Paste your API key: ');
// Disable echo so the key isn't visible in the terminal
try {
stdin.echoMode = false;
} catch (_) {
// echoMode not supported in all environments — continue anyway
}
final rawKey = stdin.readLineSync()?.trim() ?? '';
try {
stdin.echoMode = true;
} catch (_) {}
stdout.writeln('');
if (rawKey.isEmpty) {
AppLogger.error('No key entered.');
exit(ExitCodes.usage);
}
if (!rawKey.startsWith('appflight_')) {
AppLogger.error('Invalid format. Keys must start with "appflight_".');
exit(ExitCodes.authRejected);
}
AppLogger.info('Verifying key…');
try {
final dio = ApiClient.instance.forKey(rawKey);
final resp = await dio.get(Endpoints.whoami);
final data = resp.data['data'] as Map<String, dynamic>;
final creds = Credentials(
apiKey: rawKey,
uid: data['uid'] as String? ?? '',
email: data['email'] as String? ?? '',
);
creds.save();
AppLogger.success('Logged in as ${creds.email}');
} on DioException catch (e) {
final status = e.response?.statusCode;
if (status == 401 || status == 403) {
AppLogger.error('Key rejected. Check it and try again.');
exit(ExitCodes.authRejected);
}
AppLogger.error('Network error: ${e.message}');
exit(ExitCodes.usage);
}
}