Files
twenty/packages/twenty-sdk/src/cli/utilities/auth/ensure-app-registration.ts
T

80 lines
2.4 KiB
TypeScript

import { type ApiService } from '@/cli/utilities/api/api-service';
import { type ConfigService } from '@/cli/utilities/config/config-service';
import { hasGraphQLErrorSubCode } from '@/cli/utilities/error/parse-server-error';
export const ensureAppRegistration = async (
apiService: ApiService,
configService: ConfigService,
app: { name: string; universalIdentifier: string },
): Promise<{
clientId: string;
clientSecret?: string;
isNewRegistration: boolean;
}> => {
const createResult = await apiService.createApplicationRegistration({
name: app.name,
universalIdentifier: app.universalIdentifier,
});
if (createResult.success) {
const { applicationRegistration, clientSecret } = createResult.data;
await configService.setConfig({
appRegistrationId: applicationRegistration.id,
appRegistrationClientId: applicationRegistration.oAuthClientId,
appAccessToken: undefined,
appRefreshToken: undefined,
});
return {
clientId: applicationRegistration.oAuthClientId,
clientSecret,
isNewRegistration: true,
};
}
const isAlreadyClaimed = hasGraphQLErrorSubCode(
createResult.error,
'UNIVERSAL_IDENTIFIER_ALREADY_CLAIMED',
);
if (!isAlreadyClaimed) {
const errorDetail =
createResult.error instanceof Error
? createResult.error.message
: ((createResult.error as { message?: string })?.message ??
String(createResult.error));
throw new Error(`Failed to create app registration: ${errorDetail}`);
}
const findResult =
await apiService.findApplicationRegistrationByUniversalIdentifier(
app.universalIdentifier,
);
if (!findResult.success || !findResult.data) {
throw new Error(
`App registration exists but could not be found: ${app.universalIdentifier}`,
);
}
const registration = findResult.data;
await configService.setConfig({
appRegistrationId: registration.id,
appRegistrationClientId: registration.oAuthClientId,
appAccessToken: undefined,
appRefreshToken: undefined,
});
// The registration may be a catalog-synced npm app owned by another (or no)
// workspace, so rotating its shared client secret is neither allowed nor
// desirable. Dev mode mints workspace-scoped app tokens via the
// generateApplicationToken mutation instead.
return {
clientId: registration.oAuthClientId,
isNewRegistration: false,
};
};