offerCreateIfUnknown function

Future<void> offerCreateIfUnknown({
  1. required String packageName,
  2. required bool isCI,
  3. required bool hasTerminal,
  4. String? configDir,
  5. Dio? apiDio,
  6. String readAnswer()?,
})

Offers to create an unknown package on AppFlight from init (#30), via AppsService.ins.create.

init makes zero network calls today — isCI/hasTerminal are checked FIRST, before Credentials.load() and before any Dio is built, so a scripted init under CI gets no new HTTP call, no new latency, and no new failure mode. Taken as parameters rather than read from Platform.environment/stdin internally, the way util/terms_acceptance.dart takes hasTerminal — so the test drives both without a subprocess.

configDir, apiDio and readAnswer exist only for init_offer_test.dart — production callers never pass them, so real credentials, a real Dio, and real stdin are untouched.

Everything past the CI/terminal check is wrapped in a catch-all that logs and returns rather than throwing — the one place in this ticket where swallowing an error is correct: writing appflight.json must never fail because this offer's own network call did.

Implementation

Future<void> offerCreateIfUnknown({
  required String packageName,
  required bool isCI,
  required bool hasTerminal,
  String? configDir,
  Dio? apiDio,
  String Function()? readAnswer,
}) async {
  if (isCI || !hasTerminal) return;

  final creds = Credentials.load(configDir: configDir);
  if (creds == null) {
    AppLogger.info(loginNudge);
    return;
  }

  try {
    final dio = apiDio ?? ApiClient.instance.forKey(creds.apiKey);
    final isRegistered = await AppsService.ins
        .isRegistered(apiDio: dio, packageName: packageName);
    if (isRegistered) return;

    stdout.write(createPromptText(packageName));
    final answer = (readAnswer ?? _readStdinAnswer)();
    if (answer != 'y' && answer != 'yes') return;

    final created = await AppsService.ins.create(
      apiDio: dio,
      name: packageName,
      packageName: packageName,
    );
    AppLogger.success('Created app: ${created['id']}');
  } catch (e) {
    AppLogger.debug('offerCreateIfUnknown($packageName): $e');
  }
}