runAiinConnectCliFlow function
Runs the full AIIN connect flow for CLI/desktop hosts:
- binds the loopback callback server (ephemeral port),
- initiates the OAuth proxy flow for
provider, - opens the system browser at the sign-in URL (
openBrowserFn), - catches the redirect, exchanges the code for JWTs,
- registers an API key with the access JWT.
Returns null on timeout/cancel or a reported service error (status is
printed through onStatus); throws AiinAuthException never — service
failures surface through onStatus so callers can treat null as "not
connected".
Implementation
Future<AiinConnectResult?> runAiinConnectCliFlow({
required void Function(String) onStatus,
Future<bool> Function(String) openBrowserFn = openBrowser,
http.Client? client,
String authBaseUrl = aiinAuthBaseUrl,
Duration timeout = const Duration(minutes: 5),
}) async {
final server = AiinCallbackServer();
final redirectUri = await server.start(timeout: timeout);
try {
// The hosted sign-in page: AIIN lists every provider, runs the whole
// round-trip (silent for an existing session) and redirects back with
// the code + our state.
final state = aiinGenerateState();
final loginUrl = buildAiinLoginUrl(
redirectUri: redirectUri,
state: state,
clientType: 'desktop',
authBaseUrl: authBaseUrl,
);
onStatus('listening for the AIIN callback on $redirectUri');
await _openAiinBrowser(loginUrl.toString(), openBrowserFn, onStatus);
final callback = await server.waitForCallback();
return await _settleAiinCallback(
callback,
state,
client: client,
authBaseUrl: authBaseUrl,
onStatus: onStatus,
);
} on AiinAuthException catch (error) {
onStatus('AIIN sign-in failed: ${error.message}');
return null;
} finally {
await server.close();
}
}