feat(sdk): confirm authentication method on remote add (#19947)
## Summary `yarn twenty remote add` only prints `✓ Default remote set to X.` after authenticating. When using the OAuth path, the browser flow happens silently — there's no line that says _"you authenticated"_ — so users (including me this morning while installing a Twenty app) are left wondering whether auth actually completed and which method was used. This PR adds explicit confirmation of the auth step: **New remote via OAuth** ``` ✓ Remote "myremote" added (https://app.twenty.com) via OAuth. ✓ Default remote set to "myremote". ``` **New remote via API key** ``` ✓ Remote "myremote" added (https://app.twenty.com) via API key. ✓ Default remote set to "myremote". ``` **Re-authenticating an existing remote** ``` ✓ Re-authenticated "myremote" via OAuth. ✓ Default remote set to "myremote". ``` ## Implementation - `authenticate()` now returns the method actually used (`'OAuth' | 'API key'`) instead of `void`. This correctly surfaces OAuth → API-key fallback: if OAuth fails and the user drops into the API-key prompt, the success line reflects that. - New-remote and re-auth paths print distinct messages so the user can tell which path they took. - No new API calls — method name comes from which branch of `authenticate()` succeeded. ## Test plan - [x] `nx typecheck twenty-sdk` — clean - [x] `nx lint twenty-sdk` — clean - [ ] Manual smoke test: `yarn twenty remote add --as test --api-url ...` via OAuth, API key, and re-auth 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
@@ -18,20 +18,29 @@ const deriveRemoteName = (url: string): string => {
|
||||
}
|
||||
};
|
||||
|
||||
const authenticate = async (apiUrl: string, apiKey?: string): Promise<void> => {
|
||||
const result = apiKey
|
||||
? await authLogin({ apiKey, apiUrl })
|
||||
: await runOAuthWithApiKeyFallback(apiUrl);
|
||||
type AuthMethod = 'OAuth' | 'API key';
|
||||
|
||||
if (!result.success) {
|
||||
console.error(chalk.red('✗ Authentication failed.'));
|
||||
process.exit(1);
|
||||
const authenticate = async (
|
||||
apiUrl: string,
|
||||
apiKey?: string,
|
||||
): Promise<AuthMethod> => {
|
||||
if (apiKey) {
|
||||
const result = await authLogin({ apiKey, apiUrl });
|
||||
|
||||
if (!result.success) {
|
||||
console.error(chalk.red('✗ Authentication failed.'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return 'API key';
|
||||
}
|
||||
|
||||
return runOAuthWithApiKeyFallback(apiUrl);
|
||||
};
|
||||
|
||||
const runOAuthWithApiKeyFallback = async (
|
||||
apiUrl: string,
|
||||
): Promise<{ success: boolean }> => {
|
||||
): Promise<AuthMethod> => {
|
||||
await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
@@ -43,7 +52,7 @@ const runOAuthWithApiKeyFallback = async (
|
||||
const oauthResult = await authLoginOAuth({ apiUrl });
|
||||
|
||||
if (oauthResult.success) {
|
||||
return oauthResult;
|
||||
return 'OAuth';
|
||||
}
|
||||
|
||||
console.log(chalk.yellow(oauthResult.error.message));
|
||||
@@ -58,7 +67,17 @@ const runOAuthWithApiKeyFallback = async (
|
||||
},
|
||||
]);
|
||||
|
||||
return authLogin({ apiKey: keyAnswer.apiKey, apiUrl });
|
||||
const fallbackResult = await authLogin({
|
||||
apiKey: keyAnswer.apiKey,
|
||||
apiUrl,
|
||||
});
|
||||
|
||||
if (!fallbackResult.success) {
|
||||
console.error(chalk.red('✗ Authentication failed.'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return 'API key';
|
||||
};
|
||||
|
||||
export const registerRemoteCommands = (program: Command): void => {
|
||||
@@ -92,7 +111,11 @@ export const registerRemoteCommands = (program: Command): void => {
|
||||
const config = await configService.getConfigForRemote(options.as);
|
||||
|
||||
ConfigService.setActiveRemote(options.as);
|
||||
await authenticate(config.apiUrl, options.apiKey);
|
||||
const method = await authenticate(config.apiUrl, options.apiKey);
|
||||
|
||||
console.log(
|
||||
chalk.green(`✓ Re-authenticated "${options.as}" via ${method}.`),
|
||||
);
|
||||
|
||||
await configService.setDefaultRemote(options.as);
|
||||
console.log(chalk.green(`✓ Default remote set to "${options.as}".`));
|
||||
@@ -143,7 +166,11 @@ export const registerRemoteCommands = (program: Command): void => {
|
||||
const name = options.as ?? deriveRemoteName(apiUrl);
|
||||
|
||||
ConfigService.setActiveRemote(name);
|
||||
await authenticate(apiUrl, options.apiKey);
|
||||
const method = await authenticate(apiUrl, options.apiKey);
|
||||
|
||||
console.log(
|
||||
chalk.green(`✓ Remote "${name}" added (${apiUrl}) via ${method}.`),
|
||||
);
|
||||
|
||||
await configService.setDefaultRemote(name);
|
||||
console.log(chalk.green(`✓ Default remote set to "${name}".`));
|
||||
|
||||
Reference in New Issue
Block a user