import { TokenResult, getServiceAccountToken } from '@axinom/mosaic-id-link-be'; import { isNullOrWhitespace } from '@axinom/mosaic-service-common'; import axios, { AxiosError } from 'axios'; import FormData from 'form-data'; import { createReadStream, existsSync, lstatSync, readdirSync } from 'fs'; import * as path from 'path'; import { exitCode } from '../../../common'; import { GetRegisterPiletOptions } from './register-pilet-options'; export const registerPilet = async ( args: Required, ): Promise => { let serviceAccountToken: TokenResult | undefined; try { serviceAccountToken = await getServiceAccountToken( args.idServiceAuthBaseURL, args.mosaicHostingClientId, args.mosaicHostingClientSecret, ); } catch (error) { console.log( `\nFailed to get the service account token. ${ (error as Error).message }\n`, ); return; } // Extract the tenant/environment IDs from the access token const { tenantId, environmentId } = JSON.parse( Buffer.from( serviceAccountToken.accessToken.split('.')[1], 'base64', ).toString(), ) as { tenantId: string; environmentId: string }; const data = new FormData(); const config = { maxBodyLength: 52428890, // 50MB headers: { Authorization: `Bearer ${serviceAccountToken.accessToken}`, ...data.getHeaders(), }, }; try { const artifactToPublish = findArtifactToPublish(args.piletArtifactPath); data.append('', createReadStream(artifactToPublish)); } catch (error) { console.log(`\n${(error as Error).message}`); return; } try { console.log(`\nRegistering pilet...`); console.log(`path:\t\t${args.piletArtifactPath}`); console.log(`tenantId:\t${tenantId}`); console.log(`environmentId:\t${environmentId}`); console.log(`serviceId:\t${args.serviceId}\n`); const result = await axios.post( `${args.microFrontendServiceBaseURL}/v1/pilets/${tenantId}/${environmentId}/${args.serviceId}/register?override=${args.overrideRegistration}`, data, config, ); console.log('Registration of Pilet complete.'); console.log(result.data); } catch (error) { const data = (error as AxiosError).response?.data as any; console.log('Registration of Pilet failed.', { success: false, message: data?.originalError ? data?.originalError : data?.message, }); process.exit(exitCode); } }; /** * Method that validates the arguments. * We're using this to allow both input arguments and environment variables. * * @param args * @returns */ export const validateArgs = ( args: GetRegisterPiletOptions, ): [Required, string[]] => { const errorMessages: string[] = []; const idServiceAuthBaseURL = args.idServiceAuthBaseURL ?? process.env.ID_SERVICE_AUTH_BASE_URL ?? ''; const mosaicHostingClientId = args.mosaicHostingClientId ?? process.env.MOSAIC_HOSTING_CLIENT_ID ?? ''; const mosaicHostingClientSecret = args.mosaicHostingClientSecret ?? process.env.MOSAIC_HOSTING_CLIENT_SECRET ?? ''; const serviceId = args.serviceId ?? process.env.SERVICE_ID ?? ''; const piletArtifactPath = args.piletArtifactPath ?? process.env.PILET_PATH ?? ''; const microFrontendServiceBaseURL = args.microFrontendServiceBaseURL ?? process.env.MICRO_FRONTEND_SERVICE_BASE_URL ?? ''; if (isNullOrWhitespace(idServiceAuthBaseURL)) { errorMessages.push('[idServiceAuthBaseURL] is required.'); } if (isNullOrWhitespace(mosaicHostingClientId)) { errorMessages.push('[clientId] is required.'); } if (isNullOrWhitespace(mosaicHostingClientSecret)) { errorMessages.push('[clientSecret] is required.'); } if (isNullOrWhitespace(serviceId)) { errorMessages.push('[serviceId] is required.'); } if (isNullOrWhitespace(piletArtifactPath)) { errorMessages.push('[piletArtifactPath] is required,'); } if (isNullOrWhitespace(microFrontendServiceBaseURL)) { errorMessages.push('[microFrontendServiceBaseURL] is required.'); } return [ { idServiceAuthBaseURL, mosaicHostingClientId, mosaicHostingClientSecret, serviceId, piletArtifactPath, microFrontendServiceBaseURL, overrideRegistration: args.overrideRegistration ?? false, }, errorMessages, ]; }; const findArtifactToPublish = (piletPath: string): string => { if (!existsSync(piletPath)) { throw new Error( `The specified pilet artifact path [${piletPath}] does not exist.`, ); } const tgzFiles: string[] = []; // Is the path a directory? if (lstatSync(piletPath).isDirectory()) { const files = readdirSync(piletPath); for (let i = 0; i < files.length; i++) { const filename = path.join(piletPath, files[i]); const stat = lstatSync(filename); if (!stat.isDirectory() && filename.endsWith('.tgz')) { tgzFiles.push(filename); } } } // Path is a file else { tgzFiles.push(piletPath); } if (tgzFiles.length > 1) { throw new Error( `Found more than one .tgz files in the folder [${piletPath}]. Please make sure only one .tgz file exists or specify the path to the .tgz file.`, ); } if (tgzFiles.length === 0) { throw new Error( `No .tgz files found at pilet artifact path [${piletPath}].`, ); } return tgzFiles[0]; };